xref: /openbsd-src/lib/libtls/tls_config.c (revision 6a16e2b38b4c2329e78053486be431a1ce8bddf5)
1*6a16e2b3Stb /* $OpenBSD: tls_config.c,v 1.71 2024/08/02 15:00:01 tb Exp $ */
2b600beedSjsing /*
3b600beedSjsing  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4b600beedSjsing  *
5b600beedSjsing  * Permission to use, copy, modify, and distribute this software for any
6b600beedSjsing  * purpose with or without fee is hereby granted, provided that the above
7b600beedSjsing  * copyright notice and this permission notice appear in all copies.
8b600beedSjsing  *
9b600beedSjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10b600beedSjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11b600beedSjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12b600beedSjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13b600beedSjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14b600beedSjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15b600beedSjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16b600beedSjsing  */
17b600beedSjsing 
1803ce4948Sjsing #include <sys/stat.h>
1903ce4948Sjsing 
20729a1688Sjsing #include <ctype.h>
21b600beedSjsing #include <errno.h>
2203ce4948Sjsing #include <fcntl.h>
23bebb943aSjsing #include <pthread.h>
24b600beedSjsing #include <stdlib.h>
25e6d77be9Sop #include <string.h>
2603ce4948Sjsing #include <unistd.h>
27b600beedSjsing 
28b600beedSjsing #include <tls.h>
29bb4cb1b0Sjsing 
30b600beedSjsing #include "tls_internal.h"
31b600beedSjsing 
3215dff5baSbeck static const char default_ca_file[] = TLS_DEFAULT_CA_FILE;
33f6b75673Stedu 
34f6b75673Stedu const char *
35f6b75673Stedu tls_default_ca_cert_file(void)
36f6b75673Stedu {
37f6b75673Stedu 	return default_ca_file;
38f6b75673Stedu }
39f6b75673Stedu 
4003ce4948Sjsing int
4103ce4948Sjsing tls_config_load_file(struct tls_error *error, const char *filetype,
4203ce4948Sjsing     const char *filename, char **buf, size_t *len)
4303ce4948Sjsing {
4403ce4948Sjsing 	struct stat st;
4503ce4948Sjsing 	int fd = -1;
463a0b22e9Sjsing 	ssize_t n;
4703ce4948Sjsing 
4803ce4948Sjsing 	free(*buf);
4903ce4948Sjsing 	*buf = NULL;
5003ce4948Sjsing 	*len = 0;
5103ce4948Sjsing 
5203ce4948Sjsing 	if ((fd = open(filename, O_RDONLY)) == -1) {
537a756d37Sjoshua 		tls_error_set(error, TLS_ERROR_UNKNOWN,
547a756d37Sjoshua 		    "failed to open %s file '%s'",
5503ce4948Sjsing 		    filetype, filename);
567add217bSjsing 		goto err;
5703ce4948Sjsing 	}
5803ce4948Sjsing 	if (fstat(fd, &st) != 0) {
597a756d37Sjoshua 		tls_error_set(error, TLS_ERROR_UNKNOWN,
607a756d37Sjoshua 		    "failed to stat %s file '%s'",
6103ce4948Sjsing 		    filetype, filename);
627add217bSjsing 		goto err;
6303ce4948Sjsing 	}
643a0b22e9Sjsing 	if (st.st_size < 0)
657add217bSjsing 		goto err;
6603ce4948Sjsing 	*len = (size_t)st.st_size;
6703ce4948Sjsing 	if ((*buf = malloc(*len)) == NULL) {
687a756d37Sjoshua 		tls_error_set(error, TLS_ERROR_UNKNOWN,
697a756d37Sjoshua 		    "failed to allocate buffer for %s file",
707a756d37Sjoshua 		    filetype);
717add217bSjsing 		goto err;
7203ce4948Sjsing 	}
733a0b22e9Sjsing 	n = read(fd, *buf, *len);
743a0b22e9Sjsing 	if (n < 0 || (size_t)n != *len) {
757a756d37Sjoshua 		tls_error_set(error, TLS_ERROR_UNKNOWN,
767a756d37Sjoshua 		    "failed to read %s file '%s'",
7703ce4948Sjsing 		    filetype, filename);
787add217bSjsing 		goto err;
7903ce4948Sjsing 	}
8003ce4948Sjsing 	close(fd);
8103ce4948Sjsing 	return 0;
8203ce4948Sjsing 
837add217bSjsing  err:
8403ce4948Sjsing 	if (fd != -1)
8503ce4948Sjsing 		close(fd);
867de8a684Sderaadt 	freezero(*buf, *len);
8703ce4948Sjsing 	*buf = NULL;
8803ce4948Sjsing 	*len = 0;
8903ce4948Sjsing 
9003ce4948Sjsing 	return -1;
9103ce4948Sjsing }
9203ce4948Sjsing 
93b600beedSjsing struct tls_config *
94b9573a74Sjsing tls_config_new_internal(void)
95b600beedSjsing {
96b600beedSjsing 	struct tls_config *config;
9747c43cfeSclaudio 	unsigned char sid[TLS_MAX_SESSION_ID_LENGTH];
98b600beedSjsing 
99b600beedSjsing 	if ((config = calloc(1, sizeof(*config))) == NULL)
100b600beedSjsing 		return (NULL);
101b600beedSjsing 
102d7e2296cSjsing 	if (pthread_mutex_init(&config->mutex, NULL) != 0)
1031fe9fea1Sjsing 		goto err;
1041fe9fea1Sjsing 
10588c10dabSjsing 	config->refcount = 1;
1060dd084b9Sjsing 	config->session_fd = -1;
10788c10dabSjsing 
108d7e2296cSjsing 	if ((config->keypair = tls_keypair_new()) == NULL)
109d7e2296cSjsing 		goto err;
110d7e2296cSjsing 
111b600beedSjsing 	/*
112b600beedSjsing 	 * Default configuration.
113b600beedSjsing 	 */
1141d9579efSjsing 	if (tls_config_set_dheparams(config, "none") != 0)
1151d9579efSjsing 		goto err;
1164896de1eSjsing 	if (tls_config_set_ecdhecurves(config, "default") != 0)
1171d9579efSjsing 		goto err;
1181d9579efSjsing 	if (tls_config_set_ciphers(config, "secure") != 0)
1191d9579efSjsing 		goto err;
1201d9579efSjsing 
1212b50121aSjsing 	if (tls_config_set_protocols(config, TLS_PROTOCOLS_DEFAULT) != 0)
1222b50121aSjsing 		goto err;
1232b50121aSjsing 	if (tls_config_set_verify_depth(config, 6) != 0)
1242b50121aSjsing 		goto err;
125b600beedSjsing 
12647c43cfeSclaudio 	/*
12747c43cfeSclaudio 	 * Set session ID context to a random value.  For the simple case
12847c43cfeSclaudio 	 * of a single process server this is good enough. For multiprocess
12947c43cfeSclaudio 	 * servers the session ID needs to be set by the caller.
13047c43cfeSclaudio 	 */
13147c43cfeSclaudio 	arc4random_buf(sid, sizeof(sid));
13247c43cfeSclaudio 	if (tls_config_set_session_id(config, sid, sizeof(sid)) != 0)
13347c43cfeSclaudio 		goto err;
13447c43cfeSclaudio 	config->ticket_keyrev = arc4random();
13547c43cfeSclaudio 	config->ticket_autorekey = 1;
13647c43cfeSclaudio 
137c57e6ec0Sjsing 	tls_config_prefer_ciphers_server(config);
138c57e6ec0Sjsing 
139b600beedSjsing 	tls_config_verify(config);
140b600beedSjsing 
141b600beedSjsing 	return (config);
1421d9579efSjsing 
1431d9579efSjsing  err:
1441d9579efSjsing 	tls_config_free(config);
1451d9579efSjsing 	return (NULL);
146b600beedSjsing }
147b600beedSjsing 
148b9573a74Sjsing struct tls_config *
149b9573a74Sjsing tls_config_new(void)
150b9573a74Sjsing {
151b9573a74Sjsing 	if (tls_init() == -1)
152b9573a74Sjsing 		return (NULL);
153b9573a74Sjsing 
154b9573a74Sjsing 	return tls_config_new_internal();
155b9573a74Sjsing }
156b9573a74Sjsing 
157b600beedSjsing void
158b600beedSjsing tls_config_free(struct tls_config *config)
159b600beedSjsing {
1601fe9fea1Sjsing 	struct tls_keypair *kp, *nkp;
161bebb943aSjsing 	int refcount;
1621fe9fea1Sjsing 
163b600beedSjsing 	if (config == NULL)
164b600beedSjsing 		return;
165b600beedSjsing 
166bebb943aSjsing 	pthread_mutex_lock(&config->mutex);
167bebb943aSjsing 	refcount = --config->refcount;
168bebb943aSjsing 	pthread_mutex_unlock(&config->mutex);
169bebb943aSjsing 
170bebb943aSjsing 	if (refcount > 0)
17188c10dabSjsing 		return;
17288c10dabSjsing 
1731fe9fea1Sjsing 	for (kp = config->keypair; kp != NULL; kp = nkp) {
1741fe9fea1Sjsing 		nkp = kp->next;
1751fe9fea1Sjsing 		tls_keypair_free(kp);
1761fe9fea1Sjsing 	}
177b600beedSjsing 
178a88e9e95Sjsing 	free(config->error.msg);
179a88e9e95Sjsing 
180183da8c6Sjsing 	free(config->alpn);
1812c79fa3fSjsing 	free((char *)config->ca_mem);
182b600beedSjsing 	free((char *)config->ca_path);
183b600beedSjsing 	free((char *)config->ciphers);
18480bc881dSjsing 	free((char *)config->crl_mem);
1854896de1eSjsing 	free(config->ecdhecurves);
186b600beedSjsing 
187b900ccc5Sbcook 	pthread_mutex_destroy(&config->mutex);
188b900ccc5Sbcook 
189b600beedSjsing 	free(config);
190b600beedSjsing }
191b600beedSjsing 
19255272e79Sjsing static void
19355272e79Sjsing tls_config_keypair_add(struct tls_config *config, struct tls_keypair *keypair)
19455272e79Sjsing {
19555272e79Sjsing 	struct tls_keypair *kp;
19655272e79Sjsing 
19755272e79Sjsing 	kp = config->keypair;
19855272e79Sjsing 	while (kp->next != NULL)
19955272e79Sjsing 		kp = kp->next;
20055272e79Sjsing 
20155272e79Sjsing 	kp->next = keypair;
20255272e79Sjsing }
20355272e79Sjsing 
204a88e9e95Sjsing const char *
205a88e9e95Sjsing tls_config_error(struct tls_config *config)
206a88e9e95Sjsing {
207a88e9e95Sjsing 	return config->error.msg;
208a88e9e95Sjsing }
209a88e9e95Sjsing 
2107a756d37Sjoshua int
2117a756d37Sjoshua tls_config_error_code(struct tls_config *config)
2127a756d37Sjoshua {
2137a756d37Sjoshua 	return config->error.code;
2147a756d37Sjoshua }
2157a756d37Sjoshua 
216b600beedSjsing void
217b600beedSjsing tls_config_clear_keys(struct tls_config *config)
218b600beedSjsing {
2191fe9fea1Sjsing 	struct tls_keypair *kp;
2201fe9fea1Sjsing 
2211fe9fea1Sjsing 	for (kp = config->keypair; kp != NULL; kp = kp->next)
222b3064b8aSjsing 		tls_keypair_clear_key(kp);
223b600beedSjsing }
224b600beedSjsing 
225b600beedSjsing int
226729a1688Sjsing tls_config_parse_protocols(uint32_t *protocols, const char *protostr)
227729a1688Sjsing {
228729a1688Sjsing 	uint32_t proto, protos = 0;
229729a1688Sjsing 	char *s, *p, *q;
230729a1688Sjsing 	int negate;
231729a1688Sjsing 
232568004a5Sjsing 	if (protostr == NULL) {
233568004a5Sjsing 		*protocols = TLS_PROTOCOLS_DEFAULT;
234568004a5Sjsing 		return (0);
235568004a5Sjsing 	}
236c68c7b49Sjsing 
237729a1688Sjsing 	if ((s = strdup(protostr)) == NULL)
238729a1688Sjsing 		return (-1);
239729a1688Sjsing 
240729a1688Sjsing 	q = s;
241729a1688Sjsing 	while ((p = strsep(&q, ",:")) != NULL) {
242729a1688Sjsing 		while (*p == ' ' || *p == '\t')
243729a1688Sjsing 			p++;
244729a1688Sjsing 
245729a1688Sjsing 		negate = 0;
246729a1688Sjsing 		if (*p == '!') {
247729a1688Sjsing 			negate = 1;
248729a1688Sjsing 			p++;
249729a1688Sjsing 		}
250729a1688Sjsing 
251729a1688Sjsing 		if (negate && protos == 0)
252729a1688Sjsing 			protos = TLS_PROTOCOLS_ALL;
253729a1688Sjsing 
254729a1688Sjsing 		proto = 0;
255729a1688Sjsing 		if (strcasecmp(p, "all") == 0 ||
256729a1688Sjsing 		    strcasecmp(p, "legacy") == 0)
257729a1688Sjsing 			proto = TLS_PROTOCOLS_ALL;
258729a1688Sjsing 		else if (strcasecmp(p, "default") == 0 ||
259729a1688Sjsing 		    strcasecmp(p, "secure") == 0)
260729a1688Sjsing 			proto = TLS_PROTOCOLS_DEFAULT;
261729a1688Sjsing 		if (strcasecmp(p, "tlsv1") == 0)
262729a1688Sjsing 			proto = TLS_PROTOCOL_TLSv1;
263729a1688Sjsing 		else if (strcasecmp(p, "tlsv1.0") == 0)
264*6a16e2b3Stb 			proto = TLS_PROTOCOL_TLSv1_0;
265729a1688Sjsing 		else if (strcasecmp(p, "tlsv1.1") == 0)
266*6a16e2b3Stb 			proto = TLS_PROTOCOL_TLSv1_1;
267729a1688Sjsing 		else if (strcasecmp(p, "tlsv1.2") == 0)
268729a1688Sjsing 			proto = TLS_PROTOCOL_TLSv1_2;
2694c479435Sjsing 		else if (strcasecmp(p, "tlsv1.3") == 0)
2704c479435Sjsing 			proto = TLS_PROTOCOL_TLSv1_3;
271729a1688Sjsing 
272729a1688Sjsing 		if (proto == 0) {
273729a1688Sjsing 			free(s);
274729a1688Sjsing 			return (-1);
275729a1688Sjsing 		}
276729a1688Sjsing 
277729a1688Sjsing 		if (negate)
278729a1688Sjsing 			protos &= ~proto;
279729a1688Sjsing 		else
280729a1688Sjsing 			protos |= proto;
281729a1688Sjsing 	}
282729a1688Sjsing 
283729a1688Sjsing 	*protocols = protos;
284729a1688Sjsing 
285729a1688Sjsing 	free(s);
286729a1688Sjsing 
287729a1688Sjsing 	return (0);
288729a1688Sjsing }
289729a1688Sjsing 
290183da8c6Sjsing static int
291183da8c6Sjsing tls_config_parse_alpn(struct tls_config *config, const char *alpn,
292183da8c6Sjsing     char **alpn_data, size_t *alpn_len)
293183da8c6Sjsing {
294183da8c6Sjsing 	size_t buf_len, i, len;
295183da8c6Sjsing 	char *buf = NULL;
296183da8c6Sjsing 	char *s = NULL;
297183da8c6Sjsing 	char *p, *q;
298183da8c6Sjsing 
29985212ddeSjsing 	free(*alpn_data);
30085212ddeSjsing 	*alpn_data = NULL;
30185212ddeSjsing 	*alpn_len = 0;
30285212ddeSjsing 
303183da8c6Sjsing 	if ((buf_len = strlen(alpn) + 1) > 65535) {
3042d60058eSjoshua 		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
3052d60058eSjoshua 		    "alpn too large");
306183da8c6Sjsing 		goto err;
307183da8c6Sjsing 	}
308183da8c6Sjsing 
309183da8c6Sjsing 	if ((buf = malloc(buf_len)) == NULL) {
3107a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
3117a756d37Sjoshua 		    "out of memory");
312183da8c6Sjsing 		goto err;
313183da8c6Sjsing 	}
314183da8c6Sjsing 
315183da8c6Sjsing 	if ((s = strdup(alpn)) == NULL) {
3167a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
3177a756d37Sjoshua 		    "out of memory");
318183da8c6Sjsing 		goto err;
319183da8c6Sjsing 	}
320183da8c6Sjsing 
321183da8c6Sjsing 	i = 0;
322183da8c6Sjsing 	q = s;
323183da8c6Sjsing 	while ((p = strsep(&q, ",")) != NULL) {
324183da8c6Sjsing 		if ((len = strlen(p)) == 0) {
3252b31d1bdSjoshua 			tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
326183da8c6Sjsing 			    "alpn protocol with zero length");
327183da8c6Sjsing 			goto err;
328183da8c6Sjsing 		}
329183da8c6Sjsing 		if (len > 255) {
3302b31d1bdSjoshua 			tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
331183da8c6Sjsing 			    "alpn protocol too long");
332183da8c6Sjsing 			goto err;
333183da8c6Sjsing 		}
334183da8c6Sjsing 		buf[i++] = len & 0xff;
335183da8c6Sjsing 		memcpy(&buf[i], p, len);
336183da8c6Sjsing 		i += len;
337183da8c6Sjsing 	}
338183da8c6Sjsing 
339183da8c6Sjsing 	free(s);
340183da8c6Sjsing 
341183da8c6Sjsing 	*alpn_data = buf;
342183da8c6Sjsing 	*alpn_len = buf_len;
343183da8c6Sjsing 
344183da8c6Sjsing 	return (0);
345183da8c6Sjsing 
346183da8c6Sjsing  err:
347183da8c6Sjsing 	free(buf);
348183da8c6Sjsing 	free(s);
349183da8c6Sjsing 
350183da8c6Sjsing 	return (-1);
351183da8c6Sjsing }
352183da8c6Sjsing 
353183da8c6Sjsing int
354183da8c6Sjsing tls_config_set_alpn(struct tls_config *config, const char *alpn)
355183da8c6Sjsing {
356183da8c6Sjsing 	return tls_config_parse_alpn(config, alpn, &config->alpn,
357183da8c6Sjsing 	    &config->alpn_len);
358183da8c6Sjsing }
359183da8c6Sjsing 
360ef012c23Sbeck static int
361ef012c23Sbeck tls_config_add_keypair_file_internal(struct tls_config *config,
362ef012c23Sbeck     const char *cert_file, const char *key_file, const char *ocsp_file)
36355272e79Sjsing {
36455272e79Sjsing 	struct tls_keypair *keypair;
36555272e79Sjsing 
36655272e79Sjsing 	if ((keypair = tls_keypair_new()) == NULL)
36755272e79Sjsing 		return (-1);
36855272e79Sjsing 	if (tls_keypair_set_cert_file(keypair, &config->error, cert_file) != 0)
36955272e79Sjsing 		goto err;
37015339a8cSeric 	if (key_file != NULL &&
37115339a8cSeric 	    tls_keypair_set_key_file(keypair, &config->error, key_file) != 0)
37255272e79Sjsing 		goto err;
373ef012c23Sbeck 	if (ocsp_file != NULL &&
374ef012c23Sbeck 	    tls_keypair_set_ocsp_staple_file(keypair, &config->error,
375ef012c23Sbeck 		ocsp_file) != 0)
376ef012c23Sbeck 		goto err;
377ef012c23Sbeck 
378ef012c23Sbeck 	tls_config_keypair_add(config, keypair);
379ef012c23Sbeck 
380ef012c23Sbeck 	return (0);
381ef012c23Sbeck 
382ef012c23Sbeck  err:
383ef012c23Sbeck 	tls_keypair_free(keypair);
384ef012c23Sbeck 	return (-1);
385ef012c23Sbeck }
386ef012c23Sbeck 
387ef012c23Sbeck static int
388ef012c23Sbeck tls_config_add_keypair_mem_internal(struct tls_config *config, const uint8_t *cert,
389ef012c23Sbeck     size_t cert_len, const uint8_t *key, size_t key_len,
390ef012c23Sbeck     const uint8_t *staple, size_t staple_len)
391ef012c23Sbeck {
392ef012c23Sbeck 	struct tls_keypair *keypair;
393ef012c23Sbeck 
394ef012c23Sbeck 	if ((keypair = tls_keypair_new()) == NULL)
395ef012c23Sbeck 		return (-1);
3962974e8f1Sjsing 	if (tls_keypair_set_cert_mem(keypair, &config->error, cert, cert_len) != 0)
397ef012c23Sbeck 		goto err;
39815339a8cSeric 	if (key != NULL &&
39915339a8cSeric 	    tls_keypair_set_key_mem(keypair, &config->error, key, key_len) != 0)
400ef012c23Sbeck 		goto err;
401ef012c23Sbeck 	if (staple != NULL &&
4022974e8f1Sjsing 	    tls_keypair_set_ocsp_staple_mem(keypair, &config->error, staple,
4032974e8f1Sjsing 		staple_len) != 0)
404ef012c23Sbeck 		goto err;
40555272e79Sjsing 
40655272e79Sjsing 	tls_config_keypair_add(config, keypair);
40755272e79Sjsing 
40855272e79Sjsing 	return (0);
40955272e79Sjsing 
41055272e79Sjsing  err:
41155272e79Sjsing 	tls_keypair_free(keypair);
41255272e79Sjsing 	return (-1);
41355272e79Sjsing }
41455272e79Sjsing 
41555272e79Sjsing int
41655272e79Sjsing tls_config_add_keypair_mem(struct tls_config *config, const uint8_t *cert,
41755272e79Sjsing     size_t cert_len, const uint8_t *key, size_t key_len)
41855272e79Sjsing {
419ef012c23Sbeck 	return tls_config_add_keypair_mem_internal(config, cert, cert_len, key,
420ef012c23Sbeck 	    key_len, NULL, 0);
421ef012c23Sbeck }
42255272e79Sjsing 
423ef012c23Sbeck int
424ef012c23Sbeck tls_config_add_keypair_file(struct tls_config *config,
425ef012c23Sbeck     const char *cert_file, const char *key_file)
426ef012c23Sbeck {
427ef012c23Sbeck 	return tls_config_add_keypair_file_internal(config, cert_file,
428ef012c23Sbeck 	    key_file, NULL);
429ef012c23Sbeck }
43055272e79Sjsing 
431ef012c23Sbeck int
432ef012c23Sbeck tls_config_add_keypair_ocsp_mem(struct tls_config *config, const uint8_t *cert,
433ef012c23Sbeck     size_t cert_len, const uint8_t *key, size_t key_len, const uint8_t *staple,
434ef012c23Sbeck     size_t staple_len)
435ef012c23Sbeck {
436ef012c23Sbeck 	return tls_config_add_keypair_mem_internal(config, cert, cert_len, key,
437ef012c23Sbeck 	    key_len, staple, staple_len);
438ef012c23Sbeck }
43955272e79Sjsing 
440ef012c23Sbeck int
441ef012c23Sbeck tls_config_add_keypair_ocsp_file(struct tls_config *config,
442ef012c23Sbeck     const char *cert_file, const char *key_file, const char *ocsp_file)
443ef012c23Sbeck {
444ef012c23Sbeck 	return tls_config_add_keypair_file_internal(config, cert_file,
445ef012c23Sbeck 	    key_file, ocsp_file);
44655272e79Sjsing }
44755272e79Sjsing 
44855272e79Sjsing int
449b600beedSjsing tls_config_set_ca_file(struct tls_config *config, const char *ca_file)
450b600beedSjsing {
45103ce4948Sjsing 	return tls_config_load_file(&config->error, "CA", ca_file,
45203ce4948Sjsing 	    &config->ca_mem, &config->ca_len);
453b600beedSjsing }
454b600beedSjsing 
455b600beedSjsing int
456b600beedSjsing tls_config_set_ca_path(struct tls_config *config, const char *ca_path)
457b600beedSjsing {
458bb4cb1b0Sjsing 	return tls_set_string(&config->ca_path, ca_path);
459b600beedSjsing }
460b600beedSjsing 
461b600beedSjsing int
46299cfb8c5Sreyk tls_config_set_ca_mem(struct tls_config *config, const uint8_t *ca, size_t len)
46399cfb8c5Sreyk {
464bb4cb1b0Sjsing 	return tls_set_mem(&config->ca_mem, &config->ca_len, ca, len);
46599cfb8c5Sreyk }
46699cfb8c5Sreyk 
46799cfb8c5Sreyk int
468b600beedSjsing tls_config_set_cert_file(struct tls_config *config, const char *cert_file)
469b600beedSjsing {
47003ce4948Sjsing 	return tls_keypair_set_cert_file(config->keypair, &config->error,
47103ce4948Sjsing 	    cert_file);
472b600beedSjsing }
473b600beedSjsing 
474b600beedSjsing int
475b600beedSjsing tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert,
476b600beedSjsing     size_t len)
477b600beedSjsing {
4782974e8f1Sjsing 	return tls_keypair_set_cert_mem(config->keypair, &config->error,
4792974e8f1Sjsing 	    cert, len);
480b600beedSjsing }
481b600beedSjsing 
482b600beedSjsing int
483b600beedSjsing tls_config_set_ciphers(struct tls_config *config, const char *ciphers)
484b600beedSjsing {
485c3bcced5Sjsing 	SSL_CTX *ssl_ctx = NULL;
486c3bcced5Sjsing 
48785f64a89Sjsing 	if (ciphers == NULL ||
48885f64a89Sjsing 	    strcasecmp(ciphers, "default") == 0 ||
48985f64a89Sjsing 	    strcasecmp(ciphers, "secure") == 0)
49085f64a89Sjsing 		ciphers = TLS_CIPHERS_DEFAULT;
491c52398cfSjsing 	else if (strcasecmp(ciphers, "compat") == 0)
49285f64a89Sjsing 		ciphers = TLS_CIPHERS_COMPAT;
493c52398cfSjsing 	else if (strcasecmp(ciphers, "legacy") == 0)
494c52398cfSjsing 		ciphers = TLS_CIPHERS_LEGACY;
495c52398cfSjsing 	else if (strcasecmp(ciphers, "all") == 0 ||
496c52398cfSjsing 	    strcasecmp(ciphers, "insecure") == 0)
497c52398cfSjsing 		ciphers = TLS_CIPHERS_ALL;
49885f64a89Sjsing 
499c3bcced5Sjsing 	if ((ssl_ctx = SSL_CTX_new(SSLv23_method())) == NULL) {
5007a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
5017a756d37Sjoshua 		    "out of memory");
5027add217bSjsing 		goto err;
503c3bcced5Sjsing 	}
504c3bcced5Sjsing 	if (SSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
5057a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
5067a756d37Sjoshua 		    "no ciphers for '%s'", ciphers);
5077add217bSjsing 		goto err;
508c3bcced5Sjsing 	}
509c3bcced5Sjsing 
510c3bcced5Sjsing 	SSL_CTX_free(ssl_ctx);
511bb4cb1b0Sjsing 	return tls_set_string(&config->ciphers, ciphers);
512c3bcced5Sjsing 
5137add217bSjsing  err:
514c3bcced5Sjsing 	SSL_CTX_free(ssl_ctx);
515c3bcced5Sjsing 	return -1;
516b600beedSjsing }
517b600beedSjsing 
518b600beedSjsing int
51980bc881dSjsing tls_config_set_crl_file(struct tls_config *config, const char *crl_file)
52080bc881dSjsing {
52180bc881dSjsing 	return tls_config_load_file(&config->error, "CRL", crl_file,
52280bc881dSjsing 	    &config->crl_mem, &config->crl_len);
52380bc881dSjsing }
52480bc881dSjsing 
52580bc881dSjsing int
52680bc881dSjsing tls_config_set_crl_mem(struct tls_config *config, const uint8_t *crl,
52780bc881dSjsing     size_t len)
52880bc881dSjsing {
529bb4cb1b0Sjsing 	return tls_set_mem(&config->crl_mem, &config->crl_len, crl, len);
53080bc881dSjsing }
53180bc881dSjsing 
53280bc881dSjsing int
5339e5deb48Sjsing tls_config_set_dheparams(struct tls_config *config, const char *params)
5349e5deb48Sjsing {
5359e5deb48Sjsing 	int keylen;
5369e5deb48Sjsing 
5379e5deb48Sjsing 	if (params == NULL || strcasecmp(params, "none") == 0)
5389e5deb48Sjsing 		keylen = 0;
5399e5deb48Sjsing 	else if (strcasecmp(params, "auto") == 0)
5409e5deb48Sjsing 		keylen = -1;
5414ba51adaSjsing 	else if (strcasecmp(params, "legacy") == 0)
5429e5deb48Sjsing 		keylen = 1024;
543a88e9e95Sjsing 	else {
5447a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
5457a756d37Sjoshua 		    "invalid dhe param '%s'", params);
5469e5deb48Sjsing 		return (-1);
547a88e9e95Sjsing 	}
5489e5deb48Sjsing 
5499e5deb48Sjsing 	config->dheparams = keylen;
5509e5deb48Sjsing 
5519e5deb48Sjsing 	return (0);
5529e5deb48Sjsing }
5539e5deb48Sjsing 
5549e5deb48Sjsing int
5554896de1eSjsing tls_config_set_ecdhecurve(struct tls_config *config, const char *curve)
556b600beedSjsing {
5571556a9e0Sjsing 	if (curve == NULL ||
5581556a9e0Sjsing 	    strcasecmp(curve, "none") == 0 ||
5591556a9e0Sjsing 	    strcasecmp(curve, "auto") == 0) {
5601556a9e0Sjsing 		curve = TLS_ECDHE_CURVES;
5611556a9e0Sjsing 	} else if (strchr(curve, ',') != NULL || strchr(curve, ':') != NULL) {
5627a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
5637a756d37Sjoshua 		    "invalid ecdhe curve '%s'", curve);
564b600beedSjsing 		return (-1);
565a88e9e95Sjsing 	}
566b600beedSjsing 
5674896de1eSjsing 	return tls_config_set_ecdhecurves(config, curve);
5684896de1eSjsing }
5694896de1eSjsing 
5704896de1eSjsing int
5714896de1eSjsing tls_config_set_ecdhecurves(struct tls_config *config, const char *curves)
5724896de1eSjsing {
5734896de1eSjsing 	int *curves_list = NULL, *curves_new;
5744896de1eSjsing 	size_t curves_num = 0;
5754896de1eSjsing 	char *cs = NULL;
5764896de1eSjsing 	char *p, *q;
5774896de1eSjsing 	int rv = -1;
5784896de1eSjsing 	int nid;
5794896de1eSjsing 
5804896de1eSjsing 	free(config->ecdhecurves);
5814896de1eSjsing 	config->ecdhecurves = NULL;
5824896de1eSjsing 	config->ecdhecurves_len = 0;
5834896de1eSjsing 
5844896de1eSjsing 	if (curves == NULL || strcasecmp(curves, "default") == 0)
5854896de1eSjsing 		curves = TLS_ECDHE_CURVES;
5864896de1eSjsing 
5874896de1eSjsing 	if ((cs = strdup(curves)) == NULL) {
5887a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
5897a756d37Sjoshua 		    "out of memory");
5904896de1eSjsing 		goto err;
5914896de1eSjsing 	}
5924896de1eSjsing 
5934896de1eSjsing 	q = cs;
5944896de1eSjsing 	while ((p = strsep(&q, ",:")) != NULL) {
5954896de1eSjsing 		while (*p == ' ' || *p == '\t')
5964896de1eSjsing 			p++;
5974896de1eSjsing 
5984896de1eSjsing 		nid = OBJ_sn2nid(p);
5994896de1eSjsing 		if (nid == NID_undef)
6004896de1eSjsing 			nid = OBJ_ln2nid(p);
6014896de1eSjsing 		if (nid == NID_undef)
6024896de1eSjsing 			nid = EC_curve_nist2nid(p);
6034896de1eSjsing 		if (nid == NID_undef) {
6047a756d37Sjoshua 			tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
6054896de1eSjsing 			    "invalid ecdhe curve '%s'", p);
6064896de1eSjsing 			goto err;
6074896de1eSjsing 		}
6084896de1eSjsing 
6094896de1eSjsing 		if ((curves_new = reallocarray(curves_list, curves_num + 1,
6104896de1eSjsing 		    sizeof(int))) == NULL) {
6117a756d37Sjoshua 			tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
6127a756d37Sjoshua 			    "out of memory");
6134896de1eSjsing 			goto err;
6144896de1eSjsing 		}
6154896de1eSjsing 		curves_list = curves_new;
6164896de1eSjsing 		curves_list[curves_num] = nid;
6174896de1eSjsing 		curves_num++;
6184896de1eSjsing 	}
6194896de1eSjsing 
6204896de1eSjsing 	config->ecdhecurves = curves_list;
6214896de1eSjsing 	config->ecdhecurves_len = curves_num;
6224896de1eSjsing 	curves_list = NULL;
6234896de1eSjsing 
6244896de1eSjsing 	rv = 0;
6254896de1eSjsing 
6264896de1eSjsing  err:
6274896de1eSjsing 	free(cs);
6284896de1eSjsing 	free(curves_list);
6294896de1eSjsing 
6304896de1eSjsing 	return (rv);
631b600beedSjsing }
632b600beedSjsing 
633b600beedSjsing int
634b600beedSjsing tls_config_set_key_file(struct tls_config *config, const char *key_file)
635b600beedSjsing {
63603ce4948Sjsing 	return tls_keypair_set_key_file(config->keypair, &config->error,
63703ce4948Sjsing 	    key_file);
638b600beedSjsing }
639b600beedSjsing 
640b600beedSjsing int
641b600beedSjsing tls_config_set_key_mem(struct tls_config *config, const uint8_t *key,
642b600beedSjsing     size_t len)
643b600beedSjsing {
6442974e8f1Sjsing 	return tls_keypair_set_key_mem(config->keypair, &config->error,
6452974e8f1Sjsing 	    key, len);
6461fe9fea1Sjsing }
6471fe9fea1Sjsing 
648ef012c23Sbeck static int
649ef012c23Sbeck tls_config_set_keypair_file_internal(struct tls_config *config,
650ef012c23Sbeck     const char *cert_file, const char *key_file, const char *ocsp_file)
6511fe9fea1Sjsing {
6521fe9fea1Sjsing 	if (tls_config_set_cert_file(config, cert_file) != 0)
6531fe9fea1Sjsing 		return (-1);
6541fe9fea1Sjsing 	if (tls_config_set_key_file(config, key_file) != 0)
6551fe9fea1Sjsing 		return (-1);
656ef012c23Sbeck 	if (ocsp_file != NULL &&
657ef012c23Sbeck 	    tls_config_set_ocsp_staple_file(config, ocsp_file) != 0)
658ef012c23Sbeck 		return (-1);
6591fe9fea1Sjsing 
6601fe9fea1Sjsing 	return (0);
6611fe9fea1Sjsing }
6621fe9fea1Sjsing 
663ef012c23Sbeck static int
664ef012c23Sbeck tls_config_set_keypair_mem_internal(struct tls_config *config, const uint8_t *cert,
665ef012c23Sbeck     size_t cert_len, const uint8_t *key, size_t key_len,
666ef012c23Sbeck     const uint8_t *staple, size_t staple_len)
667ef012c23Sbeck {
668ef012c23Sbeck 	if (tls_config_set_cert_mem(config, cert, cert_len) != 0)
669ef012c23Sbeck 		return (-1);
670ef012c23Sbeck 	if (tls_config_set_key_mem(config, key, key_len) != 0)
671ef012c23Sbeck 		return (-1);
672ef012c23Sbeck 	if ((staple != NULL) &&
673ef012c23Sbeck 	    (tls_config_set_ocsp_staple_mem(config, staple, staple_len) != 0))
674ef012c23Sbeck 		return (-1);
675ef012c23Sbeck 
676ef012c23Sbeck 	return (0);
677ef012c23Sbeck }
678ef012c23Sbeck 
679ef012c23Sbeck int
680ef012c23Sbeck tls_config_set_keypair_file(struct tls_config *config,
681ef012c23Sbeck     const char *cert_file, const char *key_file)
682ef012c23Sbeck {
683ef012c23Sbeck 	return tls_config_set_keypair_file_internal(config, cert_file, key_file,
684ef012c23Sbeck 	    NULL);
685ef012c23Sbeck }
686ef012c23Sbeck 
6871fe9fea1Sjsing int
6881fe9fea1Sjsing tls_config_set_keypair_mem(struct tls_config *config, const uint8_t *cert,
6891fe9fea1Sjsing     size_t cert_len, const uint8_t *key, size_t key_len)
6901fe9fea1Sjsing {
691ef012c23Sbeck 	return tls_config_set_keypair_mem_internal(config, cert, cert_len,
692ef012c23Sbeck 	    key, key_len, NULL, 0);
693b600beedSjsing }
694b600beedSjsing 
6952b50121aSjsing int
696ef012c23Sbeck tls_config_set_keypair_ocsp_file(struct tls_config *config,
697ef012c23Sbeck     const char *cert_file, const char *key_file, const char *ocsp_file)
698ef012c23Sbeck {
699ef012c23Sbeck 	return tls_config_set_keypair_file_internal(config, cert_file, key_file,
700ef012c23Sbeck 	    ocsp_file);
701ef012c23Sbeck }
702ef012c23Sbeck 
703ef012c23Sbeck int
704ef012c23Sbeck tls_config_set_keypair_ocsp_mem(struct tls_config *config, const uint8_t *cert,
705ef012c23Sbeck     size_t cert_len, const uint8_t *key, size_t key_len,
706ef012c23Sbeck     const uint8_t *staple, size_t staple_len)
707ef012c23Sbeck {
708ef012c23Sbeck 	return tls_config_set_keypair_mem_internal(config, cert, cert_len,
709ef012c23Sbeck 	    key, key_len, staple, staple_len);
710ef012c23Sbeck }
711ef012c23Sbeck 
712ef012c23Sbeck 
713ef012c23Sbeck int
714b600beedSjsing tls_config_set_protocols(struct tls_config *config, uint32_t protocols)
715b600beedSjsing {
716b600beedSjsing 	config->protocols = protocols;
7172b50121aSjsing 
7182b50121aSjsing 	return (0);
719b600beedSjsing }
720b600beedSjsing 
7212b50121aSjsing int
7220dd084b9Sjsing tls_config_set_session_fd(struct tls_config *config, int session_fd)
7230dd084b9Sjsing {
7240dd084b9Sjsing 	struct stat sb;
7250dd084b9Sjsing 	mode_t mugo;
7260dd084b9Sjsing 
7270dd084b9Sjsing 	if (session_fd == -1) {
7280dd084b9Sjsing 		config->session_fd = session_fd;
7290dd084b9Sjsing 		return (0);
7300dd084b9Sjsing 	}
7310dd084b9Sjsing 
7320dd084b9Sjsing 	if (fstat(session_fd, &sb) == -1) {
7337a756d37Sjoshua 		tls_config_set_error(config, TLS_ERROR_UNKNOWN,
7347a756d37Sjoshua 		    "failed to stat session file");
7350dd084b9Sjsing 		return (-1);
7360dd084b9Sjsing 	}
7370dd084b9Sjsing 	if (!S_ISREG(sb.st_mode)) {
7387a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
7390dd084b9Sjsing 		    "session file is not a regular file");
7400dd084b9Sjsing 		return (-1);
7410dd084b9Sjsing 	}
7420dd084b9Sjsing 
7430dd084b9Sjsing 	if (sb.st_uid != getuid()) {
7447a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
7457a756d37Sjoshua 		    "session file has incorrect owner (uid %u != %u)",
7467a756d37Sjoshua 		    sb.st_uid, getuid());
7470dd084b9Sjsing 		return (-1);
7480dd084b9Sjsing 	}
7490dd084b9Sjsing 	mugo = sb.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
7500dd084b9Sjsing 	if (mugo != (S_IRUSR|S_IWUSR)) {
7517a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
7527a756d37Sjoshua 		    "session file has incorrect permissions (%o != 600)", mugo);
7530dd084b9Sjsing 		return (-1);
7540dd084b9Sjsing 	}
7550dd084b9Sjsing 
7560dd084b9Sjsing 	config->session_fd = session_fd;
7570dd084b9Sjsing 
7580dd084b9Sjsing 	return (0);
7590dd084b9Sjsing }
7600dd084b9Sjsing 
7610dd084b9Sjsing int
7629ecbddc1Seric tls_config_set_sign_cb(struct tls_config *config, tls_sign_cb cb, void *cb_arg)
7639ecbddc1Seric {
7649ecbddc1Seric 	config->use_fake_private_key = 1;
7659ecbddc1Seric 	config->skip_private_key_check = 1;
7669ecbddc1Seric 	config->sign_cb = cb;
7679ecbddc1Seric 	config->sign_cb_arg = cb_arg;
7689ecbddc1Seric 
7699ecbddc1Seric 	return (0);
7709ecbddc1Seric }
7719ecbddc1Seric 
7729ecbddc1Seric int
773b600beedSjsing tls_config_set_verify_depth(struct tls_config *config, int verify_depth)
774b600beedSjsing {
775b600beedSjsing 	config->verify_depth = verify_depth;
7762b50121aSjsing 
7772b50121aSjsing 	return (0);
778b600beedSjsing }
779b600beedSjsing 
780b600beedSjsing void
781c57e6ec0Sjsing tls_config_prefer_ciphers_client(struct tls_config *config)
782c57e6ec0Sjsing {
783c57e6ec0Sjsing 	config->ciphers_server = 0;
784c57e6ec0Sjsing }
785c57e6ec0Sjsing 
786c57e6ec0Sjsing void
787c57e6ec0Sjsing tls_config_prefer_ciphers_server(struct tls_config *config)
788c57e6ec0Sjsing {
789c57e6ec0Sjsing 	config->ciphers_server = 1;
790c57e6ec0Sjsing }
791c57e6ec0Sjsing 
792c57e6ec0Sjsing void
793b600beedSjsing tls_config_insecure_noverifycert(struct tls_config *config)
794b600beedSjsing {
795b600beedSjsing 	config->verify_cert = 0;
796b600beedSjsing }
797b600beedSjsing 
798b600beedSjsing void
7991ff22c4bSjsing tls_config_insecure_noverifyname(struct tls_config *config)
8001ff22c4bSjsing {
8011ff22c4bSjsing 	config->verify_name = 0;
8021ff22c4bSjsing }
8031ff22c4bSjsing 
8041ff22c4bSjsing void
805615956a0Sjsing tls_config_insecure_noverifytime(struct tls_config *config)
806615956a0Sjsing {
807615956a0Sjsing 	config->verify_time = 0;
808615956a0Sjsing }
809615956a0Sjsing 
810615956a0Sjsing void
811b600beedSjsing tls_config_verify(struct tls_config *config)
812b600beedSjsing {
813b600beedSjsing 	config->verify_cert = 1;
8140ca7b9dfSjsing 	config->verify_name = 1;
815615956a0Sjsing 	config->verify_time = 1;
816b600beedSjsing }
81751f3bd3dSbeck 
81851f3bd3dSbeck void
81969013f12Sbeck tls_config_ocsp_require_stapling(struct tls_config *config)
82069013f12Sbeck {
82169013f12Sbeck 	config->ocsp_require_stapling = 1;
82269013f12Sbeck }
82369013f12Sbeck 
82469013f12Sbeck void
82551f3bd3dSbeck tls_config_verify_client(struct tls_config *config)
82651f3bd3dSbeck {
82751f3bd3dSbeck 	config->verify_client = 1;
82851f3bd3dSbeck }
82951f3bd3dSbeck 
83051f3bd3dSbeck void
83151f3bd3dSbeck tls_config_verify_client_optional(struct tls_config *config)
83251f3bd3dSbeck {
83351f3bd3dSbeck 	config->verify_client = 2;
83451f3bd3dSbeck }
835668bec95Sbeck 
836c793ca29Sbeck void
837c793ca29Sbeck tls_config_skip_private_key_check(struct tls_config *config)
838c793ca29Sbeck {
839c793ca29Sbeck 	config->skip_private_key_check = 1;
840c793ca29Sbeck }
841c793ca29Sbeck 
84215339a8cSeric void
84315339a8cSeric tls_config_use_fake_private_key(struct tls_config *config)
84415339a8cSeric {
84515339a8cSeric 	config->use_fake_private_key = 1;
846e7e46248Seric 	config->skip_private_key_check = 1;
84715339a8cSeric }
84815339a8cSeric 
849668bec95Sbeck int
850668bec95Sbeck tls_config_set_ocsp_staple_file(struct tls_config *config, const char *staple_file)
851668bec95Sbeck {
8529d519145Sbeck 	return tls_keypair_set_ocsp_staple_file(config->keypair, &config->error,
8539d519145Sbeck 	    staple_file);
854668bec95Sbeck }
855668bec95Sbeck 
856668bec95Sbeck int
857ef012c23Sbeck tls_config_set_ocsp_staple_mem(struct tls_config *config, const uint8_t *staple,
858ef012c23Sbeck     size_t len)
859668bec95Sbeck {
8602974e8f1Sjsing 	return tls_keypair_set_ocsp_staple_mem(config->keypair, &config->error,
8612974e8f1Sjsing 	    staple, len);
862668bec95Sbeck }
86347c43cfeSclaudio 
86447c43cfeSclaudio int
86547c43cfeSclaudio tls_config_set_session_id(struct tls_config *config,
86647c43cfeSclaudio     const unsigned char *session_id, size_t len)
86747c43cfeSclaudio {
86847c43cfeSclaudio 	if (len > TLS_MAX_SESSION_ID_LENGTH) {
8692d60058eSjoshua 		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
8707a756d37Sjoshua 		    "session ID too large");
87147c43cfeSclaudio 		return (-1);
87247c43cfeSclaudio 	}
87347c43cfeSclaudio 	memset(config->session_id, 0, sizeof(config->session_id));
87447c43cfeSclaudio 	memcpy(config->session_id, session_id, len);
87547c43cfeSclaudio 	return (0);
87647c43cfeSclaudio }
87747c43cfeSclaudio 
87847c43cfeSclaudio int
87947c43cfeSclaudio tls_config_set_session_lifetime(struct tls_config *config, int lifetime)
88047c43cfeSclaudio {
88147c43cfeSclaudio 	if (lifetime > TLS_MAX_SESSION_TIMEOUT) {
8822d60058eSjoshua 		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
8837a756d37Sjoshua 		    "session lifetime too large");
88447c43cfeSclaudio 		return (-1);
88547c43cfeSclaudio 	}
88647c43cfeSclaudio 	if (lifetime != 0 && lifetime < TLS_MIN_SESSION_TIMEOUT) {
8872d60058eSjoshua 		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
8887a756d37Sjoshua 		    "session lifetime too small");
88947c43cfeSclaudio 		return (-1);
89047c43cfeSclaudio 	}
89147c43cfeSclaudio 
89247c43cfeSclaudio 	config->session_lifetime = lifetime;
89347c43cfeSclaudio 	return (0);
89447c43cfeSclaudio }
89547c43cfeSclaudio 
89647c43cfeSclaudio int
89747c43cfeSclaudio tls_config_add_ticket_key(struct tls_config *config, uint32_t keyrev,
89847c43cfeSclaudio     unsigned char *key, size_t keylen)
89947c43cfeSclaudio {
90047c43cfeSclaudio 	struct tls_ticket_key newkey;
90147c43cfeSclaudio 	int i;
90247c43cfeSclaudio 
90347c43cfeSclaudio 	if (TLS_TICKET_KEY_SIZE != keylen ||
90447c43cfeSclaudio 	    sizeof(newkey.aes_key) + sizeof(newkey.hmac_key) > keylen) {
9057a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
90647c43cfeSclaudio 		    "wrong amount of ticket key data");
90747c43cfeSclaudio 		return (-1);
90847c43cfeSclaudio 	}
90947c43cfeSclaudio 
91047c43cfeSclaudio 	keyrev = htonl(keyrev);
91147c43cfeSclaudio 	memset(&newkey, 0, sizeof(newkey));
91247c43cfeSclaudio 	memcpy(newkey.key_name, &keyrev, sizeof(keyrev));
91347c43cfeSclaudio 	memcpy(newkey.aes_key, key, sizeof(newkey.aes_key));
91447c43cfeSclaudio 	memcpy(newkey.hmac_key, key + sizeof(newkey.aes_key),
91547c43cfeSclaudio 	    sizeof(newkey.hmac_key));
91647c43cfeSclaudio 	newkey.time = time(NULL);
91747c43cfeSclaudio 
91847c43cfeSclaudio 	for (i = 0; i < TLS_NUM_TICKETS; i++) {
91947c43cfeSclaudio 		struct tls_ticket_key *tk = &config->ticket_keys[i];
92047c43cfeSclaudio 		if (memcmp(newkey.key_name, tk->key_name,
92147c43cfeSclaudio 		    sizeof(tk->key_name)) != 0)
92247c43cfeSclaudio 			continue;
92347c43cfeSclaudio 
92447c43cfeSclaudio 		/* allow re-entry of most recent key */
92547c43cfeSclaudio 		if (i == 0 && memcmp(newkey.aes_key, tk->aes_key,
92647c43cfeSclaudio 		    sizeof(tk->aes_key)) == 0 && memcmp(newkey.hmac_key,
92747c43cfeSclaudio 		    tk->hmac_key, sizeof(tk->hmac_key)) == 0)
92847c43cfeSclaudio 			return (0);
9297a756d37Sjoshua 		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
9307a756d37Sjoshua 		    "ticket key already present");
93147c43cfeSclaudio 		return (-1);
93247c43cfeSclaudio 	}
93347c43cfeSclaudio 
93447c43cfeSclaudio 	memmove(&config->ticket_keys[1], &config->ticket_keys[0],
93547c43cfeSclaudio 	    sizeof(config->ticket_keys) - sizeof(config->ticket_keys[0]));
93647c43cfeSclaudio 	config->ticket_keys[0] = newkey;
93747c43cfeSclaudio 
93847c43cfeSclaudio 	config->ticket_autorekey = 0;
93947c43cfeSclaudio 
94047c43cfeSclaudio 	return (0);
94147c43cfeSclaudio }
94247c43cfeSclaudio 
94347c43cfeSclaudio int
94447c43cfeSclaudio tls_config_ticket_autorekey(struct tls_config *config)
94547c43cfeSclaudio {
94647c43cfeSclaudio 	unsigned char key[TLS_TICKET_KEY_SIZE];
94747c43cfeSclaudio 	int rv;
94847c43cfeSclaudio 
94947c43cfeSclaudio 	arc4random_buf(key, sizeof(key));
95047c43cfeSclaudio 	rv = tls_config_add_ticket_key(config, config->ticket_keyrev++, key,
95147c43cfeSclaudio 	    sizeof(key));
95247c43cfeSclaudio 	config->ticket_autorekey = 1;
95347c43cfeSclaudio 	return (rv);
95447c43cfeSclaudio }
955