diff options
Diffstat (limited to 'tls.c')
-rw-r--r-- | tls.c | 134 |
1 files changed, 118 insertions, 16 deletions
diff --git a/tls.c b/tls.c index 262ec3d..91f20cf 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; @@ -445,7 +506,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; @@ -521,7 +582,7 @@ tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx) } if (ctx->config->verify_time == 0) { - X509_VERIFY_PARAM_set_flags(ssl_ctx->param, + X509_VERIFY_PARAM_set_flags(SSL_CTX_get0_param(ssl_ctx), X509_V_FLAG_NO_CHECK_TIME); } @@ -559,6 +620,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) { @@ -583,27 +686,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) { @@ -631,7 +733,7 @@ tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify) } xi->crl = NULL; } - X509_VERIFY_PARAM_set_flags(store->param, + X509_VERIFY_PARAM_set_flags(X509_STORE_get0_param(store), X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } |