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