From 111794158c106d2ca7af712dce8857d49ba64905 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Wed, 27 Jan 2016 12:50:16 +0000 Subject: [PATCH] Improve Windows CA handling code --- src/context.c | 173 ++++++++++++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 83 deletions(-) diff --git a/src/context.c b/src/context.c index ae592017..65889664 100644 --- a/src/context.c +++ b/src/context.c @@ -43,14 +43,14 @@ #else #include #include -typedef unsigned short in_port_t; - -#include -#include -#include - -#include -#include +typedef unsigned short in_port_t; + +#include +#include +#include + +#include +#include #include #endif @@ -143,57 +143,59 @@ static void set_ub_edns_maximum_udp_payload_size(struct getdns_context*, // For windows, the CA trust store is not read by openssl. // Add code to open the trust store using wincrypt API and add // the root certs into openssl trust store -X509_STORE *store; -X509_STORE_CTX *sslctx = NULL; -void add_cacerts_to_openssl_store(struct getdns_context *context) +static int +add_WIN_cacerts_to_openssl_store(SSL_CTX *tls_ctx) { - HCERTSTORE hSystemStore; - PCCERT_CONTEXT pTargetCert = NULL; - - // Call wincrypt's CertOpenStore to open the CA root store. - - if ((hSystemStore = CertOpenStore( - CERT_STORE_PROV_SYSTEM, - 0, - NULL, - // mingw does not have this const: replace with 1 << 16 from code - // CERT_SYSTEM_STORE_CURRENT_USER, - 1 << 16, - L"root")) == 0) - { - DEBUG_STUB("*** %s(CertOpenStore failed)\n", __FUNCTION__); - return; - } - store = SSL_CTX_get_cert_store(context->tls_ctx); - - // iterate over the windows cert store and add to openssl store - while (pTargetCert = CertEnumCertificatesInStore( - hSystemStore, - pTargetCert)) - { - BYTE* cert = pTargetCert->pbCertEncoded; - X509 *cert1 = d2i_X509(NULL, (const unsigned char **)&pTargetCert->pbCertEncoded, pTargetCert->cbCertEncoded); - if (!cert1) { - DEBUG_STUB("*** %s(%s)\n", __FUNCTION__, - "unable to parse certificate in memory"); - } - else { - if (X509_STORE_add_cert(store, cert1) == 0) - DEBUG_STUB("*** %s(%s)\n", __FUNCTION__, - "error adding certificate"); - X509_free(cert1); - } - } - // Clean up memory and quit. - - if (pTargetCert) - CertFreeCertificateContext(pTargetCert); - if (hSystemStore) - { - if (!CertCloseStore( - hSystemStore, 0)) - DEBUG_STUB("*** %s(%s)\n", __FUNCTION__, "CertCloseStore failed"); - } + HCERTSTORE hSystemStore; + PCCERT_CONTEXT pTargetCert = NULL; + + if !(tls_ctx) + return 1; + + // Call wincrypt's CertOpenStore to open the CA root store. + + if ((hSystemStore = CertOpenStore( + CERT_STORE_PROV_SYSTEM, + 0, + NULL, + // mingw does not have this const: replace with 1 << 16 from code + // CERT_SYSTEM_STORE_CURRENT_USER, + 1 << 16, + L"root")) == 0) + { + return 1; + } + + X509_STORE *store = SSL_CTX_get_cert_store(tls_ctx); + if (!store) + return 1; + + // iterate over the windows cert store and add to openssl store + while (pTargetCert = CertEnumCertificatesInStore( + hSystemStore, + pTargetCert)) + { + BYTE* cert = pTargetCert->pbCertEncoded; + X509 *cert1 = d2i_X509(NULL, (const unsigned char **)&pTargetCert->pbCertEncoded, pTargetCert->cbCertEncoded); + if (!cert1) + return 1; + else { + if (X509_STORE_add_cert(store, cert1) == 0) + return 1; + X509_free(cert1); + } + } + + // Clean up memory and quit. + if (pTargetCert) + CertFreeCertificateContext(pTargetCert); + if (hSystemStore) + { + if (!CertCloseStore( + hSystemStore, 0)) + return 1; + } + return 0; } #endif @@ -2691,31 +2693,7 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, /* Transport can in theory be set per query in stub mode */ if (context->resolution_type == GETDNS_RESOLUTION_STUB && tls_is_in_transports_list(context) == 1) { - if (context->tls_ctx == NULL) { -#ifdef HAVE_TLS_v1_2 - /* Create client context, use TLS v1.2 only for now */ - context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); - if(context->tls_ctx == NULL) -#ifndef USE_WINSOCK - return GETDNS_RETURN_BAD_CONTEXT; -#else - printf("Warning! Bad TLS context, check openssl version on Windows!\n"); - add_cacerts_to_openssl_store(context); -#endif - /* Be strict and only use the cipher suites recommended in RFC7525 - Unless we later fallback to opportunistic. */ - const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; - if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) - return GETDNS_RETURN_BAD_CONTEXT; - if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) - return GETDNS_RETURN_BAD_CONTEXT; -#else - if (tls_only_is_in_transports_list(context) == 1) - return GETDNS_RETURN_BAD_CONTEXT; - /* A null tls_ctx will make TLS fail and fallback to the other - transports will kick-in.*/ -#endif - } + /* Check minimum require authentication level*/ if (tls_only_is_in_transports_list(context) == 1 && context->tls_auth == GETDNS_AUTHENTICATION_REQUIRED) { context->tls_auth_min = GETDNS_AUTHENTICATION_REQUIRED; @@ -2724,6 +2702,35 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, else { context->tls_auth_min = GETDNS_AUTHENTICATION_NONE; } + + if (context->tls_ctx == NULL) { +#ifdef HAVE_TLS_v1_2 + /* Create client context, use TLS v1.2 only for now */ + context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); + if(context->tls_ctx == NULL) + return GETDNS_RETURN_BAD_CONTEXT; + /* Be strict and only use the cipher suites recommended in RFC7525 + Unless we later fallback to opportunistic. */ + const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; + if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) + return GETDNS_RETURN_BAD_CONTEXT; + /* For strict authentication, we must have local root certs available + Set up is done only when the tls_ctx is created (per getdns_context)*/ +#ifndef USE_WINSOCK + if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) { +#else + if (!add_WIN_cacerts_to_openssl_store(context)) { +#endif /* USE_WINSOCK */ + if (context->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) + return GETDNS_RETURN_BAD_CONTEXT; + } +#else /* HAVE_TLS_v1_2 */ + if (tls_only_is_in_transports_list(context) == 1) + return GETDNS_RETURN_BAD_CONTEXT; + /* A null tls_ctx will make TLS fail and fallback to the other + transports will kick-in.*/ +#endif /* HAVE_TLS_v1_2 */ + } } /* Block use of TLS ONLY in recursive mode as it won't work */