about summary refs log tree commit diff
path: root/tls.c
diff options
context:
space:
mode:
Diffstat (limited to 'tls.c')
-rw-r--r--tls.c138
1 files changed, 120 insertions, 18 deletions
diff --git a/tls.c b/tls.c
index ff33ebe..6883c58 100644
--- a/tls.c
+++ b/tls.c
@@ -21,6 +21,7 @@
 #include <limits.h>
 #include <pthread.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <openssl/bio.h>
@@ -327,6 +328,66 @@ tls_cert_pubkey_hash(X509 *cert, char **hash)
 }
 
 static int
+use_certificate_chain_bio(SSL_CTX *ctx, BIO *in)
+{
+	X509 *ca, *x = NULL;
+	unsigned long err;
+	int ret = 0;
+
+	if ((x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL)) == NULL) {
+		SSLerr(0xfff, ERR_R_PEM_LIB);
+		goto err;
+	}
+
+	if (!SSL_CTX_use_certificate(ctx, x))
+		goto err;
+
+	if (!SSL_CTX_clear_chain_certs(ctx))
+		goto err;
+
+	/* Process any additional CA certificates. */
+	while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL)) != NULL) {
+		if (!SSL_CTX_add0_chain_cert(ctx, ca)) {
+			X509_free(ca);
+			goto err;
+		}
+	}
+
+	/* When the while loop ends, it's usually just EOF. */
+	err = ERR_peek_last_error();
+	if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
+	    ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
+		ERR_clear_error();
+		ret = 1;
+	}
+
+ err:
+	X509_free(x);
+
+	return (ret);
+}
+
+static int
+use_certificate_chain_mem(SSL_CTX *ctx, void *buf, int len)
+{
+	BIO *in;
+	int ret = 0;
+
+	in = BIO_new_mem_buf(buf, len);
+	if (in == NULL) {
+		SSLerr(0xfff, ERR_R_BUF_LIB);
+		goto end;
+	}
+
+	ret = use_certificate_chain_bio(ctx, in);
+
+ end:
+	BIO_free(in);
+
+	return (ret);
+}
+
+static int
 tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pkey)
 {
 	BIO *bio = NULL;
@@ -388,7 +449,7 @@ static int
 tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *pkey)
 {
 	RSA_METHOD *rsa_method;
-	ECDSA_METHOD *ecdsa_method;
+	EC_KEY_METHOD *ecdsa_method;
 	RSA *rsa = NULL;
 	EC_KEY *eckey = NULL;
 	int ret = -1;
@@ -420,15 +481,15 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 		break;
 	case EVP_PKEY_EC:
 		if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL ||
-		    ECDSA_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0) {
+		    EC_KEY_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0) {
 			tls_set_errorx(ctx, "EC key setup failure");
 			goto err;
 		}
 		if (ctx->config->sign_cb == NULL)
 			break;
 		if ((ecdsa_method = tls_signer_ecdsa_method()) == NULL ||
-		    ECDSA_set_ex_data(eckey, 1, ctx->config) == 0 ||
-		    ECDSA_set_method(eckey, ecdsa_method) == 0) {
+		    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");
 			goto err;
 		}
@@ -463,7 +524,7 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 			goto err;
 		}
 
-		if (SSL_CTX_use_certificate_chain_mem(ssl_ctx,
+		if (use_certificate_chain_mem(ssl_ctx,
 		    keypair->cert_mem, keypair->cert_len) != 1) {
 			tls_set_errorx(ctx, "failed to load certificate");
 			goto err;
@@ -577,6 +638,48 @@ tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
 	return (0);
 }
 
+static int
+load_verify_mem(SSL_CTX *ctx, void *buf, int len)
+{
+	X509_STORE *store;
+	BIO *in = NULL;
+	STACK_OF(X509_INFO) *inf = NULL;
+	X509_INFO *itmp;
+	int i, count = 0, ok = 0;
+
+	store = SSL_CTX_get_cert_store(ctx);
+
+	if ((in = BIO_new_mem_buf(buf, len)) == NULL)
+		goto done;
+
+	if ((inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL)
+		goto done;
+
+	for (i = 0; i < sk_X509_INFO_num(inf); i++) {
+		itmp = sk_X509_INFO_value(inf, i);
+		if (itmp->x509) {
+			if ((ok = X509_STORE_add_cert(store, itmp->x509)) == 0)
+				goto done;
+			count++;
+		}
+		if (itmp->crl) {
+			if ((ok = X509_STORE_add_crl(store, itmp->crl)) == 0)
+				goto done;
+			count++;
+		}
+	}
+
+	ok = count != 0;
+ done:
+	if (count == 0)
+		X509err(0xfff, ERR_R_PEM_LIB);
+	if (inf != NULL)
+		sk_X509_INFO_pop_free(inf, X509_INFO_free);
+	if (in != NULL)
+		BIO_free(in);
+	return (ok);
+}
+
 int
 tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
 {
@@ -601,27 +704,26 @@ tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
 	if (ctx->config->verify_cert == 0)
 		goto done;
 
-	/* If no CA has been specified, attempt to load the default. */
-	if (ctx->config->ca_mem == NULL && ctx->config->ca_path == NULL) {
-		if (tls_config_load_file(&ctx->error, "CA", tls_default_ca_cert_file(),
-		    &ca_mem, &ca_len) != 0)
-			goto err;
-		ca_free = ca_mem;
-	}
-
 	if (ca_mem != NULL) {
 		if (ca_len > INT_MAX) {
 			tls_set_errorx(ctx, "ca too long");
 			goto err;
 		}
-		if (SSL_CTX_load_verify_mem(ssl_ctx, ca_mem, ca_len) != 1) {
+		if (load_verify_mem(ssl_ctx, ca_mem, ca_len) != 1) {
 			tls_set_errorx(ctx, "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");
-		goto err;
+	} else if (ctx->config->ca_path != NULL) {
+		if (SSL_CTX_load_verify_locations(ssl_ctx, NULL,
+			ctx->config->ca_path) != 1) {
+			tls_set_errorx(ctx, "ssl verify locations failure");
+			goto err;
+		}
+	} else {
+		if (SSL_CTX_set_default_verify_paths(ssl_ctx) != 1) {
+			tls_set_errorx(ctx, "ssl verify locations failure");
+			goto err;
+		}
 	}
 
 	if (crl_mem != NULL) {