summary refs log tree commit diff
path: root/tls.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2026-06-01 14:42:49 -0400
committerJune McEnroe <june@causal.agency>2026-06-01 14:42:49 -0400
commitd08958f5d2c4d71d8132ea5c6cb45e48b5c4d83d (patch)
tree01f7eb5bc8d9d0e708ec077364a6b3fda7f1bdde /tls.c
parentImport LibreSSL 3.9.2 (diff)
downloadlibretls-d08958f5d2c4d71d8132ea5c6cb45e48b5c4d83d.tar.gz
libretls-d08958f5d2c4d71d8132ea5c6cb45e48b5c4d83d.zip
Import LibreSSL 4.0.0
Diffstat (limited to 'tls.c')
-rw-r--r--tls.c176
1 files changed, 109 insertions, 67 deletions
diff --git a/tls.c b/tls.c
index fdb994d..41bb06d 100644
--- a/tls.c
+++ b/tls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls.c,v 1.98 2023/07/02 06:37:27 beck Exp $ */
+/* $OpenBSD: tls.c,v 1.104 2024/04/08 20:47:32 tb Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -72,24 +72,33 @@ tls_error(struct tls *ctx)
 	return ctx->error.msg;
 }
 
+int
+tls_error_code(struct tls *ctx)
+{
+	return ctx->error.code;
+}
+
 void
 tls_error_clear(struct tls_error *error)
 {
 	free(error->msg);
 	error->msg = NULL;
-	error->num = 0;
+	error->code = TLS_ERROR_UNKNOWN;
+	error->errno_value = 0;
 	error->tls = 0;
 }
 
 static int
-tls_error_vset(struct tls_error *error, int errnum, const char *fmt, va_list ap)
+tls_error_vset(struct tls_error *error, int code, int errno_value,
+    const char *fmt, va_list ap)
 {
 	char *errmsg = NULL;
 	int rv = -1;
 
 	tls_error_clear(error);
 
-	error->num = errnum;
+	error->code = code;
+	error->errno_value = errno_value;
 	error->tls = 1;
 
 	if (vasprintf(&errmsg, fmt, ap) == -1) {
@@ -97,12 +106,12 @@ tls_error_vset(struct tls_error *error, int errnum, const char *fmt, va_list ap)
 		goto err;
 	}
 
-	if (errnum == -1) {
+	if (errno_value == -1) {
 		error->msg = errmsg;
 		return (0);
 	}
 
-	if (asprintf(&error->msg, "%s: %s", errmsg, strerror(errnum)) == -1) {
+	if (asprintf(&error->msg, "%s: %s", errmsg, strerror(errno_value)) == -1) {
 		error->msg = NULL;
 		goto err;
 	}
@@ -115,91 +124,91 @@ tls_error_vset(struct tls_error *error, int errnum, const char *fmt, va_list ap)
 }
 
 int
-tls_error_set(struct tls_error *error, const char *fmt, ...)
+tls_error_set(struct tls_error *error, int code, const char *fmt, ...)
 {
 	va_list ap;
-	int errnum, rv;
+	int errno_value, rv;
 
-	errnum = errno;
+	errno_value = errno;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(error, errnum, fmt, ap);
+	rv = tls_error_vset(error, code, errno_value, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_error_setx(struct tls_error *error, const char *fmt, ...)
+tls_error_setx(struct tls_error *error, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(error, -1, fmt, ap);
+	rv = tls_error_vset(error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_config_set_error(struct tls_config *config, const char *fmt, ...)
+tls_config_set_error(struct tls_config *config, int code, const char *fmt, ...)
 {
 	va_list ap;
-	int errnum, rv;
+	int errno_value, rv;
 
-	errnum = errno;
+	errno_value = errno;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&config->error, errnum, fmt, ap);
+	rv = tls_error_vset(&config->error, code, errno_value, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_config_set_errorx(struct tls_config *config, const char *fmt, ...)
+tls_config_set_errorx(struct tls_config *config, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&config->error, -1, fmt, ap);
+	rv = tls_error_vset(&config->error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_set_error(struct tls *ctx, const char *fmt, ...)
+tls_set_error(struct tls *ctx, int code, const char *fmt, ...)
 {
 	va_list ap;
-	int errnum, rv;
+	int errno_value, rv;
 
-	errnum = errno;
+	errno_value = errno;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&ctx->error, errnum, fmt, ap);
+	rv = tls_error_vset(&ctx->error, code, errno_value, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_set_errorx(struct tls *ctx, const char *fmt, ...)
+tls_set_errorx(struct tls *ctx, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&ctx->error, -1, fmt, ap);
+	rv = tls_error_vset(&ctx->error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_set_ssl_errorx(struct tls *ctx, const char *fmt, ...)
+tls_set_ssl_errorx(struct tls *ctx, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
@@ -209,7 +218,7 @@ tls_set_ssl_errorx(struct tls *ctx, const char *fmt, ...)
 		return (0);
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&ctx->error, -1, fmt, ap);
+	rv = tls_error_vset(&ctx->error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
@@ -350,30 +359,34 @@ tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pke
 		return (0);
 
 	if (len > INT_MAX) {
-		tls_set_errorx(ctx, ctx->config->use_fake_private_key ?
-		    "cert too long" : "key too long");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+		    ctx->config->use_fake_private_key ?
+		    "certificate too long" : "key too long");
 		goto err;
 	}
 
 	if ((bio = BIO_new_mem_buf(mem, len)) == NULL) {
-		tls_set_errorx(ctx, "failed to create buffer");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "failed to create buffer");
 		goto err;
 	}
 
 	if (ctx->config->use_fake_private_key) {
 		if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb,
 		    NULL)) == NULL) {
-			tls_set_errorx(ctx, "failed to read X509 certificate");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to read X509 certificate");
 			goto err;
 		}
 		if ((*pkey = X509_get_pubkey(x509)) == NULL) {
-			tls_set_errorx(ctx, "failed to retrieve pubkey");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to retrieve pubkey");
 			goto err;
 		}
 	} else {
 		if ((*pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
 		    NULL)) ==  NULL) {
-			tls_set_errorx(ctx, "failed to read private key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to read private key");
 			goto err;
 		}
 	}
@@ -399,7 +412,7 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 		return (0);
 
 	if (keypair->pubkey_hash == NULL) {
-		tls_set_errorx(ctx, "public key hash not set");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "public key hash not set");
 		goto err;
 	}
 
@@ -407,7 +420,8 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 	case EVP_PKEY_RSA:
 		if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
 		    RSA_set_ex_data(rsa, 0, keypair->pubkey_hash) == 0) {
-			tls_set_errorx(ctx, "RSA key setup failure");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "RSA key setup failure");
 			goto err;
 		}
 		if (ctx->config->sign_cb != NULL) {
@@ -415,20 +429,23 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 			if (rsa_method == NULL ||
 			    RSA_set_ex_data(rsa, 1, ctx->config) == 0 ||
 			    RSA_set_method(rsa, rsa_method) == 0) {
-				tls_set_errorx(ctx, "failed to setup RSA key");
+				tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+				    "failed to setup RSA key");
 				goto err;
 			}
 		}
 		/* Reset the key to work around caching in OpenSSL 3. */
 		if (EVP_PKEY_set1_RSA(pkey, rsa) == 0) {
-			tls_set_errorx(ctx, "failed to set RSA key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set RSA key");
 			goto err;
 		}
 		break;
 	case EVP_PKEY_EC:
 		if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL ||
 		    EC_KEY_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0) {
-			tls_set_errorx(ctx, "EC key setup failure");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "EC key setup failure");
 			goto err;
 		}
 		if (ctx->config->sign_cb != NULL) {
@@ -436,18 +453,20 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 			if (ecdsa_method == NULL ||
 			    EC_KEY_set_ex_data(eckey, 1, ctx->config) == 0 ||
 			    EC_KEY_set_method(eckey, ecdsa_method) == 0) {
-				tls_set_errorx(ctx, "failed to setup EC key");
+				tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+				    "failed to setup EC key");
 				goto err;
 			}
 		}
 		/* Reset the key to work around caching in OpenSSL 3. */
 		if (EVP_PKEY_set1_EC_KEY(pkey, eckey) == 0) {
-			tls_set_errorx(ctx, "failed to set EC key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set EC key");
 			goto err;
 		}
 		break;
 	default:
-		tls_set_errorx(ctx, "incorrect key type");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "incorrect key type");
 		goto err;
 	}
 
@@ -472,13 +491,15 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 
 	if (keypair->cert_mem != NULL) {
 		if (keypair->cert_len > INT_MAX) {
-			tls_set_errorx(ctx, "certificate too long");
+			tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+			    "certificate too long");
 			goto err;
 		}
 
 		if (SSL_CTX_use_certificate_chain_mem(ssl_ctx,
 		    keypair->cert_mem, keypair->cert_len) != 1) {
-			tls_set_errorx(ctx, "failed to load certificate");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to load certificate");
 			goto err;
 		}
 	}
@@ -489,7 +510,8 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 		if (tls_keypair_setup_pkey(ctx, keypair, pkey) == -1)
 			goto err;
 		if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) {
-			tls_set_errorx(ctx, "failed to load private key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to load private key");
 			goto err;
 		}
 		EVP_PKEY_free(pkey);
@@ -498,7 +520,8 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 
 	if (!ctx->config->skip_private_key_check &&
 	    SSL_CTX_check_private_key(ssl_ctx) != 1) {
-		tls_set_errorx(ctx, "private/public key mismatch");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "private/public key mismatch");
 		goto err;
 	}
 
@@ -534,7 +557,8 @@ tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
 	if (ctx->config->alpn != NULL) {
 		if (SSL_CTX_set_alpn_protos(ssl_ctx, ctx->config->alpn,
 		    ctx->config->alpn_len) != 0) {
-			tls_set_errorx(ctx, "failed to set alpn");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set alpn");
 			goto err;
 		}
 	}
@@ -542,7 +566,8 @@ tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
 	if (ctx->config->ciphers != NULL) {
 		if (SSL_CTX_set_cipher_list(ssl_ctx,
 		    ctx->config->ciphers) != 1) {
-			tls_set_errorx(ctx, "failed to set ciphers");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set ciphers");
 			goto err;
 		}
 	}
@@ -572,7 +597,8 @@ tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
 		return (1);
 
 	if ((X509_verify_cert(x509_ctx)) < 0) {
-		tls_set_errorx(ctx, "X509 verify cert failed");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "X509 verify cert failed");
 		return (0);
 	}
 
@@ -580,7 +606,8 @@ tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
 	if (x509_err == X509_V_OK)
 		return (1);
 
-	tls_set_errorx(ctx, "certificate verification failed: %s",
+	tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+	    "certificate verification failed: %s",
 	    X509_verify_cert_error_string(x509_err));
 
 	return (0);
@@ -620,31 +647,37 @@ tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
 
 	if (ca_mem != NULL) {
 		if (ca_len > INT_MAX) {
-			tls_set_errorx(ctx, "ca too long");
+			tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+			    "ca too long");
 			goto err;
 		}
 		if (SSL_CTX_load_verify_mem(ssl_ctx, ca_mem, ca_len) != 1) {
-			tls_set_errorx(ctx, "ssl verify memory setup failure");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "ssl verify memory setup failure");
 			goto err;
 		}
 	} else if (SSL_CTX_load_verify_locations(ssl_ctx, NULL,
 	    ctx->config->ca_path) != 1) {
-		tls_set_errorx(ctx, "ssl verify locations failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl verify locations failure");
 		goto err;
 	}
 
 	if (crl_mem != NULL) {
 		if (crl_len > INT_MAX) {
-			tls_set_errorx(ctx, "crl too long");
+			tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+			    "crl too long");
 			goto err;
 		}
 		if ((bio = BIO_new_mem_buf(crl_mem, crl_len)) == NULL) {
-			tls_set_errorx(ctx, "failed to create buffer");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to create buffer");
 			goto err;
 		}
 		if ((xis = PEM_X509_INFO_read_bio(bio, NULL, tls_password_cb,
 		    NULL)) == NULL) {
-			tls_set_errorx(ctx, "failed to parse crl");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to parse crl");
 			goto err;
 		}
 		store = SSL_CTX_get_cert_store(ssl_ctx);
@@ -653,7 +686,8 @@ tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
 			if (xi->crl == NULL)
 				continue;
 			if (!X509_STORE_add_crl(store, xi->crl)) {
-				tls_set_error(ctx, "failed to add crl");
+				tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+				    "failed to add crl");
 				goto err;
 			}
 		}
@@ -709,7 +743,7 @@ tls_reset(struct tls *ctx)
 
 	free(ctx->error.msg);
 	ctx->error.msg = NULL;
-	ctx->error.num = -1;
+	ctx->error.errno_value = -1;
 
 	tls_conninfo_free(ctx->conninfo);
 	ctx->conninfo = NULL;
@@ -759,21 +793,24 @@ tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix)
 		} else if (ssl_ret == -1) {
 			errstr = strerror(errno);
 		}
-		tls_set_ssl_errorx(ctx, "%s failed: %s", prefix, errstr);
+		tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "%s failed: %s", prefix, errstr);
 		return (-1);
 
 	case SSL_ERROR_SSL:
 		if ((err = ERR_peek_error()) != 0) {
 			errstr = ERR_error_string(err, NULL);
 		}
-		tls_set_ssl_errorx(ctx, "%s failed: %s", prefix, errstr);
+		tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "%s failed: %s", prefix, errstr);
 		return (-1);
 
 	case SSL_ERROR_WANT_CONNECT:
 	case SSL_ERROR_WANT_ACCEPT:
 	case SSL_ERROR_WANT_X509_LOOKUP:
 	default:
-		tls_set_ssl_errorx(ctx, "%s failed (%d)", prefix, ssl_err);
+		tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "%s failed (%d)", prefix, ssl_err);
 		return (-1);
 	}
 }
@@ -786,12 +823,14 @@ tls_handshake(struct tls *ctx)
 	tls_error_clear(&ctx->error);
 
 	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
-		tls_set_errorx(ctx, "invalid operation for context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "invalid operation for context");
 		goto out;
 	}
 
 	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
-		tls_set_errorx(ctx, "handshake already completed");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "handshake already completed");
 		goto out;
 	}
 
@@ -828,7 +867,8 @@ tls_read(struct tls *ctx, void *buf, size_t buflen)
 	}
 
 	if (buflen > INT_MAX) {
-		tls_set_errorx(ctx, "buflen too long");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+		    "buflen too long");
 		goto out;
 	}
 
@@ -859,7 +899,8 @@ tls_write(struct tls *ctx, const void *buf, size_t buflen)
 	}
 
 	if (buflen > INT_MAX) {
-		tls_set_errorx(ctx, "buflen too long");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+		    "buflen too long");
 		goto out;
 	}
 
@@ -885,7 +926,8 @@ tls_close(struct tls *ctx)
 	tls_error_clear(&ctx->error);
 
 	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
-		tls_set_errorx(ctx, "invalid operation for context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "invalid operation for context");
 		rv = -1;
 		goto out;
 	}
@@ -906,13 +948,13 @@ tls_close(struct tls *ctx)
 		if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
 			if (rv == 0 &&
 			    errno != ENOTCONN && errno != ECONNRESET) {
-				tls_set_error(ctx, "shutdown");
+				tls_set_error(ctx, TLS_ERROR_UNKNOWN, "shutdown");
 				rv = -1;
 			}
 		}
 		if (close(ctx->socket) != 0) {
 			if (rv == 0) {
-				tls_set_error(ctx, "close");
+				tls_set_error(ctx, TLS_ERROR_UNKNOWN, "close");
 				rv = -1;
 			}
 		}
@@ -920,7 +962,7 @@ tls_close(struct tls *ctx)
 	}
 
 	if ((ctx->state & TLS_EOF_NO_CLOSE_NOTIFY) != 0) {
-		tls_set_errorx(ctx, "EOF without close notify");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "EOF without close notify");
 		rv = -1;
 	}