about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tls.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/tls.c b/tls.c
index 2a42510..9e5a58d 100644
--- a/tls.c
+++ b/tls.c
@@ -327,6 +327,66 @@ tls_cert_pubkey_hash(X509 *cert, char **hash)
 	return (rv);
 }
 
+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);
+}
+
 int
 tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
     struct tls_keypair *keypair, int required)
@@ -345,7 +405,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;