Changeset: 652d00b37663 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/652d00b37663 Added Files: clients/mapilib/openssl_windows.c Modified Files: clients/mapilib/CMakeLists.txt clients/mapilib/connect_openssl.c clients/mapilib/mapi_intern.h Branch: monetdburl Log Message:
Use Windows Crypt API to extract system certificates diffs (290 lines): diff --git a/clients/mapilib/CMakeLists.txt b/clients/mapilib/CMakeLists.txt --- a/clients/mapilib/CMakeLists.txt +++ b/clients/mapilib/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(mapi parseurl.c $<$<BOOL:${HAVE_SYS_UN_H}>:connect_unix.c> $<$<BOOL:${OPENSSL_FOUND}>:connect_openssl.c> + $<$<BOOL:${OPENSSL_FOUND}>:$<$<BOOL:${WIN32}>:openssl_windows.c>> mapi_intern.h PUBLIC $<BUILD_INTERFACE:$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/mapi.h> @@ -46,6 +47,7 @@ target_link_libraries(mapi stream mutils $<$<BOOL:${OPENSSL_FOUND}>:OpenSSL::SSL> + $<$<BOOL:${OPENSSL_FOUND}>:$<$<BOOL:${WIN32}>:crypt32>> $<$<PLATFORM_ID:Windows>:ws2_32>) target_compile_definitions(mapi diff --git a/clients/mapilib/connect_openssl.c b/clients/mapilib/connect_openssl.c --- a/clients/mapilib/connect_openssl.c +++ b/clients/mapilib/connect_openssl.c @@ -11,10 +11,8 @@ #include <openssl/ssl.h> #include <openssl/err.h> -static MapiMsg croak(Mapi mid, const char *action, const char *fmt, ...) - __attribute__(( __format__(__printf__, 3, 4) )); -static MapiMsg -croak(Mapi mid, const char *action, const char *fmt, ...) +MapiMsg +croak_openssl(Mapi mid, const char *action, const char *fmt, ...) { va_list ap; char buffer[800]; @@ -38,6 +36,16 @@ croak(Mapi mid, const char *action, cons return mapi_printError(mid, action, MERROR, "TLS error: %s", buffer); } +#ifndef NATIVE_WIN32 +MapiMsg +add_system_certificates(Mapi mid, SSL_CTX *ctx) +{ + (void)mid; + (void)ctx; + return MOK; +} +#endif + static MapiMsg make_ssl_context(Mapi mid, SSL_CTX **ctx_out) { @@ -50,10 +58,10 @@ make_ssl_context(Mapi mid, SSL_CTX **ctx const SSL_METHOD *method = TLS_method(); if (!method) - return croak(mid, __func__, "TLS_method"); + return croak_openssl(mid, __func__, "TLS_method"); SSL_CTX *ctx = SSL_CTX_new(method); if (!ctx) - return croak(mid, __func__, "SSL_CTX_new"); + return croak_openssl(mid, __func__, "SSL_CTX_new"); // From here on we need to free 'ctx' on failure SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); @@ -72,13 +80,18 @@ make_ssl_context(Mapi mid, SSL_CTX **ctx cert = msetting_string(mid->settings, MP_CERT); if (1 != SSL_CTX_load_verify_locations(ctx, cert, NULL)) { SSL_CTX_free(ctx); - return croak(mid, __func__, "SSL_CTX_load_verify_file: %s", cert); + return croak_openssl(mid, __func__, "SSL_CTX_load_verify_file: %s", cert); } break; case verify_system: if (1 != SSL_CTX_set_default_verify_paths(ctx)) { SSL_CTX_free(ctx); - return croak(mid, __func__, "SSL_CTX_set_default_verify_paths"); + return croak_openssl(mid, __func__, "SSL_CTX_set_default_verify_paths"); + } + MapiMsg msg = add_system_certificates(mid, ctx); + if (msg != MOK) { + SSL_CTX_free(ctx); + return msg; } break; } @@ -123,7 +136,7 @@ wrap_tls(Mapi mid, SOCKET sock) if (bio == NULL) { closesocket(sock); SSL_CTX_free(ctx); - return croak(mid, __func__, "BIO_new_ssl"); + return croak_openssl(mid, __func__, "BIO_new_ssl"); } // BIO_new_ssl() inc'd the reference count of ctx so we can drop our // reference here. @@ -134,7 +147,7 @@ wrap_tls(Mapi mid, SOCKET sock) if (1 != BIO_get_ssl(bio, &ssl)) { closesocket(sock); BIO_free(bio); - return croak(mid, __func__, "BIO_get_ssl"); + return croak_openssl(mid, __func__, "BIO_get_ssl"); } // As far as I know the SSL returned by BIO_get_ssl has not had // its refcount inc'd so we don't need to free it. @@ -150,7 +163,7 @@ wrap_tls(Mapi mid, SOCKET sock) if (sockbio == NULL) { closesocket(sock); BIO_free_all(bio); - return croak(mid, __func__, "BIO_new_socket"); + return croak_openssl(mid, __func__, "BIO_new_socket"); } // From here on, 'sock' will be free'd by 'sockbio'. // On error: free 'sockbio' and free 'bio'. @@ -158,7 +171,7 @@ wrap_tls(Mapi mid, SOCKET sock) if (!BIO_up_ref(sockbio)) { BIO_free_all(sockbio); BIO_free_all(bio); - return croak(mid, __func__, "BIO_up_ref sockbio"); + return croak_openssl(mid, __func__, "BIO_up_ref sockbio"); } SSL_set0_rbio(ssl, sockbio); // consumes first ref SSL_set0_wbio(ssl, sockbio); // consumes second ref @@ -167,13 +180,13 @@ wrap_tls(Mapi mid, SOCKET sock) if (!SSL_set_tlsext_host_name(ssl, host)) { BIO_free_all(bio); - return croak(mid, __func__, "SSL_set_tlsext_host_name"); + return croak_openssl(mid, __func__, "SSL_set_tlsext_host_name"); } // handshake if (1 != SSL_connect(ssl)) { BIO_free_all(bio); - return croak(mid, __func__, "SSL_connect"); + return croak_openssl(mid, __func__, "SSL_connect"); } ///////////////////////////////////////////////////////////////////// @@ -181,7 +194,7 @@ wrap_tls(Mapi mid, SOCKET sock) if (!BIO_up_ref(bio)) { BIO_free_all(bio); - return croak(mid, __func__, "BIO_up_ref bio"); + return croak_openssl(mid, __func__, "BIO_up_ref bio"); } // On error: free 'bio' twice @@ -194,7 +207,7 @@ wrap_tls(Mapi mid, SOCKET sock) BIO_free_all(bio); // drops first ref BIO_free_all(bio); // drops second ref free(hostcolonport); - return croak(mid, __func__, "openssl_rstream: %s", mnstr_peek_error(rstream)); + return croak_openssl(mid, __func__, "openssl_rstream: %s", mnstr_peek_error(rstream)); } // On error: free 'bio' and close 'rstream'. stream *wstream = openssl_wstream(hostcolonport ? hostcolonport : "ssl wstream", bio); @@ -202,7 +215,7 @@ wrap_tls(Mapi mid, SOCKET sock) if (wstream == NULL || mnstr_errnr(wstream) != MNSTR_NO__ERROR) { BIO_free_all(bio); mnstr_close(rstream); - return croak(mid, __func__, "openssl_wstream: %s", mnstr_peek_error(wstream)); + return croak_openssl(mid, __func__, "openssl_wstream: %s", mnstr_peek_error(wstream)); } // On error: free 'rstream' and 'wstream'. msg = mapi_wrap_streams(mid, rstream, wstream); diff --git a/clients/mapilib/mapi_intern.h b/clients/mapilib/mapi_intern.h --- a/clients/mapilib/mapi_intern.h +++ b/clients/mapilib/mapi_intern.h @@ -44,6 +44,11 @@ # include <sys/time.h> /* gettimeofday */ #endif +#ifdef HAVE_OPENSSL +#include <openssl/ssl.h> +#endif + + /* Copied from gdk_posix, but without taking a lock because we don't have access to * MT_lock_set/unset here. We just have to hope for the best */ @@ -312,3 +317,10 @@ MapiMsg wrap_socket(Mapi mid, SOCKET soc void close_connection(Mapi mid); void set_uri(Mapi mid); + +#ifdef HAVE_OPENSSL +MapiMsg croak_openssl(Mapi mid, const char *action, const char *fmt, ...) + __attribute__(( __format__(__printf__, 3, 4) )); + +MapiMsg add_system_certificates(Mapi mid, SSL_CTX *ctx); +#endif diff --git a/clients/mapilib/openssl_windows.c b/clients/mapilib/openssl_windows.c new file mode 100644 --- /dev/null +++ b/clients/mapilib/openssl_windows.c @@ -0,0 +1,94 @@ +#include "monetdb_config.h" + +#include "stream.h" +#include "mapi.h" +#include "mapi_intern.h" + +#include <wincrypt.h> + +MapiMsg +croak_win32(Mapi mid, const char *action, DWORD error) +{ + return mapi_printError(mid, action, MERROR, "System Error #%d", error); +} + +static MapiMsg +process_sysstore_item(Mapi mid, X509_STORE *x509_store, int nr, const CERT_CONTEXT *item) +{ + DWORD typ = item->dwCertEncodingType; + const unsigned char *data = item->pbCertEncoded; + size_t size = item->cbCertEncoded; + + bool is_x509 = (typ & X509_ASN_ENCODING); + bool is_pkcs7 = (typ & PKCS_7_ASN_ENCODING); + mapi_log_record( + mid, "CONN", "Processing item #%d of type %lu [%s%s], size %zu", + nr, + typ, (is_x509 ? "X" : ""), (is_pkcs7 ? "P" : ""), + size + ); + + if (!is_x509) + return mapi_printError(mid, __func__, MERROR, "sys store certificate #%d must be in X509 format", nr); + + X509 *x509 = d2i_X509(NULL, &data, (long)size); + if (!x509) + return croak_openssl(mid, __func__, "sys store certificate #%d: d2i_X509"); + + MapiMsg msg; + if (1 == X509_STORE_add_cert(x509_store, x509)) { + msg = MOK; + } else { + msg = mapi_printError(mid, __func__, MERROR, "sys store certificate #%d: X509_STORE_add_cert"); + } + X509_free(x509); + + return msg; +} + +MapiMsg +add_system_certificates(Mapi mid, SSL_CTX *ctx) +{ + MapiMsg msg; + X509_STORE *x509_store = SSL_CTX_get_cert_store(ctx); + HCERTSTORE sysstore = NULL; + const CERT_CONTEXT *item = NULL; + + mapi_log_record(mid, "CONN", "Enumerating system certificates"); + + sysstore = CertOpenSystemStoreW(0, L"ROOT"); + if (!sysstore) + return croak_win32(mid, __func__, GetLastError()); + + int count = 0; + while (1) { + item = CertEnumCertificatesInStore(sysstore, item); + if (item == NULL) + break; + msg = process_sysstore_item(mid, x509_store, ++count, item); + if (msg != MOK) { + CertFreeCertificateContext(item); + CertCloseStore(sysstore, 0); + return msg; + } + } + + // We get here if CertEnumCertificatesInStore returned NULL. + DWORD error = GetLastError(); + assert(item == NULL); + CertCloseStore(sysstore, 0); + switch (error) { + case 0: + case CRYPT_E_NOT_FOUND: + case ERROR_NO_MORE_FILES: + // Normal exit codes according to the documentation at + // https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certenumcertificatesinstore + mapi_log_record(mid, "CONN", "Added %d certificates", count); + return MOK; + default: + // Anything else is problematic + return croak_win32(mid, __func__, error); + } +} + + _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org