xref: /dflybsd-src/crypto/libressl/tls/tls.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: tls.c,v 1.94 2022/02/08 19:13:50 tb Exp $ */
2f5b1c8a1SJohn Marino /*
3f5b1c8a1SJohn Marino  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4f5b1c8a1SJohn Marino  *
5f5b1c8a1SJohn Marino  * Permission to use, copy, modify, and distribute this software for any
6f5b1c8a1SJohn Marino  * purpose with or without fee is hereby granted, provided that the above
7f5b1c8a1SJohn Marino  * copyright notice and this permission notice appear in all copies.
8f5b1c8a1SJohn Marino  *
9f5b1c8a1SJohn Marino  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10f5b1c8a1SJohn Marino  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11f5b1c8a1SJohn Marino  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12f5b1c8a1SJohn Marino  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13f5b1c8a1SJohn Marino  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14f5b1c8a1SJohn Marino  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15f5b1c8a1SJohn Marino  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16f5b1c8a1SJohn Marino  */
17f5b1c8a1SJohn Marino 
18f5b1c8a1SJohn Marino #include <sys/socket.h>
19f5b1c8a1SJohn Marino 
20f5b1c8a1SJohn Marino #include <errno.h>
21f5b1c8a1SJohn Marino #include <limits.h>
2272c33676SMaxim Ag #include <pthread.h>
23f5b1c8a1SJohn Marino #include <stdlib.h>
24f5b1c8a1SJohn Marino #include <unistd.h>
25f5b1c8a1SJohn Marino 
26f5b1c8a1SJohn Marino #include <openssl/bio.h>
27f5b1c8a1SJohn Marino #include <openssl/err.h>
28f5b1c8a1SJohn Marino #include <openssl/evp.h>
29f5b1c8a1SJohn Marino #include <openssl/pem.h>
3072c33676SMaxim Ag #include <openssl/safestack.h>
3172c33676SMaxim Ag #include <openssl/ssl.h>
32f5b1c8a1SJohn Marino #include <openssl/x509.h>
33f5b1c8a1SJohn Marino 
34f5b1c8a1SJohn Marino #include <tls.h>
35f5b1c8a1SJohn Marino #include "tls_internal.h"
36f5b1c8a1SJohn Marino 
37f5b1c8a1SJohn Marino static struct tls_config *tls_config_default;
38f5b1c8a1SJohn Marino 
3972c33676SMaxim Ag static int tls_init_rv = -1;
4072c33676SMaxim Ag 
4172c33676SMaxim Ag static void
tls_do_init(void)4272c33676SMaxim Ag tls_do_init(void)
4372c33676SMaxim Ag {
4472c33676SMaxim Ag 	OPENSSL_init_ssl(OPENSSL_INIT_NO_LOAD_CONFIG, NULL);
4572c33676SMaxim Ag 
4672c33676SMaxim Ag 	if (BIO_sock_init() != 1)
4772c33676SMaxim Ag 		return;
4872c33676SMaxim Ag 
4972c33676SMaxim Ag 	if ((tls_config_default = tls_config_new_internal()) == NULL)
5072c33676SMaxim Ag 		return;
5172c33676SMaxim Ag 
5272c33676SMaxim Ag 	tls_config_default->refcount++;
5372c33676SMaxim Ag 
5472c33676SMaxim Ag 	tls_init_rv = 0;
5572c33676SMaxim Ag }
5672c33676SMaxim Ag 
57f5b1c8a1SJohn Marino int
tls_init(void)58f5b1c8a1SJohn Marino tls_init(void)
59f5b1c8a1SJohn Marino {
6072c33676SMaxim Ag 	static pthread_once_t once = PTHREAD_ONCE_INIT;
61f5b1c8a1SJohn Marino 
6272c33676SMaxim Ag 	if (pthread_once(&once, tls_do_init) != 0)
6372c33676SMaxim Ag 		return -1;
64f5b1c8a1SJohn Marino 
6572c33676SMaxim Ag 	return tls_init_rv;
66f5b1c8a1SJohn Marino }
67f5b1c8a1SJohn Marino 
68f5b1c8a1SJohn Marino const char *
tls_error(struct tls * ctx)69f5b1c8a1SJohn Marino tls_error(struct tls *ctx)
70f5b1c8a1SJohn Marino {
71f5b1c8a1SJohn Marino 	return ctx->error.msg;
72f5b1c8a1SJohn Marino }
73f5b1c8a1SJohn Marino 
7472c33676SMaxim Ag void
tls_error_clear(struct tls_error * error)7572c33676SMaxim Ag tls_error_clear(struct tls_error *error)
7672c33676SMaxim Ag {
7772c33676SMaxim Ag 	free(error->msg);
7872c33676SMaxim Ag 	error->msg = NULL;
7972c33676SMaxim Ag 	error->num = 0;
8072c33676SMaxim Ag 	error->tls = 0;
8172c33676SMaxim Ag }
8272c33676SMaxim Ag 
83f5b1c8a1SJohn Marino static int
tls_error_vset(struct tls_error * error,int errnum,const char * fmt,va_list ap)84f5b1c8a1SJohn Marino tls_error_vset(struct tls_error *error, int errnum, const char *fmt, va_list ap)
85f5b1c8a1SJohn Marino {
86f5b1c8a1SJohn Marino 	char *errmsg = NULL;
87f5b1c8a1SJohn Marino 	int rv = -1;
88f5b1c8a1SJohn Marino 
8972c33676SMaxim Ag 	tls_error_clear(error);
9072c33676SMaxim Ag 
91f5b1c8a1SJohn Marino 	error->num = errnum;
9272c33676SMaxim Ag 	error->tls = 1;
93f5b1c8a1SJohn Marino 
94f5b1c8a1SJohn Marino 	if (vasprintf(&errmsg, fmt, ap) == -1) {
95f5b1c8a1SJohn Marino 		errmsg = NULL;
96f5b1c8a1SJohn Marino 		goto err;
97f5b1c8a1SJohn Marino 	}
98f5b1c8a1SJohn Marino 
99f5b1c8a1SJohn Marino 	if (errnum == -1) {
100f5b1c8a1SJohn Marino 		error->msg = errmsg;
101f5b1c8a1SJohn Marino 		return (0);
102f5b1c8a1SJohn Marino 	}
103f5b1c8a1SJohn Marino 
104f5b1c8a1SJohn Marino 	if (asprintf(&error->msg, "%s: %s", errmsg, strerror(errnum)) == -1) {
105f5b1c8a1SJohn Marino 		error->msg = NULL;
106f5b1c8a1SJohn Marino 		goto err;
107f5b1c8a1SJohn Marino 	}
108f5b1c8a1SJohn Marino 	rv = 0;
109f5b1c8a1SJohn Marino 
110f5b1c8a1SJohn Marino  err:
111f5b1c8a1SJohn Marino 	free(errmsg);
112f5b1c8a1SJohn Marino 
113f5b1c8a1SJohn Marino 	return (rv);
114f5b1c8a1SJohn Marino }
115f5b1c8a1SJohn Marino 
116f5b1c8a1SJohn Marino int
tls_error_set(struct tls_error * error,const char * fmt,...)117f5b1c8a1SJohn Marino tls_error_set(struct tls_error *error, const char *fmt, ...)
118f5b1c8a1SJohn Marino {
119f5b1c8a1SJohn Marino 	va_list ap;
120f5b1c8a1SJohn Marino 	int errnum, rv;
121f5b1c8a1SJohn Marino 
122f5b1c8a1SJohn Marino 	errnum = errno;
123f5b1c8a1SJohn Marino 
124f5b1c8a1SJohn Marino 	va_start(ap, fmt);
125f5b1c8a1SJohn Marino 	rv = tls_error_vset(error, errnum, fmt, ap);
126f5b1c8a1SJohn Marino 	va_end(ap);
127f5b1c8a1SJohn Marino 
128f5b1c8a1SJohn Marino 	return (rv);
129f5b1c8a1SJohn Marino }
130f5b1c8a1SJohn Marino 
131f5b1c8a1SJohn Marino int
tls_error_setx(struct tls_error * error,const char * fmt,...)132f5b1c8a1SJohn Marino tls_error_setx(struct tls_error *error, const char *fmt, ...)
133f5b1c8a1SJohn Marino {
134f5b1c8a1SJohn Marino 	va_list ap;
135f5b1c8a1SJohn Marino 	int rv;
136f5b1c8a1SJohn Marino 
137f5b1c8a1SJohn Marino 	va_start(ap, fmt);
138f5b1c8a1SJohn Marino 	rv = tls_error_vset(error, -1, fmt, ap);
139f5b1c8a1SJohn Marino 	va_end(ap);
140f5b1c8a1SJohn Marino 
141f5b1c8a1SJohn Marino 	return (rv);
142f5b1c8a1SJohn Marino }
143f5b1c8a1SJohn Marino 
144f5b1c8a1SJohn Marino int
tls_config_set_error(struct tls_config * config,const char * fmt,...)145f5b1c8a1SJohn Marino tls_config_set_error(struct tls_config *config, const char *fmt, ...)
146f5b1c8a1SJohn Marino {
147f5b1c8a1SJohn Marino 	va_list ap;
148f5b1c8a1SJohn Marino 	int errnum, rv;
149f5b1c8a1SJohn Marino 
150f5b1c8a1SJohn Marino 	errnum = errno;
151f5b1c8a1SJohn Marino 
152f5b1c8a1SJohn Marino 	va_start(ap, fmt);
153f5b1c8a1SJohn Marino 	rv = tls_error_vset(&config->error, errnum, fmt, ap);
154f5b1c8a1SJohn Marino 	va_end(ap);
155f5b1c8a1SJohn Marino 
156f5b1c8a1SJohn Marino 	return (rv);
157f5b1c8a1SJohn Marino }
158f5b1c8a1SJohn Marino 
159f5b1c8a1SJohn Marino int
tls_config_set_errorx(struct tls_config * config,const char * fmt,...)160f5b1c8a1SJohn Marino tls_config_set_errorx(struct tls_config *config, const char *fmt, ...)
161f5b1c8a1SJohn Marino {
162f5b1c8a1SJohn Marino 	va_list ap;
163f5b1c8a1SJohn Marino 	int rv;
164f5b1c8a1SJohn Marino 
165f5b1c8a1SJohn Marino 	va_start(ap, fmt);
166f5b1c8a1SJohn Marino 	rv = tls_error_vset(&config->error, -1, fmt, ap);
167f5b1c8a1SJohn Marino 	va_end(ap);
168f5b1c8a1SJohn Marino 
169f5b1c8a1SJohn Marino 	return (rv);
170f5b1c8a1SJohn Marino }
171f5b1c8a1SJohn Marino 
172f5b1c8a1SJohn Marino int
tls_set_error(struct tls * ctx,const char * fmt,...)173f5b1c8a1SJohn Marino tls_set_error(struct tls *ctx, const char *fmt, ...)
174f5b1c8a1SJohn Marino {
175f5b1c8a1SJohn Marino 	va_list ap;
176f5b1c8a1SJohn Marino 	int errnum, rv;
177f5b1c8a1SJohn Marino 
178f5b1c8a1SJohn Marino 	errnum = errno;
179f5b1c8a1SJohn Marino 
180f5b1c8a1SJohn Marino 	va_start(ap, fmt);
181f5b1c8a1SJohn Marino 	rv = tls_error_vset(&ctx->error, errnum, fmt, ap);
182f5b1c8a1SJohn Marino 	va_end(ap);
183f5b1c8a1SJohn Marino 
184f5b1c8a1SJohn Marino 	return (rv);
185f5b1c8a1SJohn Marino }
186f5b1c8a1SJohn Marino 
187f5b1c8a1SJohn Marino int
tls_set_errorx(struct tls * ctx,const char * fmt,...)188f5b1c8a1SJohn Marino tls_set_errorx(struct tls *ctx, const char *fmt, ...)
189f5b1c8a1SJohn Marino {
190f5b1c8a1SJohn Marino 	va_list ap;
191f5b1c8a1SJohn Marino 	int rv;
192f5b1c8a1SJohn Marino 
193f5b1c8a1SJohn Marino 	va_start(ap, fmt);
194f5b1c8a1SJohn Marino 	rv = tls_error_vset(&ctx->error, -1, fmt, ap);
195f5b1c8a1SJohn Marino 	va_end(ap);
196f5b1c8a1SJohn Marino 
197f5b1c8a1SJohn Marino 	return (rv);
198f5b1c8a1SJohn Marino }
199f5b1c8a1SJohn Marino 
20072c33676SMaxim Ag int
tls_set_ssl_errorx(struct tls * ctx,const char * fmt,...)20172c33676SMaxim Ag tls_set_ssl_errorx(struct tls *ctx, const char *fmt, ...)
20272c33676SMaxim Ag {
20372c33676SMaxim Ag 	va_list ap;
20472c33676SMaxim Ag 	int rv;
20572c33676SMaxim Ag 
20672c33676SMaxim Ag 	/* Only set an error if a more specific one does not already exist. */
20772c33676SMaxim Ag 	if (ctx->error.tls != 0)
20872c33676SMaxim Ag 		return (0);
20972c33676SMaxim Ag 
21072c33676SMaxim Ag 	va_start(ap, fmt);
21172c33676SMaxim Ag 	rv = tls_error_vset(&ctx->error, -1, fmt, ap);
21272c33676SMaxim Ag 	va_end(ap);
21372c33676SMaxim Ag 
21472c33676SMaxim Ag 	return (rv);
21572c33676SMaxim Ag }
21672c33676SMaxim Ag 
21772c33676SMaxim Ag struct tls_sni_ctx *
tls_sni_ctx_new(void)21872c33676SMaxim Ag tls_sni_ctx_new(void)
21972c33676SMaxim Ag {
22072c33676SMaxim Ag 	return (calloc(1, sizeof(struct tls_sni_ctx)));
22172c33676SMaxim Ag }
22272c33676SMaxim Ag 
22372c33676SMaxim Ag void
tls_sni_ctx_free(struct tls_sni_ctx * sni_ctx)22472c33676SMaxim Ag tls_sni_ctx_free(struct tls_sni_ctx *sni_ctx)
22572c33676SMaxim Ag {
22672c33676SMaxim Ag 	if (sni_ctx == NULL)
22772c33676SMaxim Ag 		return;
22872c33676SMaxim Ag 
22972c33676SMaxim Ag 	SSL_CTX_free(sni_ctx->ssl_ctx);
23072c33676SMaxim Ag 	X509_free(sni_ctx->ssl_cert);
23172c33676SMaxim Ag 
23272c33676SMaxim Ag 	free(sni_ctx);
23372c33676SMaxim Ag }
23472c33676SMaxim Ag 
235f5b1c8a1SJohn Marino struct tls *
tls_new(void)236f5b1c8a1SJohn Marino tls_new(void)
237f5b1c8a1SJohn Marino {
238f5b1c8a1SJohn Marino 	struct tls *ctx;
239f5b1c8a1SJohn Marino 
240f5b1c8a1SJohn Marino 	if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
241f5b1c8a1SJohn Marino 		return (NULL);
242f5b1c8a1SJohn Marino 
243f5b1c8a1SJohn Marino 	tls_reset(ctx);
244f5b1c8a1SJohn Marino 
24572c33676SMaxim Ag 	if (tls_configure(ctx, tls_config_default) == -1) {
24672c33676SMaxim Ag 		free(ctx);
24772c33676SMaxim Ag 		return NULL;
24872c33676SMaxim Ag 	}
24972c33676SMaxim Ag 
250f5b1c8a1SJohn Marino 	return (ctx);
251f5b1c8a1SJohn Marino }
252f5b1c8a1SJohn Marino 
253f5b1c8a1SJohn Marino int
tls_configure(struct tls * ctx,struct tls_config * config)254f5b1c8a1SJohn Marino tls_configure(struct tls *ctx, struct tls_config *config)
255f5b1c8a1SJohn Marino {
256f5b1c8a1SJohn Marino 	if (config == NULL)
257f5b1c8a1SJohn Marino 		config = tls_config_default;
258f5b1c8a1SJohn Marino 
25972c33676SMaxim Ag 	pthread_mutex_lock(&config->mutex);
26072c33676SMaxim Ag 	config->refcount++;
26172c33676SMaxim Ag 	pthread_mutex_unlock(&config->mutex);
26272c33676SMaxim Ag 
26372c33676SMaxim Ag 	tls_config_free(ctx->config);
26472c33676SMaxim Ag 
265f5b1c8a1SJohn Marino 	ctx->config = config;
26672c33676SMaxim Ag 	ctx->keypair = config->keypair;
267f5b1c8a1SJohn Marino 
268f5b1c8a1SJohn Marino 	if ((ctx->flags & TLS_SERVER) != 0)
269f5b1c8a1SJohn Marino 		return (tls_configure_server(ctx));
270f5b1c8a1SJohn Marino 
271f5b1c8a1SJohn Marino 	return (0);
272f5b1c8a1SJohn Marino }
273f5b1c8a1SJohn Marino 
274f5b1c8a1SJohn Marino int
tls_cert_hash(X509 * cert,char ** hash)27572c33676SMaxim Ag tls_cert_hash(X509 *cert, char **hash)
27672c33676SMaxim Ag {
27772c33676SMaxim Ag 	char d[EVP_MAX_MD_SIZE], *dhex = NULL;
27872c33676SMaxim Ag 	int dlen, rv = -1;
27972c33676SMaxim Ag 
28072c33676SMaxim Ag 	free(*hash);
28172c33676SMaxim Ag 	*hash = NULL;
28272c33676SMaxim Ag 
28372c33676SMaxim Ag 	if (X509_digest(cert, EVP_sha256(), d, &dlen) != 1)
28472c33676SMaxim Ag 		goto err;
28572c33676SMaxim Ag 
28672c33676SMaxim Ag 	if (tls_hex_string(d, dlen, &dhex, NULL) != 0)
28772c33676SMaxim Ag 		goto err;
28872c33676SMaxim Ag 
28972c33676SMaxim Ag 	if (asprintf(hash, "SHA256:%s", dhex) == -1) {
29072c33676SMaxim Ag 		*hash = NULL;
29172c33676SMaxim Ag 		goto err;
29272c33676SMaxim Ag 	}
29372c33676SMaxim Ag 
29472c33676SMaxim Ag 	rv = 0;
29572c33676SMaxim Ag  err:
29672c33676SMaxim Ag 	free(dhex);
29772c33676SMaxim Ag 
29872c33676SMaxim Ag 	return (rv);
29972c33676SMaxim Ag }
30072c33676SMaxim Ag 
30172c33676SMaxim Ag int
tls_cert_pubkey_hash(X509 * cert,char ** hash)30272c33676SMaxim Ag tls_cert_pubkey_hash(X509 *cert, char **hash)
30372c33676SMaxim Ag {
30472c33676SMaxim Ag 	char d[EVP_MAX_MD_SIZE], *dhex = NULL;
30572c33676SMaxim Ag 	int dlen, rv = -1;
30672c33676SMaxim Ag 
30772c33676SMaxim Ag 	free(*hash);
30872c33676SMaxim Ag 	*hash = NULL;
30972c33676SMaxim Ag 
31072c33676SMaxim Ag 	if (X509_pubkey_digest(cert, EVP_sha256(), d, &dlen) != 1)
31172c33676SMaxim Ag 		goto err;
31272c33676SMaxim Ag 
31372c33676SMaxim Ag 	if (tls_hex_string(d, dlen, &dhex, NULL) != 0)
31472c33676SMaxim Ag 		goto err;
31572c33676SMaxim Ag 
31672c33676SMaxim Ag 	if (asprintf(hash, "SHA256:%s", dhex) == -1) {
31772c33676SMaxim Ag 		*hash = NULL;
31872c33676SMaxim Ag 		goto err;
31972c33676SMaxim Ag 	}
32072c33676SMaxim Ag 
32172c33676SMaxim Ag 	rv = 0;
32272c33676SMaxim Ag 
32372c33676SMaxim Ag  err:
32472c33676SMaxim Ag 	free(dhex);
32572c33676SMaxim Ag 
32672c33676SMaxim Ag 	return (rv);
32772c33676SMaxim Ag }
32872c33676SMaxim Ag 
329*de0e0e4dSAntonio Huete Jimenez static int
tls_keypair_to_pkey(struct tls * ctx,struct tls_keypair * keypair,EVP_PKEY ** pkey)330*de0e0e4dSAntonio Huete Jimenez tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pkey)
331*de0e0e4dSAntonio Huete Jimenez {
332*de0e0e4dSAntonio Huete Jimenez 	BIO *bio = NULL;
333*de0e0e4dSAntonio Huete Jimenez 	X509 *x509 = NULL;
334*de0e0e4dSAntonio Huete Jimenez 	char *mem;
335*de0e0e4dSAntonio Huete Jimenez 	size_t len;
336*de0e0e4dSAntonio Huete Jimenez 	int ret = -1;
337*de0e0e4dSAntonio Huete Jimenez 
338*de0e0e4dSAntonio Huete Jimenez 	*pkey = NULL;
339*de0e0e4dSAntonio Huete Jimenez 
340*de0e0e4dSAntonio Huete Jimenez 	if (ctx->config->use_fake_private_key) {
341*de0e0e4dSAntonio Huete Jimenez 		mem = keypair->cert_mem;
342*de0e0e4dSAntonio Huete Jimenez 		len = keypair->cert_len;
343*de0e0e4dSAntonio Huete Jimenez 	} else {
344*de0e0e4dSAntonio Huete Jimenez 		mem = keypair->key_mem;
345*de0e0e4dSAntonio Huete Jimenez 		len = keypair->key_len;
346*de0e0e4dSAntonio Huete Jimenez 	}
347*de0e0e4dSAntonio Huete Jimenez 
348*de0e0e4dSAntonio Huete Jimenez 	if (mem == NULL)
349*de0e0e4dSAntonio Huete Jimenez 		return (0);
350*de0e0e4dSAntonio Huete Jimenez 
351*de0e0e4dSAntonio Huete Jimenez 	if (len > INT_MAX) {
352*de0e0e4dSAntonio Huete Jimenez 		tls_set_errorx(ctx, ctx->config->use_fake_private_key ?
353*de0e0e4dSAntonio Huete Jimenez 		    "cert too long" : "key too long");
354*de0e0e4dSAntonio Huete Jimenez 		goto err;
355*de0e0e4dSAntonio Huete Jimenez 	}
356*de0e0e4dSAntonio Huete Jimenez 
357*de0e0e4dSAntonio Huete Jimenez 	if ((bio = BIO_new_mem_buf(mem, len)) == NULL) {
358*de0e0e4dSAntonio Huete Jimenez 		tls_set_errorx(ctx, "failed to create buffer");
359*de0e0e4dSAntonio Huete Jimenez 		goto err;
360*de0e0e4dSAntonio Huete Jimenez 	}
361*de0e0e4dSAntonio Huete Jimenez 
362*de0e0e4dSAntonio Huete Jimenez 	if (ctx->config->use_fake_private_key) {
363*de0e0e4dSAntonio Huete Jimenez 		if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb,
364*de0e0e4dSAntonio Huete Jimenez 		    NULL)) == NULL) {
365*de0e0e4dSAntonio Huete Jimenez 			tls_set_errorx(ctx, "failed to read X509 certificate");
366*de0e0e4dSAntonio Huete Jimenez 			goto err;
367*de0e0e4dSAntonio Huete Jimenez 		}
368*de0e0e4dSAntonio Huete Jimenez 		if ((*pkey = X509_get_pubkey(x509)) == NULL) {
369*de0e0e4dSAntonio Huete Jimenez 			tls_set_errorx(ctx, "failed to retrieve pubkey");
370*de0e0e4dSAntonio Huete Jimenez 			goto err;
371*de0e0e4dSAntonio Huete Jimenez 		}
372*de0e0e4dSAntonio Huete Jimenez 	} else {
373*de0e0e4dSAntonio Huete Jimenez 		if ((*pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
374*de0e0e4dSAntonio Huete Jimenez 		    NULL)) ==  NULL) {
375*de0e0e4dSAntonio Huete Jimenez 			tls_set_errorx(ctx, "failed to read private key");
376*de0e0e4dSAntonio Huete Jimenez 			goto err;
377*de0e0e4dSAntonio Huete Jimenez 		}
378*de0e0e4dSAntonio Huete Jimenez 	}
379*de0e0e4dSAntonio Huete Jimenez 
380*de0e0e4dSAntonio Huete Jimenez 	ret = 0;
381*de0e0e4dSAntonio Huete Jimenez  err:
382*de0e0e4dSAntonio Huete Jimenez 	BIO_free(bio);
383*de0e0e4dSAntonio Huete Jimenez 	X509_free(x509);
384*de0e0e4dSAntonio Huete Jimenez 	return (ret);
385*de0e0e4dSAntonio Huete Jimenez }
386*de0e0e4dSAntonio Huete Jimenez 
387*de0e0e4dSAntonio Huete Jimenez static int
tls_keypair_setup_pkey(struct tls * ctx,struct tls_keypair * keypair,EVP_PKEY * pkey)388*de0e0e4dSAntonio Huete Jimenez tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *pkey)
389*de0e0e4dSAntonio Huete Jimenez {
390*de0e0e4dSAntonio Huete Jimenez 	RSA_METHOD *rsa_method;
391*de0e0e4dSAntonio Huete Jimenez 	ECDSA_METHOD *ecdsa_method;
392*de0e0e4dSAntonio Huete Jimenez 	RSA *rsa = NULL;
393*de0e0e4dSAntonio Huete Jimenez 	EC_KEY *eckey = NULL;
394*de0e0e4dSAntonio Huete Jimenez 	int ret = -1;
395*de0e0e4dSAntonio Huete Jimenez 
396*de0e0e4dSAntonio Huete Jimenez 	/* Only install the pubkey hash if fake private keys are used. */
397*de0e0e4dSAntonio Huete Jimenez 	if (!ctx->config->skip_private_key_check)
398*de0e0e4dSAntonio Huete Jimenez 		return (0);
399*de0e0e4dSAntonio Huete Jimenez 
400*de0e0e4dSAntonio Huete Jimenez 	if (keypair->pubkey_hash == NULL) {
401*de0e0e4dSAntonio Huete Jimenez 		tls_set_errorx(ctx, "public key hash not set");
402*de0e0e4dSAntonio Huete Jimenez 		goto err;
403*de0e0e4dSAntonio Huete Jimenez 	}
404*de0e0e4dSAntonio Huete Jimenez 
405*de0e0e4dSAntonio Huete Jimenez 	switch (EVP_PKEY_id(pkey)) {
406*de0e0e4dSAntonio Huete Jimenez 	case EVP_PKEY_RSA:
407*de0e0e4dSAntonio Huete Jimenez 		if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
408*de0e0e4dSAntonio Huete Jimenez 		    RSA_set_ex_data(rsa, 0, keypair->pubkey_hash) == 0) {
409*de0e0e4dSAntonio Huete Jimenez 			tls_set_errorx(ctx, "RSA key setup failure");
410*de0e0e4dSAntonio Huete Jimenez 			goto err;
411*de0e0e4dSAntonio Huete Jimenez 		}
412*de0e0e4dSAntonio Huete Jimenez 		if (ctx->config->sign_cb == NULL)
413*de0e0e4dSAntonio Huete Jimenez 			break;
414*de0e0e4dSAntonio Huete Jimenez 		if ((rsa_method = tls_signer_rsa_method()) == NULL ||
415*de0e0e4dSAntonio Huete Jimenez 		    RSA_set_ex_data(rsa, 1, ctx->config) == 0 ||
416*de0e0e4dSAntonio Huete Jimenez 		    RSA_set_method(rsa, rsa_method) == 0) {
417*de0e0e4dSAntonio Huete Jimenez 			tls_set_errorx(ctx, "failed to setup RSA key");
418*de0e0e4dSAntonio Huete Jimenez 			goto err;
419*de0e0e4dSAntonio Huete Jimenez 		}
420*de0e0e4dSAntonio Huete Jimenez 		break;
421*de0e0e4dSAntonio Huete Jimenez 	case EVP_PKEY_EC:
422*de0e0e4dSAntonio Huete Jimenez 		if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL ||
423*de0e0e4dSAntonio Huete Jimenez 		    ECDSA_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0) {
424*de0e0e4dSAntonio Huete Jimenez 			tls_set_errorx(ctx, "EC key setup failure");
425*de0e0e4dSAntonio Huete Jimenez 			goto err;
426*de0e0e4dSAntonio Huete Jimenez 		}
427*de0e0e4dSAntonio Huete Jimenez 		if (ctx->config->sign_cb == NULL)
428*de0e0e4dSAntonio Huete Jimenez 			break;
429*de0e0e4dSAntonio Huete Jimenez 		if ((ecdsa_method = tls_signer_ecdsa_method()) == NULL ||
430*de0e0e4dSAntonio Huete Jimenez 		    ECDSA_set_ex_data(eckey, 1, ctx->config) == 0 ||
431*de0e0e4dSAntonio Huete Jimenez 		    ECDSA_set_method(eckey, ecdsa_method) == 0) {
432*de0e0e4dSAntonio Huete Jimenez 			tls_set_errorx(ctx, "failed to setup EC key");
433*de0e0e4dSAntonio Huete Jimenez 			goto err;
434*de0e0e4dSAntonio Huete Jimenez 		}
435*de0e0e4dSAntonio Huete Jimenez 		break;
436*de0e0e4dSAntonio Huete Jimenez 	default:
437*de0e0e4dSAntonio Huete Jimenez 		tls_set_errorx(ctx, "incorrect key type");
438*de0e0e4dSAntonio Huete Jimenez 		goto err;
439*de0e0e4dSAntonio Huete Jimenez 	}
440*de0e0e4dSAntonio Huete Jimenez 
441*de0e0e4dSAntonio Huete Jimenez 	ret = 0;
442*de0e0e4dSAntonio Huete Jimenez 
443*de0e0e4dSAntonio Huete Jimenez  err:
444*de0e0e4dSAntonio Huete Jimenez 	RSA_free(rsa);
445*de0e0e4dSAntonio Huete Jimenez 	EC_KEY_free(eckey);
446*de0e0e4dSAntonio Huete Jimenez 	return (ret);
447*de0e0e4dSAntonio Huete Jimenez }
448*de0e0e4dSAntonio Huete Jimenez 
44972c33676SMaxim Ag int
tls_configure_ssl_keypair(struct tls * ctx,SSL_CTX * ssl_ctx,struct tls_keypair * keypair,int required)45072c33676SMaxim Ag tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
451f5b1c8a1SJohn Marino     struct tls_keypair *keypair, int required)
452f5b1c8a1SJohn Marino {
453f5b1c8a1SJohn Marino 	EVP_PKEY *pkey = NULL;
454f5b1c8a1SJohn Marino 
455f5b1c8a1SJohn Marino 	if (!required &&
456f5b1c8a1SJohn Marino 	    keypair->cert_mem == NULL &&
45772c33676SMaxim Ag 	    keypair->key_mem == NULL)
458f5b1c8a1SJohn Marino 		return(0);
459f5b1c8a1SJohn Marino 
460f5b1c8a1SJohn Marino 	if (keypair->cert_mem != NULL) {
461f5b1c8a1SJohn Marino 		if (keypair->cert_len > INT_MAX) {
462f5b1c8a1SJohn Marino 			tls_set_errorx(ctx, "certificate too long");
463f5b1c8a1SJohn Marino 			goto err;
464f5b1c8a1SJohn Marino 		}
465f5b1c8a1SJohn Marino 
466f5b1c8a1SJohn Marino 		if (SSL_CTX_use_certificate_chain_mem(ssl_ctx,
467f5b1c8a1SJohn Marino 		    keypair->cert_mem, keypair->cert_len) != 1) {
468f5b1c8a1SJohn Marino 			tls_set_errorx(ctx, "failed to load certificate");
469f5b1c8a1SJohn Marino 			goto err;
470f5b1c8a1SJohn Marino 		}
471f5b1c8a1SJohn Marino 	}
47272c33676SMaxim Ag 
473*de0e0e4dSAntonio Huete Jimenez 	if (tls_keypair_to_pkey(ctx, keypair, &pkey) == -1)
474f5b1c8a1SJohn Marino 		goto err;
475*de0e0e4dSAntonio Huete Jimenez 	if (pkey != NULL) {
476*de0e0e4dSAntonio Huete Jimenez 		if (tls_keypair_setup_pkey(ctx, keypair, pkey) == -1)
477f5b1c8a1SJohn Marino 			goto err;
478f5b1c8a1SJohn Marino 		if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) {
479f5b1c8a1SJohn Marino 			tls_set_errorx(ctx, "failed to load private key");
480f5b1c8a1SJohn Marino 			goto err;
481f5b1c8a1SJohn Marino 		}
482f5b1c8a1SJohn Marino 		EVP_PKEY_free(pkey);
483f5b1c8a1SJohn Marino 		pkey = NULL;
484f5b1c8a1SJohn Marino 	}
485f5b1c8a1SJohn Marino 
48672c33676SMaxim Ag 	if (!ctx->config->skip_private_key_check &&
48772c33676SMaxim Ag 	    SSL_CTX_check_private_key(ssl_ctx) != 1) {
488f5b1c8a1SJohn Marino 		tls_set_errorx(ctx, "private/public key mismatch");
489f5b1c8a1SJohn Marino 		goto err;
490f5b1c8a1SJohn Marino 	}
491f5b1c8a1SJohn Marino 
492f5b1c8a1SJohn Marino 	return (0);
493f5b1c8a1SJohn Marino 
494f5b1c8a1SJohn Marino  err:
495f5b1c8a1SJohn Marino 	EVP_PKEY_free(pkey);
496f5b1c8a1SJohn Marino 
497*de0e0e4dSAntonio Huete Jimenez 	return (-1);
498f5b1c8a1SJohn Marino }
499f5b1c8a1SJohn Marino 
500f5b1c8a1SJohn Marino int
tls_configure_ssl(struct tls * ctx,SSL_CTX * ssl_ctx)50172c33676SMaxim Ag tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
502f5b1c8a1SJohn Marino {
5038edacedfSDaniel Fojt 	SSL_CTX_clear_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
5048edacedfSDaniel Fojt 
50572c33676SMaxim Ag 	SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
50672c33676SMaxim Ag 	SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
507f5b1c8a1SJohn Marino 
50872c33676SMaxim Ag 	SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2);
50972c33676SMaxim Ag 	SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv3);
510f5b1c8a1SJohn Marino 
51172c33676SMaxim Ag 	SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1);
51272c33676SMaxim Ag 	SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
51372c33676SMaxim Ag 	SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
514cca6fc52SDaniel Fojt 	SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_3);
515f5b1c8a1SJohn Marino 
516f5b1c8a1SJohn Marino 	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0)
51772c33676SMaxim Ag 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1);
518f5b1c8a1SJohn Marino 	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0)
51972c33676SMaxim Ag 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
520f5b1c8a1SJohn Marino 	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
52172c33676SMaxim Ag 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
522cca6fc52SDaniel Fojt 	if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_3) == 0)
523cca6fc52SDaniel Fojt 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3);
52472c33676SMaxim Ag 
52572c33676SMaxim Ag 	if (ctx->config->alpn != NULL) {
52672c33676SMaxim Ag 		if (SSL_CTX_set_alpn_protos(ssl_ctx, ctx->config->alpn,
52772c33676SMaxim Ag 		    ctx->config->alpn_len) != 0) {
52872c33676SMaxim Ag 			tls_set_errorx(ctx, "failed to set alpn");
52972c33676SMaxim Ag 			goto err;
53072c33676SMaxim Ag 		}
53172c33676SMaxim Ag 	}
532f5b1c8a1SJohn Marino 
533f5b1c8a1SJohn Marino 	if (ctx->config->ciphers != NULL) {
53472c33676SMaxim Ag 		if (SSL_CTX_set_cipher_list(ssl_ctx,
535f5b1c8a1SJohn Marino 		    ctx->config->ciphers) != 1) {
536f5b1c8a1SJohn Marino 			tls_set_errorx(ctx, "failed to set ciphers");
537f5b1c8a1SJohn Marino 			goto err;
538f5b1c8a1SJohn Marino 		}
539f5b1c8a1SJohn Marino 	}
540f5b1c8a1SJohn Marino 
541f5b1c8a1SJohn Marino 	if (ctx->config->verify_time == 0) {
542*de0e0e4dSAntonio Huete Jimenez 		X509_VERIFY_PARAM_set_flags(SSL_CTX_get0_param(ssl_ctx),
543f5b1c8a1SJohn Marino 		    X509_V_FLAG_NO_CHECK_TIME);
544f5b1c8a1SJohn Marino 	}
545f5b1c8a1SJohn Marino 
54672c33676SMaxim Ag 	/* Disable any form of session caching by default */
54772c33676SMaxim Ag 	SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF);
54872c33676SMaxim Ag 	SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
54972c33676SMaxim Ag 
550f5b1c8a1SJohn Marino 	return (0);
551f5b1c8a1SJohn Marino 
552f5b1c8a1SJohn Marino  err:
553f5b1c8a1SJohn Marino 	return (-1);
554f5b1c8a1SJohn Marino }
555f5b1c8a1SJohn Marino 
55672c33676SMaxim Ag static int
tls_ssl_cert_verify_cb(X509_STORE_CTX * x509_ctx,void * arg)55772c33676SMaxim Ag tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
55872c33676SMaxim Ag {
55972c33676SMaxim Ag 	struct tls *ctx = arg;
56072c33676SMaxim Ag 	int x509_err;
56172c33676SMaxim Ag 
56272c33676SMaxim Ag 	if (ctx->config->verify_cert == 0)
56372c33676SMaxim Ag 		return (1);
56472c33676SMaxim Ag 
56572c33676SMaxim Ag 	if ((X509_verify_cert(x509_ctx)) < 0) {
56672c33676SMaxim Ag 		tls_set_errorx(ctx, "X509 verify cert failed");
56772c33676SMaxim Ag 		return (0);
56872c33676SMaxim Ag 	}
56972c33676SMaxim Ag 
57072c33676SMaxim Ag 	x509_err = X509_STORE_CTX_get_error(x509_ctx);
57172c33676SMaxim Ag 	if (x509_err == X509_V_OK)
57272c33676SMaxim Ag 		return (1);
57372c33676SMaxim Ag 
57472c33676SMaxim Ag 	tls_set_errorx(ctx, "certificate verification failed: %s",
57572c33676SMaxim Ag 	    X509_verify_cert_error_string(x509_err));
57672c33676SMaxim Ag 
57772c33676SMaxim Ag 	return (0);
57872c33676SMaxim Ag }
57972c33676SMaxim Ag 
580f5b1c8a1SJohn Marino int
tls_configure_ssl_verify(struct tls * ctx,SSL_CTX * ssl_ctx,int verify)58172c33676SMaxim Ag tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
582f5b1c8a1SJohn Marino {
58372c33676SMaxim Ag 	size_t ca_len = ctx->config->ca_len;
58472c33676SMaxim Ag 	char *ca_mem = ctx->config->ca_mem;
58572c33676SMaxim Ag 	char *crl_mem = ctx->config->crl_mem;
58672c33676SMaxim Ag 	size_t crl_len = ctx->config->crl_len;
58772c33676SMaxim Ag 	char *ca_free = NULL;
58872c33676SMaxim Ag 	STACK_OF(X509_INFO) *xis = NULL;
58972c33676SMaxim Ag 	X509_STORE *store;
59072c33676SMaxim Ag 	X509_INFO *xi;
59172c33676SMaxim Ag 	BIO *bio = NULL;
59272c33676SMaxim Ag 	int rv = -1;
59372c33676SMaxim Ag 	int i;
594f5b1c8a1SJohn Marino 
59572c33676SMaxim Ag 	SSL_CTX_set_verify(ssl_ctx, verify, NULL);
59672c33676SMaxim Ag 	SSL_CTX_set_cert_verify_callback(ssl_ctx, tls_ssl_cert_verify_cb, ctx);
59772c33676SMaxim Ag 
59872c33676SMaxim Ag 	if (ctx->config->verify_depth >= 0)
59972c33676SMaxim Ag 		SSL_CTX_set_verify_depth(ssl_ctx, ctx->config->verify_depth);
60072c33676SMaxim Ag 
60172c33676SMaxim Ag 	if (ctx->config->verify_cert == 0)
60272c33676SMaxim Ag 		goto done;
60372c33676SMaxim Ag 
60472c33676SMaxim Ag 	/* If no CA has been specified, attempt to load the default. */
60572c33676SMaxim Ag 	if (ctx->config->ca_mem == NULL && ctx->config->ca_path == NULL) {
60672c33676SMaxim Ag 		if (tls_config_load_file(&ctx->error, "CA", tls_default_ca_cert_file(),
60772c33676SMaxim Ag 		    &ca_mem, &ca_len) != 0)
60872c33676SMaxim Ag 			goto err;
60972c33676SMaxim Ag 		ca_free = ca_mem;
61072c33676SMaxim Ag 	}
61172c33676SMaxim Ag 
61272c33676SMaxim Ag 	if (ca_mem != NULL) {
61372c33676SMaxim Ag 		if (ca_len > INT_MAX) {
614f5b1c8a1SJohn Marino 			tls_set_errorx(ctx, "ca too long");
615f5b1c8a1SJohn Marino 			goto err;
616f5b1c8a1SJohn Marino 		}
61772c33676SMaxim Ag 		if (SSL_CTX_load_verify_mem(ssl_ctx, ca_mem, ca_len) != 1) {
618f5b1c8a1SJohn Marino 			tls_set_errorx(ctx, "ssl verify memory setup failure");
619f5b1c8a1SJohn Marino 			goto err;
620f5b1c8a1SJohn Marino 		}
62172c33676SMaxim Ag 	} else if (SSL_CTX_load_verify_locations(ssl_ctx, NULL,
62272c33676SMaxim Ag 	    ctx->config->ca_path) != 1) {
62372c33676SMaxim Ag 		tls_set_errorx(ctx, "ssl verify locations failure");
624f5b1c8a1SJohn Marino 		goto err;
625f5b1c8a1SJohn Marino 	}
626f5b1c8a1SJohn Marino 
62772c33676SMaxim Ag 	if (crl_mem != NULL) {
62872c33676SMaxim Ag 		if (crl_len > INT_MAX) {
62972c33676SMaxim Ag 			tls_set_errorx(ctx, "crl too long");
63072c33676SMaxim Ag 			goto err;
63172c33676SMaxim Ag 		}
63272c33676SMaxim Ag 		if ((bio = BIO_new_mem_buf(crl_mem, crl_len)) == NULL) {
63372c33676SMaxim Ag 			tls_set_errorx(ctx, "failed to create buffer");
63472c33676SMaxim Ag 			goto err;
63572c33676SMaxim Ag 		}
63672c33676SMaxim Ag 		if ((xis = PEM_X509_INFO_read_bio(bio, NULL, tls_password_cb,
63772c33676SMaxim Ag 		    NULL)) == NULL) {
63872c33676SMaxim Ag 			tls_set_errorx(ctx, "failed to parse crl");
63972c33676SMaxim Ag 			goto err;
64072c33676SMaxim Ag 		}
64172c33676SMaxim Ag 		store = SSL_CTX_get_cert_store(ssl_ctx);
64272c33676SMaxim Ag 		for (i = 0; i < sk_X509_INFO_num(xis); i++) {
64372c33676SMaxim Ag 			xi = sk_X509_INFO_value(xis, i);
64472c33676SMaxim Ag 			if (xi->crl == NULL)
64572c33676SMaxim Ag 				continue;
64672c33676SMaxim Ag 			if (!X509_STORE_add_crl(store, xi->crl)) {
64772c33676SMaxim Ag 				tls_set_error(ctx, "failed to add crl");
64872c33676SMaxim Ag 				goto err;
64972c33676SMaxim Ag 			}
65072c33676SMaxim Ag 		}
651*de0e0e4dSAntonio Huete Jimenez 		X509_STORE_set_flags(store,
65272c33676SMaxim Ag 		    X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
65372c33676SMaxim Ag 	}
65472c33676SMaxim Ag 
65572c33676SMaxim Ag  done:
65672c33676SMaxim Ag 	rv = 0;
657f5b1c8a1SJohn Marino 
658f5b1c8a1SJohn Marino  err:
65972c33676SMaxim Ag 	sk_X509_INFO_pop_free(xis, X509_INFO_free);
66072c33676SMaxim Ag 	BIO_free(bio);
66172c33676SMaxim Ag 	free(ca_free);
66272c33676SMaxim Ag 
66372c33676SMaxim Ag 	return (rv);
664f5b1c8a1SJohn Marino }
665f5b1c8a1SJohn Marino 
666f5b1c8a1SJohn Marino void
tls_free(struct tls * ctx)667f5b1c8a1SJohn Marino tls_free(struct tls *ctx)
668f5b1c8a1SJohn Marino {
669f5b1c8a1SJohn Marino 	if (ctx == NULL)
670f5b1c8a1SJohn Marino 		return;
67172c33676SMaxim Ag 
672f5b1c8a1SJohn Marino 	tls_reset(ctx);
67372c33676SMaxim Ag 
674f5b1c8a1SJohn Marino 	free(ctx);
675f5b1c8a1SJohn Marino }
676f5b1c8a1SJohn Marino 
677f5b1c8a1SJohn Marino void
tls_reset(struct tls * ctx)678f5b1c8a1SJohn Marino tls_reset(struct tls *ctx)
679f5b1c8a1SJohn Marino {
68072c33676SMaxim Ag 	struct tls_sni_ctx *sni, *nsni;
68172c33676SMaxim Ag 
68272c33676SMaxim Ag 	tls_config_free(ctx->config);
68372c33676SMaxim Ag 	ctx->config = NULL;
68472c33676SMaxim Ag 
685f5b1c8a1SJohn Marino 	SSL_CTX_free(ctx->ssl_ctx);
686f5b1c8a1SJohn Marino 	SSL_free(ctx->ssl_conn);
687f5b1c8a1SJohn Marino 	X509_free(ctx->ssl_peer_cert);
688f5b1c8a1SJohn Marino 
689f5b1c8a1SJohn Marino 	ctx->ssl_conn = NULL;
690f5b1c8a1SJohn Marino 	ctx->ssl_ctx = NULL;
691f5b1c8a1SJohn Marino 	ctx->ssl_peer_cert = NULL;
69272c33676SMaxim Ag 	/* X509 objects in chain are freed with the SSL */
69372c33676SMaxim Ag 	ctx->ssl_peer_chain = NULL;
694f5b1c8a1SJohn Marino 
695f5b1c8a1SJohn Marino 	ctx->socket = -1;
696f5b1c8a1SJohn Marino 	ctx->state = 0;
697f5b1c8a1SJohn Marino 
698f5b1c8a1SJohn Marino 	free(ctx->servername);
699f5b1c8a1SJohn Marino 	ctx->servername = NULL;
700f5b1c8a1SJohn Marino 
701f5b1c8a1SJohn Marino 	free(ctx->error.msg);
702f5b1c8a1SJohn Marino 	ctx->error.msg = NULL;
703f5b1c8a1SJohn Marino 	ctx->error.num = -1;
704f5b1c8a1SJohn Marino 
70572c33676SMaxim Ag 	tls_conninfo_free(ctx->conninfo);
706f5b1c8a1SJohn Marino 	ctx->conninfo = NULL;
70772c33676SMaxim Ag 
70872c33676SMaxim Ag 	tls_ocsp_free(ctx->ocsp);
70972c33676SMaxim Ag 	ctx->ocsp = NULL;
71072c33676SMaxim Ag 
71172c33676SMaxim Ag 	for (sni = ctx->sni_ctx; sni != NULL; sni = nsni) {
71272c33676SMaxim Ag 		nsni = sni->next;
71372c33676SMaxim Ag 		tls_sni_ctx_free(sni);
71472c33676SMaxim Ag 	}
71572c33676SMaxim Ag 	ctx->sni_ctx = NULL;
71672c33676SMaxim Ag 
71772c33676SMaxim Ag 	ctx->read_cb = NULL;
71872c33676SMaxim Ag 	ctx->write_cb = NULL;
71972c33676SMaxim Ag 	ctx->cb_arg = NULL;
720f5b1c8a1SJohn Marino }
721f5b1c8a1SJohn Marino 
722f5b1c8a1SJohn Marino int
tls_ssl_error(struct tls * ctx,SSL * ssl_conn,int ssl_ret,const char * prefix)723f5b1c8a1SJohn Marino tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix)
724f5b1c8a1SJohn Marino {
725f5b1c8a1SJohn Marino 	const char *errstr = "unknown error";
726f5b1c8a1SJohn Marino 	unsigned long err;
727f5b1c8a1SJohn Marino 	int ssl_err;
728f5b1c8a1SJohn Marino 
729f5b1c8a1SJohn Marino 	ssl_err = SSL_get_error(ssl_conn, ssl_ret);
730f5b1c8a1SJohn Marino 	switch (ssl_err) {
731f5b1c8a1SJohn Marino 	case SSL_ERROR_NONE:
732f5b1c8a1SJohn Marino 	case SSL_ERROR_ZERO_RETURN:
733f5b1c8a1SJohn Marino 		return (0);
734f5b1c8a1SJohn Marino 
735f5b1c8a1SJohn Marino 	case SSL_ERROR_WANT_READ:
736f5b1c8a1SJohn Marino 		return (TLS_WANT_POLLIN);
737f5b1c8a1SJohn Marino 
738f5b1c8a1SJohn Marino 	case SSL_ERROR_WANT_WRITE:
739f5b1c8a1SJohn Marino 		return (TLS_WANT_POLLOUT);
740f5b1c8a1SJohn Marino 
741f5b1c8a1SJohn Marino 	case SSL_ERROR_SYSCALL:
742f5b1c8a1SJohn Marino 		if ((err = ERR_peek_error()) != 0) {
743f5b1c8a1SJohn Marino 			errstr = ERR_error_string(err, NULL);
744f5b1c8a1SJohn Marino 		} else if (ssl_ret == 0) {
745f5b1c8a1SJohn Marino 			if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
746f5b1c8a1SJohn Marino 				ctx->state |= TLS_EOF_NO_CLOSE_NOTIFY;
747f5b1c8a1SJohn Marino 				return (0);
748f5b1c8a1SJohn Marino 			}
749f5b1c8a1SJohn Marino 			errstr = "unexpected EOF";
750f5b1c8a1SJohn Marino 		} else if (ssl_ret == -1) {
751f5b1c8a1SJohn Marino 			errstr = strerror(errno);
752f5b1c8a1SJohn Marino 		}
75372c33676SMaxim Ag 		tls_set_ssl_errorx(ctx, "%s failed: %s", prefix, errstr);
754f5b1c8a1SJohn Marino 		return (-1);
755f5b1c8a1SJohn Marino 
756f5b1c8a1SJohn Marino 	case SSL_ERROR_SSL:
757f5b1c8a1SJohn Marino 		if ((err = ERR_peek_error()) != 0) {
758f5b1c8a1SJohn Marino 			errstr = ERR_error_string(err, NULL);
759f5b1c8a1SJohn Marino 		}
76072c33676SMaxim Ag 		tls_set_ssl_errorx(ctx, "%s failed: %s", prefix, errstr);
761f5b1c8a1SJohn Marino 		return (-1);
762f5b1c8a1SJohn Marino 
763f5b1c8a1SJohn Marino 	case SSL_ERROR_WANT_CONNECT:
764f5b1c8a1SJohn Marino 	case SSL_ERROR_WANT_ACCEPT:
765f5b1c8a1SJohn Marino 	case SSL_ERROR_WANT_X509_LOOKUP:
766f5b1c8a1SJohn Marino 	default:
767*de0e0e4dSAntonio Huete Jimenez 		tls_set_ssl_errorx(ctx, "%s failed (%d)", prefix, ssl_err);
768f5b1c8a1SJohn Marino 		return (-1);
769f5b1c8a1SJohn Marino 	}
770f5b1c8a1SJohn Marino }
771f5b1c8a1SJohn Marino 
772f5b1c8a1SJohn Marino int
tls_handshake(struct tls * ctx)773f5b1c8a1SJohn Marino tls_handshake(struct tls *ctx)
774f5b1c8a1SJohn Marino {
775f5b1c8a1SJohn Marino 	int rv = -1;
776f5b1c8a1SJohn Marino 
77772c33676SMaxim Ag 	tls_error_clear(&ctx->error);
77872c33676SMaxim Ag 
779f5b1c8a1SJohn Marino 	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
780f5b1c8a1SJohn Marino 		tls_set_errorx(ctx, "invalid operation for context");
781f5b1c8a1SJohn Marino 		goto out;
782f5b1c8a1SJohn Marino 	}
783f5b1c8a1SJohn Marino 
78472c33676SMaxim Ag 	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
78572c33676SMaxim Ag 		tls_set_errorx(ctx, "handshake already completed");
786f5b1c8a1SJohn Marino 		goto out;
78772c33676SMaxim Ag 	}
788f5b1c8a1SJohn Marino 
789f5b1c8a1SJohn Marino 	if ((ctx->flags & TLS_CLIENT) != 0)
790f5b1c8a1SJohn Marino 		rv = tls_handshake_client(ctx);
791f5b1c8a1SJohn Marino 	else if ((ctx->flags & TLS_SERVER_CONN) != 0)
792f5b1c8a1SJohn Marino 		rv = tls_handshake_server(ctx);
793f5b1c8a1SJohn Marino 
794f5b1c8a1SJohn Marino 	if (rv == 0) {
795f5b1c8a1SJohn Marino 		ctx->ssl_peer_cert = SSL_get_peer_certificate(ctx->ssl_conn);
79672c33676SMaxim Ag 		ctx->ssl_peer_chain = SSL_get_peer_cert_chain(ctx->ssl_conn);
79772c33676SMaxim Ag 		if (tls_conninfo_populate(ctx) == -1)
798f5b1c8a1SJohn Marino 			rv = -1;
79972c33676SMaxim Ag 		if (ctx->ocsp == NULL)
80072c33676SMaxim Ag 			ctx->ocsp = tls_ocsp_setup_from_peer(ctx);
801f5b1c8a1SJohn Marino 	}
802f5b1c8a1SJohn Marino  out:
803f5b1c8a1SJohn Marino 	/* Prevent callers from performing incorrect error handling */
804f5b1c8a1SJohn Marino 	errno = 0;
805f5b1c8a1SJohn Marino 	return (rv);
806f5b1c8a1SJohn Marino }
807f5b1c8a1SJohn Marino 
808f5b1c8a1SJohn Marino ssize_t
tls_read(struct tls * ctx,void * buf,size_t buflen)809f5b1c8a1SJohn Marino tls_read(struct tls *ctx, void *buf, size_t buflen)
810f5b1c8a1SJohn Marino {
811f5b1c8a1SJohn Marino 	ssize_t rv = -1;
812f5b1c8a1SJohn Marino 	int ssl_ret;
813f5b1c8a1SJohn Marino 
81472c33676SMaxim Ag 	tls_error_clear(&ctx->error);
81572c33676SMaxim Ag 
816f5b1c8a1SJohn Marino 	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
817f5b1c8a1SJohn Marino 		if ((rv = tls_handshake(ctx)) != 0)
818f5b1c8a1SJohn Marino 			goto out;
819f5b1c8a1SJohn Marino 	}
820f5b1c8a1SJohn Marino 
821f5b1c8a1SJohn Marino 	if (buflen > INT_MAX) {
822f5b1c8a1SJohn Marino 		tls_set_errorx(ctx, "buflen too long");
823f5b1c8a1SJohn Marino 		goto out;
824f5b1c8a1SJohn Marino 	}
825f5b1c8a1SJohn Marino 
826f5b1c8a1SJohn Marino 	ERR_clear_error();
827f5b1c8a1SJohn Marino 	if ((ssl_ret = SSL_read(ctx->ssl_conn, buf, buflen)) > 0) {
828f5b1c8a1SJohn Marino 		rv = (ssize_t)ssl_ret;
829f5b1c8a1SJohn Marino 		goto out;
830f5b1c8a1SJohn Marino 	}
831f5b1c8a1SJohn Marino 	rv = (ssize_t)tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "read");
832f5b1c8a1SJohn Marino 
833f5b1c8a1SJohn Marino  out:
834f5b1c8a1SJohn Marino 	/* Prevent callers from performing incorrect error handling */
835f5b1c8a1SJohn Marino 	errno = 0;
836f5b1c8a1SJohn Marino 	return (rv);
837f5b1c8a1SJohn Marino }
838f5b1c8a1SJohn Marino 
839f5b1c8a1SJohn Marino ssize_t
tls_write(struct tls * ctx,const void * buf,size_t buflen)840f5b1c8a1SJohn Marino tls_write(struct tls *ctx, const void *buf, size_t buflen)
841f5b1c8a1SJohn Marino {
842f5b1c8a1SJohn Marino 	ssize_t rv = -1;
843f5b1c8a1SJohn Marino 	int ssl_ret;
844f5b1c8a1SJohn Marino 
84572c33676SMaxim Ag 	tls_error_clear(&ctx->error);
84672c33676SMaxim Ag 
847f5b1c8a1SJohn Marino 	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
848f5b1c8a1SJohn Marino 		if ((rv = tls_handshake(ctx)) != 0)
849f5b1c8a1SJohn Marino 			goto out;
850f5b1c8a1SJohn Marino 	}
851f5b1c8a1SJohn Marino 
852f5b1c8a1SJohn Marino 	if (buflen > INT_MAX) {
853f5b1c8a1SJohn Marino 		tls_set_errorx(ctx, "buflen too long");
854f5b1c8a1SJohn Marino 		goto out;
855f5b1c8a1SJohn Marino 	}
856f5b1c8a1SJohn Marino 
857f5b1c8a1SJohn Marino 	ERR_clear_error();
858f5b1c8a1SJohn Marino 	if ((ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen)) > 0) {
859f5b1c8a1SJohn Marino 		rv = (ssize_t)ssl_ret;
860f5b1c8a1SJohn Marino 		goto out;
861f5b1c8a1SJohn Marino 	}
862f5b1c8a1SJohn Marino 	rv = (ssize_t)tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "write");
863f5b1c8a1SJohn Marino 
864f5b1c8a1SJohn Marino  out:
865f5b1c8a1SJohn Marino 	/* Prevent callers from performing incorrect error handling */
866f5b1c8a1SJohn Marino 	errno = 0;
867f5b1c8a1SJohn Marino 	return (rv);
868f5b1c8a1SJohn Marino }
869f5b1c8a1SJohn Marino 
870f5b1c8a1SJohn Marino int
tls_close(struct tls * ctx)871f5b1c8a1SJohn Marino tls_close(struct tls *ctx)
872f5b1c8a1SJohn Marino {
873f5b1c8a1SJohn Marino 	int ssl_ret;
874f5b1c8a1SJohn Marino 	int rv = 0;
875f5b1c8a1SJohn Marino 
87672c33676SMaxim Ag 	tls_error_clear(&ctx->error);
87772c33676SMaxim Ag 
878f5b1c8a1SJohn Marino 	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
879f5b1c8a1SJohn Marino 		tls_set_errorx(ctx, "invalid operation for context");
880f5b1c8a1SJohn Marino 		rv = -1;
881f5b1c8a1SJohn Marino 		goto out;
882f5b1c8a1SJohn Marino 	}
883f5b1c8a1SJohn Marino 
88472c33676SMaxim Ag 	if (ctx->state & TLS_SSL_NEEDS_SHUTDOWN) {
885f5b1c8a1SJohn Marino 		ERR_clear_error();
886f5b1c8a1SJohn Marino 		ssl_ret = SSL_shutdown(ctx->ssl_conn);
887f5b1c8a1SJohn Marino 		if (ssl_ret < 0) {
888f5b1c8a1SJohn Marino 			rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret,
889f5b1c8a1SJohn Marino 			    "shutdown");
890f5b1c8a1SJohn Marino 			if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
891f5b1c8a1SJohn Marino 				goto out;
892f5b1c8a1SJohn Marino 		}
89372c33676SMaxim Ag 		ctx->state &= ~TLS_SSL_NEEDS_SHUTDOWN;
894f5b1c8a1SJohn Marino 	}
895f5b1c8a1SJohn Marino 
896f5b1c8a1SJohn Marino 	if (ctx->socket != -1) {
897f5b1c8a1SJohn Marino 		if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
898f5b1c8a1SJohn Marino 			if (rv == 0 &&
899f5b1c8a1SJohn Marino 			    errno != ENOTCONN && errno != ECONNRESET) {
900f5b1c8a1SJohn Marino 				tls_set_error(ctx, "shutdown");
901f5b1c8a1SJohn Marino 				rv = -1;
902f5b1c8a1SJohn Marino 			}
903f5b1c8a1SJohn Marino 		}
904f5b1c8a1SJohn Marino 		if (close(ctx->socket) != 0) {
905f5b1c8a1SJohn Marino 			if (rv == 0) {
906f5b1c8a1SJohn Marino 				tls_set_error(ctx, "close");
907f5b1c8a1SJohn Marino 				rv = -1;
908f5b1c8a1SJohn Marino 			}
909f5b1c8a1SJohn Marino 		}
910f5b1c8a1SJohn Marino 		ctx->socket = -1;
911f5b1c8a1SJohn Marino 	}
912f5b1c8a1SJohn Marino 
913f5b1c8a1SJohn Marino 	if ((ctx->state & TLS_EOF_NO_CLOSE_NOTIFY) != 0) {
914f5b1c8a1SJohn Marino 		tls_set_errorx(ctx, "EOF without close notify");
915f5b1c8a1SJohn Marino 		rv = -1;
916f5b1c8a1SJohn Marino 	}
917f5b1c8a1SJohn Marino 
918f5b1c8a1SJohn Marino  out:
919f5b1c8a1SJohn Marino 	/* Prevent callers from performing incorrect error handling */
920f5b1c8a1SJohn Marino 	errno = 0;
921f5b1c8a1SJohn Marino 	return (rv);
922f5b1c8a1SJohn Marino }
923