about summary refs log tree commit diff
path: root/tls.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tls.c129
1 files changed, 115 insertions, 14 deletions
diff --git a/tls.c b/tls.c
index fdb994d..d387952 100644
--- a/tls.c
+++ b/tls.c
@@ -328,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;
@@ -476,7 +536,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;
@@ -586,6 +646,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)
 {
@@ -610,27 +712,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) {