Added some comments.
[BearSSL] / samples / 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
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37
38 #include "bearssl.h"
39
40 /*
41 * This sample code can use three possible certificate chains:
42 * -- A full-RSA chain (server key is RSA, certificates are signed with RSA)
43 * -- A full-EC chain (server key is EC, certificates are signed with ECDSA)
44 * -- A mixed chain (server key is EC, certificates are signed with RSA)
45 *
46 * The macros below define which chain is selected. This impacts the list
47 * of supported cipher suites.
48 */
49
50 #if !(SERVER_RSA || SERVER_EC || SERVER_MIXED)
51 #define SERVER_RSA 1
52 #define SERVER_EC 0
53 #define SERVER_MIXED 0
54 #endif
55
56 #if SERVER_RSA
57 #include "chain-rsa.h"
58 #include "key-rsa.h"
59 #define SKEY RSA
60 #elif SERVER_EC
61 #include "chain-ec.h"
62 #include "key-ec.h"
63 #define SKEY EC
64 #elif SERVER_MIXED
65 #include "chain-ec+rsa.h"
66 #include "key-ec.h"
67 #define SKEY EC
68 #else
69 #error Must use one of RSA, EC or MIXED chains.
70 #endif
71
72 /*
73 * Create a server socket bound to the specified host and port. If 'host'
74 * is NULL, this will bind "generically" (all addresses).
75 *
76 * Returned value is the server socket descriptor, or -1 on error.
77 */
78 static int
79 host_bind(const char *host, const char *port)
80 {
81 struct addrinfo hints, *si, *p;
82 int fd;
83 int err;
84
85 memset(&hints, 0, sizeof hints);
86 hints.ai_family = PF_UNSPEC;
87 hints.ai_socktype = SOCK_STREAM;
88 err = getaddrinfo(host, port, &hints, &si);
89 if (err != 0) {
90 fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
91 gai_strerror(err));
92 return -1;
93 }
94 fd = -1;
95 for (p = si; p != NULL; p = p->ai_next) {
96 struct sockaddr *sa;
97 struct sockaddr_in sa4;
98 struct sockaddr_in6 sa6;
99 size_t sa_len;
100 void *addr;
101 char tmp[INET6_ADDRSTRLEN + 50];
102 int opt;
103
104 sa = (struct sockaddr *)p->ai_addr;
105 if (sa->sa_family == AF_INET) {
106 sa4 = *(struct sockaddr_in *)sa;
107 sa = (struct sockaddr *)&sa4;
108 sa_len = sizeof sa4;
109 addr = &sa4.sin_addr;
110 if (host == NULL) {
111 sa4.sin_addr.s_addr = INADDR_ANY;
112 }
113 } else if (sa->sa_family == AF_INET6) {
114 sa6 = *(struct sockaddr_in6 *)sa;
115 sa = (struct sockaddr *)&sa6;
116 sa_len = sizeof sa6;
117 addr = &sa6.sin6_addr;
118 if (host == NULL) {
119 sa6.sin6_addr = in6addr_any;
120 }
121 } else {
122 addr = NULL;
123 sa_len = p->ai_addrlen;
124 }
125 if (addr != NULL) {
126 inet_ntop(p->ai_family, addr, tmp, sizeof tmp);
127 } else {
128 sprintf(tmp, "<unknown family: %d>",
129 (int)sa->sa_family);
130 }
131 fprintf(stderr, "binding to: %s\n", tmp);
132 fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
133 if (fd < 0) {
134 perror("socket()");
135 continue;
136 }
137 opt = 1;
138 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
139 opt = 0;
140 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt);
141 if (bind(fd, sa, sa_len) < 0) {
142 perror("bind()");
143 close(fd);
144 continue;
145 }
146 break;
147 }
148 if (p == NULL) {
149 freeaddrinfo(si);
150 fprintf(stderr, "ERROR: failed to bind\n");
151 return -1;
152 }
153 freeaddrinfo(si);
154 if (listen(fd, 5) < 0) {
155 perror("listen()");
156 close(fd);
157 return -1;
158 }
159 fprintf(stderr, "bound.\n");
160 return fd;
161 }
162
163 /*
164 * Accept a single client on the provided server socket. This is blocking.
165 * On error, this returns -1.
166 */
167 static int
168 accept_client(int server_fd)
169 {
170 int fd;
171 struct sockaddr sa;
172 socklen_t sa_len;
173 char tmp[INET6_ADDRSTRLEN + 50];
174 const char *name;
175
176 sa_len = sizeof sa;
177 fd = accept(server_fd, &sa, &sa_len);
178 if (fd < 0) {
179 perror("accept()");
180 return -1;
181 }
182 name = NULL;
183 switch (sa.sa_family) {
184 case AF_INET:
185 name = inet_ntop(AF_INET,
186 &((struct sockaddr_in *)&sa)->sin_addr,
187 tmp, sizeof tmp);
188 break;
189 case AF_INET6:
190 name = inet_ntop(AF_INET,
191 &((struct sockaddr_in *)&sa)->sin_addr,
192 tmp, sizeof tmp);
193 break;
194 }
195 if (name == NULL) {
196 sprintf(tmp, "<unknown: %lu>", (unsigned long)sa.sa_family);
197 name = tmp;
198 }
199 fprintf(stderr, "accepting connection from: %s\n", name);
200 return fd;
201 }
202
203 /*
204 * Low-level data read callback for the simplified SSL I/O API.
205 */
206 static int
207 sock_read(void *ctx, unsigned char *buf, size_t len)
208 {
209 for (;;) {
210 ssize_t rlen;
211
212 rlen = read(*(int *)ctx, buf, len);
213 if (rlen <= 0) {
214 if (rlen < 0 && errno == EINTR) {
215 continue;
216 }
217 return -1;
218 }
219 return (int)rlen;
220 }
221 }
222
223 /*
224 * Low-level data write callback for the simplified SSL I/O API.
225 */
226 static int
227 sock_write(void *ctx, const unsigned char *buf, size_t len)
228 {
229 for (;;) {
230 ssize_t wlen;
231
232 wlen = write(*(int *)ctx, buf, len);
233 if (wlen <= 0) {
234 if (wlen < 0 && errno == EINTR) {
235 continue;
236 }
237 return -1;
238 }
239 return (int)wlen;
240 }
241 }
242
243 /*
244 * Sample HTTP response to send.
245 */
246 static const char *HTTP_RES =
247 "HTTP/1.0 200 OK\r\n"
248 "Content-Length: 46\r\n"
249 "Connection: close\r\n"
250 "Content-Type: text/html; charset=iso-8859-1\r\n"
251 "\r\n"
252 "<html>\r\n"
253 "<body>\r\n"
254 "<p>Test!</p>\r\n"
255 "</body>\r\n"
256 "</html>\r\n";
257
258 /*
259 * Main program: this is a simple program that expects 1 argument: a
260 * port number. This will start a simple network server on that port,
261 * that expects incoming SSL clients. It handles only one client at a
262 * time (handling several would require threads, sub-processes, or
263 * multiplexing with select()/poll(), all of which being possible).
264 *
265 * For each client, the server will wait for two successive newline
266 * characters (ignoring CR characters, so CR+LF is accepted), then
267 * produce a sample static HTTP response. This is very crude, but
268 * sufficient for explanatory purposes.
269 */
270 int
271 main(int argc, char *argv[])
272 {
273 const char *port;
274 int fd;
275
276 if (argc != 2) {
277 return EXIT_FAILURE;
278 }
279 port = argv[1];
280
281 /*
282 * Open the server socket.
283 */
284 fd = host_bind(NULL, port);
285 if (fd < 0) {
286 return EXIT_FAILURE;
287 }
288
289 /*
290 * Process each client, one at a time.
291 */
292 for (;;) {
293 int cfd;
294 br_ssl_server_context sc;
295 unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
296 br_sslio_context ioc;
297 int lcwn, err;
298
299 cfd = accept_client(fd);
300 if (cfd < 0) {
301 return EXIT_FAILURE;
302 }
303
304 /*
305 * Initialise the context with the cipher suites and
306 * algorithms. This depends on the server key type
307 * (and, for EC keys, the signature algorithm used by
308 * the CA to sign the server's certificate).
309 *
310 * Depending on the defined macros, we may select one of
311 * the "minimal" profiles. Key exchange algorithm depends
312 * on the key type:
313 * RSA key: RSA or ECDHE_RSA
314 * EC key, cert signed with ECDSA: ECDH_ECDSA or ECDHE_ECDSA
315 * EC key, cert signed with RSA: ECDH_RSA or ECDHE_ECDSA
316 */
317 #if SERVER_RSA
318 #if SERVER_PROFILE_MIN_FS
319 br_ssl_server_init_mine2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
320 #elif SERVER_PROFILE_MIN_NOFS
321 br_ssl_server_init_minr2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
322 #else
323 br_ssl_server_init_full_rsa(&sc, CHAIN, CHAIN_LEN, &SKEY);
324 #endif
325 #elif SERVER_EC
326 #if SERVER_PROFILE_MIN_FS
327 br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
328 #elif SERVER_PROFILE_MIN_NOFS
329 br_ssl_server_init_minv2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
330 #else
331 br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
332 BR_KEYTYPE_EC, &SKEY);
333 #endif
334 #else /* SERVER_MIXED */
335 #if SERVER_PROFILE_MIN_FS
336 br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
337 #elif SERVER_PROFILE_MIN_NOFS
338 br_ssl_server_init_minu2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
339 #else
340 br_ssl_server_init_full_ec(&sc, CHAIN, CHAIN_LEN,
341 BR_KEYTYPE_RSA, &SKEY);
342 #endif
343 #endif
344 /*
345 * Set the I/O buffer to the provided array. We
346 * allocated a buffer large enough for full-duplex
347 * behaviour with all allowed sizes of SSL records,
348 * hence we set the last argument to 1 (which means
349 * "split the buffer into separate input and output
350 * areas").
351 */
352 br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
353
354 /*
355 * Reset the server context, for a new handshake.
356 */
357 br_ssl_server_reset(&sc);
358
359 /*
360 * Initialise the simplified I/O wrapper context.
361 */
362 br_sslio_init(&ioc, &sc.eng, sock_read, &cfd, sock_write, &cfd);
363
364 /*
365 * Read bytes until two successive LF (or CR+LF) are received.
366 */
367 lcwn = 0;
368 for (;;) {
369 unsigned char x;
370
371 if (br_sslio_read(&ioc, &x, 1) < 0) {
372 goto client_drop;
373 }
374 if (x == 0x0D) {
375 continue;
376 }
377 if (x == 0x0A) {
378 if (lcwn) {
379 break;
380 }
381 lcwn = 1;
382 } else {
383 lcwn = 0;
384 }
385 }
386
387 /*
388 * Write a response and close the connection.
389 */
390 br_sslio_write_all(&ioc, HTTP_RES, strlen(HTTP_RES));
391 br_sslio_close(&ioc);
392
393 client_drop:
394 err = br_ssl_engine_last_error(&sc.eng);
395 if (err == 0) {
396 fprintf(stderr, "SSL closed (correctly).\n");
397 } else {
398 fprintf(stderr, "SSL error: %d\n", err);
399 }
400 close(cfd);
401 }
402 }