2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
32 #include <sys/types.h>
33 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
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)
47 * The macros below define which chain is selected. This impacts the list
48 * of supported cipher suites.
50 * Other macros, which can be defined (with a non-zero value):
52 * SERVER_PROFILE_MIN_FS
53 * Select a "minimal" profile with forward security (ECDHE cipher
56 * SERVER_PROFILE_MIN_NOFS
57 * Select a "minimal" profile without forward security (RSA or ECDH
58 * cipher suite, but not ECDHE).
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.
67 #if !(SERVER_RSA || SERVER_EC || SERVER_MIXED)
70 #define SERVER_MIXED 0
74 #include "chain-rsa.h"
82 #include "chain-ec+rsa.h"
86 #error Must use one of RSA, EC or MIXED chains.
90 * Create a server socket bound to the specified host and port. If 'host'
91 * is NULL, this will bind "generically" (all addresses).
93 * Returned value is the server socket descriptor, or -1 on error.
96 host_bind(const char *host, const char *port)
98 struct addrinfo hints, *si, *p;
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);
107 fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
112 for (p = si; p != NULL; p = p->ai_next) {
114 struct sockaddr_in sa4;
115 struct sockaddr_in6 sa6;
118 char tmp[INET6_ADDRSTRLEN + 50];
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;
126 addr = &sa4.sin_addr;
128 sa4.sin_addr.s_addr = INADDR_ANY;
130 } else if (sa->sa_family == AF_INET6) {
131 sa6 = *(struct sockaddr_in6 *)sa;
132 sa = (struct sockaddr *)&sa6;
134 addr = &sa6.sin6_addr;
136 sa6.sin6_addr = in6addr_any;
140 sa_len = p->ai_addrlen;
143 inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
145 sprintf(tmp, "<unknown family: %d>",
148 fprintf(stderr, "binding to: %s\n", tmp);
149 fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
155 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
157 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt);
158 if (bind(fd, sa, sa_len) < 0) {
167 fprintf(stderr, "ERROR: failed to bind\n");
171 if (listen(fd, 5) < 0) {
176 fprintf(stderr, "bound.\n");
181 * Accept a single client on the provided server socket. This is blocking.
182 * On error, this returns -1.
185 accept_client(int server_fd)
190 char tmp[INET6_ADDRSTRLEN + 50];
194 fd = accept(server_fd, &sa, &sa_len);
200 switch (sa.sa_family) {
202 name = inet_ntop(AF_INET,
203 &((struct sockaddr_in *)&sa)->sin_addr,
207 name = inet_ntop(AF_INET6,
208 &((struct sockaddr_in6 *)&sa)->sin6_addr,
213 sprintf(tmp, "<unknown: %lu>", (unsigned long)sa.sa_family);
216 fprintf(stderr, "accepting connection from: %s\n", name);
221 * Low-level data read callback for the simplified SSL I/O API.
224 sock_read(void *ctx, unsigned char *buf, size_t len)
229 rlen = read(*(int *)ctx, buf, len);
231 if (rlen < 0 && errno == EINTR) {
241 * Low-level data write callback for the simplified SSL I/O API.
244 sock_write(void *ctx, const unsigned char *buf, size_t len)
249 wlen = write(*(int *)ctx, buf, len);
251 if (wlen < 0 && errno == EINTR) {
261 * Sample HTTP response to send.
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"
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).
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.
288 main(int argc, char *argv[])
299 * Ignore SIGPIPE to avoid crashing in case of abrupt socket close.
301 signal(SIGPIPE, SIG_IGN);
304 * Open the server socket.
306 fd = host_bind(NULL, port);
312 * Process each client, one at a time.
316 br_ssl_server_context sc;
317 unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
318 br_sslio_context ioc;
321 cfd = accept_client(fd);
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).
332 * Depending on the defined macros, we may select one of
333 * the "minimal" profiles. Key exchange algorithm depends
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
340 #if SERVER_PROFILE_MIN_FS
342 br_ssl_server_init_mine2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
344 br_ssl_server_init_mine2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
346 #elif SERVER_PROFILE_MIN_NOFS
347 br_ssl_server_init_minr2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
349 br_ssl_server_init_full_rsa(&sc, CHAIN, CHAIN_LEN, &SKEY);
352 #if SERVER_PROFILE_MIN_FS
354 br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
356 br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
358 #elif SERVER_PROFILE_MIN_NOFS
359 br_ssl_server_init_minv2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
361 br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
362 BR_KEYTYPE_EC, &SKEY);
364 #else /* SERVER_MIXED */
365 #if SERVER_PROFILE_MIN_FS
367 br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
369 br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
371 #elif SERVER_PROFILE_MIN_NOFS
372 br_ssl_server_init_minu2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
374 br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
375 BR_KEYTYPE_RSA, &SKEY);
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
386 br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
389 * Reset the server context, for a new handshake.
391 br_ssl_server_reset(&sc);
394 * Initialise the simplified I/O wrapper context.
396 br_sslio_init(&ioc, &sc.eng, sock_read, &cfd, sock_write, &cfd);
399 * Read bytes until two successive LF (or CR+LF) are received.
405 if (br_sslio_read(&ioc, &x, 1) < 0) {
422 * Write a response and close the connection.
424 br_sslio_write_all(&ioc, HTTP_RES, strlen(HTTP_RES));
425 br_sslio_close(&ioc);
428 err = br_ssl_engine_last_error(&sc.eng);
430 fprintf(stderr, "SSL closed (correctly).\n");
432 fprintf(stderr, "SSL error: %d\n", err);