xref: /freebsd-src/contrib/bearssl/tools/server.c (revision 2aaf9152a852aba9eb2036b95f4948ee77988826)
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 #ifdef _WIN32
33*0957b409SSimon J. Gerraty #include <winsock2.h>
34*0957b409SSimon J. Gerraty #include <ws2tcpip.h>
35*0957b409SSimon J. Gerraty #else
36*0957b409SSimon J. Gerraty #include <sys/types.h>
37*0957b409SSimon J. Gerraty #include <sys/socket.h>
38*0957b409SSimon J. Gerraty #include <netdb.h>
39*0957b409SSimon J. Gerraty #include <netinet/in.h>
40*0957b409SSimon J. Gerraty #include <arpa/inet.h>
41*0957b409SSimon J. Gerraty #include <unistd.h>
42*0957b409SSimon J. Gerraty #include <fcntl.h>
43*0957b409SSimon J. Gerraty 
44*0957b409SSimon J. Gerraty #define SOCKET             int
45*0957b409SSimon J. Gerraty #define INVALID_SOCKET     (-1)
46*0957b409SSimon J. Gerraty #define SOCKADDR_STORAGE   struct sockaddr_storage
47*0957b409SSimon J. Gerraty #endif
48*0957b409SSimon J. Gerraty 
49*0957b409SSimon J. Gerraty #include "brssl.h"
50*0957b409SSimon J. Gerraty 
51*0957b409SSimon J. Gerraty static SOCKET
host_bind(const char * host,const char * port,int verbose)52*0957b409SSimon J. Gerraty host_bind(const char *host, const char *port, int verbose)
53*0957b409SSimon J. Gerraty {
54*0957b409SSimon J. Gerraty 	struct addrinfo hints, *si, *p;
55*0957b409SSimon J. Gerraty 	SOCKET fd;
56*0957b409SSimon J. Gerraty 	int err;
57*0957b409SSimon J. Gerraty 
58*0957b409SSimon J. Gerraty 	memset(&hints, 0, sizeof hints);
59*0957b409SSimon J. Gerraty 	hints.ai_family = PF_UNSPEC;
60*0957b409SSimon J. Gerraty 	hints.ai_socktype = SOCK_STREAM;
61*0957b409SSimon J. Gerraty 	err = getaddrinfo(host, port, &hints, &si);
62*0957b409SSimon J. Gerraty 	if (err != 0) {
63*0957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: getaddrinfo(): %s\n",
64*0957b409SSimon J. Gerraty 			gai_strerror(err));
65*0957b409SSimon J. Gerraty 		return INVALID_SOCKET;
66*0957b409SSimon J. Gerraty 	}
67*0957b409SSimon J. Gerraty 	fd = INVALID_SOCKET;
68*0957b409SSimon J. Gerraty 	for (p = si; p != NULL; p = p->ai_next) {
69*0957b409SSimon J. Gerraty 		struct sockaddr *sa;
70*0957b409SSimon J. Gerraty 		struct sockaddr_in sa4;
71*0957b409SSimon J. Gerraty 		struct sockaddr_in6 sa6;
72*0957b409SSimon J. Gerraty 		size_t sa_len;
73*0957b409SSimon J. Gerraty 		void *addr;
74*0957b409SSimon J. Gerraty 		int opt;
75*0957b409SSimon J. Gerraty 
76*0957b409SSimon J. Gerraty 		sa = (struct sockaddr *)p->ai_addr;
77*0957b409SSimon J. Gerraty 		if (sa->sa_family == AF_INET) {
78*0957b409SSimon J. Gerraty 			memcpy(&sa4, sa, sizeof sa4);
79*0957b409SSimon J. Gerraty 			sa = (struct sockaddr *)&sa4;
80*0957b409SSimon J. Gerraty 			sa_len = sizeof sa4;
81*0957b409SSimon J. Gerraty 			addr = &sa4.sin_addr;
82*0957b409SSimon J. Gerraty 			if (host == NULL) {
83*0957b409SSimon J. Gerraty 				sa4.sin_addr.s_addr = INADDR_ANY;
84*0957b409SSimon J. Gerraty 			}
85*0957b409SSimon J. Gerraty 		} else if (sa->sa_family == AF_INET6) {
86*0957b409SSimon J. Gerraty 			memcpy(&sa6, sa, sizeof sa6);
87*0957b409SSimon J. Gerraty 			sa = (struct sockaddr *)&sa6;
88*0957b409SSimon J. Gerraty 			sa_len = sizeof sa6;
89*0957b409SSimon J. Gerraty 			addr = &sa6.sin6_addr;
90*0957b409SSimon J. Gerraty 			if (host == NULL) {
91*0957b409SSimon J. Gerraty 				sa6.sin6_addr = in6addr_any;
92*0957b409SSimon J. Gerraty 			}
93*0957b409SSimon J. Gerraty 		} else {
94*0957b409SSimon J. Gerraty 			addr = NULL;
95*0957b409SSimon J. Gerraty 			sa_len = p->ai_addrlen;
96*0957b409SSimon J. Gerraty 		}
97*0957b409SSimon J. Gerraty 		if (verbose) {
98*0957b409SSimon J. Gerraty 			char tmp[INET6_ADDRSTRLEN + 50];
99*0957b409SSimon J. Gerraty 
100*0957b409SSimon J. Gerraty 			if (addr != NULL) {
101*0957b409SSimon J. Gerraty 				if (!inet_ntop(p->ai_family, addr,
102*0957b409SSimon J. Gerraty 					tmp, sizeof tmp))
103*0957b409SSimon J. Gerraty 				{
104*0957b409SSimon J. Gerraty 					strcpy(tmp, "<invalid>");
105*0957b409SSimon J. Gerraty 				}
106*0957b409SSimon J. Gerraty 			} else {
107*0957b409SSimon J. Gerraty 				sprintf(tmp, "<unknown family: %d>",
108*0957b409SSimon J. Gerraty 					(int)sa->sa_family);
109*0957b409SSimon J. Gerraty 			}
110*0957b409SSimon J. Gerraty 			fprintf(stderr, "binding to: %s\n", tmp);
111*0957b409SSimon J. Gerraty 		}
112*0957b409SSimon J. Gerraty 		fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
113*0957b409SSimon J. Gerraty 		if (fd == INVALID_SOCKET) {
114*0957b409SSimon J. Gerraty 			if (verbose) {
115*0957b409SSimon J. Gerraty 				perror("socket()");
116*0957b409SSimon J. Gerraty 			}
117*0957b409SSimon J. Gerraty 			continue;
118*0957b409SSimon J. Gerraty 		}
119*0957b409SSimon J. Gerraty 		opt = 1;
120*0957b409SSimon J. Gerraty 		setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
121*0957b409SSimon J. Gerraty 			(void *)&opt, sizeof opt);
122*0957b409SSimon J. Gerraty #ifdef IPV6_V6ONLY
123*0957b409SSimon J. Gerraty 		/*
124*0957b409SSimon J. Gerraty 		 * We want to make sure that the server socket works for
125*0957b409SSimon J. Gerraty 		 * both IPv4 and IPv6. But IPV6_V6ONLY is not defined on
126*0957b409SSimon J. Gerraty 		 * some very old systems.
127*0957b409SSimon J. Gerraty 		 */
128*0957b409SSimon J. Gerraty 		opt = 0;
129*0957b409SSimon J. Gerraty 		setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
130*0957b409SSimon J. Gerraty 			(void *)&opt, sizeof opt);
131*0957b409SSimon J. Gerraty #endif
132*0957b409SSimon J. Gerraty 		if (bind(fd, sa, sa_len) < 0) {
133*0957b409SSimon J. Gerraty 			if (verbose) {
134*0957b409SSimon J. Gerraty 				perror("bind()");
135*0957b409SSimon J. Gerraty 			}
136*0957b409SSimon J. Gerraty #ifdef _WIN32
137*0957b409SSimon J. Gerraty 			closesocket(fd);
138*0957b409SSimon J. Gerraty #else
139*0957b409SSimon J. Gerraty 			close(fd);
140*0957b409SSimon J. Gerraty #endif
141*0957b409SSimon J. Gerraty 			continue;
142*0957b409SSimon J. Gerraty 		}
143*0957b409SSimon J. Gerraty 		break;
144*0957b409SSimon J. Gerraty 	}
145*0957b409SSimon J. Gerraty 	if (p == NULL) {
146*0957b409SSimon J. Gerraty 		freeaddrinfo(si);
147*0957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: failed to bind\n");
148*0957b409SSimon J. Gerraty 		return INVALID_SOCKET;
149*0957b409SSimon J. Gerraty 	}
150*0957b409SSimon J. Gerraty 	freeaddrinfo(si);
151*0957b409SSimon J. Gerraty 	if (listen(fd, 5) < 0) {
152*0957b409SSimon J. Gerraty 		if (verbose) {
153*0957b409SSimon J. Gerraty 			perror("listen()");
154*0957b409SSimon J. Gerraty 		}
155*0957b409SSimon J. Gerraty #ifdef _WIN32
156*0957b409SSimon J. Gerraty 		closesocket(fd);
157*0957b409SSimon J. Gerraty #else
158*0957b409SSimon J. Gerraty 		close(fd);
159*0957b409SSimon J. Gerraty #endif
160*0957b409SSimon J. Gerraty 		return INVALID_SOCKET;
161*0957b409SSimon J. Gerraty 	}
162*0957b409SSimon J. Gerraty 	if (verbose) {
163*0957b409SSimon J. Gerraty 		fprintf(stderr, "bound.\n");
164*0957b409SSimon J. Gerraty 	}
165*0957b409SSimon J. Gerraty 	return fd;
166*0957b409SSimon J. Gerraty }
167*0957b409SSimon J. Gerraty 
168*0957b409SSimon J. Gerraty static SOCKET
accept_client(SOCKET server_fd,int verbose,int nonblock)169*0957b409SSimon J. Gerraty accept_client(SOCKET server_fd, int verbose, int nonblock)
170*0957b409SSimon J. Gerraty {
171*0957b409SSimon J. Gerraty 	int fd;
172*0957b409SSimon J. Gerraty 	SOCKADDR_STORAGE sa;
173*0957b409SSimon J. Gerraty 	socklen_t sa_len;
174*0957b409SSimon J. Gerraty 
175*0957b409SSimon J. Gerraty 	sa_len = sizeof sa;
176*0957b409SSimon J. Gerraty 	fd = accept(server_fd, (struct sockaddr *)&sa, &sa_len);
177*0957b409SSimon J. Gerraty 	if (fd == INVALID_SOCKET) {
178*0957b409SSimon J. Gerraty 		if (verbose) {
179*0957b409SSimon J. Gerraty 			perror("accept()");
180*0957b409SSimon J. Gerraty 		}
181*0957b409SSimon J. Gerraty 		return INVALID_SOCKET;
182*0957b409SSimon J. Gerraty 	}
183*0957b409SSimon J. Gerraty 	if (verbose) {
184*0957b409SSimon J. Gerraty 		char tmp[INET6_ADDRSTRLEN + 50];
185*0957b409SSimon J. Gerraty 		const char *name;
186*0957b409SSimon J. Gerraty 
187*0957b409SSimon J. Gerraty 		name = NULL;
188*0957b409SSimon J. Gerraty 		switch (((struct sockaddr *)&sa)->sa_family) {
189*0957b409SSimon J. Gerraty 		case AF_INET:
190*0957b409SSimon J. Gerraty 			name = inet_ntop(AF_INET,
191*0957b409SSimon J. Gerraty 				&((struct sockaddr_in *)&sa)->sin_addr,
192*0957b409SSimon J. Gerraty 				tmp, sizeof tmp);
193*0957b409SSimon J. Gerraty 			break;
194*0957b409SSimon J. Gerraty 		case AF_INET6:
195*0957b409SSimon J. Gerraty 			name = inet_ntop(AF_INET6,
196*0957b409SSimon J. Gerraty 				&((struct sockaddr_in6 *)&sa)->sin6_addr,
197*0957b409SSimon J. Gerraty 				tmp, sizeof tmp);
198*0957b409SSimon J. Gerraty 			break;
199*0957b409SSimon J. Gerraty 		}
200*0957b409SSimon J. Gerraty 		if (name == NULL) {
201*0957b409SSimon J. Gerraty 			sprintf(tmp, "<unknown: %lu>", (unsigned long)
202*0957b409SSimon J. Gerraty 				((struct sockaddr *)&sa)->sa_family);
203*0957b409SSimon J. Gerraty 			name = tmp;
204*0957b409SSimon J. Gerraty 		}
205*0957b409SSimon J. Gerraty 		fprintf(stderr, "accepting connection from: %s\n", name);
206*0957b409SSimon J. Gerraty 	}
207*0957b409SSimon J. Gerraty 
208*0957b409SSimon J. Gerraty 	/*
209*0957b409SSimon J. Gerraty 	 * We make the socket non-blocking, since we are going to use
210*0957b409SSimon J. Gerraty 	 * poll() or select() to organise I/O.
211*0957b409SSimon J. Gerraty 	 */
212*0957b409SSimon J. Gerraty 	if (nonblock) {
213*0957b409SSimon J. Gerraty #ifdef _WIN32
214*0957b409SSimon J. Gerraty 		u_long arg;
215*0957b409SSimon J. Gerraty 
216*0957b409SSimon J. Gerraty 		arg = 1;
217*0957b409SSimon J. Gerraty 		ioctlsocket(fd, FIONBIO, &arg);
218*0957b409SSimon J. Gerraty #else
219*0957b409SSimon J. Gerraty 		fcntl(fd, F_SETFL, O_NONBLOCK);
220*0957b409SSimon J. Gerraty #endif
221*0957b409SSimon J. Gerraty 	}
222*0957b409SSimon J. Gerraty 	return fd;
223*0957b409SSimon J. Gerraty }
224*0957b409SSimon J. Gerraty 
225*0957b409SSimon J. Gerraty static void
usage_server(void)226*0957b409SSimon J. Gerraty usage_server(void)
227*0957b409SSimon J. Gerraty {
228*0957b409SSimon J. Gerraty 	fprintf(stderr,
229*0957b409SSimon J. Gerraty "usage: brssl server [ options ]\n");
230*0957b409SSimon J. Gerraty 	fprintf(stderr,
231*0957b409SSimon J. Gerraty "options:\n");
232*0957b409SSimon J. Gerraty 	fprintf(stderr,
233*0957b409SSimon J. Gerraty "   -q              suppress verbose messages\n");
234*0957b409SSimon J. Gerraty 	fprintf(stderr,
235*0957b409SSimon J. Gerraty "   -trace          activate extra debug messages (dump of all packets)\n");
236*0957b409SSimon J. Gerraty 	fprintf(stderr,
237*0957b409SSimon J. Gerraty "   -b name         bind to a specific address or host name\n");
238*0957b409SSimon J. Gerraty 	fprintf(stderr,
239*0957b409SSimon J. Gerraty "   -p port         bind to a specific port (default: 4433)\n");
240*0957b409SSimon J. Gerraty 	fprintf(stderr,
241*0957b409SSimon J. Gerraty "   -mono           use monodirectional buffering\n");
242*0957b409SSimon J. Gerraty 	fprintf(stderr,
243*0957b409SSimon J. Gerraty "   -buf length     set the I/O buffer length (in bytes)\n");
244*0957b409SSimon J. Gerraty 	fprintf(stderr,
245*0957b409SSimon J. Gerraty "   -cache length   set the session cache storage length (in bytes)\n");
246*0957b409SSimon J. Gerraty 	fprintf(stderr,
247*0957b409SSimon J. Gerraty "   -cert fname     read certificate chain from file 'fname'\n");
248*0957b409SSimon J. Gerraty 	fprintf(stderr,
249*0957b409SSimon J. Gerraty "   -key fname      read private key from file 'fname'\n");
250*0957b409SSimon J. Gerraty 	fprintf(stderr,
251*0957b409SSimon J. Gerraty "   -CA file        add trust anchors from 'file' (for client auth)\n");
252*0957b409SSimon J. Gerraty 	fprintf(stderr,
253*0957b409SSimon J. Gerraty "   -anon_ok        request but do not require a client certificate\n");
254*0957b409SSimon J. Gerraty 	fprintf(stderr,
255*0957b409SSimon J. Gerraty "   -list           list supported names (protocols, algorithms...)\n");
256*0957b409SSimon J. Gerraty 	fprintf(stderr,
257*0957b409SSimon J. Gerraty "   -vmin name      set minimum supported version (default: TLS-1.0)\n");
258*0957b409SSimon J. Gerraty 	fprintf(stderr,
259*0957b409SSimon J. Gerraty "   -vmax name      set maximum supported version (default: TLS-1.2)\n");
260*0957b409SSimon J. Gerraty 	fprintf(stderr,
261*0957b409SSimon J. Gerraty "   -cs names       set list of supported cipher suites (comma-separated)\n");
262*0957b409SSimon J. Gerraty 	fprintf(stderr,
263*0957b409SSimon J. Gerraty "   -hf names       add support for some hash functions (comma-separated)\n");
264*0957b409SSimon J. Gerraty 	fprintf(stderr,
265*0957b409SSimon J. Gerraty "   -cbhash         test hashing in policy callback\n");
266*0957b409SSimon J. Gerraty 	fprintf(stderr,
267*0957b409SSimon J. Gerraty "   -serverpref     enforce server's preferences for cipher suites\n");
268*0957b409SSimon J. Gerraty 	fprintf(stderr,
269*0957b409SSimon J. Gerraty "   -noreneg        prohibit renegotiations\n");
270*0957b409SSimon J. Gerraty 	fprintf(stderr,
271*0957b409SSimon J. Gerraty "   -alpn name      add protocol name to list of protocols (ALPN extension)\n");
272*0957b409SSimon J. Gerraty 	fprintf(stderr,
273*0957b409SSimon J. Gerraty "   -strictalpn     fail on ALPN mismatch\n");
274*0957b409SSimon J. Gerraty 	exit(EXIT_FAILURE);
275*0957b409SSimon J. Gerraty }
276*0957b409SSimon J. Gerraty 
277*0957b409SSimon J. Gerraty typedef struct {
278*0957b409SSimon J. Gerraty 	const br_ssl_server_policy_class *vtable;
279*0957b409SSimon J. Gerraty 	int verbose;
280*0957b409SSimon J. Gerraty 	br_x509_certificate *chain;
281*0957b409SSimon J. Gerraty 	size_t chain_len;
282*0957b409SSimon J. Gerraty 	int cert_signer_algo;
283*0957b409SSimon J. Gerraty 	private_key *sk;
284*0957b409SSimon J. Gerraty 	int cbhash;
285*0957b409SSimon J. Gerraty } policy_context;
286*0957b409SSimon J. Gerraty 
287*0957b409SSimon J. Gerraty static void
print_hashes(unsigned chashes)288*0957b409SSimon J. Gerraty print_hashes(unsigned chashes)
289*0957b409SSimon J. Gerraty {
290*0957b409SSimon J. Gerraty 	int i;
291*0957b409SSimon J. Gerraty 
292*0957b409SSimon J. Gerraty 	for (i = 2; i <= 6; i ++) {
293*0957b409SSimon J. Gerraty 		if ((chashes >> i) & 1) {
294*0957b409SSimon J. Gerraty 			int z;
295*0957b409SSimon J. Gerraty 
296*0957b409SSimon J. Gerraty 			switch (i) {
297*0957b409SSimon J. Gerraty 			case 3: z = 224; break;
298*0957b409SSimon J. Gerraty 			case 4: z = 256; break;
299*0957b409SSimon J. Gerraty 			case 5: z = 384; break;
300*0957b409SSimon J. Gerraty 			case 6: z = 512; break;
301*0957b409SSimon J. Gerraty 			default:
302*0957b409SSimon J. Gerraty 				z = 1;
303*0957b409SSimon J. Gerraty 				break;
304*0957b409SSimon J. Gerraty 			}
305*0957b409SSimon J. Gerraty 			fprintf(stderr, " sha%d", z);
306*0957b409SSimon J. Gerraty 		}
307*0957b409SSimon J. Gerraty 	}
308*0957b409SSimon J. Gerraty }
309*0957b409SSimon J. Gerraty 
310*0957b409SSimon J. Gerraty static unsigned
choose_hash(unsigned chashes)311*0957b409SSimon J. Gerraty choose_hash(unsigned chashes)
312*0957b409SSimon J. Gerraty {
313*0957b409SSimon J. Gerraty 	unsigned hash_id;
314*0957b409SSimon J. Gerraty 
315*0957b409SSimon J. Gerraty 	for (hash_id = 6; hash_id >= 2; hash_id --) {
316*0957b409SSimon J. Gerraty 		if (((chashes >> hash_id) & 1) != 0) {
317*0957b409SSimon J. Gerraty 			return hash_id;
318*0957b409SSimon J. Gerraty 		}
319*0957b409SSimon J. Gerraty 	}
320*0957b409SSimon J. Gerraty 	/*
321*0957b409SSimon J. Gerraty 	 * Normally unreachable.
322*0957b409SSimon J. Gerraty 	 */
323*0957b409SSimon J. Gerraty 	return 0;
324*0957b409SSimon J. Gerraty }
325*0957b409SSimon J. Gerraty 
326*0957b409SSimon J. Gerraty static int
sp_choose(const br_ssl_server_policy_class ** pctx,const br_ssl_server_context * cc,br_ssl_server_choices * choices)327*0957b409SSimon J. Gerraty sp_choose(const br_ssl_server_policy_class **pctx,
328*0957b409SSimon J. Gerraty 	const br_ssl_server_context *cc,
329*0957b409SSimon J. Gerraty 	br_ssl_server_choices *choices)
330*0957b409SSimon J. Gerraty {
331*0957b409SSimon J. Gerraty 	policy_context *pc;
332*0957b409SSimon J. Gerraty 	const br_suite_translated *st;
333*0957b409SSimon J. Gerraty 	size_t u, st_num;
334*0957b409SSimon J. Gerraty 	unsigned chashes;
335*0957b409SSimon J. Gerraty 
336*0957b409SSimon J. Gerraty 	pc = (policy_context *)pctx;
337*0957b409SSimon J. Gerraty 	st = br_ssl_server_get_client_suites(cc, &st_num);
338*0957b409SSimon J. Gerraty 	chashes = br_ssl_server_get_client_hashes(cc);
339*0957b409SSimon J. Gerraty 	if (pc->verbose) {
340*0957b409SSimon J. Gerraty 		fprintf(stderr, "Client parameters:\n");
341*0957b409SSimon J. Gerraty 		fprintf(stderr, "   Maximum version:      ");
342*0957b409SSimon J. Gerraty 		switch (cc->client_max_version) {
343*0957b409SSimon J. Gerraty 		case BR_SSL30:
344*0957b409SSimon J. Gerraty 			fprintf(stderr, "SSL 3.0");
345*0957b409SSimon J. Gerraty 			break;
346*0957b409SSimon J. Gerraty 		case BR_TLS10:
347*0957b409SSimon J. Gerraty 			fprintf(stderr, "TLS 1.0");
348*0957b409SSimon J. Gerraty 			break;
349*0957b409SSimon J. Gerraty 		case BR_TLS11:
350*0957b409SSimon J. Gerraty 			fprintf(stderr, "TLS 1.1");
351*0957b409SSimon J. Gerraty 			break;
352*0957b409SSimon J. Gerraty 		case BR_TLS12:
353*0957b409SSimon J. Gerraty 			fprintf(stderr, "TLS 1.2");
354*0957b409SSimon J. Gerraty 			break;
355*0957b409SSimon J. Gerraty 		default:
356*0957b409SSimon J. Gerraty 			fprintf(stderr, "unknown (0x%04X)",
357*0957b409SSimon J. Gerraty 				(unsigned)cc->client_max_version);
358*0957b409SSimon J. Gerraty 			break;
359*0957b409SSimon J. Gerraty 		}
360*0957b409SSimon J. Gerraty 		fprintf(stderr, "\n");
361*0957b409SSimon J. Gerraty 		fprintf(stderr, "   Compatible cipher suites:\n");
362*0957b409SSimon J. Gerraty 		for (u = 0; u < st_num; u ++) {
363*0957b409SSimon J. Gerraty 			char csn[80];
364*0957b409SSimon J. Gerraty 
365*0957b409SSimon J. Gerraty 			get_suite_name_ext(st[u][0], csn, sizeof csn);
366*0957b409SSimon J. Gerraty 			fprintf(stderr, "      %s\n", csn);
367*0957b409SSimon J. Gerraty 		}
368*0957b409SSimon J. Gerraty 		fprintf(stderr, "   Common sign+hash functions:\n");
369*0957b409SSimon J. Gerraty 		if ((chashes & 0xFF) != 0) {
370*0957b409SSimon J. Gerraty 			fprintf(stderr, "      with RSA:");
371*0957b409SSimon J. Gerraty 			print_hashes(chashes);
372*0957b409SSimon J. Gerraty 			fprintf(stderr, "\n");
373*0957b409SSimon J. Gerraty 		}
374*0957b409SSimon J. Gerraty 		if ((chashes >> 8) != 0) {
375*0957b409SSimon J. Gerraty 			fprintf(stderr, "      with ECDSA:");
376*0957b409SSimon J. Gerraty 			print_hashes(chashes >> 8);
377*0957b409SSimon J. Gerraty 			fprintf(stderr, "\n");
378*0957b409SSimon J. Gerraty 		}
379*0957b409SSimon J. Gerraty 	}
380*0957b409SSimon J. Gerraty 	for (u = 0; u < st_num; u ++) {
381*0957b409SSimon J. Gerraty 		unsigned tt;
382*0957b409SSimon J. Gerraty 
383*0957b409SSimon J. Gerraty 		tt = st[u][1];
384*0957b409SSimon J. Gerraty 		switch (tt >> 12) {
385*0957b409SSimon J. Gerraty 		case BR_SSLKEYX_RSA:
386*0957b409SSimon J. Gerraty 			if (pc->sk->key_type == BR_KEYTYPE_RSA) {
387*0957b409SSimon J. Gerraty 				choices->cipher_suite = st[u][0];
388*0957b409SSimon J. Gerraty 				goto choose_ok;
389*0957b409SSimon J. Gerraty 			}
390*0957b409SSimon J. Gerraty 			break;
391*0957b409SSimon J. Gerraty 		case BR_SSLKEYX_ECDHE_RSA:
392*0957b409SSimon J. Gerraty 			if (pc->sk->key_type == BR_KEYTYPE_RSA) {
393*0957b409SSimon J. Gerraty 				choices->cipher_suite = st[u][0];
394*0957b409SSimon J. Gerraty 				if (br_ssl_engine_get_version(&cc->eng)
395*0957b409SSimon J. Gerraty 					< BR_TLS12)
396*0957b409SSimon J. Gerraty 				{
397*0957b409SSimon J. Gerraty 					if (pc->cbhash) {
398*0957b409SSimon J. Gerraty 						choices->algo_id = 0x0001;
399*0957b409SSimon J. Gerraty 					} else {
400*0957b409SSimon J. Gerraty 						choices->algo_id = 0xFF00;
401*0957b409SSimon J. Gerraty 					}
402*0957b409SSimon J. Gerraty 				} else {
403*0957b409SSimon J. Gerraty 					unsigned id;
404*0957b409SSimon J. Gerraty 
405*0957b409SSimon J. Gerraty 					id = choose_hash(chashes);
406*0957b409SSimon J. Gerraty 					if (pc->cbhash) {
407*0957b409SSimon J. Gerraty 						choices->algo_id =
408*0957b409SSimon J. Gerraty 							(id << 8) + 0x01;
409*0957b409SSimon J. Gerraty 					} else {
410*0957b409SSimon J. Gerraty 						choices->algo_id = 0xFF00 + id;
411*0957b409SSimon J. Gerraty 					}
412*0957b409SSimon J. Gerraty 				}
413*0957b409SSimon J. Gerraty 				goto choose_ok;
414*0957b409SSimon J. Gerraty 			}
415*0957b409SSimon J. Gerraty 			break;
416*0957b409SSimon J. Gerraty 		case BR_SSLKEYX_ECDHE_ECDSA:
417*0957b409SSimon J. Gerraty 			if (pc->sk->key_type == BR_KEYTYPE_EC) {
418*0957b409SSimon J. Gerraty 				choices->cipher_suite = st[u][0];
419*0957b409SSimon J. Gerraty 				if (br_ssl_engine_get_version(&cc->eng)
420*0957b409SSimon J. Gerraty 					< BR_TLS12)
421*0957b409SSimon J. Gerraty 				{
422*0957b409SSimon J. Gerraty 					if (pc->cbhash) {
423*0957b409SSimon J. Gerraty 						choices->algo_id = 0x0203;
424*0957b409SSimon J. Gerraty 					} else {
425*0957b409SSimon J. Gerraty 						choices->algo_id =
426*0957b409SSimon J. Gerraty 							0xFF00 + br_sha1_ID;
427*0957b409SSimon J. Gerraty 					}
428*0957b409SSimon J. Gerraty 				} else {
429*0957b409SSimon J. Gerraty 					unsigned id;
430*0957b409SSimon J. Gerraty 
431*0957b409SSimon J. Gerraty 					id = choose_hash(chashes >> 8);
432*0957b409SSimon J. Gerraty 					if (pc->cbhash) {
433*0957b409SSimon J. Gerraty 						choices->algo_id =
434*0957b409SSimon J. Gerraty 							(id << 8) + 0x03;
435*0957b409SSimon J. Gerraty 					} else {
436*0957b409SSimon J. Gerraty 						choices->algo_id =
437*0957b409SSimon J. Gerraty 							0xFF00 + id;
438*0957b409SSimon J. Gerraty 					}
439*0957b409SSimon J. Gerraty 				}
440*0957b409SSimon J. Gerraty 				goto choose_ok;
441*0957b409SSimon J. Gerraty 			}
442*0957b409SSimon J. Gerraty 			break;
443*0957b409SSimon J. Gerraty 		case BR_SSLKEYX_ECDH_RSA:
444*0957b409SSimon J. Gerraty 			if (pc->sk->key_type == BR_KEYTYPE_EC
445*0957b409SSimon J. Gerraty 				&& pc->cert_signer_algo == BR_KEYTYPE_RSA)
446*0957b409SSimon J. Gerraty 			{
447*0957b409SSimon J. Gerraty 				choices->cipher_suite = st[u][0];
448*0957b409SSimon J. Gerraty 				goto choose_ok;
449*0957b409SSimon J. Gerraty 			}
450*0957b409SSimon J. Gerraty 			break;
451*0957b409SSimon J. Gerraty 		case BR_SSLKEYX_ECDH_ECDSA:
452*0957b409SSimon J. Gerraty 			if (pc->sk->key_type == BR_KEYTYPE_EC
453*0957b409SSimon J. Gerraty 				&& pc->cert_signer_algo == BR_KEYTYPE_EC)
454*0957b409SSimon J. Gerraty 			{
455*0957b409SSimon J. Gerraty 				choices->cipher_suite = st[u][0];
456*0957b409SSimon J. Gerraty 				goto choose_ok;
457*0957b409SSimon J. Gerraty 			}
458*0957b409SSimon J. Gerraty 			break;
459*0957b409SSimon J. Gerraty 		}
460*0957b409SSimon J. Gerraty 	}
461*0957b409SSimon J. Gerraty 	return 0;
462*0957b409SSimon J. Gerraty 
463*0957b409SSimon J. Gerraty choose_ok:
464*0957b409SSimon J. Gerraty 	choices->chain = pc->chain;
465*0957b409SSimon J. Gerraty 	choices->chain_len = pc->chain_len;
466*0957b409SSimon J. Gerraty 	if (pc->verbose) {
467*0957b409SSimon J. Gerraty 		char csn[80];
468*0957b409SSimon J. Gerraty 
469*0957b409SSimon J. Gerraty 		get_suite_name_ext(choices->cipher_suite, csn, sizeof csn);
470*0957b409SSimon J. Gerraty 		fprintf(stderr, "Using: %s\n", csn);
471*0957b409SSimon J. Gerraty 	}
472*0957b409SSimon J. Gerraty 	return 1;
473*0957b409SSimon J. Gerraty }
474*0957b409SSimon J. Gerraty 
475*0957b409SSimon J. Gerraty static uint32_t
sp_do_keyx(const br_ssl_server_policy_class ** pctx,unsigned char * data,size_t * len)476*0957b409SSimon J. Gerraty sp_do_keyx(const br_ssl_server_policy_class **pctx,
477*0957b409SSimon J. Gerraty 	unsigned char *data, size_t *len)
478*0957b409SSimon J. Gerraty {
479*0957b409SSimon J. Gerraty 	policy_context *pc;
480*0957b409SSimon J. Gerraty 	uint32_t r;
481*0957b409SSimon J. Gerraty 	size_t xoff, xlen;
482*0957b409SSimon J. Gerraty 
483*0957b409SSimon J. Gerraty 	pc = (policy_context *)pctx;
484*0957b409SSimon J. Gerraty 	switch (pc->sk->key_type) {
485*0957b409SSimon J. Gerraty 		const br_ec_impl *iec;
486*0957b409SSimon J. Gerraty 
487*0957b409SSimon J. Gerraty 	case BR_KEYTYPE_RSA:
488*0957b409SSimon J. Gerraty 		return br_rsa_ssl_decrypt(
489*0957b409SSimon J. Gerraty 			br_rsa_private_get_default(),
490*0957b409SSimon J. Gerraty 			&pc->sk->key.rsa, data, *len);
491*0957b409SSimon J. Gerraty 	case BR_KEYTYPE_EC:
492*0957b409SSimon J. Gerraty 		iec = br_ec_get_default();
493*0957b409SSimon J. Gerraty 		r = iec->mul(data, *len, pc->sk->key.ec.x,
494*0957b409SSimon J. Gerraty 			pc->sk->key.ec.xlen, pc->sk->key.ec.curve);
495*0957b409SSimon J. Gerraty 		xoff = iec->xoff(pc->sk->key.ec.curve, &xlen);
496*0957b409SSimon J. Gerraty 		memmove(data, data + xoff, xlen);
497*0957b409SSimon J. Gerraty 		*len = xlen;
498*0957b409SSimon J. Gerraty 		return r;
499*0957b409SSimon J. Gerraty 	default:
500*0957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: unknown private key type (%d)\n",
501*0957b409SSimon J. Gerraty 			(int)pc->sk->key_type);
502*0957b409SSimon J. Gerraty 		return 0;
503*0957b409SSimon J. Gerraty 	}
504*0957b409SSimon J. Gerraty }
505*0957b409SSimon J. Gerraty 
506*0957b409SSimon J. Gerraty static size_t
sp_do_sign(const br_ssl_server_policy_class ** pctx,unsigned algo_id,unsigned char * data,size_t hv_len,size_t len)507*0957b409SSimon J. Gerraty sp_do_sign(const br_ssl_server_policy_class **pctx,
508*0957b409SSimon J. Gerraty 	unsigned algo_id, unsigned char *data, size_t hv_len, size_t len)
509*0957b409SSimon J. Gerraty {
510*0957b409SSimon J. Gerraty 	policy_context *pc;
511*0957b409SSimon J. Gerraty 	unsigned char hv[64];
512*0957b409SSimon J. Gerraty 
513*0957b409SSimon J. Gerraty 	pc = (policy_context *)pctx;
514*0957b409SSimon J. Gerraty 	if (algo_id >= 0xFF00) {
515*0957b409SSimon J. Gerraty 		algo_id &= 0xFF;
516*0957b409SSimon J. Gerraty 		memcpy(hv, data, hv_len);
517*0957b409SSimon J. Gerraty 	} else {
518*0957b409SSimon J. Gerraty 		const br_hash_class *hc;
519*0957b409SSimon J. Gerraty 		br_hash_compat_context zc;
520*0957b409SSimon J. Gerraty 
521*0957b409SSimon J. Gerraty 		if (pc->verbose) {
522*0957b409SSimon J. Gerraty 			fprintf(stderr, "Callback hashing, algo = 0x%04X,"
523*0957b409SSimon J. Gerraty 				" data_len = %lu\n",
524*0957b409SSimon J. Gerraty 				algo_id, (unsigned long)hv_len);
525*0957b409SSimon J. Gerraty 		}
526*0957b409SSimon J. Gerraty 		algo_id >>= 8;
527*0957b409SSimon J. Gerraty 		hc = get_hash_impl(algo_id);
528*0957b409SSimon J. Gerraty 		if (hc == NULL) {
529*0957b409SSimon J. Gerraty 			if (pc->verbose) {
530*0957b409SSimon J. Gerraty 				fprintf(stderr,
531*0957b409SSimon J. Gerraty 					"ERROR: unsupported hash function %u\n",
532*0957b409SSimon J. Gerraty 					algo_id);
533*0957b409SSimon J. Gerraty 			}
534*0957b409SSimon J. Gerraty 			return 0;
535*0957b409SSimon J. Gerraty 		}
536*0957b409SSimon J. Gerraty 		hc->init(&zc.vtable);
537*0957b409SSimon J. Gerraty 		hc->update(&zc.vtable, data, hv_len);
538*0957b409SSimon J. Gerraty 		hc->out(&zc.vtable, hv);
539*0957b409SSimon J. Gerraty 		hv_len = (hc->desc >> BR_HASHDESC_OUT_OFF)
540*0957b409SSimon J. Gerraty 			& BR_HASHDESC_OUT_MASK;
541*0957b409SSimon J. Gerraty 	}
542*0957b409SSimon J. Gerraty 	switch (pc->sk->key_type) {
543*0957b409SSimon J. Gerraty 		size_t sig_len;
544*0957b409SSimon J. Gerraty 		uint32_t x;
545*0957b409SSimon J. Gerraty 		const unsigned char *hash_oid;
546*0957b409SSimon J. Gerraty 		const br_hash_class *hc;
547*0957b409SSimon J. Gerraty 
548*0957b409SSimon J. Gerraty 	case BR_KEYTYPE_RSA:
549*0957b409SSimon J. Gerraty 		hash_oid = get_hash_oid(algo_id);
550*0957b409SSimon J. Gerraty 		if (hash_oid == NULL && algo_id != 0) {
551*0957b409SSimon J. Gerraty 			if (pc->verbose) {
552*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: cannot RSA-sign with"
553*0957b409SSimon J. Gerraty 					" unknown hash function: %u\n",
554*0957b409SSimon J. Gerraty 					algo_id);
555*0957b409SSimon J. Gerraty 			}
556*0957b409SSimon J. Gerraty 			return 0;
557*0957b409SSimon J. Gerraty 		}
558*0957b409SSimon J. Gerraty 		sig_len = (pc->sk->key.rsa.n_bitlen + 7) >> 3;
559*0957b409SSimon J. Gerraty 		if (len < sig_len) {
560*0957b409SSimon J. Gerraty 			if (pc->verbose) {
561*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: cannot RSA-sign,"
562*0957b409SSimon J. Gerraty 					" buffer is too small"
563*0957b409SSimon J. Gerraty 					" (sig=%lu, buf=%lu)\n",
564*0957b409SSimon J. Gerraty 					(unsigned long)sig_len,
565*0957b409SSimon J. Gerraty 					(unsigned long)len);
566*0957b409SSimon J. Gerraty 			}
567*0957b409SSimon J. Gerraty 			return 0;
568*0957b409SSimon J. Gerraty 		}
569*0957b409SSimon J. Gerraty 		x = br_rsa_pkcs1_sign_get_default()(
570*0957b409SSimon J. Gerraty 			hash_oid, hv, hv_len, &pc->sk->key.rsa, data);
571*0957b409SSimon J. Gerraty 		if (!x) {
572*0957b409SSimon J. Gerraty 			if (pc->verbose) {
573*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: RSA-sign failure\n");
574*0957b409SSimon J. Gerraty 			}
575*0957b409SSimon J. Gerraty 			return 0;
576*0957b409SSimon J. Gerraty 		}
577*0957b409SSimon J. Gerraty 		return sig_len;
578*0957b409SSimon J. Gerraty 
579*0957b409SSimon J. Gerraty 	case BR_KEYTYPE_EC:
580*0957b409SSimon J. Gerraty 		hc = get_hash_impl(algo_id);
581*0957b409SSimon J. Gerraty 		if (hc == NULL) {
582*0957b409SSimon J. Gerraty 			if (pc->verbose) {
583*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: cannot ECDSA-sign with"
584*0957b409SSimon J. Gerraty 					" unknown hash function: %u\n",
585*0957b409SSimon J. Gerraty 					algo_id);
586*0957b409SSimon J. Gerraty 			}
587*0957b409SSimon J. Gerraty 			return 0;
588*0957b409SSimon J. Gerraty 		}
589*0957b409SSimon J. Gerraty 		if (len < 139) {
590*0957b409SSimon J. Gerraty 			if (pc->verbose) {
591*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: cannot ECDSA-sign"
592*0957b409SSimon J. Gerraty 					" (output buffer = %lu)\n",
593*0957b409SSimon J. Gerraty 					(unsigned long)len);
594*0957b409SSimon J. Gerraty 			}
595*0957b409SSimon J. Gerraty 			return 0;
596*0957b409SSimon J. Gerraty 		}
597*0957b409SSimon J. Gerraty 		sig_len = br_ecdsa_sign_asn1_get_default()(
598*0957b409SSimon J. Gerraty 			br_ec_get_default(), hc, hv, &pc->sk->key.ec, data);
599*0957b409SSimon J. Gerraty 		if (sig_len == 0) {
600*0957b409SSimon J. Gerraty 			if (pc->verbose) {
601*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: ECDSA-sign failure\n");
602*0957b409SSimon J. Gerraty 			}
603*0957b409SSimon J. Gerraty 			return 0;
604*0957b409SSimon J. Gerraty 		}
605*0957b409SSimon J. Gerraty 		return sig_len;
606*0957b409SSimon J. Gerraty 
607*0957b409SSimon J. Gerraty 	default:
608*0957b409SSimon J. Gerraty 		return 0;
609*0957b409SSimon J. Gerraty 	}
610*0957b409SSimon J. Gerraty }
611*0957b409SSimon J. Gerraty 
612*0957b409SSimon J. Gerraty static const br_ssl_server_policy_class policy_vtable = {
613*0957b409SSimon J. Gerraty 	sizeof(policy_context),
614*0957b409SSimon J. Gerraty 	sp_choose,
615*0957b409SSimon J. Gerraty 	sp_do_keyx,
616*0957b409SSimon J. Gerraty 	sp_do_sign
617*0957b409SSimon J. Gerraty };
618*0957b409SSimon J. Gerraty 
619*0957b409SSimon J. Gerraty void
free_alpn(void * alpn)620*0957b409SSimon J. Gerraty free_alpn(void *alpn)
621*0957b409SSimon J. Gerraty {
622*0957b409SSimon J. Gerraty 	xfree(*(char **)alpn);
623*0957b409SSimon J. Gerraty }
624*0957b409SSimon J. Gerraty 
625*0957b409SSimon J. Gerraty /* see brssl.h */
626*0957b409SSimon J. Gerraty int
do_server(int argc,char * argv[])627*0957b409SSimon J. Gerraty do_server(int argc, char *argv[])
628*0957b409SSimon J. Gerraty {
629*0957b409SSimon J. Gerraty 	int retcode;
630*0957b409SSimon J. Gerraty 	int verbose;
631*0957b409SSimon J. Gerraty 	int trace;
632*0957b409SSimon J. Gerraty 	int i, bidi;
633*0957b409SSimon J. Gerraty 	const char *bind_name;
634*0957b409SSimon J. Gerraty 	const char *port;
635*0957b409SSimon J. Gerraty 	unsigned vmin, vmax;
636*0957b409SSimon J. Gerraty 	cipher_suite *suites;
637*0957b409SSimon J. Gerraty 	size_t num_suites;
638*0957b409SSimon J. Gerraty 	uint16_t *suite_ids;
639*0957b409SSimon J. Gerraty 	unsigned hfuns;
640*0957b409SSimon J. Gerraty 	int cbhash;
641*0957b409SSimon J. Gerraty 	br_x509_certificate *chain;
642*0957b409SSimon J. Gerraty 	size_t chain_len;
643*0957b409SSimon J. Gerraty 	int cert_signer_algo;
644*0957b409SSimon J. Gerraty 	private_key *sk;
645*0957b409SSimon J. Gerraty 	anchor_list anchors = VEC_INIT;
646*0957b409SSimon J. Gerraty 	VECTOR(char *) alpn_names = VEC_INIT;
647*0957b409SSimon J. Gerraty 	br_x509_minimal_context xc;
648*0957b409SSimon J. Gerraty 	const br_hash_class *dnhash;
649*0957b409SSimon J. Gerraty 	size_t u;
650*0957b409SSimon J. Gerraty 	br_ssl_server_context cc;
651*0957b409SSimon J. Gerraty 	policy_context pc;
652*0957b409SSimon J. Gerraty 	br_ssl_session_cache_lru lru;
653*0957b409SSimon J. Gerraty 	unsigned char *iobuf, *cache;
654*0957b409SSimon J. Gerraty 	size_t iobuf_len, cache_len;
655*0957b409SSimon J. Gerraty 	uint32_t flags;
656*0957b409SSimon J. Gerraty 	SOCKET server_fd, fd;
657*0957b409SSimon J. Gerraty 
658*0957b409SSimon J. Gerraty 	retcode = 0;
659*0957b409SSimon J. Gerraty 	verbose = 1;
660*0957b409SSimon J. Gerraty 	trace = 0;
661*0957b409SSimon J. Gerraty 	bind_name = NULL;
662*0957b409SSimon J. Gerraty 	port = NULL;
663*0957b409SSimon J. Gerraty 	bidi = 1;
664*0957b409SSimon J. Gerraty 	vmin = 0;
665*0957b409SSimon J. Gerraty 	vmax = 0;
666*0957b409SSimon J. Gerraty 	suites = NULL;
667*0957b409SSimon J. Gerraty 	num_suites = 0;
668*0957b409SSimon J. Gerraty 	hfuns = 0;
669*0957b409SSimon J. Gerraty 	cbhash = 0;
670*0957b409SSimon J. Gerraty 	suite_ids = NULL;
671*0957b409SSimon J. Gerraty 	chain = NULL;
672*0957b409SSimon J. Gerraty 	chain_len = 0;
673*0957b409SSimon J. Gerraty 	sk = NULL;
674*0957b409SSimon J. Gerraty 	iobuf = NULL;
675*0957b409SSimon J. Gerraty 	iobuf_len = 0;
676*0957b409SSimon J. Gerraty 	cache = NULL;
677*0957b409SSimon J. Gerraty 	cache_len = (size_t)-1;
678*0957b409SSimon J. Gerraty 	flags = 0;
679*0957b409SSimon J. Gerraty 	server_fd = INVALID_SOCKET;
680*0957b409SSimon J. Gerraty 	fd = INVALID_SOCKET;
681*0957b409SSimon J. Gerraty 	for (i = 0; i < argc; i ++) {
682*0957b409SSimon J. Gerraty 		const char *arg;
683*0957b409SSimon J. Gerraty 
684*0957b409SSimon J. Gerraty 		arg = argv[i];
685*0957b409SSimon J. Gerraty 		if (arg[0] != '-') {
686*0957b409SSimon J. Gerraty 			usage_server();
687*0957b409SSimon J. Gerraty 			goto server_exit_error;
688*0957b409SSimon J. Gerraty 		}
689*0957b409SSimon J. Gerraty 		if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
690*0957b409SSimon J. Gerraty 			verbose = 1;
691*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
692*0957b409SSimon J. Gerraty 			verbose = 0;
693*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-trace")) {
694*0957b409SSimon J. Gerraty 			trace = 1;
695*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-b")) {
696*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
697*0957b409SSimon J. Gerraty 				fprintf(stderr,
698*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-b'\n");
699*0957b409SSimon J. Gerraty 				usage_server();
700*0957b409SSimon J. Gerraty 				goto server_exit_error;
701*0957b409SSimon J. Gerraty 			}
702*0957b409SSimon J. Gerraty 			if (bind_name != NULL) {
703*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: duplicate bind host\n");
704*0957b409SSimon J. Gerraty 				usage_server();
705*0957b409SSimon J. Gerraty 				goto server_exit_error;
706*0957b409SSimon J. Gerraty 			}
707*0957b409SSimon J. Gerraty 			bind_name = argv[i];
708*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-p")) {
709*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
710*0957b409SSimon J. Gerraty 				fprintf(stderr,
711*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-p'\n");
712*0957b409SSimon J. Gerraty 				usage_server();
713*0957b409SSimon J. Gerraty 				goto server_exit_error;
714*0957b409SSimon J. Gerraty 			}
715*0957b409SSimon J. Gerraty 			if (port != NULL) {
716*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: duplicate bind port\n");
717*0957b409SSimon J. Gerraty 				usage_server();
718*0957b409SSimon J. Gerraty 				goto server_exit_error;
719*0957b409SSimon J. Gerraty 			}
720*0957b409SSimon J. Gerraty 			port = argv[i];
721*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-mono")) {
722*0957b409SSimon J. Gerraty 			bidi = 0;
723*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-buf")) {
724*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
725*0957b409SSimon J. Gerraty 				fprintf(stderr,
726*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-buf'\n");
727*0957b409SSimon J. Gerraty 				usage_server();
728*0957b409SSimon J. Gerraty 				goto server_exit_error;
729*0957b409SSimon J. Gerraty 			}
730*0957b409SSimon J. Gerraty 			arg = argv[i];
731*0957b409SSimon J. Gerraty 			if (iobuf_len != 0) {
732*0957b409SSimon J. Gerraty 				fprintf(stderr,
733*0957b409SSimon J. Gerraty 					"ERROR: duplicate I/O buffer length\n");
734*0957b409SSimon J. Gerraty 				usage_server();
735*0957b409SSimon J. Gerraty 				goto server_exit_error;
736*0957b409SSimon J. Gerraty 			}
737*0957b409SSimon J. Gerraty 			iobuf_len = parse_size(arg);
738*0957b409SSimon J. Gerraty 			if (iobuf_len == (size_t)-1) {
739*0957b409SSimon J. Gerraty 				usage_server();
740*0957b409SSimon J. Gerraty 				goto server_exit_error;
741*0957b409SSimon J. Gerraty 			}
742*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-cache")) {
743*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
744*0957b409SSimon J. Gerraty 				fprintf(stderr,
745*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-cache'\n");
746*0957b409SSimon J. Gerraty 				usage_server();
747*0957b409SSimon J. Gerraty 				goto server_exit_error;
748*0957b409SSimon J. Gerraty 			}
749*0957b409SSimon J. Gerraty 			arg = argv[i];
750*0957b409SSimon J. Gerraty 			if (cache_len != (size_t)-1) {
751*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: duplicate session"
752*0957b409SSimon J. Gerraty 					" cache length\n");
753*0957b409SSimon J. Gerraty 				usage_server();
754*0957b409SSimon J. Gerraty 				goto server_exit_error;
755*0957b409SSimon J. Gerraty 			}
756*0957b409SSimon J. Gerraty 			cache_len = parse_size(arg);
757*0957b409SSimon J. Gerraty 			if (cache_len == (size_t)-1) {
758*0957b409SSimon J. Gerraty 				usage_server();
759*0957b409SSimon J. Gerraty 				goto server_exit_error;
760*0957b409SSimon J. Gerraty 			}
761*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-cert")) {
762*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
763*0957b409SSimon J. Gerraty 				fprintf(stderr,
764*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-cert'\n");
765*0957b409SSimon J. Gerraty 				usage_server();
766*0957b409SSimon J. Gerraty 				goto server_exit_error;
767*0957b409SSimon J. Gerraty 			}
768*0957b409SSimon J. Gerraty 			if (chain != NULL) {
769*0957b409SSimon J. Gerraty 				fprintf(stderr,
770*0957b409SSimon J. Gerraty 					"ERROR: duplicate certificate chain\n");
771*0957b409SSimon J. Gerraty 				usage_server();
772*0957b409SSimon J. Gerraty 				goto server_exit_error;
773*0957b409SSimon J. Gerraty 			}
774*0957b409SSimon J. Gerraty 			arg = argv[i];
775*0957b409SSimon J. Gerraty 			chain = read_certificates(arg, &chain_len);
776*0957b409SSimon J. Gerraty 			if (chain == NULL || chain_len == 0) {
777*0957b409SSimon J. Gerraty 				goto server_exit_error;
778*0957b409SSimon J. Gerraty 			}
779*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-key")) {
780*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
781*0957b409SSimon J. Gerraty 				fprintf(stderr,
782*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-key'\n");
783*0957b409SSimon J. Gerraty 				usage_server();
784*0957b409SSimon J. Gerraty 				goto server_exit_error;
785*0957b409SSimon J. Gerraty 			}
786*0957b409SSimon J. Gerraty 			if (sk != NULL) {
787*0957b409SSimon J. Gerraty 				fprintf(stderr,
788*0957b409SSimon J. Gerraty 					"ERROR: duplicate private key\n");
789*0957b409SSimon J. Gerraty 				usage_server();
790*0957b409SSimon J. Gerraty 				goto server_exit_error;
791*0957b409SSimon J. Gerraty 			}
792*0957b409SSimon J. Gerraty 			arg = argv[i];
793*0957b409SSimon J. Gerraty 			sk = read_private_key(arg);
794*0957b409SSimon J. Gerraty 			if (sk == NULL) {
795*0957b409SSimon J. Gerraty 				goto server_exit_error;
796*0957b409SSimon J. Gerraty 			}
797*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-CA")) {
798*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
799*0957b409SSimon J. Gerraty 				fprintf(stderr,
800*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-CA'\n");
801*0957b409SSimon J. Gerraty 				usage_server();
802*0957b409SSimon J. Gerraty 				goto server_exit_error;
803*0957b409SSimon J. Gerraty 			}
804*0957b409SSimon J. Gerraty 			arg = argv[i];
805*0957b409SSimon J. Gerraty 			if (read_trust_anchors(&anchors, arg) == 0) {
806*0957b409SSimon J. Gerraty 				usage_server();
807*0957b409SSimon J. Gerraty 				goto server_exit_error;
808*0957b409SSimon J. Gerraty 			}
809*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-anon_ok")) {
810*0957b409SSimon J. Gerraty 			flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH;
811*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-list")) {
812*0957b409SSimon J. Gerraty 			list_names();
813*0957b409SSimon J. Gerraty 			goto server_exit;
814*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-vmin")) {
815*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
816*0957b409SSimon J. Gerraty 				fprintf(stderr,
817*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-vmin'\n");
818*0957b409SSimon J. Gerraty 				usage_server();
819*0957b409SSimon J. Gerraty 				goto server_exit_error;
820*0957b409SSimon J. Gerraty 			}
821*0957b409SSimon J. Gerraty 			arg = argv[i];
822*0957b409SSimon J. Gerraty 			if (vmin != 0) {
823*0957b409SSimon J. Gerraty 				fprintf(stderr,
824*0957b409SSimon J. Gerraty 					"ERROR: duplicate minimum version\n");
825*0957b409SSimon J. Gerraty 				usage_server();
826*0957b409SSimon J. Gerraty 				goto server_exit_error;
827*0957b409SSimon J. Gerraty 			}
828*0957b409SSimon J. Gerraty 			vmin = parse_version(arg, strlen(arg));
829*0957b409SSimon J. Gerraty 			if (vmin == 0) {
830*0957b409SSimon J. Gerraty 				fprintf(stderr,
831*0957b409SSimon J. Gerraty 					"ERROR: unrecognised version '%s'\n",
832*0957b409SSimon J. Gerraty 					arg);
833*0957b409SSimon J. Gerraty 				usage_server();
834*0957b409SSimon J. Gerraty 				goto server_exit_error;
835*0957b409SSimon J. Gerraty 			}
836*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-vmax")) {
837*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
838*0957b409SSimon J. Gerraty 				fprintf(stderr,
839*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-vmax'\n");
840*0957b409SSimon J. Gerraty 				usage_server();
841*0957b409SSimon J. Gerraty 				goto server_exit_error;
842*0957b409SSimon J. Gerraty 			}
843*0957b409SSimon J. Gerraty 			arg = argv[i];
844*0957b409SSimon J. Gerraty 			if (vmax != 0) {
845*0957b409SSimon J. Gerraty 				fprintf(stderr,
846*0957b409SSimon J. Gerraty 					"ERROR: duplicate maximum version\n");
847*0957b409SSimon J. Gerraty 				usage_server();
848*0957b409SSimon J. Gerraty 				goto server_exit_error;
849*0957b409SSimon J. Gerraty 			}
850*0957b409SSimon J. Gerraty 			vmax = parse_version(arg, strlen(arg));
851*0957b409SSimon J. Gerraty 			if (vmax == 0) {
852*0957b409SSimon J. Gerraty 				fprintf(stderr,
853*0957b409SSimon J. Gerraty 					"ERROR: unrecognised version '%s'\n",
854*0957b409SSimon J. Gerraty 					arg);
855*0957b409SSimon J. Gerraty 				usage_server();
856*0957b409SSimon J. Gerraty 				goto server_exit_error;
857*0957b409SSimon J. Gerraty 			}
858*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-cs")) {
859*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
860*0957b409SSimon J. Gerraty 				fprintf(stderr,
861*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-cs'\n");
862*0957b409SSimon J. Gerraty 				usage_server();
863*0957b409SSimon J. Gerraty 				goto server_exit_error;
864*0957b409SSimon J. Gerraty 			}
865*0957b409SSimon J. Gerraty 			arg = argv[i];
866*0957b409SSimon J. Gerraty 			if (suites != NULL) {
867*0957b409SSimon J. Gerraty 				fprintf(stderr, "ERROR: duplicate list"
868*0957b409SSimon J. Gerraty 					" of cipher suites\n");
869*0957b409SSimon J. Gerraty 				usage_server();
870*0957b409SSimon J. Gerraty 				goto server_exit_error;
871*0957b409SSimon J. Gerraty 			}
872*0957b409SSimon J. Gerraty 			suites = parse_suites(arg, &num_suites);
873*0957b409SSimon J. Gerraty 			if (suites == NULL) {
874*0957b409SSimon J. Gerraty 				usage_server();
875*0957b409SSimon J. Gerraty 				goto server_exit_error;
876*0957b409SSimon J. Gerraty 			}
877*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-hf")) {
878*0957b409SSimon J. Gerraty 			unsigned x;
879*0957b409SSimon J. Gerraty 
880*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
881*0957b409SSimon J. Gerraty 				fprintf(stderr,
882*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-hf'\n");
883*0957b409SSimon J. Gerraty 				usage_server();
884*0957b409SSimon J. Gerraty 				goto server_exit_error;
885*0957b409SSimon J. Gerraty 			}
886*0957b409SSimon J. Gerraty 			arg = argv[i];
887*0957b409SSimon J. Gerraty 			x = parse_hash_functions(arg);
888*0957b409SSimon J. Gerraty 			if (x == 0) {
889*0957b409SSimon J. Gerraty 				usage_server();
890*0957b409SSimon J. Gerraty 				goto server_exit_error;
891*0957b409SSimon J. Gerraty 			}
892*0957b409SSimon J. Gerraty 			hfuns |= x;
893*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-cbhash")) {
894*0957b409SSimon J. Gerraty 			cbhash = 1;
895*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-serverpref")) {
896*0957b409SSimon J. Gerraty 			flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES;
897*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-noreneg")) {
898*0957b409SSimon J. Gerraty 			flags |= BR_OPT_NO_RENEGOTIATION;
899*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-alpn")) {
900*0957b409SSimon J. Gerraty 			if (++ i >= argc) {
901*0957b409SSimon J. Gerraty 				fprintf(stderr,
902*0957b409SSimon J. Gerraty 					"ERROR: no argument for '-alpn'\n");
903*0957b409SSimon J. Gerraty 				usage_server();
904*0957b409SSimon J. Gerraty 				goto server_exit_error;
905*0957b409SSimon J. Gerraty 			}
906*0957b409SSimon J. Gerraty 			VEC_ADD(alpn_names, xstrdup(argv[i]));
907*0957b409SSimon J. Gerraty 		} else if (eqstr(arg, "-strictalpn")) {
908*0957b409SSimon J. Gerraty 			flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH;
909*0957b409SSimon J. Gerraty 		} else {
910*0957b409SSimon J. Gerraty 			fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
911*0957b409SSimon J. Gerraty 			usage_server();
912*0957b409SSimon J. Gerraty 			goto server_exit_error;
913*0957b409SSimon J. Gerraty 		}
914*0957b409SSimon J. Gerraty 	}
915*0957b409SSimon J. Gerraty 	if (port == NULL) {
916*0957b409SSimon J. Gerraty 		port = "4433";
917*0957b409SSimon J. Gerraty 	}
918*0957b409SSimon J. Gerraty 	if (vmin == 0) {
919*0957b409SSimon J. Gerraty 		vmin = BR_TLS10;
920*0957b409SSimon J. Gerraty 	}
921*0957b409SSimon J. Gerraty 	if (vmax == 0) {
922*0957b409SSimon J. Gerraty 		vmax = BR_TLS12;
923*0957b409SSimon J. Gerraty 	}
924*0957b409SSimon J. Gerraty 	if (vmax < vmin) {
925*0957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
926*0957b409SSimon J. Gerraty 			" version combination\n");
927*0957b409SSimon J. Gerraty 		usage_server();
928*0957b409SSimon J. Gerraty 		goto server_exit_error;
929*0957b409SSimon J. Gerraty 	}
930*0957b409SSimon J. Gerraty 	if (suites == NULL) {
931*0957b409SSimon J. Gerraty 		num_suites = 0;
932*0957b409SSimon J. Gerraty 
933*0957b409SSimon J. Gerraty 		for (u = 0; cipher_suites[u].name; u ++) {
934*0957b409SSimon J. Gerraty 			if ((cipher_suites[u].req & REQ_TLS12) == 0
935*0957b409SSimon J. Gerraty 				|| vmax >= BR_TLS12)
936*0957b409SSimon J. Gerraty 			{
937*0957b409SSimon J. Gerraty 				num_suites ++;
938*0957b409SSimon J. Gerraty 			}
939*0957b409SSimon J. Gerraty 		}
940*0957b409SSimon J. Gerraty 		suites = xmalloc(num_suites * sizeof *suites);
941*0957b409SSimon J. Gerraty 		num_suites = 0;
942*0957b409SSimon J. Gerraty 		for (u = 0; cipher_suites[u].name; u ++) {
943*0957b409SSimon J. Gerraty 			if ((cipher_suites[u].req & REQ_TLS12) == 0
944*0957b409SSimon J. Gerraty 				|| vmax >= BR_TLS12)
945*0957b409SSimon J. Gerraty 			{
946*0957b409SSimon J. Gerraty 				suites[num_suites ++] = cipher_suites[u];
947*0957b409SSimon J. Gerraty 			}
948*0957b409SSimon J. Gerraty 		}
949*0957b409SSimon J. Gerraty 	}
950*0957b409SSimon J. Gerraty 	if (hfuns == 0) {
951*0957b409SSimon J. Gerraty 		hfuns = (unsigned)-1;
952*0957b409SSimon J. Gerraty 	}
953*0957b409SSimon J. Gerraty 	if (chain == NULL || chain_len == 0) {
954*0957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: no certificate chain provided\n");
955*0957b409SSimon J. Gerraty 		goto server_exit_error;
956*0957b409SSimon J. Gerraty 	}
957*0957b409SSimon J. Gerraty 	if (sk == NULL) {
958*0957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: no private key provided\n");
959*0957b409SSimon J. Gerraty 		goto server_exit_error;
960*0957b409SSimon J. Gerraty 	}
961*0957b409SSimon J. Gerraty 	switch (sk->key_type) {
962*0957b409SSimon J. Gerraty 		int curve;
963*0957b409SSimon J. Gerraty 		uint32_t supp;
964*0957b409SSimon J. Gerraty 
965*0957b409SSimon J. Gerraty 	case BR_KEYTYPE_RSA:
966*0957b409SSimon J. Gerraty 		break;
967*0957b409SSimon J. Gerraty 	case BR_KEYTYPE_EC:
968*0957b409SSimon J. Gerraty 		curve = sk->key.ec.curve;
969*0957b409SSimon J. Gerraty 		supp = br_ec_get_default()->supported_curves;
970*0957b409SSimon J. Gerraty 		if (curve > 31 || !((supp >> curve) & 1)) {
971*0957b409SSimon J. Gerraty 			fprintf(stderr, "ERROR: private key curve (%d)"
972*0957b409SSimon J. Gerraty 				" is not supported\n", curve);
973*0957b409SSimon J. Gerraty 			goto server_exit_error;
974*0957b409SSimon J. Gerraty 		}
975*0957b409SSimon J. Gerraty 		break;
976*0957b409SSimon J. Gerraty 	default:
977*0957b409SSimon J. Gerraty 		fprintf(stderr, "ERROR: unsupported private key type (%d)\n",
978*0957b409SSimon J. Gerraty 			sk->key_type);
979*0957b409SSimon J. Gerraty 		break;
980*0957b409SSimon J. Gerraty 	}
981*0957b409SSimon J. Gerraty 	cert_signer_algo = get_cert_signer_algo(chain);
982*0957b409SSimon J. Gerraty 	if (cert_signer_algo == 0) {
983*0957b409SSimon J. Gerraty 		goto server_exit_error;
984*0957b409SSimon J. Gerraty 	}
985*0957b409SSimon J. Gerraty 	if (verbose) {
986*0957b409SSimon J. Gerraty 		const char *csas;
987*0957b409SSimon J. Gerraty 
988*0957b409SSimon J. Gerraty 		switch (cert_signer_algo) {
989*0957b409SSimon J. Gerraty 		case BR_KEYTYPE_RSA: csas = "RSA"; break;
990*0957b409SSimon J. Gerraty 		case BR_KEYTYPE_EC:  csas = "EC"; break;
991*0957b409SSimon J. Gerraty 		default:
992*0957b409SSimon J. Gerraty 			csas = "unknown";
993*0957b409SSimon J. Gerraty 			break;
994*0957b409SSimon J. Gerraty 		}
995*0957b409SSimon J. Gerraty 		fprintf(stderr, "Issuing CA key type: %d (%s)\n",
996*0957b409SSimon J. Gerraty 			cert_signer_algo, csas);
997*0957b409SSimon J. Gerraty 	}
998*0957b409SSimon J. Gerraty 	if (iobuf_len == 0) {
999*0957b409SSimon J. Gerraty 		if (bidi) {
1000*0957b409SSimon J. Gerraty 			iobuf_len = BR_SSL_BUFSIZE_BIDI;
1001*0957b409SSimon J. Gerraty 		} else {
1002*0957b409SSimon J. Gerraty 			iobuf_len = BR_SSL_BUFSIZE_MONO;
1003*0957b409SSimon J. Gerraty 		}
1004*0957b409SSimon J. Gerraty 	}
1005*0957b409SSimon J. Gerraty 	iobuf = xmalloc(iobuf_len);
1006*0957b409SSimon J. Gerraty 	if (cache_len == (size_t)-1) {
1007*0957b409SSimon J. Gerraty 		cache_len = 5000;
1008*0957b409SSimon J. Gerraty 	}
1009*0957b409SSimon J. Gerraty 	cache = xmalloc(cache_len);
1010*0957b409SSimon J. Gerraty 
1011*0957b409SSimon J. Gerraty 	/*
1012*0957b409SSimon J. Gerraty 	 * Compute implementation requirements and inject implementations.
1013*0957b409SSimon J. Gerraty 	 */
1014*0957b409SSimon J. Gerraty 	suite_ids = xmalloc(num_suites * sizeof *suite_ids);
1015*0957b409SSimon J. Gerraty 	br_ssl_server_zero(&cc);
1016*0957b409SSimon J. Gerraty 	br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
1017*0957b409SSimon J. Gerraty 	br_ssl_engine_set_all_flags(&cc.eng, flags);
1018*0957b409SSimon J. Gerraty 	if (vmin <= BR_TLS11) {
1019*0957b409SSimon J. Gerraty 		if (!(hfuns & (1 << br_md5_ID))) {
1020*0957b409SSimon J. Gerraty 			fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
1021*0957b409SSimon J. Gerraty 			goto server_exit_error;
1022*0957b409SSimon J. Gerraty 		}
1023*0957b409SSimon J. Gerraty 		if (!(hfuns & (1 << br_sha1_ID))) {
1024*0957b409SSimon J. Gerraty 			fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
1025*0957b409SSimon J. Gerraty 			goto server_exit_error;
1026*0957b409SSimon J. Gerraty 		}
1027*0957b409SSimon J. Gerraty 	}
1028*0957b409SSimon J. Gerraty 	for (u = 0; u < num_suites; u ++) {
1029*0957b409SSimon J. Gerraty 		unsigned req;
1030*0957b409SSimon J. Gerraty 
1031*0957b409SSimon J. Gerraty 		req = suites[u].req;
1032*0957b409SSimon J. Gerraty 		suite_ids[u] = suites[u].suite;
1033*0957b409SSimon J. Gerraty 		if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
1034*0957b409SSimon J. Gerraty 			fprintf(stderr,
1035*0957b409SSimon J. Gerraty 				"ERROR: cipher suite %s requires TLS 1.2\n",
1036*0957b409SSimon J. Gerraty 				suites[u].name);
1037*0957b409SSimon J. Gerraty 			goto server_exit_error;
1038*0957b409SSimon J. Gerraty 		}
1039*0957b409SSimon J. Gerraty 		if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
1040*0957b409SSimon J. Gerraty 			fprintf(stderr,
1041*0957b409SSimon J. Gerraty 				"ERROR: cipher suite %s requires SHA-1\n",
1042*0957b409SSimon J. Gerraty 				suites[u].name);
1043*0957b409SSimon J. Gerraty 			goto server_exit_error;
1044*0957b409SSimon J. Gerraty 		}
1045*0957b409SSimon J. Gerraty 		if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
1046*0957b409SSimon J. Gerraty 			fprintf(stderr,
1047*0957b409SSimon J. Gerraty 				"ERROR: cipher suite %s requires SHA-256\n",
1048*0957b409SSimon J. Gerraty 				suites[u].name);
1049*0957b409SSimon J. Gerraty 			goto server_exit_error;
1050*0957b409SSimon J. Gerraty 		}
1051*0957b409SSimon J. Gerraty 		if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
1052*0957b409SSimon J. Gerraty 			fprintf(stderr,
1053*0957b409SSimon J. Gerraty 				"ERROR: cipher suite %s requires SHA-384\n",
1054*0957b409SSimon J. Gerraty 				suites[u].name);
1055*0957b409SSimon J. Gerraty 			goto server_exit_error;
1056*0957b409SSimon J. Gerraty 		}
1057*0957b409SSimon J. Gerraty 		/* TODO: algorithm implementation selection */
1058*0957b409SSimon J. Gerraty 		if ((req & REQ_AESCBC) != 0) {
1059*0957b409SSimon J. Gerraty 			br_ssl_engine_set_default_aes_cbc(&cc.eng);
1060*0957b409SSimon J. Gerraty 		}
1061*0957b409SSimon J. Gerraty 		if ((req & REQ_AESCCM) != 0) {
1062*0957b409SSimon J. Gerraty 			br_ssl_engine_set_default_aes_ccm(&cc.eng);
1063*0957b409SSimon J. Gerraty 		}
1064*0957b409SSimon J. Gerraty 		if ((req & REQ_AESGCM) != 0) {
1065*0957b409SSimon J. Gerraty 			br_ssl_engine_set_default_aes_gcm(&cc.eng);
1066*0957b409SSimon J. Gerraty 		}
1067*0957b409SSimon J. Gerraty 		if ((req & REQ_CHAPOL) != 0) {
1068*0957b409SSimon J. Gerraty 			br_ssl_engine_set_default_chapol(&cc.eng);
1069*0957b409SSimon J. Gerraty 		}
1070*0957b409SSimon J. Gerraty 		if ((req & REQ_3DESCBC) != 0) {
1071*0957b409SSimon J. Gerraty 			br_ssl_engine_set_default_des_cbc(&cc.eng);
1072*0957b409SSimon J. Gerraty 		}
1073*0957b409SSimon J. Gerraty 		if ((req & (REQ_ECDHE_RSA | REQ_ECDHE_ECDSA)) != 0) {
1074*0957b409SSimon J. Gerraty 			br_ssl_engine_set_default_ec(&cc.eng);
1075*0957b409SSimon J. Gerraty 		}
1076*0957b409SSimon J. Gerraty 	}
1077*0957b409SSimon J. Gerraty 	br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
1078*0957b409SSimon J. Gerraty 
1079*0957b409SSimon J. Gerraty 	dnhash = NULL;
1080*0957b409SSimon J. Gerraty 	for (u = 0; hash_functions[u].name; u ++) {
1081*0957b409SSimon J. Gerraty 		const br_hash_class *hc;
1082*0957b409SSimon J. Gerraty 		int id;
1083*0957b409SSimon J. Gerraty 
1084*0957b409SSimon J. Gerraty 		hc = hash_functions[u].hclass;
1085*0957b409SSimon J. Gerraty 		id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
1086*0957b409SSimon J. Gerraty 		if ((hfuns & ((unsigned)1 << id)) != 0) {
1087*0957b409SSimon J. Gerraty 			dnhash = hc;
1088*0957b409SSimon J. Gerraty 			br_ssl_engine_set_hash(&cc.eng, id, hc);
1089*0957b409SSimon J. Gerraty 		}
1090*0957b409SSimon J. Gerraty 	}
1091*0957b409SSimon J. Gerraty 	if (vmin <= BR_TLS11) {
1092*0957b409SSimon J. Gerraty 		br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
1093*0957b409SSimon J. Gerraty 	}
1094*0957b409SSimon J. Gerraty 	if (vmax >= BR_TLS12) {
1095*0957b409SSimon J. Gerraty 		if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
1096*0957b409SSimon J. Gerraty 			br_ssl_engine_set_prf_sha256(&cc.eng,
1097*0957b409SSimon J. Gerraty 				&br_tls12_sha256_prf);
1098*0957b409SSimon J. Gerraty 		}
1099*0957b409SSimon J. Gerraty 		if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
1100*0957b409SSimon J. Gerraty 			br_ssl_engine_set_prf_sha384(&cc.eng,
1101*0957b409SSimon J. Gerraty 				&br_tls12_sha384_prf);
1102*0957b409SSimon J. Gerraty 		}
1103*0957b409SSimon J. Gerraty 	}
1104*0957b409SSimon J. Gerraty 
1105*0957b409SSimon J. Gerraty 	br_ssl_session_cache_lru_init(&lru, cache, cache_len);
1106*0957b409SSimon J. Gerraty 	br_ssl_server_set_cache(&cc, &lru.vtable);
1107*0957b409SSimon J. Gerraty 
1108*0957b409SSimon J. Gerraty 	if (VEC_LEN(alpn_names) != 0) {
1109*0957b409SSimon J. Gerraty 		br_ssl_engine_set_protocol_names(&cc.eng,
1110*0957b409SSimon J. Gerraty 			(const char **)&VEC_ELT(alpn_names, 0),
1111*0957b409SSimon J. Gerraty 			VEC_LEN(alpn_names));
1112*0957b409SSimon J. Gerraty 	}
1113*0957b409SSimon J. Gerraty 
1114*0957b409SSimon J. Gerraty 	/*
1115*0957b409SSimon J. Gerraty 	 * Set the policy handler (that chooses the actual cipher suite,
1116*0957b409SSimon J. Gerraty 	 * selects the certificate chain, and runs the private key
1117*0957b409SSimon J. Gerraty 	 * operations).
1118*0957b409SSimon J. Gerraty 	 */
1119*0957b409SSimon J. Gerraty 	pc.vtable = &policy_vtable;
1120*0957b409SSimon J. Gerraty 	pc.verbose = verbose;
1121*0957b409SSimon J. Gerraty 	pc.chain = chain;
1122*0957b409SSimon J. Gerraty 	pc.chain_len = chain_len;
1123*0957b409SSimon J. Gerraty 	pc.cert_signer_algo = cert_signer_algo;
1124*0957b409SSimon J. Gerraty 	pc.sk = sk;
1125*0957b409SSimon J. Gerraty 	pc.cbhash = cbhash;
1126*0957b409SSimon J. Gerraty 	br_ssl_server_set_policy(&cc, &pc.vtable);
1127*0957b409SSimon J. Gerraty 
1128*0957b409SSimon J. Gerraty 	/*
1129*0957b409SSimon J. Gerraty 	 * If trust anchors have been configured, then set an X.509
1130*0957b409SSimon J. Gerraty 	 * validation engine and activate client certificate
1131*0957b409SSimon J. Gerraty 	 * authentication.
1132*0957b409SSimon J. Gerraty 	 */
1133*0957b409SSimon J. Gerraty 	if (VEC_LEN(anchors) != 0) {
1134*0957b409SSimon J. Gerraty 		br_x509_minimal_init(&xc, dnhash,
1135*0957b409SSimon J. Gerraty 			&VEC_ELT(anchors, 0), VEC_LEN(anchors));
1136*0957b409SSimon J. Gerraty 		for (u = 0; hash_functions[u].name; u ++) {
1137*0957b409SSimon J. Gerraty 			const br_hash_class *hc;
1138*0957b409SSimon J. Gerraty 			int id;
1139*0957b409SSimon J. Gerraty 
1140*0957b409SSimon J. Gerraty 			hc = hash_functions[u].hclass;
1141*0957b409SSimon J. Gerraty 			id = (hc->desc >> BR_HASHDESC_ID_OFF)
1142*0957b409SSimon J. Gerraty 				& BR_HASHDESC_ID_MASK;
1143*0957b409SSimon J. Gerraty 			if ((hfuns & ((unsigned)1 << id)) != 0) {
1144*0957b409SSimon J. Gerraty 				br_x509_minimal_set_hash(&xc, id, hc);
1145*0957b409SSimon J. Gerraty 			}
1146*0957b409SSimon J. Gerraty 		}
1147*0957b409SSimon J. Gerraty 		br_ssl_engine_set_default_rsavrfy(&cc.eng);
1148*0957b409SSimon J. Gerraty 		br_ssl_engine_set_default_ecdsa(&cc.eng);
1149*0957b409SSimon J. Gerraty 		br_x509_minimal_set_rsa(&xc, br_rsa_pkcs1_vrfy_get_default());
1150*0957b409SSimon J. Gerraty 		br_x509_minimal_set_ecdsa(&xc,
1151*0957b409SSimon J. Gerraty 			br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
1152*0957b409SSimon J. Gerraty 		br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
1153*0957b409SSimon J. Gerraty 		br_ssl_server_set_trust_anchor_names_alt(&cc,
1154*0957b409SSimon J. Gerraty 			&VEC_ELT(anchors, 0), VEC_LEN(anchors));
1155*0957b409SSimon J. Gerraty 	}
1156*0957b409SSimon J. Gerraty 
1157*0957b409SSimon J. Gerraty 	br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
1158*0957b409SSimon J. Gerraty 
1159*0957b409SSimon J. Gerraty 	/*
1160*0957b409SSimon J. Gerraty 	 * On Unix systems, we need to ignore SIGPIPE.
1161*0957b409SSimon J. Gerraty 	 */
1162*0957b409SSimon J. Gerraty #ifndef _WIN32
1163*0957b409SSimon J. Gerraty 	signal(SIGPIPE, SIG_IGN);
1164*0957b409SSimon J. Gerraty #endif
1165*0957b409SSimon J. Gerraty 
1166*0957b409SSimon J. Gerraty 	/*
1167*0957b409SSimon J. Gerraty 	 * Open the server socket.
1168*0957b409SSimon J. Gerraty 	 */
1169*0957b409SSimon J. Gerraty 	server_fd = host_bind(bind_name, port, verbose);
1170*0957b409SSimon J. Gerraty 	if (server_fd == INVALID_SOCKET) {
1171*0957b409SSimon J. Gerraty 		goto server_exit_error;
1172*0957b409SSimon J. Gerraty 	}
1173*0957b409SSimon J. Gerraty 
1174*0957b409SSimon J. Gerraty 	/*
1175*0957b409SSimon J. Gerraty 	 * Process incoming clients, one at a time. Note that we do not
1176*0957b409SSimon J. Gerraty 	 * accept any client until the previous connection has finished:
1177*0957b409SSimon J. Gerraty 	 * this is voluntary, since the tool uses stdin/stdout for
1178*0957b409SSimon J. Gerraty 	 * application data, and thus cannot really run two connections
1179*0957b409SSimon J. Gerraty 	 * simultaneously.
1180*0957b409SSimon J. Gerraty 	 */
1181*0957b409SSimon J. Gerraty 	for (;;) {
1182*0957b409SSimon J. Gerraty 		int x;
1183*0957b409SSimon J. Gerraty 		unsigned run_flags;
1184*0957b409SSimon J. Gerraty 
1185*0957b409SSimon J. Gerraty 		fd = accept_client(server_fd, verbose, 1);
1186*0957b409SSimon J. Gerraty 		if (fd == INVALID_SOCKET) {
1187*0957b409SSimon J. Gerraty 			goto server_exit_error;
1188*0957b409SSimon J. Gerraty 		}
1189*0957b409SSimon J. Gerraty 		br_ssl_server_reset(&cc);
1190*0957b409SSimon J. Gerraty 		run_flags = (verbose ? RUN_ENGINE_VERBOSE : 0)
1191*0957b409SSimon J. Gerraty 			| (trace ? RUN_ENGINE_TRACE : 0);
1192*0957b409SSimon J. Gerraty 		x = run_ssl_engine(&cc.eng, fd, run_flags);
1193*0957b409SSimon J. Gerraty #ifdef _WIN32
1194*0957b409SSimon J. Gerraty 		closesocket(fd);
1195*0957b409SSimon J. Gerraty #else
1196*0957b409SSimon J. Gerraty 		close(fd);
1197*0957b409SSimon J. Gerraty #endif
1198*0957b409SSimon J. Gerraty 		fd = INVALID_SOCKET;
1199*0957b409SSimon J. Gerraty 		if (x < -1) {
1200*0957b409SSimon J. Gerraty 			goto server_exit_error;
1201*0957b409SSimon J. Gerraty 		}
1202*0957b409SSimon J. Gerraty 	}
1203*0957b409SSimon J. Gerraty 
1204*0957b409SSimon J. Gerraty 	/*
1205*0957b409SSimon J. Gerraty 	 * Release allocated structures.
1206*0957b409SSimon J. Gerraty 	 */
1207*0957b409SSimon J. Gerraty server_exit:
1208*0957b409SSimon J. Gerraty 	xfree(suites);
1209*0957b409SSimon J. Gerraty 	xfree(suite_ids);
1210*0957b409SSimon J. Gerraty 	free_certificates(chain, chain_len);
1211*0957b409SSimon J. Gerraty 	free_private_key(sk);
1212*0957b409SSimon J. Gerraty 	VEC_CLEAREXT(anchors, &free_ta_contents);
1213*0957b409SSimon J. Gerraty 	VEC_CLEAREXT(alpn_names, &free_alpn);
1214*0957b409SSimon J. Gerraty 	xfree(iobuf);
1215*0957b409SSimon J. Gerraty 	xfree(cache);
1216*0957b409SSimon J. Gerraty 	if (fd != INVALID_SOCKET) {
1217*0957b409SSimon J. Gerraty #ifdef _WIN32
1218*0957b409SSimon J. Gerraty 		closesocket(fd);
1219*0957b409SSimon J. Gerraty #else
1220*0957b409SSimon J. Gerraty 		close(fd);
1221*0957b409SSimon J. Gerraty #endif
1222*0957b409SSimon J. Gerraty 	}
1223*0957b409SSimon J. Gerraty 	if (server_fd != INVALID_SOCKET) {
1224*0957b409SSimon J. Gerraty #ifdef _WIN32
1225*0957b409SSimon J. Gerraty 		closesocket(server_fd);
1226*0957b409SSimon J. Gerraty #else
1227*0957b409SSimon J. Gerraty 		close(server_fd);
1228*0957b409SSimon J. Gerraty #endif
1229*0957b409SSimon J. Gerraty 	}
1230*0957b409SSimon J. Gerraty 	return retcode;
1231*0957b409SSimon J. Gerraty 
1232*0957b409SSimon J. Gerraty server_exit_error:
1233*0957b409SSimon J. Gerraty 	retcode = -1;
1234*0957b409SSimon J. Gerraty 	goto server_exit;
1235*0957b409SSimon J. Gerraty }
1236