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