1*13bba76fStb /* $OpenBSD: tls.c,v 1.104 2024/04/08 20:47:32 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
18b600beedSjsing #include <sys/socket.h>
19b600beedSjsing
20b600beedSjsing #include <errno.h>
21c81cfcc3Sdoug #include <limits.h>
22c029eb32Sbeck #include <pthread.h>
23b600beedSjsing #include <stdlib.h>
24e6d77be9Sop #include <string.h>
25b600beedSjsing #include <unistd.h>
26b600beedSjsing
27b600beedSjsing #include <openssl/bio.h>
28f832f19aSjsing #include <openssl/err.h>
29b600beedSjsing #include <openssl/evp.h>
30b600beedSjsing #include <openssl/pem.h>
3180bc881dSjsing #include <openssl/safestack.h>
3280bc881dSjsing #include <openssl/ssl.h>
33b600beedSjsing #include <openssl/x509.h>
34b600beedSjsing
35b600beedSjsing #include <tls.h>
36b600beedSjsing #include "tls_internal.h"
37b600beedSjsing
38b600beedSjsing static struct tls_config *tls_config_default;
39b600beedSjsing
40c029eb32Sbeck static int tls_init_rv = -1;
41c029eb32Sbeck
42c029eb32Sbeck static void
tls_do_init(void)43c029eb32Sbeck tls_do_init(void)
44b600beedSjsing {
45c650228dSjsing OPENSSL_init_ssl(OPENSSL_INIT_NO_LOAD_CONFIG, NULL);
46b600beedSjsing
471d3c3f1fSbcook if (BIO_sock_init() != 1)
48c029eb32Sbeck return;
491d3c3f1fSbcook
50b9573a74Sjsing if ((tls_config_default = tls_config_new_internal()) == NULL)
51c029eb32Sbeck return;
52b600beedSjsing
5388c10dabSjsing tls_config_default->refcount++;
5488c10dabSjsing
55c029eb32Sbeck tls_init_rv = 0;
56c029eb32Sbeck }
57b600beedSjsing
58c029eb32Sbeck int
tls_init(void)59c029eb32Sbeck tls_init(void)
60c029eb32Sbeck {
61c029eb32Sbeck static pthread_once_t once = PTHREAD_ONCE_INIT;
62c029eb32Sbeck
63c029eb32Sbeck if (pthread_once(&once, tls_do_init) != 0)
64c029eb32Sbeck return -1;
65c029eb32Sbeck
66c029eb32Sbeck return tls_init_rv;
67b600beedSjsing }
68b600beedSjsing
69b600beedSjsing const char *
tls_error(struct tls * ctx)70b600beedSjsing tls_error(struct tls *ctx)
71b600beedSjsing {
72a88e9e95Sjsing return ctx->error.msg;
73b600beedSjsing }
74b600beedSjsing
757a756d37Sjoshua int
tls_error_code(struct tls * ctx)767a756d37Sjoshua tls_error_code(struct tls *ctx)
777a756d37Sjoshua {
787a756d37Sjoshua return ctx->error.code;
797a756d37Sjoshua }
807a756d37Sjoshua
819e219fcdSjsing void
tls_error_clear(struct tls_error * error)829e219fcdSjsing tls_error_clear(struct tls_error *error)
839e219fcdSjsing {
849e219fcdSjsing free(error->msg);
859e219fcdSjsing error->msg = NULL;
867a756d37Sjoshua error->code = TLS_ERROR_UNKNOWN;
87deae75adSjoshua error->errno_value = 0;
889e219fcdSjsing error->tls = 0;
899e219fcdSjsing }
909e219fcdSjsing
91fdb1c79fSjsing static int
tls_error_vset(struct tls_error * error,int code,int errno_value,const char * fmt,va_list ap)927a756d37Sjoshua tls_error_vset(struct tls_error *error, int code, int errno_value,
937a756d37Sjoshua const char *fmt, va_list ap)
94fdb1c79fSjsing {
95fdb1c79fSjsing char *errmsg = NULL;
96fdb1c79fSjsing int rv = -1;
97fdb1c79fSjsing
989e219fcdSjsing tls_error_clear(error);
999e219fcdSjsing
1007a756d37Sjoshua error->code = code;
101deae75adSjoshua error->errno_value = errno_value;
1029e219fcdSjsing error->tls = 1;
103fdb1c79fSjsing
104fdb1c79fSjsing if (vasprintf(&errmsg, fmt, ap) == -1) {
105fdb1c79fSjsing errmsg = NULL;
106fdb1c79fSjsing goto err;
107fdb1c79fSjsing }
108fdb1c79fSjsing
109deae75adSjoshua if (errno_value == -1) {
110a88e9e95Sjsing error->msg = errmsg;
111fdb1c79fSjsing return (0);
112fdb1c79fSjsing }
113fdb1c79fSjsing
114deae75adSjoshua if (asprintf(&error->msg, "%s: %s", errmsg, strerror(errno_value)) == -1) {
115a88e9e95Sjsing error->msg = NULL;
116fdb1c79fSjsing goto err;
117fdb1c79fSjsing }
118fdb1c79fSjsing rv = 0;
119fdb1c79fSjsing
120fdb1c79fSjsing err:
121fdb1c79fSjsing free(errmsg);
122fdb1c79fSjsing
123fdb1c79fSjsing return (rv);
124fdb1c79fSjsing }
125fdb1c79fSjsing
126b600beedSjsing int
tls_error_set(struct tls_error * error,int code,const char * fmt,...)1277a756d37Sjoshua tls_error_set(struct tls_error *error, int code, const char *fmt, ...)
128a88e9e95Sjsing {
129a88e9e95Sjsing va_list ap;
130deae75adSjoshua int errno_value, rv;
131a88e9e95Sjsing
132deae75adSjoshua errno_value = errno;
133a88e9e95Sjsing
134a88e9e95Sjsing va_start(ap, fmt);
1357a756d37Sjoshua rv = tls_error_vset(error, code, errno_value, fmt, ap);
136a88e9e95Sjsing va_end(ap);
137a88e9e95Sjsing
138a88e9e95Sjsing return (rv);
139a88e9e95Sjsing }
140a88e9e95Sjsing
141a88e9e95Sjsing int
tls_error_setx(struct tls_error * error,int code,const char * fmt,...)1427a756d37Sjoshua tls_error_setx(struct tls_error *error, int code, const char *fmt, ...)
143b600beedSjsing {
144b600beedSjsing va_list ap;
145b600beedSjsing int rv;
146b600beedSjsing
147a88e9e95Sjsing va_start(ap, fmt);
1487a756d37Sjoshua rv = tls_error_vset(error, code, -1, fmt, ap);
149f8289792Sjsing va_end(ap);
150f8289792Sjsing
151f8289792Sjsing return (rv);
152f8289792Sjsing }
153f8289792Sjsing
154f8289792Sjsing int
tls_config_set_error(struct tls_config * config,int code,const char * fmt,...)1557a756d37Sjoshua tls_config_set_error(struct tls_config *config, int code, const char *fmt, ...)
156f8289792Sjsing {
157f8289792Sjsing va_list ap;
158aa2571bdSjoshua int errno_value, rv;
159f8289792Sjsing
160aa2571bdSjoshua errno_value = errno;
161f8289792Sjsing
162f8289792Sjsing va_start(ap, fmt);
1637a756d37Sjoshua rv = tls_error_vset(&config->error, code, errno_value, fmt, ap);
164f8289792Sjsing va_end(ap);
165f8289792Sjsing
166f8289792Sjsing return (rv);
167f8289792Sjsing }
168f8289792Sjsing
169f8289792Sjsing int
tls_config_set_errorx(struct tls_config * config,int code,const char * fmt,...)1707a756d37Sjoshua tls_config_set_errorx(struct tls_config *config, int code, const char *fmt, ...)
171f8289792Sjsing {
172f8289792Sjsing va_list ap;
173f8289792Sjsing int rv;
174f8289792Sjsing
175f8289792Sjsing va_start(ap, fmt);
1767a756d37Sjoshua rv = tls_error_vset(&config->error, code, -1, fmt, ap);
177a88e9e95Sjsing va_end(ap);
178a88e9e95Sjsing
179a88e9e95Sjsing return (rv);
180a88e9e95Sjsing }
181a88e9e95Sjsing
182a88e9e95Sjsing int
tls_set_error(struct tls * ctx,int code,const char * fmt,...)1837a756d37Sjoshua tls_set_error(struct tls *ctx, int code, const char *fmt, ...)
184a88e9e95Sjsing {
185a88e9e95Sjsing va_list ap;
186aa2571bdSjoshua int errno_value, rv;
187a88e9e95Sjsing
188aa2571bdSjoshua errno_value = errno;
189b600beedSjsing
190b600beedSjsing va_start(ap, fmt);
1917a756d37Sjoshua rv = tls_error_vset(&ctx->error, code, errno_value, fmt, ap);
192fdb1c79fSjsing va_end(ap);
193fdb1c79fSjsing
194fdb1c79fSjsing return (rv);
195fdb1c79fSjsing }
196fdb1c79fSjsing
197fdb1c79fSjsing int
tls_set_errorx(struct tls * ctx,int code,const char * fmt,...)1987a756d37Sjoshua tls_set_errorx(struct tls *ctx, int code, const char *fmt, ...)
199fdb1c79fSjsing {
200fdb1c79fSjsing va_list ap;
201fdb1c79fSjsing int rv;
202fdb1c79fSjsing
203fdb1c79fSjsing va_start(ap, fmt);
2047a756d37Sjoshua rv = tls_error_vset(&ctx->error, code, -1, fmt, ap);
205b600beedSjsing va_end(ap);
206b600beedSjsing
207b600beedSjsing return (rv);
208b600beedSjsing }
209b600beedSjsing
2109e219fcdSjsing int
tls_set_ssl_errorx(struct tls * ctx,int code,const char * fmt,...)2117a756d37Sjoshua tls_set_ssl_errorx(struct tls *ctx, int code, const char *fmt, ...)
2129e219fcdSjsing {
2139e219fcdSjsing va_list ap;
2149e219fcdSjsing int rv;
2159e219fcdSjsing
2169e219fcdSjsing /* Only set an error if a more specific one does not already exist. */
2179e219fcdSjsing if (ctx->error.tls != 0)
2189e219fcdSjsing return (0);
2199e219fcdSjsing
2209e219fcdSjsing va_start(ap, fmt);
2217a756d37Sjoshua rv = tls_error_vset(&ctx->error, code, -1, fmt, ap);
2229e219fcdSjsing va_end(ap);
2239e219fcdSjsing
2249e219fcdSjsing return (rv);
2259e219fcdSjsing }
2269e219fcdSjsing
227f89edc01Sjsing struct tls_sni_ctx *
tls_sni_ctx_new(void)228f89edc01Sjsing tls_sni_ctx_new(void)
229f89edc01Sjsing {
230f89edc01Sjsing return (calloc(1, sizeof(struct tls_sni_ctx)));
231f89edc01Sjsing }
232f89edc01Sjsing
233f89edc01Sjsing void
tls_sni_ctx_free(struct tls_sni_ctx * sni_ctx)234f89edc01Sjsing tls_sni_ctx_free(struct tls_sni_ctx *sni_ctx)
235f89edc01Sjsing {
236f89edc01Sjsing if (sni_ctx == NULL)
237f89edc01Sjsing return;
238f89edc01Sjsing
239f89edc01Sjsing SSL_CTX_free(sni_ctx->ssl_ctx);
240f89edc01Sjsing X509_free(sni_ctx->ssl_cert);
241f89edc01Sjsing
242f89edc01Sjsing free(sni_ctx);
243f89edc01Sjsing }
244f89edc01Sjsing
245b600beedSjsing struct tls *
tls_new(void)246b600beedSjsing tls_new(void)
247b600beedSjsing {
248b600beedSjsing struct tls *ctx;
249b600beedSjsing
250b600beedSjsing if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
251b600beedSjsing return (NULL);
252b600beedSjsing
253b600beedSjsing tls_reset(ctx);
2549ee433b9Sjsing
255e4972b9bSbeck if (tls_configure(ctx, tls_config_default) == -1) {
256e4972b9bSbeck free(ctx);
257e4972b9bSbeck return NULL;
258e4972b9bSbeck }
259b600beedSjsing
260b600beedSjsing return (ctx);
261b600beedSjsing }
262b600beedSjsing
263b600beedSjsing int
tls_configure(struct tls * ctx,struct tls_config * config)264b600beedSjsing tls_configure(struct tls *ctx, struct tls_config *config)
265b600beedSjsing {
266b600beedSjsing if (config == NULL)
267b600beedSjsing config = tls_config_default;
268b600beedSjsing
269bebb943aSjsing pthread_mutex_lock(&config->mutex);
27088c10dabSjsing config->refcount++;
271bebb943aSjsing pthread_mutex_unlock(&config->mutex);
27288c10dabSjsing
27388c10dabSjsing tls_config_free(ctx->config);
2749ee433b9Sjsing
275b600beedSjsing ctx->config = config;
2769ee433b9Sjsing ctx->keypair = config->keypair;
277b600beedSjsing
278b600beedSjsing if ((ctx->flags & TLS_SERVER) != 0)
279b600beedSjsing return (tls_configure_server(ctx));
280b600beedSjsing
281b600beedSjsing return (0);
282b600beedSjsing }
283b600beedSjsing
284b600beedSjsing int
tls_cert_hash(X509 * cert,char ** hash)285c793ca29Sbeck tls_cert_hash(X509 *cert, char **hash)
286c793ca29Sbeck {
287c793ca29Sbeck char d[EVP_MAX_MD_SIZE], *dhex = NULL;
288c793ca29Sbeck int dlen, rv = -1;
289c793ca29Sbeck
2900a095d8fSjsing free(*hash);
291c793ca29Sbeck *hash = NULL;
2920a095d8fSjsing
293c793ca29Sbeck if (X509_digest(cert, EVP_sha256(), d, &dlen) != 1)
294c793ca29Sbeck goto err;
295c793ca29Sbeck
296c793ca29Sbeck if (tls_hex_string(d, dlen, &dhex, NULL) != 0)
297c793ca29Sbeck goto err;
298c793ca29Sbeck
299c793ca29Sbeck if (asprintf(hash, "SHA256:%s", dhex) == -1) {
300c793ca29Sbeck *hash = NULL;
301c793ca29Sbeck goto err;
302c793ca29Sbeck }
303c793ca29Sbeck
304c793ca29Sbeck rv = 0;
305c793ca29Sbeck err:
306c793ca29Sbeck free(dhex);
307c793ca29Sbeck
308c793ca29Sbeck return (rv);
309c793ca29Sbeck }
310c793ca29Sbeck
311c793ca29Sbeck int
tls_cert_pubkey_hash(X509 * cert,char ** hash)3122974e8f1Sjsing tls_cert_pubkey_hash(X509 *cert, char **hash)
3132974e8f1Sjsing {
3142974e8f1Sjsing char d[EVP_MAX_MD_SIZE], *dhex = NULL;
3152974e8f1Sjsing int dlen, rv = -1;
3162974e8f1Sjsing
3172974e8f1Sjsing free(*hash);
3182974e8f1Sjsing *hash = NULL;
3192974e8f1Sjsing
3202974e8f1Sjsing if (X509_pubkey_digest(cert, EVP_sha256(), d, &dlen) != 1)
3212974e8f1Sjsing goto err;
3222974e8f1Sjsing
3232974e8f1Sjsing if (tls_hex_string(d, dlen, &dhex, NULL) != 0)
3242974e8f1Sjsing goto err;
3252974e8f1Sjsing
3262974e8f1Sjsing if (asprintf(hash, "SHA256:%s", dhex) == -1) {
3272974e8f1Sjsing *hash = NULL;
3282974e8f1Sjsing goto err;
3292974e8f1Sjsing }
3302974e8f1Sjsing
3312974e8f1Sjsing rv = 0;
3322974e8f1Sjsing
3332974e8f1Sjsing err:
3342974e8f1Sjsing free(dhex);
3352974e8f1Sjsing
3362974e8f1Sjsing return (rv);
3372974e8f1Sjsing }
3382974e8f1Sjsing
33915339a8cSeric static int
tls_keypair_to_pkey(struct tls * ctx,struct tls_keypair * keypair,EVP_PKEY ** pkey)34015339a8cSeric tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pkey)
34115339a8cSeric {
34215339a8cSeric BIO *bio = NULL;
34315339a8cSeric X509 *x509 = NULL;
34415339a8cSeric char *mem;
34515339a8cSeric size_t len;
34615339a8cSeric int ret = -1;
34715339a8cSeric
34815339a8cSeric *pkey = NULL;
34915339a8cSeric
35015339a8cSeric if (ctx->config->use_fake_private_key) {
35115339a8cSeric mem = keypair->cert_mem;
35215339a8cSeric len = keypair->cert_len;
35315339a8cSeric } else {
35415339a8cSeric mem = keypair->key_mem;
35515339a8cSeric len = keypair->key_len;
35615339a8cSeric }
35715339a8cSeric
35815339a8cSeric if (mem == NULL)
35915339a8cSeric return (0);
36015339a8cSeric
36115339a8cSeric if (len > INT_MAX) {
3622b31d1bdSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
3637a756d37Sjoshua ctx->config->use_fake_private_key ?
3642b31d1bdSjoshua "certificate too long" : "key too long");
36515339a8cSeric goto err;
36615339a8cSeric }
36715339a8cSeric
36815339a8cSeric if ((bio = BIO_new_mem_buf(mem, len)) == NULL) {
3697a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "failed to create buffer");
37015339a8cSeric goto err;
37115339a8cSeric }
37215339a8cSeric
37315339a8cSeric if (ctx->config->use_fake_private_key) {
37415339a8cSeric if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb,
37515339a8cSeric NULL)) == NULL) {
3767a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
3777a756d37Sjoshua "failed to read X509 certificate");
37815339a8cSeric goto err;
37915339a8cSeric }
38015339a8cSeric if ((*pkey = X509_get_pubkey(x509)) == NULL) {
3817a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
3827a756d37Sjoshua "failed to retrieve pubkey");
38315339a8cSeric goto err;
38415339a8cSeric }
38515339a8cSeric } else {
38615339a8cSeric if ((*pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
38715339a8cSeric NULL)) == NULL) {
3887a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
3897a756d37Sjoshua "failed to read private key");
39015339a8cSeric goto err;
39115339a8cSeric }
39215339a8cSeric }
39315339a8cSeric
39415339a8cSeric ret = 0;
39515339a8cSeric err:
39615339a8cSeric BIO_free(bio);
39715339a8cSeric X509_free(x509);
39815339a8cSeric return (ret);
39915339a8cSeric }
40015339a8cSeric
401f8e1ec60Seric static int
tls_keypair_setup_pkey(struct tls * ctx,struct tls_keypair * keypair,EVP_PKEY * pkey)402f8e1ec60Seric tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *pkey)
403f8e1ec60Seric {
4049ecbddc1Seric RSA_METHOD *rsa_method;
4059dba47cfSop EC_KEY_METHOD *ecdsa_method;
406f8e1ec60Seric RSA *rsa = NULL;
407f8e1ec60Seric EC_KEY *eckey = NULL;
408f8e1ec60Seric int ret = -1;
409f8e1ec60Seric
410f8e1ec60Seric /* Only install the pubkey hash if fake private keys are used. */
411f8e1ec60Seric if (!ctx->config->skip_private_key_check)
412f8e1ec60Seric return (0);
413f8e1ec60Seric
414f8e1ec60Seric if (keypair->pubkey_hash == NULL) {
4157a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "public key hash not set");
416f8e1ec60Seric goto err;
417f8e1ec60Seric }
418f8e1ec60Seric
419f8e1ec60Seric switch (EVP_PKEY_id(pkey)) {
420f8e1ec60Seric case EVP_PKEY_RSA:
421f8e1ec60Seric if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
422f8e1ec60Seric RSA_set_ex_data(rsa, 0, keypair->pubkey_hash) == 0) {
4237a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
4247a756d37Sjoshua "RSA key setup failure");
425f8e1ec60Seric goto err;
426f8e1ec60Seric }
427508824d4Sop if (ctx->config->sign_cb != NULL) {
428508824d4Sop rsa_method = tls_signer_rsa_method();
429508824d4Sop if (rsa_method == NULL ||
4309ecbddc1Seric RSA_set_ex_data(rsa, 1, ctx->config) == 0 ||
4319ecbddc1Seric RSA_set_method(rsa, rsa_method) == 0) {
4327a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
4337a756d37Sjoshua "failed to setup RSA key");
4349ecbddc1Seric goto err;
4359ecbddc1Seric }
436508824d4Sop }
437508824d4Sop /* Reset the key to work around caching in OpenSSL 3. */
438508824d4Sop if (EVP_PKEY_set1_RSA(pkey, rsa) == 0) {
4397a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
4407a756d37Sjoshua "failed to set RSA key");
441508824d4Sop goto err;
442508824d4Sop }
443f8e1ec60Seric break;
444f8e1ec60Seric case EVP_PKEY_EC:
445f8e1ec60Seric if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL ||
4469dba47cfSop EC_KEY_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0) {
4477a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
4487a756d37Sjoshua "EC key setup failure");
449f8e1ec60Seric goto err;
450f8e1ec60Seric }
451508824d4Sop if (ctx->config->sign_cb != NULL) {
452508824d4Sop ecdsa_method = tls_signer_ecdsa_method();
453508824d4Sop if (ecdsa_method == NULL ||
4549dba47cfSop EC_KEY_set_ex_data(eckey, 1, ctx->config) == 0 ||
4559dba47cfSop EC_KEY_set_method(eckey, ecdsa_method) == 0) {
4567a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
4577a756d37Sjoshua "failed to setup EC key");
4589ecbddc1Seric goto err;
4599ecbddc1Seric }
460508824d4Sop }
461508824d4Sop /* Reset the key to work around caching in OpenSSL 3. */
462508824d4Sop if (EVP_PKEY_set1_EC_KEY(pkey, eckey) == 0) {
4637a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
4647a756d37Sjoshua "failed to set EC key");
465508824d4Sop goto err;
466508824d4Sop }
467f8e1ec60Seric break;
468f8e1ec60Seric default:
4697a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "incorrect key type");
470f8e1ec60Seric goto err;
471f8e1ec60Seric }
472f8e1ec60Seric
473f8e1ec60Seric ret = 0;
474f8e1ec60Seric
475f8e1ec60Seric err:
476f8e1ec60Seric RSA_free(rsa);
477f8e1ec60Seric EC_KEY_free(eckey);
478f8e1ec60Seric return (ret);
479f8e1ec60Seric }
480f8e1ec60Seric
4812974e8f1Sjsing int
tls_configure_ssl_keypair(struct tls * ctx,SSL_CTX * ssl_ctx,struct tls_keypair * keypair,int required)482b7f318e7Sjsing tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
4831fe9fea1Sjsing struct tls_keypair *keypair, int required)
484b600beedSjsing {
485b600beedSjsing EVP_PKEY *pkey = NULL;
486b600beedSjsing
48751f3bd3dSbeck if (!required &&
4881fe9fea1Sjsing keypair->cert_mem == NULL &&
48903ce4948Sjsing keypair->key_mem == NULL)
49051f3bd3dSbeck return(0);
49151f3bd3dSbeck
4921fe9fea1Sjsing if (keypair->cert_mem != NULL) {
4931fe9fea1Sjsing if (keypair->cert_len > INT_MAX) {
4942b31d1bdSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
4957a756d37Sjoshua "certificate too long");
496c81cfcc3Sdoug goto err;
497c81cfcc3Sdoug }
498c81cfcc3Sdoug
4991fe9fea1Sjsing if (SSL_CTX_use_certificate_chain_mem(ssl_ctx,
5001fe9fea1Sjsing keypair->cert_mem, keypair->cert_len) != 1) {
5017a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
5027a756d37Sjoshua "failed to load certificate");
503b600beedSjsing goto err;
504b600beedSjsing }
505b600beedSjsing }
506c793ca29Sbeck
50715339a8cSeric if (tls_keypair_to_pkey(ctx, keypair, &pkey) == -1)
508c81cfcc3Sdoug goto err;
50915339a8cSeric if (pkey != NULL) {
510f8e1ec60Seric if (tls_keypair_setup_pkey(ctx, keypair, pkey) == -1)
511f8e1ec60Seric goto err;
5121fe9fea1Sjsing if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) {
5137a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
5147a756d37Sjoshua "failed to load private key");
515b600beedSjsing goto err;
516b600beedSjsing }
517b600beedSjsing EVP_PKEY_free(pkey);
518b600beedSjsing pkey = NULL;
519b600beedSjsing }
520b600beedSjsing
521c793ca29Sbeck if (!ctx->config->skip_private_key_check &&
522c793ca29Sbeck SSL_CTX_check_private_key(ssl_ctx) != 1) {
5237a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
5247a756d37Sjoshua "private/public key mismatch");
525b600beedSjsing goto err;
526b600beedSjsing }
527b600beedSjsing
528b600beedSjsing return (0);
529b600beedSjsing
530b600beedSjsing err:
531b600beedSjsing EVP_PKEY_free(pkey);
532b600beedSjsing
533b609dc20Seric return (-1);
534b600beedSjsing }
535b600beedSjsing
536b600beedSjsing int
tls_configure_ssl(struct tls * ctx,SSL_CTX * ssl_ctx)537b7f318e7Sjsing tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
538b600beedSjsing {
5393c640480Sjsing SSL_CTX_clear_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
5403c640480Sjsing
541b7f318e7Sjsing SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
542b7f318e7Sjsing SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
54377b60f9aSbluhm
544b7f318e7Sjsing SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2);
545b7f318e7Sjsing SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv3);
5465c389b79Sbeck SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1);
5475c389b79Sbeck SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1);
548b600beedSjsing
549b7f318e7Sjsing SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
5504c479435Sjsing SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_3);
551b600beedSjsing
552b600beedSjsing if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
553b7f318e7Sjsing SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2);
5544c479435Sjsing if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_3) == 0)
5554c479435Sjsing SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3);
556b600beedSjsing
557183da8c6Sjsing if (ctx->config->alpn != NULL) {
558b7f318e7Sjsing if (SSL_CTX_set_alpn_protos(ssl_ctx, ctx->config->alpn,
559183da8c6Sjsing ctx->config->alpn_len) != 0) {
5607a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
5617a756d37Sjoshua "failed to set alpn");
562183da8c6Sjsing goto err;
563183da8c6Sjsing }
564183da8c6Sjsing }
565183da8c6Sjsing
566b600beedSjsing if (ctx->config->ciphers != NULL) {
567b7f318e7Sjsing if (SSL_CTX_set_cipher_list(ssl_ctx,
568b600beedSjsing ctx->config->ciphers) != 1) {
5697a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
5707a756d37Sjoshua "failed to set ciphers");
571b600beedSjsing goto err;
572b600beedSjsing }
573b600beedSjsing }
574b600beedSjsing
575615956a0Sjsing if (ctx->config->verify_time == 0) {
57661298c2bSjsing X509_VERIFY_PARAM_set_flags(SSL_CTX_get0_param(ssl_ctx),
577615956a0Sjsing X509_V_FLAG_NO_CHECK_TIME);
578615956a0Sjsing }
579615956a0Sjsing
5808aee94d7Sclaudio /* Disable any form of session caching by default */
5818aee94d7Sclaudio SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF);
5828aee94d7Sclaudio SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
5838aee94d7Sclaudio
584b600beedSjsing return (0);
585b600beedSjsing
586b600beedSjsing err:
587b600beedSjsing return (-1);
588b600beedSjsing }
589b600beedSjsing
590888c565eSjsing static int
tls_ssl_cert_verify_cb(X509_STORE_CTX * x509_ctx,void * arg)591888c565eSjsing tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
592888c565eSjsing {
593888c565eSjsing struct tls *ctx = arg;
5948147afa4Sjsing int x509_err;
595888c565eSjsing
596888c565eSjsing if (ctx->config->verify_cert == 0)
597888c565eSjsing return (1);
598888c565eSjsing
5998147afa4Sjsing if ((X509_verify_cert(x509_ctx)) < 0) {
6007a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
6017a756d37Sjoshua "X509 verify cert failed");
602888c565eSjsing return (0);
603888c565eSjsing }
604888c565eSjsing
605888c565eSjsing x509_err = X509_STORE_CTX_get_error(x509_ctx);
6068147afa4Sjsing if (x509_err == X509_V_OK)
6078147afa4Sjsing return (1);
608888c565eSjsing
6097a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
6107a756d37Sjoshua "certificate verification failed: %s",
611888c565eSjsing X509_verify_cert_error_string(x509_err));
612888c565eSjsing
613888c565eSjsing return (0);
614888c565eSjsing }
615888c565eSjsing
61651f3bd3dSbeck int
tls_configure_ssl_verify(struct tls * ctx,SSL_CTX * ssl_ctx,int verify)617b7f318e7Sjsing tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
61851f3bd3dSbeck {
61903ce4948Sjsing size_t ca_len = ctx->config->ca_len;
62003ce4948Sjsing char *ca_mem = ctx->config->ca_mem;
62180bc881dSjsing char *crl_mem = ctx->config->crl_mem;
62280bc881dSjsing size_t crl_len = ctx->config->crl_len;
62303ce4948Sjsing char *ca_free = NULL;
62480bc881dSjsing STACK_OF(X509_INFO) *xis = NULL;
62580bc881dSjsing X509_STORE *store;
62680bc881dSjsing X509_INFO *xi;
62780bc881dSjsing BIO *bio = NULL;
628888c565eSjsing int rv = -1;
62980bc881dSjsing int i;
63003ce4948Sjsing
631b7f318e7Sjsing SSL_CTX_set_verify(ssl_ctx, verify, NULL);
63217d46c2aSjsing SSL_CTX_set_cert_verify_callback(ssl_ctx, tls_ssl_cert_verify_cb, ctx);
63317d46c2aSjsing
63417d46c2aSjsing if (ctx->config->verify_depth >= 0)
63517d46c2aSjsing SSL_CTX_set_verify_depth(ssl_ctx, ctx->config->verify_depth);
63617d46c2aSjsing
63717d46c2aSjsing if (ctx->config->verify_cert == 0)
63817d46c2aSjsing goto done;
63951f3bd3dSbeck
64003ce4948Sjsing /* If no CA has been specified, attempt to load the default. */
64103ce4948Sjsing if (ctx->config->ca_mem == NULL && ctx->config->ca_path == NULL) {
642f6b75673Stedu if (tls_config_load_file(&ctx->error, "CA", tls_default_ca_cert_file(),
64303ce4948Sjsing &ca_mem, &ca_len) != 0)
64403ce4948Sjsing goto err;
64503ce4948Sjsing ca_free = ca_mem;
64603ce4948Sjsing }
64703ce4948Sjsing
64803ce4948Sjsing if (ca_mem != NULL) {
64903ce4948Sjsing if (ca_len > INT_MAX) {
6502b31d1bdSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
6512b31d1bdSjoshua "ca too long");
65251f3bd3dSbeck goto err;
65351f3bd3dSbeck }
654b7f318e7Sjsing if (SSL_CTX_load_verify_mem(ssl_ctx, ca_mem, ca_len) != 1) {
6557a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
6567a756d37Sjoshua "ssl verify memory setup failure");
65751f3bd3dSbeck goto err;
65851f3bd3dSbeck }
659b7f318e7Sjsing } else if (SSL_CTX_load_verify_locations(ssl_ctx, NULL,
66003ce4948Sjsing ctx->config->ca_path) != 1) {
6617a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
6627a756d37Sjoshua "ssl verify locations failure");
66351f3bd3dSbeck goto err;
66451f3bd3dSbeck }
66521514b59Sjsing
66680bc881dSjsing if (crl_mem != NULL) {
66780bc881dSjsing if (crl_len > INT_MAX) {
6682b31d1bdSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
6692b31d1bdSjoshua "crl too long");
67080bc881dSjsing goto err;
67180bc881dSjsing }
67280bc881dSjsing if ((bio = BIO_new_mem_buf(crl_mem, crl_len)) == NULL) {
6737a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
6747a756d37Sjoshua "failed to create buffer");
67580bc881dSjsing goto err;
67680bc881dSjsing }
67780bc881dSjsing if ((xis = PEM_X509_INFO_read_bio(bio, NULL, tls_password_cb,
67880bc881dSjsing NULL)) == NULL) {
6797a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
6807a756d37Sjoshua "failed to parse crl");
68180bc881dSjsing goto err;
68280bc881dSjsing }
68380bc881dSjsing store = SSL_CTX_get_cert_store(ssl_ctx);
68480bc881dSjsing for (i = 0; i < sk_X509_INFO_num(xis); i++) {
68580bc881dSjsing xi = sk_X509_INFO_value(xis, i);
68680bc881dSjsing if (xi->crl == NULL)
68780bc881dSjsing continue;
68880bc881dSjsing if (!X509_STORE_add_crl(store, xi->crl)) {
6897a756d37Sjoshua tls_set_error(ctx, TLS_ERROR_UNKNOWN,
6907a756d37Sjoshua "failed to add crl");
69180bc881dSjsing goto err;
69280bc881dSjsing }
69380bc881dSjsing }
694cbc8ac2bStb X509_STORE_set_flags(store,
69580bc881dSjsing X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
69680bc881dSjsing }
69780bc881dSjsing
69817d46c2aSjsing done:
699888c565eSjsing rv = 0;
70051f3bd3dSbeck
70151f3bd3dSbeck err:
70280bc881dSjsing sk_X509_INFO_pop_free(xis, X509_INFO_free);
70380bc881dSjsing BIO_free(bio);
70403ce4948Sjsing free(ca_free);
70503ce4948Sjsing
706888c565eSjsing return (rv);
70751f3bd3dSbeck }
70851f3bd3dSbeck
709b600beedSjsing void
tls_free(struct tls * ctx)710b600beedSjsing tls_free(struct tls *ctx)
711b600beedSjsing {
712b600beedSjsing if (ctx == NULL)
713b600beedSjsing return;
714dc559dc0Sjsing
715b600beedSjsing tls_reset(ctx);
716dc559dc0Sjsing
717b600beedSjsing free(ctx);
718b600beedSjsing }
719b600beedSjsing
720b600beedSjsing void
tls_reset(struct tls * ctx)721b600beedSjsing tls_reset(struct tls *ctx)
722b600beedSjsing {
723f89edc01Sjsing struct tls_sni_ctx *sni, *nsni;
724f89edc01Sjsing
72588c10dabSjsing tls_config_free(ctx->config);
72688c10dabSjsing ctx->config = NULL;
72788c10dabSjsing
728b600beedSjsing SSL_CTX_free(ctx->ssl_ctx);
729b600beedSjsing SSL_free(ctx->ssl_conn);
730e98425b4Sjsing X509_free(ctx->ssl_peer_cert);
731b600beedSjsing
732b600beedSjsing ctx->ssl_conn = NULL;
733b600beedSjsing ctx->ssl_ctx = NULL;
734e98425b4Sjsing ctx->ssl_peer_cert = NULL;
735c67861f7Sbeck /* X509 objects in chain are freed with the SSL */
736c67861f7Sbeck ctx->ssl_peer_chain = NULL;
737b600beedSjsing
738b600beedSjsing ctx->socket = -1;
73993310cfaSjsing ctx->state = 0;
740b600beedSjsing
741e2b71c11Sjsing free(ctx->servername);
742e2b71c11Sjsing ctx->servername = NULL;
743e2b71c11Sjsing
744a88e9e95Sjsing free(ctx->error.msg);
745a88e9e95Sjsing ctx->error.msg = NULL;
746deae75adSjoshua ctx->error.errno_value = -1;
747ab8f2ec6Sbeck
748dc559dc0Sjsing tls_conninfo_free(ctx->conninfo);
749ab8f2ec6Sbeck ctx->conninfo = NULL;
750f89edc01Sjsing
7516ffc3042Sbeck tls_ocsp_free(ctx->ocsp);
7526ffc3042Sbeck ctx->ocsp = NULL;
7532dc6b4e4Sbeck
754f89edc01Sjsing for (sni = ctx->sni_ctx; sni != NULL; sni = nsni) {
755f89edc01Sjsing nsni = sni->next;
756f89edc01Sjsing tls_sni_ctx_free(sni);
757f89edc01Sjsing }
758f89edc01Sjsing ctx->sni_ctx = NULL;
759ed19021fSbcook
760ed19021fSbcook ctx->read_cb = NULL;
761ed19021fSbcook ctx->write_cb = NULL;
762ed19021fSbcook ctx->cb_arg = NULL;
763b600beedSjsing }
764b600beedSjsing
765d474f84fSjsing int
tls_ssl_error(struct tls * ctx,SSL * ssl_conn,int ssl_ret,const char * prefix)7665251ab8eSjsing tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix)
767f832f19aSjsing {
768f832f19aSjsing const char *errstr = "unknown error";
769f832f19aSjsing unsigned long err;
770f832f19aSjsing int ssl_err;
771f832f19aSjsing
7725251ab8eSjsing ssl_err = SSL_get_error(ssl_conn, ssl_ret);
773f832f19aSjsing switch (ssl_err) {
774f832f19aSjsing case SSL_ERROR_NONE:
775f832f19aSjsing case SSL_ERROR_ZERO_RETURN:
7762c02f8b2Sjsing return (0);
777f832f19aSjsing
778f832f19aSjsing case SSL_ERROR_WANT_READ:
779ab00dbefSbeck return (TLS_WANT_POLLIN);
780f832f19aSjsing
781f832f19aSjsing case SSL_ERROR_WANT_WRITE:
782ab00dbefSbeck return (TLS_WANT_POLLOUT);
783f832f19aSjsing
784f832f19aSjsing case SSL_ERROR_SYSCALL:
785f832f19aSjsing if ((err = ERR_peek_error()) != 0) {
786f832f19aSjsing errstr = ERR_error_string(err, NULL);
787f832f19aSjsing } else if (ssl_ret == 0) {
78838c90daaSjsing if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
78939389942Sjsing ctx->state |= TLS_EOF_NO_CLOSE_NOTIFY;
79039389942Sjsing return (0);
79138c90daaSjsing }
79238c90daaSjsing errstr = "unexpected EOF";
793f832f19aSjsing } else if (ssl_ret == -1) {
794f832f19aSjsing errstr = strerror(errno);
795f832f19aSjsing }
7967a756d37Sjoshua tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
7977a756d37Sjoshua "%s failed: %s", prefix, errstr);
798f832f19aSjsing return (-1);
799f832f19aSjsing
800f832f19aSjsing case SSL_ERROR_SSL:
801f832f19aSjsing if ((err = ERR_peek_error()) != 0) {
802f832f19aSjsing errstr = ERR_error_string(err, NULL);
803f832f19aSjsing }
8047a756d37Sjoshua tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
8057a756d37Sjoshua "%s failed: %s", prefix, errstr);
806f832f19aSjsing return (-1);
807f832f19aSjsing
808f832f19aSjsing case SSL_ERROR_WANT_CONNECT:
809f832f19aSjsing case SSL_ERROR_WANT_ACCEPT:
810f832f19aSjsing case SSL_ERROR_WANT_X509_LOOKUP:
811f832f19aSjsing default:
8127a756d37Sjoshua tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
8137a756d37Sjoshua "%s failed (%d)", prefix, ssl_err);
814f832f19aSjsing return (-1);
815f832f19aSjsing }
816f832f19aSjsing }
817f832f19aSjsing
818b600beedSjsing int
tls_handshake(struct tls * ctx)819e2b71c11Sjsing tls_handshake(struct tls *ctx)
820e2b71c11Sjsing {
821e2b71c11Sjsing int rv = -1;
822e2b71c11Sjsing
8239e219fcdSjsing tls_error_clear(&ctx->error);
8249e219fcdSjsing
825cb3c676dSjsing if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
82640ae7d6bSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
8277a756d37Sjoshua "invalid operation for context");
828cb3c676dSjsing goto out;
829cb3c676dSjsing }
830cb3c676dSjsing
831ef1e76eaSjsing if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
8327a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
8337a756d37Sjoshua "handshake already completed");
834ef1e76eaSjsing goto out;
835ef1e76eaSjsing }
836ef1e76eaSjsing
837e2b71c11Sjsing if ((ctx->flags & TLS_CLIENT) != 0)
838e2b71c11Sjsing rv = tls_handshake_client(ctx);
839e2b71c11Sjsing else if ((ctx->flags & TLS_SERVER_CONN) != 0)
840e2b71c11Sjsing rv = tls_handshake_server(ctx);
841e2b71c11Sjsing
842cbeeb52cSbeck if (rv == 0) {
843cbeeb52cSbeck ctx->ssl_peer_cert = SSL_get_peer_certificate(ctx->ssl_conn);
844c67861f7Sbeck ctx->ssl_peer_chain = SSL_get_peer_cert_chain(ctx->ssl_conn);
845dc559dc0Sjsing if (tls_conninfo_populate(ctx) == -1)
846ab8f2ec6Sbeck rv = -1;
8476ffc3042Sbeck if (ctx->ocsp == NULL)
8486ffc3042Sbeck ctx->ocsp = tls_ocsp_setup_from_peer(ctx);
849cbeeb52cSbeck }
850ab8f2ec6Sbeck out:
85141dd5705Sbeck /* Prevent callers from performing incorrect error handling */
852e2b71c11Sjsing errno = 0;
853e2b71c11Sjsing return (rv);
854e2b71c11Sjsing }
855e2b71c11Sjsing
8561eeda1ffSbeck ssize_t
tls_read(struct tls * ctx,void * buf,size_t buflen)8571eeda1ffSbeck tls_read(struct tls *ctx, void *buf, size_t buflen)
858b600beedSjsing {
8591eeda1ffSbeck ssize_t rv = -1;
860f832f19aSjsing int ssl_ret;
86198f83bbfSjsing
8629e219fcdSjsing tls_error_clear(&ctx->error);
8639e219fcdSjsing
864e2b71c11Sjsing if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
865e2b71c11Sjsing if ((rv = tls_handshake(ctx)) != 0)
866e2b71c11Sjsing goto out;
867e2b71c11Sjsing }
868e2b71c11Sjsing
869c81cfcc3Sdoug if (buflen > INT_MAX) {
8702b31d1bdSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
8717a756d37Sjoshua "buflen too long");
872b71eb829Sbeck goto out;
873c81cfcc3Sdoug }
874c81cfcc3Sdoug
8759ba095aaSjsing ERR_clear_error();
87639389942Sjsing if ((ssl_ret = SSL_read(ctx->ssl_conn, buf, buflen)) > 0) {
8771eeda1ffSbeck rv = (ssize_t)ssl_ret;
878b71eb829Sbeck goto out;
879b600beedSjsing }
8801eeda1ffSbeck rv = (ssize_t)tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "read");
8819ba095aaSjsing
882b71eb829Sbeck out:
88341dd5705Sbeck /* Prevent callers from performing incorrect error handling */
884b71eb829Sbeck errno = 0;
885b71eb829Sbeck return (rv);
886b600beedSjsing }
887b600beedSjsing
8881eeda1ffSbeck ssize_t
tls_write(struct tls * ctx,const void * buf,size_t buflen)8891eeda1ffSbeck tls_write(struct tls *ctx, const void *buf, size_t buflen)
890b600beedSjsing {
8911eeda1ffSbeck ssize_t rv = -1;
892f832f19aSjsing int ssl_ret;
89398f83bbfSjsing
8949e219fcdSjsing tls_error_clear(&ctx->error);
8959e219fcdSjsing
896e2b71c11Sjsing if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
897e2b71c11Sjsing if ((rv = tls_handshake(ctx)) != 0)
898e2b71c11Sjsing goto out;
899e2b71c11Sjsing }
900e2b71c11Sjsing
901c81cfcc3Sdoug if (buflen > INT_MAX) {
9022b31d1bdSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
9037a756d37Sjoshua "buflen too long");
904b71eb829Sbeck goto out;
905c81cfcc3Sdoug }
906c81cfcc3Sdoug
9079ba095aaSjsing ERR_clear_error();
90839389942Sjsing if ((ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen)) > 0) {
9091eeda1ffSbeck rv = (ssize_t)ssl_ret;
910b71eb829Sbeck goto out;
911b600beedSjsing }
9121eeda1ffSbeck rv = (ssize_t)tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "write");
9139ba095aaSjsing
914b71eb829Sbeck out:
91541dd5705Sbeck /* Prevent callers from performing incorrect error handling */
916b71eb829Sbeck errno = 0;
917b71eb829Sbeck return (rv);
918b600beedSjsing }
919b600beedSjsing
920b600beedSjsing int
tls_close(struct tls * ctx)921b600beedSjsing tls_close(struct tls *ctx)
922b600beedSjsing {
923d29228b9Sjsing int ssl_ret;
9246dce3cf3Sjsing int rv = 0;
925d29228b9Sjsing
9269e219fcdSjsing tls_error_clear(&ctx->error);
9279e219fcdSjsing
928cb3c676dSjsing if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
92940ae7d6bSjoshua tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
9307a756d37Sjoshua "invalid operation for context");
931cb3c676dSjsing rv = -1;
932cb3c676dSjsing goto out;
933cb3c676dSjsing }
934cb3c676dSjsing
9355a752462Sjsing if (ctx->state & TLS_SSL_NEEDS_SHUTDOWN) {
9369ba095aaSjsing ERR_clear_error();
937d29228b9Sjsing ssl_ret = SSL_shutdown(ctx->ssl_conn);
9386dce3cf3Sjsing if (ssl_ret < 0) {
9396dce3cf3Sjsing rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret,
940d29228b9Sjsing "shutdown");
941ab00dbefSbeck if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
942b71eb829Sbeck goto out;
9436dce3cf3Sjsing }
9445a752462Sjsing ctx->state &= ~TLS_SSL_NEEDS_SHUTDOWN;
945b600beedSjsing }
946b600beedSjsing
947b600beedSjsing if (ctx->socket != -1) {
948b600beedSjsing if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
9496dce3cf3Sjsing if (rv == 0 &&
9506dce3cf3Sjsing errno != ENOTCONN && errno != ECONNRESET) {
9517a756d37Sjoshua tls_set_error(ctx, TLS_ERROR_UNKNOWN, "shutdown");
9526dce3cf3Sjsing rv = -1;
9536dce3cf3Sjsing }
954b600beedSjsing }
955b600beedSjsing if (close(ctx->socket) != 0) {
9566dce3cf3Sjsing if (rv == 0) {
9577a756d37Sjoshua tls_set_error(ctx, TLS_ERROR_UNKNOWN, "close");
9586dce3cf3Sjsing rv = -1;
9596dce3cf3Sjsing }
960b600beedSjsing }
961b600beedSjsing ctx->socket = -1;
962b600beedSjsing }
96339389942Sjsing
96439389942Sjsing if ((ctx->state & TLS_EOF_NO_CLOSE_NOTIFY) != 0) {
9657a756d37Sjoshua tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "EOF without close notify");
96639389942Sjsing rv = -1;
96739389942Sjsing }
96839389942Sjsing
969b71eb829Sbeck out:
97041dd5705Sbeck /* Prevent callers from performing incorrect error handling */
971b71eb829Sbeck errno = 0;
9726dce3cf3Sjsing return (rv);
973b600beedSjsing }
974