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 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 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 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 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 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