diff options
Diffstat (limited to 'tls.c')
-rw-r--r-- | tls.c | 138 |
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) { |