/ samples / server_basic.c
server_basic.c
  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  }