From: Wouter Wijngaards Date: Mon, 28 May 2018 13:22:10 +0000 (+0000) Subject: - Add routine from getdns to add windows cert store to the SSL_CTX. X-Git-Tag: release-1.7.2rc1~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a726fb61f1def4d17baabfcfe4f829f3c024590;p=thirdparty%2Funbound.git - Add routine from getdns to add windows cert store to the SSL_CTX. git-svn-id: file:///svn/unbound/trunk@4697 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/configure b/configure index 45cb7198d..3f38929d8 100755 --- a/configure +++ b/configure @@ -19468,7 +19468,7 @@ else WINDRES="$ac_cv_prog_WINDRES" fi - LIBS="$LIBS -liphlpapi" + LIBS="$LIBS -liphlpapi -lcrypt32" WINAPPS="unbound-service-install.exe unbound-service-remove.exe anchor-update.exe" WIN_DAEMON_SRC="winrc/win_svc.c winrc/w_inst.c" diff --git a/configure.ac b/configure.ac index 35a1096eb..b4c484ec9 100644 --- a/configure.ac +++ b/configure.ac @@ -1246,7 +1246,7 @@ if test "$USE_WINSOCK" = 1; then #include ]) AC_CHECK_TOOL(WINDRES, windres) - LIBS="$LIBS -liphlpapi" + LIBS="$LIBS -liphlpapi -lcrypt32" WINAPPS="unbound-service-install.exe unbound-service-remove.exe anchor-update.exe" AC_SUBST(WINAPPS) WIN_DAEMON_SRC="winrc/win_svc.c winrc/w_inst.c" diff --git a/daemon/unbound.c b/daemon/unbound.c index e4caf0048..138311013 100644 --- a/daemon/unbound.c +++ b/daemon/unbound.c @@ -431,7 +431,7 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, fatal_exit("could not set up listen SSL_CTX"); } if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, - cfg->tls_cert_bundle))) + cfg->tls_cert_bundle, cfg->tls_win_cert))) fatal_exit("could not set up connect SSL_CTX"); #endif diff --git a/doc/Changelog b/doc/Changelog index 84e3fac6d..fe1310f98 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,5 +1,6 @@ 28 May 2018: Wouter - Fix windows tcp and tls spin on events. + - Add routine from getdns to add windows cert store to the SSL_CTX. 25 May 2018: Wouter - For TCP and TLS connections that don't establish, perform address diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 4aa9656af..3dcaa7818 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -158,9 +158,9 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) hints_delete(w->env->hints); w->env->hints = NULL; } - if(cfg->ssl_upstream || (cfg->tls_cert_bundle && cfg->tls_cert_bundle[0])) { + if(cfg->ssl_upstream || (cfg->tls_cert_bundle && cfg->tls_cert_bundle[0]) || cfg->tls_win_cert) { w->sslctx = connect_sslctx_create(NULL, NULL, - cfg->tls_cert_bundle); + cfg->tls_cert_bundle, cfg->tls_win_cert); if(!w->sslctx) { /* to make the setup fail after unlock */ hints_delete(w->env->hints); diff --git a/testcode/streamtcp.c b/testcode/streamtcp.c index b494507de..0a636395f 100644 --- a/testcode/streamtcp.c +++ b/testcode/streamtcp.c @@ -284,7 +284,7 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int num, char** qs) SSL* ssl = NULL; if(!buf) fatal_exit("out of memory"); if(usessl) { - ctx = connect_sslctx_create(NULL, NULL, NULL); + ctx = connect_sslctx_create(NULL, NULL, NULL, 0); if(!ctx) fatal_exit("cannot create ssl ctx"); ssl = outgoing_ssl_fd(ctx, fd); if(!ssl) fatal_exit("cannot create ssl"); diff --git a/util/config_file.c b/util/config_file.c index be9027134..9f623533f 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -109,6 +109,7 @@ config_create(void) cfg->ssl_port = UNBOUND_DNS_OVER_TLS_PORT; cfg->ssl_upstream = 0; cfg->tls_cert_bundle = NULL; + cfg->tls_win_cert = 0; cfg->use_syslog = 1; cfg->log_identity = NULL; /* changed later with argv[0] */ cfg->log_time_ascii = 0; diff --git a/util/config_file.h b/util/config_file.h index 2b49d9c6e..0473b2acf 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -102,6 +102,8 @@ struct config_file { int ssl_upstream; /** cert bundle for outgoing connections */ char* tls_cert_bundle; + /** should the system certificate store get added to the cert bundle */ + int tls_win_cert; /** additional tls ports */ struct config_strlist* additional_tls_port; diff --git a/util/net_help.c b/util/net_help.c index 40bfefb64..a5059b0ad 100644 --- a/util/net_help.c +++ b/util/net_help.c @@ -52,6 +52,9 @@ #ifdef HAVE_OPENSSL_ERR_H #include #endif +#ifdef USE_WINSOCK +#include +#endif /** max length of an IP address (the address portion) that we allow */ #define MAX_ADDR_STRLEN 128 /* characters */ @@ -796,7 +799,97 @@ void* listen_sslctx_create(char* key, char* pem, char* verifypem) #endif } -void* connect_sslctx_create(char* key, char* pem, char* verifypem) +#ifdef USE_WINSOCK +/* 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 */ +static int +add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx) +{ + HCERTSTORE hSystemStore; + PCCERT_CONTEXT pTargetCert = NULL; + X509_STORE* store; + + verbose(VERB_ALGO, "Adding Windows certificates from system root store to CA store"); + + /* load just once per context lifetime for this version + TODO: dynamically update CA trust changes as they are available */ + if (!tls_ctx) + return 0; + + /* Call wincrypt's CertOpenStore to open the CA root store. */ + + if ((hSystemStore = CertOpenStore( + CERT_STORE_PROV_SYSTEM, + 0, + 0, + /* NOTE: mingw does not have this const: replace with 1 << 16 from code + CERT_SYSTEM_STORE_CURRENT_USER, */ + 1 << 16, + L"root")) == 0) + { + return 0; + } + + store = SSL_CTX_get_cert_store(tls_ctx); + if (!store) + return 0; + + /* failure if the CA store is empty or the call fails */ + if ((pTargetCert = CertEnumCertificatesInStore( + hSystemStore, pTargetCert)) == 0) { + verbose(VERB_ALGO, "CA certificate store for Windows is empty."); + return 0; + } + /* iterate over the windows cert store and add to openssl store */ + do + { + X509 *cert1 = d2i_X509(NULL, + (const unsigned char **)&pTargetCert->pbCertEncoded, + pTargetCert->cbCertEncoded); + if (!cert1) { + /* return error if a cert fails */ + verbose(VERB_ALGO, "%s %d:%s", + "Unable to parse certificate in memory", + (int)ERR_get_error(), ERR_error_string(ERR_get_error(), NULL)); + return 0; + } + else { + /* return error if a cert add to store fails */ + if (X509_STORE_add_cert(store, cert1) == 0) { + unsigned long error = ERR_peek_last_error(); + + /* Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the + * certificate is already in the store. */ + if(ERR_GET_LIB(error) != ERR_LIB_X509 || + ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { + verbose(VERB_ALGO, "%s %d:%s\n", + "Error adding certificate", (int)ERR_get_error(), + ERR_error_string(ERR_get_error(), NULL)); + X509_free(cert1); + return 0; + } + } + X509_free(cert1); + } + } while ((pTargetCert = CertEnumCertificatesInStore( + hSystemStore, pTargetCert)) != 0); + + /* Clean up memory and quit. */ + if (pTargetCert) + CertFreeCertificateContext(pTargetCert); + if (hSystemStore) + { + if (!CertCloseStore( + hSystemStore, 0)) + return 0; + } + verbose(VERB_ALGO, "Completed adding Windows certificates to CA store successfully"); + return 1; +} +#endif /* USE_WINSOCK */ + +void* connect_sslctx_create(char* key, char* pem, char* verifypem, int wincert) { #ifdef HAVE_SSL SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method()); @@ -836,17 +929,30 @@ void* connect_sslctx_create(char* key, char* pem, char* verifypem) return NULL; } } - if(verifypem && verifypem[0]) { - if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { - log_crypto_err("error in SSL_CTX verify"); - SSL_CTX_free(ctx); - return NULL; + if((verifypem && verifypem[0]) || wincert) { + if(verifypem && verifypem[0]) { + if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { + log_crypto_err("error in SSL_CTX verify"); + SSL_CTX_free(ctx); + return NULL; + } + } +#ifdef USE_WINSOCK + if(wincert) { + if(!add_WIN_cacerts_to_openssl_store(ctx)) { + log_crypto_err("error in add_WIN_cacerts_to_openssl_store"); + SSL_CTX_free(ctx); + return NULL; + } } +#else + (void)wincert; +#endif SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); } return ctx; #else - (void)key; (void)pem; (void)verifypem; + (void)key; (void)pem; (void)verifypem; (void)wincert; return NULL; #endif } diff --git a/util/net_help.h b/util/net_help.h index 1ecb13999..de2e1accf 100644 --- a/util/net_help.h +++ b/util/net_help.h @@ -395,9 +395,11 @@ void* listen_sslctx_create(char* key, char* pem, char* verifypem); * @param key: if nonNULL (also pem nonNULL), the client private key. * @param pem: client public key (or NULL if key is NULL). * @param verifypem: if nonNULL used for verifylocation file. + * @param wincert: add system certificate store to ctx (add to verifypem ca + * certs). * @return SSL_CTX* or NULL on failure (logged). */ -void* connect_sslctx_create(char* key, char* pem, char* verifypem); +void* connect_sslctx_create(char* key, char* pem, char* verifypem, int wincert); /** * accept a new fd and wrap it in a BIO in SSL diff --git a/winrc/win_svc.c b/winrc/win_svc.c index c5082ac3d..a87d73bf1 100644 --- a/winrc/win_svc.c +++ b/winrc/win_svc.c @@ -364,7 +364,7 @@ service_init(int r, struct daemon** d, struct config_file** c) fatal_exit("could not set up listen SSL_CTX"); } if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, - cfg->tls_cert_bundle))) + cfg->tls_cert_bundle, cfg->tls_win_cert))) fatal_exit("could not set up connect SSL_CTX"); /* open ports */