diff options
Diffstat (limited to 'ssl_openssl.c')
-rw-r--r-- | ssl_openssl.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/ssl_openssl.c b/ssl_openssl.c index 45b83d2..e71c9ef 100644 --- a/ssl_openssl.c +++ b/ssl_openssl.c @@ -645,6 +645,214 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) #endif +#if ENABLE_INLINE_FILES +static int +xname_cmp(const X509_NAME * const *a, const X509_NAME * const *b) +{ + return(X509_NAME_cmp(*a,*b)); +} + +static STACK_OF(X509_NAME) * +use_inline_load_client_CA_file (SSL_CTX *ctx, const char *ca_string) +{ + BIO *in = NULL; + X509 *x = NULL; + X509_NAME *xn = NULL; + STACK_OF(X509_NAME) *ret = NULL, *sk; + + sk=sk_X509_NAME_new(xname_cmp); + + in = BIO_new_mem_buf ((char *)ca_string, -1); + if (!in) + goto err; + + if ((sk == NULL) || (in == NULL)) + goto err; + + for (;;) + { + if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL) + break; + if (ret == NULL) + { + ret = sk_X509_NAME_new_null(); + if (ret == NULL) + goto err; + } + if ((xn=X509_get_subject_name(x)) == NULL) goto err; + /* check for duplicates */ + xn=X509_NAME_dup(xn); + if (xn == NULL) goto err; + if (sk_X509_NAME_find(sk,xn) >= 0) + X509_NAME_free(xn); + else + { + sk_X509_NAME_push(sk,xn); + sk_X509_NAME_push(ret,xn); + } + } + + if (0) + { + err: + if (ret != NULL) sk_X509_NAME_pop_free(ret,X509_NAME_free); + ret=NULL; + } + if (sk != NULL) sk_X509_NAME_free(sk); + if (in != NULL) BIO_free(in); + if (x != NULL) X509_free(x); + if (ret != NULL) + ERR_clear_error(); + return(ret); +} + +static int +use_inline_load_verify_locations (SSL_CTX *ctx, const char *ca_string) +{ + X509_STORE *store = NULL; + X509* cert = NULL; + BIO *in = NULL; + int ret = 0; + + in = BIO_new_mem_buf ((char *)ca_string, -1); + if (!in) + goto err; + + for (;;) + { + if (!PEM_read_bio_X509 (in, &cert, 0, NULL)) + { + ret = 1; + break; + } + if (!cert) + break; + + store = SSL_CTX_get_cert_store (ctx); + if (!store) + break; + + if (!X509_STORE_add_cert (store, cert)) + break; + + if (cert) + { + X509_free (cert); + cert = NULL; + } + } + + err: + if (cert) + X509_free (cert); + if (in) + BIO_free (in); + return ret; +} +#endif /* ENABLE_INLINE_FILES */ + +void +tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, +#if ENABLE_INLINE_FILES + const char *ca_file_inline, +#endif + const char *ca_path, bool tls_server + ) +{ + int status; + + ASSERT(NULL != ctx); + +#if ENABLE_INLINE_FILES + if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline) + { + status = use_inline_load_verify_locations (ctx->ctx, ca_file_inline); + } + else +#endif + { + /* Load CA file for verifying peer supplied certificate */ + status = SSL_CTX_load_verify_locations (ctx->ctx, ca_file, ca_path); + } + + if (!status) + msg (M_SSLERR, "Cannot load CA certificate file %s path %s (SSL_CTX_load_verify_locations)", np(ca_file), np(ca_path)); + + /* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */ + if (ca_path) { + X509_STORE *store = SSL_CTX_get_cert_store(ctx->ctx); + + if (store) + { + X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (!X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM)) + X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); + else + msg(M_WARN, "WARNING: experimental option --capath %s", ca_path); +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); +#else + msg(M_WARN, "WARNING: this version of OpenSSL cannot handle CRL files in capath"); +#endif + } + else + msg(M_SSLERR, "Cannot get certificate store (SSL_CTX_get_cert_store)"); + } + + /* Load names of CAs from file and use it as a client CA list */ + if (ca_file && tls_server) { + STACK_OF(X509_NAME) *cert_names = NULL; +#if ENABLE_INLINE_FILES + if (!strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline) + { + cert_names = use_inline_load_client_CA_file (ctx->ctx, ca_file_inline); + } + else +#endif + { + cert_names = SSL_load_client_CA_file (ca_file); + } + if (!cert_names) + msg (M_SSLERR, "Cannot load CA certificate file %s (SSL_load_client_CA_file)", ca_file); + SSL_CTX_set_client_CA_list (ctx->ctx, cert_names); + } + +} + +void +tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file +#if ENABLE_INLINE_FILES + , const char *extra_certs_file_inline +#endif + ) +{ + BIO *bio; + X509 *cert; +#if ENABLE_INLINE_FILES + if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline) + { + bio = BIO_new_mem_buf ((char *)extra_certs_file_inline, -1); + } + else +#endif + { + bio = BIO_new(BIO_s_file()); + if (BIO_read_filename(bio, extra_certs_file) <= 0) + msg (M_SSLERR, "Cannot load extra-certs file: %s", extra_certs_file); + } + for (;;) + { + cert = NULL; + if (!PEM_read_bio_X509 (bio, &cert, 0, NULL)) /* takes ownership of cert */ + break; + if (!cert) + msg (M_SSLERR, "Error reading extra-certs certificate"); + if (SSL_CTX_add_extra_chain_cert(ctx->ctx, cert) != 1) + msg (M_SSLERR, "Error adding extra-certs certificate"); + } + BIO_free (bio); +} + void show_available_tls_ciphers () { |