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

Reply via email to