Improve Windows CA handling code

This commit is contained in:
Sara Dickinson 2016-01-27 12:50:16 +00:00
parent 7e9563faed
commit 111794158c
1 changed files with 90 additions and 83 deletions

View File

@ -43,14 +43,14 @@
#else
#include <winsock2.h>
#include <iphlpapi.h>
typedef unsigned short in_port_t;
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <stdio.h>
#include <windows.h>
typedef unsigned short in_port_t;
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#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 */