1*ae8c08e7SSimon J. Gerraty /*
2*ae8c08e7SSimon J. Gerraty * Copyright (c) 2016 Thomas Pornin <[email protected]>
3*ae8c08e7SSimon J. Gerraty *
4*ae8c08e7SSimon J. Gerraty * Permission is hereby granted, free of charge, to any person obtaining
5*ae8c08e7SSimon J. Gerraty * a copy of this software and associated documentation files (the
6*ae8c08e7SSimon J. Gerraty * "Software"), to deal in the Software without restriction, including
7*ae8c08e7SSimon J. Gerraty * without limitation the rights to use, copy, modify, merge, publish,
8*ae8c08e7SSimon J. Gerraty * distribute, sublicense, and/or sell copies of the Software, and to
9*ae8c08e7SSimon J. Gerraty * permit persons to whom the Software is furnished to do so, subject to
10*ae8c08e7SSimon J. Gerraty * the following conditions:
11*ae8c08e7SSimon J. Gerraty *
12*ae8c08e7SSimon J. Gerraty * The above copyright notice and this permission notice shall be
13*ae8c08e7SSimon J. Gerraty * included in all copies or substantial portions of the Software.
14*ae8c08e7SSimon J. Gerraty *
15*ae8c08e7SSimon J. Gerraty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*ae8c08e7SSimon J. Gerraty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*ae8c08e7SSimon J. Gerraty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*ae8c08e7SSimon J. Gerraty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19*ae8c08e7SSimon J. Gerraty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20*ae8c08e7SSimon J. Gerraty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21*ae8c08e7SSimon J. Gerraty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*ae8c08e7SSimon J. Gerraty * SOFTWARE.
23*ae8c08e7SSimon J. Gerraty */
24*ae8c08e7SSimon J. Gerraty
25*ae8c08e7SSimon J. Gerraty #include <stdio.h>
26*ae8c08e7SSimon J. Gerraty #include <stdlib.h>
27*ae8c08e7SSimon J. Gerraty #include <string.h>
28*ae8c08e7SSimon J. Gerraty #include <stdint.h>
29*ae8c08e7SSimon J. Gerraty #include <errno.h>
30*ae8c08e7SSimon J. Gerraty #include <signal.h>
31*ae8c08e7SSimon J. Gerraty
32*ae8c08e7SSimon J. Gerraty #include <sys/types.h>
33*ae8c08e7SSimon J. Gerraty #include <sys/socket.h>
34*ae8c08e7SSimon J. Gerraty #include <netdb.h>
35*ae8c08e7SSimon J. Gerraty #include <netinet/in.h>
36*ae8c08e7SSimon J. Gerraty #include <arpa/inet.h>
37*ae8c08e7SSimon J. Gerraty #include <unistd.h>
38*ae8c08e7SSimon J. Gerraty
39*ae8c08e7SSimon J. Gerraty #include "bearssl.h"
40*ae8c08e7SSimon J. Gerraty
41*ae8c08e7SSimon J. Gerraty /*
42*ae8c08e7SSimon J. Gerraty * This sample code can use three possible certificate chains:
43*ae8c08e7SSimon J. Gerraty * -- A full-RSA chain (server key is RSA, certificates are signed with RSA)
44*ae8c08e7SSimon J. Gerraty * -- A full-EC chain (server key is EC, certificates are signed with ECDSA)
45*ae8c08e7SSimon J. Gerraty * -- A mixed chain (server key is EC, certificates are signed with RSA)
46*ae8c08e7SSimon J. Gerraty *
47*ae8c08e7SSimon J. Gerraty * The macros below define which chain is selected. This impacts the list
48*ae8c08e7SSimon J. Gerraty * of supported cipher suites.
49*ae8c08e7SSimon J. Gerraty *
50*ae8c08e7SSimon J. Gerraty * Other macros, which can be defined (with a non-zero value):
51*ae8c08e7SSimon J. Gerraty *
52*ae8c08e7SSimon J. Gerraty * SERVER_PROFILE_MIN_FS
53*ae8c08e7SSimon J. Gerraty * Select a "minimal" profile with forward security (ECDHE cipher
54*ae8c08e7SSimon J. Gerraty * suite).
55*ae8c08e7SSimon J. Gerraty *
56*ae8c08e7SSimon J. Gerraty * SERVER_PROFILE_MIN_NOFS
57*ae8c08e7SSimon J. Gerraty * Select a "minimal" profile without forward security (RSA or ECDH
58*ae8c08e7SSimon J. Gerraty * cipher suite, but not ECDHE).
59*ae8c08e7SSimon J. Gerraty *
60*ae8c08e7SSimon J. Gerraty * SERVER_CHACHA20
61*ae8c08e7SSimon J. Gerraty * If SERVER_PROFILE_MIN_FS is selected, then this macro selects
62*ae8c08e7SSimon J. Gerraty * a cipher suite with ChaCha20+Poly1305; otherwise, AES/GCM is
63*ae8c08e7SSimon J. Gerraty * used. This macro has no effect otherwise, since there is no
64*ae8c08e7SSimon J. Gerraty * non-forward secure cipher suite that uses ChaCha20+Poly1305.
65*ae8c08e7SSimon J. Gerraty */
66*ae8c08e7SSimon J. Gerraty
67*ae8c08e7SSimon J. Gerraty #if !(SERVER_RSA || SERVER_EC || SERVER_MIXED)
68*ae8c08e7SSimon J. Gerraty #define SERVER_RSA 1
69*ae8c08e7SSimon J. Gerraty #define SERVER_EC 0
70*ae8c08e7SSimon J. Gerraty #define SERVER_MIXED 0
71*ae8c08e7SSimon J. Gerraty #endif
72*ae8c08e7SSimon J. Gerraty
73*ae8c08e7SSimon J. Gerraty #if SERVER_RSA
74*ae8c08e7SSimon J. Gerraty #include "chain-rsa.h"
75*ae8c08e7SSimon J. Gerraty #include "key-rsa.h"
76*ae8c08e7SSimon J. Gerraty #define SKEY RSA
77*ae8c08e7SSimon J. Gerraty #elif SERVER_EC
78*ae8c08e7SSimon J. Gerraty #include "chain-ec.h"
79*ae8c08e7SSimon J. Gerraty #include "key-ec.h"
80*ae8c08e7SSimon J. Gerraty #define SKEY EC
81*ae8c08e7SSimon J. Gerraty #elif SERVER_MIXED
82*ae8c08e7SSimon J. Gerraty #include "chain-ec+rsa.h"
83*ae8c08e7SSimon J. Gerraty #include "key-ec.h"
84*ae8c08e7SSimon J. Gerraty #define SKEY EC
85*ae8c08e7SSimon J. Gerraty #else
86*ae8c08e7SSimon J. Gerraty #error Must use one of RSA, EC or MIXED chains.
87*ae8c08e7SSimon J. Gerraty #endif
88*ae8c08e7SSimon J. Gerraty
89*ae8c08e7SSimon J. Gerraty /*
90*ae8c08e7SSimon J. Gerraty * Create a server socket bound to the specified host and port. If 'host'
91*ae8c08e7SSimon J. Gerraty * is NULL, this will bind "generically" (all addresses).
92*ae8c08e7SSimon J. Gerraty *
93*ae8c08e7SSimon J. Gerraty * Returned value is the server socket descriptor, or -1 on error.
94*ae8c08e7SSimon J. Gerraty */
95*ae8c08e7SSimon J. Gerraty static int
host_bind(const char * host,const char * port)96*ae8c08e7SSimon J. Gerraty host_bind(const char *host, const char *port)
97*ae8c08e7SSimon J. Gerraty {
98*ae8c08e7SSimon J. Gerraty struct addrinfo hints, *si, *p;
99*ae8c08e7SSimon J. Gerraty int fd;
100*ae8c08e7SSimon J. Gerraty int err;
101*ae8c08e7SSimon J. Gerraty
102*ae8c08e7SSimon J. Gerraty memset(&hints, 0, sizeof hints);
103*ae8c08e7SSimon J. Gerraty hints.ai_family = PF_UNSPEC;
104*ae8c08e7SSimon J. Gerraty hints.ai_socktype = SOCK_STREAM;
105*ae8c08e7SSimon J. Gerraty err = getaddrinfo(host, port, &hints, &si);
106*ae8c08e7SSimon J. Gerraty if (err != 0) {
107*ae8c08e7SSimon J. Gerraty fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
108*ae8c08e7SSimon J. Gerraty gai_strerror(err));
109*ae8c08e7SSimon J. Gerraty return -1;
110*ae8c08e7SSimon J. Gerraty }
111*ae8c08e7SSimon J. Gerraty fd = -1;
112*ae8c08e7SSimon J. Gerraty for (p = si; p != NULL; p = p->ai_next) {
113*ae8c08e7SSimon J. Gerraty struct sockaddr *sa;
114*ae8c08e7SSimon J. Gerraty struct sockaddr_in sa4;
115*ae8c08e7SSimon J. Gerraty struct sockaddr_in6 sa6;
116*ae8c08e7SSimon J. Gerraty size_t sa_len;
117*ae8c08e7SSimon J. Gerraty void *addr;
118*ae8c08e7SSimon J. Gerraty char tmp[INET6_ADDRSTRLEN + 50];
119*ae8c08e7SSimon J. Gerraty int opt;
120*ae8c08e7SSimon J. Gerraty
121*ae8c08e7SSimon J. Gerraty sa = (struct sockaddr *)p->ai_addr;
122*ae8c08e7SSimon J. Gerraty if (sa->sa_family == AF_INET) {
123*ae8c08e7SSimon J. Gerraty sa4 = *(struct sockaddr_in *)sa;
124*ae8c08e7SSimon J. Gerraty sa = (struct sockaddr *)&sa4;
125*ae8c08e7SSimon J. Gerraty sa_len = sizeof sa4;
126*ae8c08e7SSimon J. Gerraty addr = &sa4.sin_addr;
127*ae8c08e7SSimon J. Gerraty if (host == NULL) {
128*ae8c08e7SSimon J. Gerraty sa4.sin_addr.s_addr = INADDR_ANY;
129*ae8c08e7SSimon J. Gerraty }
130*ae8c08e7SSimon J. Gerraty } else if (sa->sa_family == AF_INET6) {
131*ae8c08e7SSimon J. Gerraty sa6 = *(struct sockaddr_in6 *)sa;
132*ae8c08e7SSimon J. Gerraty sa = (struct sockaddr *)&sa6;
133*ae8c08e7SSimon J. Gerraty sa_len = sizeof sa6;
134*ae8c08e7SSimon J. Gerraty addr = &sa6.sin6_addr;
135*ae8c08e7SSimon J. Gerraty if (host == NULL) {
136*ae8c08e7SSimon J. Gerraty sa6.sin6_addr = in6addr_any;
137*ae8c08e7SSimon J. Gerraty }
138*ae8c08e7SSimon J. Gerraty } else {
139*ae8c08e7SSimon J. Gerraty addr = NULL;
140*ae8c08e7SSimon J. Gerraty sa_len = p->ai_addrlen;
141*ae8c08e7SSimon J. Gerraty }
142*ae8c08e7SSimon J. Gerraty if (addr != NULL) {
143*ae8c08e7SSimon J. Gerraty inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
144*ae8c08e7SSimon J. Gerraty } else {
145*ae8c08e7SSimon J. Gerraty sprintf(tmp, "<unknown family: %d>",
146*ae8c08e7SSimon J. Gerraty (int)sa->sa_family);
147*ae8c08e7SSimon J. Gerraty }
148*ae8c08e7SSimon J. Gerraty fprintf(stderr, "binding to: %s\n", tmp);
149*ae8c08e7SSimon J. Gerraty fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
150*ae8c08e7SSimon J. Gerraty if (fd < 0) {
151*ae8c08e7SSimon J. Gerraty perror("socket()");
152*ae8c08e7SSimon J. Gerraty continue;
153*ae8c08e7SSimon J. Gerraty }
154*ae8c08e7SSimon J. Gerraty opt = 1;
155*ae8c08e7SSimon J. Gerraty setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
156*ae8c08e7SSimon J. Gerraty opt = 0;
157*ae8c08e7SSimon J. Gerraty setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt);
158*ae8c08e7SSimon J. Gerraty if (bind(fd, sa, sa_len) < 0) {
159*ae8c08e7SSimon J. Gerraty perror("bind()");
160*ae8c08e7SSimon J. Gerraty close(fd);
161*ae8c08e7SSimon J. Gerraty continue;
162*ae8c08e7SSimon J. Gerraty }
163*ae8c08e7SSimon J. Gerraty break;
164*ae8c08e7SSimon J. Gerraty }
165*ae8c08e7SSimon J. Gerraty if (p == NULL) {
166*ae8c08e7SSimon J. Gerraty freeaddrinfo(si);
167*ae8c08e7SSimon J. Gerraty fprintf(stderr, "ERROR: failed to bind\n");
168*ae8c08e7SSimon J. Gerraty return -1;
169*ae8c08e7SSimon J. Gerraty }
170*ae8c08e7SSimon J. Gerraty freeaddrinfo(si);
171*ae8c08e7SSimon J. Gerraty if (listen(fd, 5) < 0) {
172*ae8c08e7SSimon J. Gerraty perror("listen()");
173*ae8c08e7SSimon J. Gerraty close(fd);
174*ae8c08e7SSimon J. Gerraty return -1;
175*ae8c08e7SSimon J. Gerraty }
176*ae8c08e7SSimon J. Gerraty fprintf(stderr, "bound.\n");
177*ae8c08e7SSimon J. Gerraty return fd;
178*ae8c08e7SSimon J. Gerraty }
179*ae8c08e7SSimon J. Gerraty
180*ae8c08e7SSimon J. Gerraty /*
181*ae8c08e7SSimon J. Gerraty * Accept a single client on the provided server socket. This is blocking.
182*ae8c08e7SSimon J. Gerraty * On error, this returns -1.
183*ae8c08e7SSimon J. Gerraty */
184*ae8c08e7SSimon J. Gerraty static int
accept_client(int server_fd)185*ae8c08e7SSimon J. Gerraty accept_client(int server_fd)
186*ae8c08e7SSimon J. Gerraty {
187*ae8c08e7SSimon J. Gerraty int fd;
188*ae8c08e7SSimon J. Gerraty struct sockaddr sa;
189*ae8c08e7SSimon J. Gerraty socklen_t sa_len;
190*ae8c08e7SSimon J. Gerraty char tmp[INET6_ADDRSTRLEN + 50];
191*ae8c08e7SSimon J. Gerraty const char *name;
192*ae8c08e7SSimon J. Gerraty
193*ae8c08e7SSimon J. Gerraty sa_len = sizeof sa;
194*ae8c08e7SSimon J. Gerraty fd = accept(server_fd, &sa, &sa_len);
195*ae8c08e7SSimon J. Gerraty if (fd < 0) {
196*ae8c08e7SSimon J. Gerraty perror("accept()");
197*ae8c08e7SSimon J. Gerraty return -1;
198*ae8c08e7SSimon J. Gerraty }
199*ae8c08e7SSimon J. Gerraty name = NULL;
200*ae8c08e7SSimon J. Gerraty switch (sa.sa_family) {
201*ae8c08e7SSimon J. Gerraty case AF_INET:
202*ae8c08e7SSimon J. Gerraty name = inet_ntop(AF_INET,
203*ae8c08e7SSimon J. Gerraty &((struct sockaddr_in *)&sa)->sin_addr,
204*ae8c08e7SSimon J. Gerraty tmp, sizeof tmp);
205*ae8c08e7SSimon J. Gerraty break;
206*ae8c08e7SSimon J. Gerraty case AF_INET6:
207*ae8c08e7SSimon J. Gerraty name = inet_ntop(AF_INET6,
208*ae8c08e7SSimon J. Gerraty &((struct sockaddr_in6 *)&sa)->sin6_addr,
209*ae8c08e7SSimon J. Gerraty tmp, sizeof tmp);
210*ae8c08e7SSimon J. Gerraty break;
211*ae8c08e7SSimon J. Gerraty }
212*ae8c08e7SSimon J. Gerraty if (name == NULL) {
213*ae8c08e7SSimon J. Gerraty sprintf(tmp, "<unknown: %lu>", (unsigned long)sa.sa_family);
214*ae8c08e7SSimon J. Gerraty name = tmp;
215*ae8c08e7SSimon J. Gerraty }
216*ae8c08e7SSimon J. Gerraty fprintf(stderr, "accepting connection from: %s\n", name);
217*ae8c08e7SSimon J. Gerraty return fd;
218*ae8c08e7SSimon J. Gerraty }
219*ae8c08e7SSimon J. Gerraty
220*ae8c08e7SSimon J. Gerraty /*
221*ae8c08e7SSimon J. Gerraty * Low-level data read callback for the simplified SSL I/O API.
222*ae8c08e7SSimon J. Gerraty */
223*ae8c08e7SSimon J. Gerraty static int
sock_read(void * ctx,unsigned char * buf,size_t len)224*ae8c08e7SSimon J. Gerraty sock_read(void *ctx, unsigned char *buf, size_t len)
225*ae8c08e7SSimon J. Gerraty {
226*ae8c08e7SSimon J. Gerraty for (;;) {
227*ae8c08e7SSimon J. Gerraty ssize_t rlen;
228*ae8c08e7SSimon J. Gerraty
229*ae8c08e7SSimon J. Gerraty rlen = read(*(int *)ctx, buf, len);
230*ae8c08e7SSimon J. Gerraty if (rlen <= 0) {
231*ae8c08e7SSimon J. Gerraty if (rlen < 0 && errno == EINTR) {
232*ae8c08e7SSimon J. Gerraty continue;
233*ae8c08e7SSimon J. Gerraty }
234*ae8c08e7SSimon J. Gerraty return -1;
235*ae8c08e7SSimon J. Gerraty }
236*ae8c08e7SSimon J. Gerraty return (int)rlen;
237*ae8c08e7SSimon J. Gerraty }
238*ae8c08e7SSimon J. Gerraty }
239*ae8c08e7SSimon J. Gerraty
240*ae8c08e7SSimon J. Gerraty /*
241*ae8c08e7SSimon J. Gerraty * Low-level data write callback for the simplified SSL I/O API.
242*ae8c08e7SSimon J. Gerraty */
243*ae8c08e7SSimon J. Gerraty static int
sock_write(void * ctx,const unsigned char * buf,size_t len)244*ae8c08e7SSimon J. Gerraty sock_write(void *ctx, const unsigned char *buf, size_t len)
245*ae8c08e7SSimon J. Gerraty {
246*ae8c08e7SSimon J. Gerraty for (;;) {
247*ae8c08e7SSimon J. Gerraty ssize_t wlen;
248*ae8c08e7SSimon J. Gerraty
249*ae8c08e7SSimon J. Gerraty wlen = write(*(int *)ctx, buf, len);
250*ae8c08e7SSimon J. Gerraty if (wlen <= 0) {
251*ae8c08e7SSimon J. Gerraty if (wlen < 0 && errno == EINTR) {
252*ae8c08e7SSimon J. Gerraty continue;
253*ae8c08e7SSimon J. Gerraty }
254*ae8c08e7SSimon J. Gerraty return -1;
255*ae8c08e7SSimon J. Gerraty }
256*ae8c08e7SSimon J. Gerraty return (int)wlen;
257*ae8c08e7SSimon J. Gerraty }
258*ae8c08e7SSimon J. Gerraty }
259*ae8c08e7SSimon J. Gerraty
260*ae8c08e7SSimon J. Gerraty /*
261*ae8c08e7SSimon J. Gerraty * Sample HTTP response to send.
262*ae8c08e7SSimon J. Gerraty */
263*ae8c08e7SSimon J. Gerraty static const char *HTTP_RES =
264*ae8c08e7SSimon J. Gerraty "HTTP/1.0 200 OK\r\n"
265*ae8c08e7SSimon J. Gerraty "Content-Length: 46\r\n"
266*ae8c08e7SSimon J. Gerraty "Connection: close\r\n"
267*ae8c08e7SSimon J. Gerraty "Content-Type: text/html; charset=iso-8859-1\r\n"
268*ae8c08e7SSimon J. Gerraty "\r\n"
269*ae8c08e7SSimon J. Gerraty "<html>\r\n"
270*ae8c08e7SSimon J. Gerraty "<body>\r\n"
271*ae8c08e7SSimon J. Gerraty "<p>Test!</p>\r\n"
272*ae8c08e7SSimon J. Gerraty "</body>\r\n"
273*ae8c08e7SSimon J. Gerraty "</html>\r\n";
274*ae8c08e7SSimon J. Gerraty
275*ae8c08e7SSimon J. Gerraty /*
276*ae8c08e7SSimon J. Gerraty * Main program: this is a simple program that expects 1 argument: a
277*ae8c08e7SSimon J. Gerraty * port number. This will start a simple network server on that port,
278*ae8c08e7SSimon J. Gerraty * that expects incoming SSL clients. It handles only one client at a
279*ae8c08e7SSimon J. Gerraty * time (handling several would require threads, sub-processes, or
280*ae8c08e7SSimon J. Gerraty * multiplexing with select()/poll(), all of which being possible).
281*ae8c08e7SSimon J. Gerraty *
282*ae8c08e7SSimon J. Gerraty * For each client, the server will wait for two successive newline
283*ae8c08e7SSimon J. Gerraty * characters (ignoring CR characters, so CR+LF is accepted), then
284*ae8c08e7SSimon J. Gerraty * produce a sample static HTTP response. This is very crude, but
285*ae8c08e7SSimon J. Gerraty * sufficient for explanatory purposes.
286*ae8c08e7SSimon J. Gerraty */
287*ae8c08e7SSimon J. Gerraty int
main(int argc,char * argv[])288*ae8c08e7SSimon J. Gerraty main(int argc, char *argv[])
289*ae8c08e7SSimon J. Gerraty {
290*ae8c08e7SSimon J. Gerraty const char *port;
291*ae8c08e7SSimon J. Gerraty int fd;
292*ae8c08e7SSimon J. Gerraty
293*ae8c08e7SSimon J. Gerraty if (argc != 2) {
294*ae8c08e7SSimon J. Gerraty return EXIT_FAILURE;
295*ae8c08e7SSimon J. Gerraty }
296*ae8c08e7SSimon J. Gerraty port = argv[1];
297*ae8c08e7SSimon J. Gerraty
298*ae8c08e7SSimon J. Gerraty /*
299*ae8c08e7SSimon J. Gerraty * Ignore SIGPIPE to avoid crashing in case of abrupt socket close.
300*ae8c08e7SSimon J. Gerraty */
301*ae8c08e7SSimon J. Gerraty signal(SIGPIPE, SIG_IGN);
302*ae8c08e7SSimon J. Gerraty
303*ae8c08e7SSimon J. Gerraty /*
304*ae8c08e7SSimon J. Gerraty * Open the server socket.
305*ae8c08e7SSimon J. Gerraty */
306*ae8c08e7SSimon J. Gerraty fd = host_bind(NULL, port);
307*ae8c08e7SSimon J. Gerraty if (fd < 0) {
308*ae8c08e7SSimon J. Gerraty return EXIT_FAILURE;
309*ae8c08e7SSimon J. Gerraty }
310*ae8c08e7SSimon J. Gerraty
311*ae8c08e7SSimon J. Gerraty /*
312*ae8c08e7SSimon J. Gerraty * Process each client, one at a time.
313*ae8c08e7SSimon J. Gerraty */
314*ae8c08e7SSimon J. Gerraty for (;;) {
315*ae8c08e7SSimon J. Gerraty int cfd;
316*ae8c08e7SSimon J. Gerraty br_ssl_server_context sc;
317*ae8c08e7SSimon J. Gerraty unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
318*ae8c08e7SSimon J. Gerraty br_sslio_context ioc;
319*ae8c08e7SSimon J. Gerraty int lcwn, err;
320*ae8c08e7SSimon J. Gerraty
321*ae8c08e7SSimon J. Gerraty cfd = accept_client(fd);
322*ae8c08e7SSimon J. Gerraty if (cfd < 0) {
323*ae8c08e7SSimon J. Gerraty return EXIT_FAILURE;
324*ae8c08e7SSimon J. Gerraty }
325*ae8c08e7SSimon J. Gerraty
326*ae8c08e7SSimon J. Gerraty /*
327*ae8c08e7SSimon J. Gerraty * Initialise the context with the cipher suites and
328*ae8c08e7SSimon J. Gerraty * algorithms. This depends on the server key type
329*ae8c08e7SSimon J. Gerraty * (and, for EC keys, the signature algorithm used by
330*ae8c08e7SSimon J. Gerraty * the CA to sign the server's certificate).
331*ae8c08e7SSimon J. Gerraty *
332*ae8c08e7SSimon J. Gerraty * Depending on the defined macros, we may select one of
333*ae8c08e7SSimon J. Gerraty * the "minimal" profiles. Key exchange algorithm depends
334*ae8c08e7SSimon J. Gerraty * on the key type:
335*ae8c08e7SSimon J. Gerraty * RSA key: RSA or ECDHE_RSA
336*ae8c08e7SSimon J. Gerraty * EC key, cert signed with ECDSA: ECDH_ECDSA or ECDHE_ECDSA
337*ae8c08e7SSimon J. Gerraty * EC key, cert signed with RSA: ECDH_RSA or ECDHE_ECDSA
338*ae8c08e7SSimon J. Gerraty */
339*ae8c08e7SSimon J. Gerraty #if SERVER_RSA
340*ae8c08e7SSimon J. Gerraty #if SERVER_PROFILE_MIN_FS
341*ae8c08e7SSimon J. Gerraty #if SERVER_CHACHA20
342*ae8c08e7SSimon J. Gerraty br_ssl_server_init_mine2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
343*ae8c08e7SSimon J. Gerraty #else
344*ae8c08e7SSimon J. Gerraty br_ssl_server_init_mine2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
345*ae8c08e7SSimon J. Gerraty #endif
346*ae8c08e7SSimon J. Gerraty #elif SERVER_PROFILE_MIN_NOFS
347*ae8c08e7SSimon J. Gerraty br_ssl_server_init_minr2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
348*ae8c08e7SSimon J. Gerraty #else
349*ae8c08e7SSimon J. Gerraty br_ssl_server_init_full_rsa(&sc, CHAIN, CHAIN_LEN, &SKEY);
350*ae8c08e7SSimon J. Gerraty #endif
351*ae8c08e7SSimon J. Gerraty #elif SERVER_EC
352*ae8c08e7SSimon J. Gerraty #if SERVER_PROFILE_MIN_FS
353*ae8c08e7SSimon J. Gerraty #if SERVER_CHACHA20
354*ae8c08e7SSimon J. Gerraty br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
355*ae8c08e7SSimon J. Gerraty #else
356*ae8c08e7SSimon J. Gerraty br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
357*ae8c08e7SSimon J. Gerraty #endif
358*ae8c08e7SSimon J. Gerraty #elif SERVER_PROFILE_MIN_NOFS
359*ae8c08e7SSimon J. Gerraty br_ssl_server_init_minv2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
360*ae8c08e7SSimon J. Gerraty #else
361*ae8c08e7SSimon J. Gerraty br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
362*ae8c08e7SSimon J. Gerraty BR_KEYTYPE_EC, &SKEY);
363*ae8c08e7SSimon J. Gerraty #endif
364*ae8c08e7SSimon J. Gerraty #else /* SERVER_MIXED */
365*ae8c08e7SSimon J. Gerraty #if SERVER_PROFILE_MIN_FS
366*ae8c08e7SSimon J. Gerraty #if SERVER_CHACHA20
367*ae8c08e7SSimon J. Gerraty br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
368*ae8c08e7SSimon J. Gerraty #else
369*ae8c08e7SSimon J. Gerraty br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
370*ae8c08e7SSimon J. Gerraty #endif
371*ae8c08e7SSimon J. Gerraty #elif SERVER_PROFILE_MIN_NOFS
372*ae8c08e7SSimon J. Gerraty br_ssl_server_init_minu2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
373*ae8c08e7SSimon J. Gerraty #else
374*ae8c08e7SSimon J. Gerraty br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
375*ae8c08e7SSimon J. Gerraty BR_KEYTYPE_RSA, &SKEY);
376*ae8c08e7SSimon J. Gerraty #endif
377*ae8c08e7SSimon J. Gerraty #endif
378*ae8c08e7SSimon J. Gerraty /*
379*ae8c08e7SSimon J. Gerraty * Set the I/O buffer to the provided array. We
380*ae8c08e7SSimon J. Gerraty * allocated a buffer large enough for full-duplex
381*ae8c08e7SSimon J. Gerraty * behaviour with all allowed sizes of SSL records,
382*ae8c08e7SSimon J. Gerraty * hence we set the last argument to 1 (which means
383*ae8c08e7SSimon J. Gerraty * "split the buffer into separate input and output
384*ae8c08e7SSimon J. Gerraty * areas").
385*ae8c08e7SSimon J. Gerraty */
386*ae8c08e7SSimon J. Gerraty br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
387*ae8c08e7SSimon J. Gerraty
388*ae8c08e7SSimon J. Gerraty /*
389*ae8c08e7SSimon J. Gerraty * Reset the server context, for a new handshake.
390*ae8c08e7SSimon J. Gerraty */
391*ae8c08e7SSimon J. Gerraty br_ssl_server_reset(&sc);
392*ae8c08e7SSimon J. Gerraty
393*ae8c08e7SSimon J. Gerraty /*
394*ae8c08e7SSimon J. Gerraty * Initialise the simplified I/O wrapper context.
395*ae8c08e7SSimon J. Gerraty */
396*ae8c08e7SSimon J. Gerraty br_sslio_init(&ioc, &sc.eng, sock_read, &cfd, sock_write, &cfd);
397*ae8c08e7SSimon J. Gerraty
398*ae8c08e7SSimon J. Gerraty /*
399*ae8c08e7SSimon J. Gerraty * Read bytes until two successive LF (or CR+LF) are received.
400*ae8c08e7SSimon J. Gerraty */
401*ae8c08e7SSimon J. Gerraty lcwn = 0;
402*ae8c08e7SSimon J. Gerraty for (;;) {
403*ae8c08e7SSimon J. Gerraty unsigned char x;
404*ae8c08e7SSimon J. Gerraty
405*ae8c08e7SSimon J. Gerraty if (br_sslio_read(&ioc, &x, 1) < 0) {
406*ae8c08e7SSimon J. Gerraty goto client_drop;
407*ae8c08e7SSimon J. Gerraty }
408*ae8c08e7SSimon J. Gerraty if (x == 0x0D) {
409*ae8c08e7SSimon J. Gerraty continue;
410*ae8c08e7SSimon J. Gerraty }
411*ae8c08e7SSimon J. Gerraty if (x == 0x0A) {
412*ae8c08e7SSimon J. Gerraty if (lcwn) {
413*ae8c08e7SSimon J. Gerraty break;
414*ae8c08e7SSimon J. Gerraty }
415*ae8c08e7SSimon J. Gerraty lcwn = 1;
416*ae8c08e7SSimon J. Gerraty } else {
417*ae8c08e7SSimon J. Gerraty lcwn = 0;
418*ae8c08e7SSimon J. Gerraty }
419*ae8c08e7SSimon J. Gerraty }
420*ae8c08e7SSimon J. Gerraty
421*ae8c08e7SSimon J. Gerraty /*
422*ae8c08e7SSimon J. Gerraty * Write a response and close the connection.
423*ae8c08e7SSimon J. Gerraty */
424*ae8c08e7SSimon J. Gerraty br_sslio_write_all(&ioc, HTTP_RES, strlen(HTTP_RES));
425*ae8c08e7SSimon J. Gerraty br_sslio_close(&ioc);
426*ae8c08e7SSimon J. Gerraty
427*ae8c08e7SSimon J. Gerraty client_drop:
428*ae8c08e7SSimon J. Gerraty err = br_ssl_engine_last_error(&sc.eng);
429*ae8c08e7SSimon J. Gerraty if (err == 0) {
430*ae8c08e7SSimon J. Gerraty fprintf(stderr, "SSL closed (correctly).\n");
431*ae8c08e7SSimon J. Gerraty } else {
432*ae8c08e7SSimon J. Gerraty fprintf(stderr, "SSL error: %d\n", err);
433*ae8c08e7SSimon J. Gerraty }
434*ae8c08e7SSimon J. Gerraty close(cfd);
435*ae8c08e7SSimon J. Gerraty }
436*ae8c08e7SSimon J. Gerraty }
437