Merge pull request #1 from saradickinson/feature/wincrypt

Improve Windows CA handling code
This commit is contained in:
gmadkat 2016-01-27 10:42:30 -05:00
commit 9d7fcba575
1 changed files with 90 additions and 83 deletions

View File

@ -43,14 +43,14 @@
#else #else
#include <winsock2.h> #include <winsock2.h>
#include <iphlpapi.h> #include <iphlpapi.h>
typedef unsigned short in_port_t; typedef unsigned short in_port_t;
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/bio.h> #include <openssl/bio.h>
#include <stdio.h> #include <stdio.h>
#include <windows.h> #include <windows.h>
#include <Wincrypt.h> #include <Wincrypt.h>
#endif #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. // For windows, the CA trust store is not read by openssl.
// Add code to open the trust store using wincrypt API and add // Add code to open the trust store using wincrypt API and add
// the root certs into openssl trust store // the root certs into openssl trust store
X509_STORE *store; static int
X509_STORE_CTX *sslctx = NULL; add_WIN_cacerts_to_openssl_store(SSL_CTX *tls_ctx)
void add_cacerts_to_openssl_store(struct getdns_context *context)
{ {
HCERTSTORE hSystemStore; HCERTSTORE hSystemStore;
PCCERT_CONTEXT pTargetCert = NULL; PCCERT_CONTEXT pTargetCert = NULL;
// Call wincrypt's CertOpenStore to open the CA root store. if !(tls_ctx)
return 1;
if ((hSystemStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM, // Call wincrypt's CertOpenStore to open the CA root store.
0,
NULL, if ((hSystemStore = CertOpenStore(
// mingw does not have this const: replace with 1 << 16 from code CERT_STORE_PROV_SYSTEM,
// CERT_SYSTEM_STORE_CURRENT_USER, 0,
1 << 16, NULL,
L"root")) == 0) // mingw does not have this const: replace with 1 << 16 from code
{ // CERT_SYSTEM_STORE_CURRENT_USER,
DEBUG_STUB("*** %s(CertOpenStore failed)\n", __FUNCTION__); 1 << 16,
return; L"root")) == 0)
} {
store = SSL_CTX_get_cert_store(context->tls_ctx); return 1;
}
// iterate over the windows cert store and add to openssl store
while (pTargetCert = CertEnumCertificatesInStore( X509_STORE *store = SSL_CTX_get_cert_store(tls_ctx);
hSystemStore, if (!store)
pTargetCert)) return 1;
{
BYTE* cert = pTargetCert->pbCertEncoded; // iterate over the windows cert store and add to openssl store
X509 *cert1 = d2i_X509(NULL, (const unsigned char **)&pTargetCert->pbCertEncoded, pTargetCert->cbCertEncoded); while (pTargetCert = CertEnumCertificatesInStore(
if (!cert1) { hSystemStore,
DEBUG_STUB("*** %s(%s)\n", __FUNCTION__, pTargetCert))
"unable to parse certificate in memory"); {
} BYTE* cert = pTargetCert->pbCertEncoded;
else { X509 *cert1 = d2i_X509(NULL, (const unsigned char **)&pTargetCert->pbCertEncoded, pTargetCert->cbCertEncoded);
if (X509_STORE_add_cert(store, cert1) == 0) if (!cert1)
DEBUG_STUB("*** %s(%s)\n", __FUNCTION__, return 1;
"error adding certificate"); else {
X509_free(cert1); if (X509_STORE_add_cert(store, cert1) == 0)
} return 1;
} X509_free(cert1);
// Clean up memory and quit. }
}
if (pTargetCert)
CertFreeCertificateContext(pTargetCert); // Clean up memory and quit.
if (hSystemStore) if (pTargetCert)
{ CertFreeCertificateContext(pTargetCert);
if (!CertCloseStore( if (hSystemStore)
hSystemStore, 0)) {
DEBUG_STUB("*** %s(%s)\n", __FUNCTION__, "CertCloseStore failed"); if (!CertCloseStore(
} hSystemStore, 0))
return 1;
}
return 0;
} }
#endif #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 */ /* Transport can in theory be set per query in stub mode */
if (context->resolution_type == GETDNS_RESOLUTION_STUB && if (context->resolution_type == GETDNS_RESOLUTION_STUB &&
tls_is_in_transports_list(context) == 1) { tls_is_in_transports_list(context) == 1) {
if (context->tls_ctx == NULL) { /* Check minimum require authentication level*/
#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
}
if (tls_only_is_in_transports_list(context) == 1 && if (tls_only_is_in_transports_list(context) == 1 &&
context->tls_auth == GETDNS_AUTHENTICATION_REQUIRED) { context->tls_auth == GETDNS_AUTHENTICATION_REQUIRED) {
context->tls_auth_min = GETDNS_AUTHENTICATION_REQUIRED; context->tls_auth_min = GETDNS_AUTHENTICATION_REQUIRED;
@ -2724,6 +2702,35 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context,
else { else {
context->tls_auth_min = GETDNS_AUTHENTICATION_NONE; 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 */ /* Block use of TLS ONLY in recursive mode as it won't work */