Changeset: 07883ebf5747 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/07883ebf5747
Added Files:
        common/stream/openssl_stream.c
Modified Files:
        clients/mapilib/connect_openssl.c
        common/stream/CMakeLists.txt
        common/stream/stream.h
Branch: monetdburl
Log Message:

Complete the TLS handshake, openssl_stream not yet implemented


diffs (truncated from 303 to 300 lines):

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,36 +11,6 @@
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 
-typedef struct ssl_state {
-       SOCKET socket;
-       SSL_CTX *ctx;
-       SSL *ssl;
-} ssl_state;
-
-static ssl_state*
-create_ssl_state(void)
-{
-       ssl_state *st = malloc(sizeof(*st));
-       if (st == NULL)
-               return NULL;
-       *st = (ssl_state) {
-               .socket = INVALID_SOCKET,
-       };
-       return st;
-}
-
-static void
-destroy_ssl_state(struct ssl_state *st)
-{
-       if (st) {
-               if (st->socket != INVALID_SOCKET)
-                       closesocket(st->socket);
-               if (st->ctx != NULL)
-                       SSL_CTX_free(st->ctx);
-       }
-       free(st);
-}
-
 static MapiMsg croak(Mapi mid, const char *action, const char *fmt, ...)
        __attribute__(( __format__(__printf__, 3, 4) ));
 static MapiMsg
@@ -59,101 +29,156 @@ croak(Mapi mid, const char *action, cons
                : ERR_reason_error_string(err);
        if (errmsg)
                return mapi_printError(mid, action, MERROR, "TLS error: %s: 
%s", buffer, errmsg);
+       else if (err != 0)
+               return mapi_printError(mid, action, MERROR, "TLS error: %s: 
failed with error %lu (0x%lx)", buffer, err, err);
        else
-               return mapi_printError(mid, action, MERROR, "TLS error: %s: 
failed with error %lu (0x%lx)", buffer, err, err);
+               return mapi_printError(mid, action, MERROR, "TLS error: %s", 
buffer);
 }
 
 static MapiMsg
-perform_handshake(Mapi mid, ssl_state *state, SOCKET sock)
+make_ssl_context(Mapi mid, SSL_CTX **ctx_out)
 {
-       // Based on the example on the OpenSSL wiki:
-       // https://wiki.openssl.org/index.php/SSL/TLS_Client
-       const msettings *settings = mid->settings;
+       // Today we just create a new one but if we load the system trust store
+       // the result could be cached for a while.
+       // (What's a reasonable amount of time for a process to pick up changes 
to
+       // the system trust store?)
 
-       // Clear any earlier errrors
-       do {} while (ERR_get_error() != 0);
-
-       /////////////////////////////////////////////////////////////////////
-       // Set up the context
+       *ctx_out = NULL;
 
        const SSL_METHOD *method = TLS_method();
        if (!method)
                return croak(mid, __func__, "TLS_method");
-       SSL_CTX *ctx = state->ctx = SSL_CTX_new(method);
+       SSL_CTX *ctx = SSL_CTX_new(method);
        if (!ctx)
                return croak(mid, __func__, "SSL_CTX_new");
+       // From here on we need to free 'ctx' on failure
 
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
-       // SSL_CTX_set_verify_depth: why change the default?
        SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
        SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
        // Because we use at least TLSv1.3 we don't need to mess with
        // SSL_CTX_set_cipher_list() and SSL_CTX_set_ciphersuites().
 
-       switch (msettings_connect_tls_verify(settings)) {
+       switch (msettings_connect_tls_verify(mid->settings)) {
                case verify_none:
                case verify_hash:
                        SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
                        break;
                case verify_cert:
-                       const char *cert = msetting_string(settings, MP_CERT);
-                       if (1 != SSL_CTX_load_verify_file(ctx, cert))
+                       const char *cert = msetting_string(mid->settings, 
MP_CERT);
+                       if (1 != SSL_CTX_load_verify_file(ctx, cert)) {
+                               SSL_CTX_free(ctx);
                                return croak(mid, __func__, 
"SSL_CTX_load_verify_file: %s", cert);
+                       }
                        break;
                case verify_system:
-                       if (1 != SSL_CTX_set_default_verify_paths(ctx))
+                       if (1 != SSL_CTX_set_default_verify_paths(ctx)) {
+                               SSL_CTX_free(ctx);
                                return croak(mid, __func__, 
"SSL_CTX_set_default_verify_paths");
+                       }
                        break;
        }
 
+       *ctx_out = ctx;
+       return MOK;
+}
+
+MapiMsg
+wrap_tls(Mapi mid, SOCKET sock)
+{
+       // Based on the example on the OpenSSL wiki:
+       // https://wiki.openssl.org/index.php/SSL/TLS_Client
+
+       // On error: close 'sock'.
+
+       MapiMsg msg = MOK;
+       const msettings *settings = mid->settings;
+
+       // Clear any earlier errrors
+       do {} while (ERR_get_error() != 0);
+
+       SSL_CTX *ctx = NULL;
+       msg = make_ssl_context(mid, &ctx);
+       if (msg != MOK) {
+               closesocket(sock);
+               return msg;
+       }
+       // On error: close 'sock' and free 'ctx'.
+
        /////////////////////////////////////////////////////////////////////
        // Create the SSL connection
 
-       SSL *ssl = state->ssl = SSL_new(ctx);
+       SSL *ssl = SSL_new(ctx);
        if (ssl == NULL) {
+               closesocket(sock);
+               SSL_CTX_free(ctx);
                return croak(mid, __func__, "SSL_new");
        }
+       // SSL_new has inc'd the refcount of ctx. We can now drop our ref
+       // so we don't have to call SSL_CTX_free all the time
+       SSL_CTX_free(ctx);
+       // On error: close 'sock' and free 'ssl'.
 
-       BIO *bio = BIO_new_socket(sock, BIO_NOCLOSE);
-       if (bio == NULL)
+       BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
+       if (bio == NULL) {
+               closesocket(sock);
+               SSL_free(ssl);
                return croak(mid, __func__, "BIO_new_socket");
+       }
+       // From here on, 'sock' will be free'd by 'bio'.
+       // On error: free 'bio' and free 'ssl'.
+
        if (!BIO_up_ref(bio)) {
                BIO_free_all(bio);
+               SSL_free(ssl);
                return croak(mid, __func__, "BIO_up_ref");
        }
        SSL_set0_rbio(ssl, bio); // consumes first ref
        SSL_set0_wbio(ssl, bio); // consumes second ref
        // from here on 'bio' will be freed through 'ssl'.
+       // On error: free 'ssl'.
 
        const char *hostname = msettings_connect_tcp(settings);
-       if (!SSL_set_tlsext_host_name(ssl, hostname))
+       if (!SSL_set_tlsext_host_name(ssl, hostname)) {
+               SSL_free(ssl);
                return croak(mid, __func__, "SSL_set_tlsext_host_name");
-
-       if (1 != SSL_connect(ssl))
-               return croak(mid, __func__, "SSL_connect");
-
+       }
 
-       return mapi_setError(mid, "that's how far we get", __func__, MERROR);
-}
-
-
-MapiMsg
-wrap_tls(Mapi mid, SOCKET sock)
-{
-       ssl_state *state = create_ssl_state();
-       if (!state) {
-               mapi_setError(mid, "malloc failed", __func__, MERROR);
-               goto bailout;
+       // handshake
+       if (1 != SSL_connect(ssl)) {
+               SSL_free(ssl);
+               return croak(mid, __func__, "SSL_connect");
        }
 
-       if (perform_handshake(mid, state, sock) != MOK)
-               goto bailout;
-
-
-       return mapi_setError(mid, "it's still a work in progress", __func__, 
MERROR);
+       /////////////////////////////////////////////////////////////////////
+       // Attach the connection to 'mid'
 
-bailout:
-       assert(mid->error != MOK);
-       destroy_ssl_state(state);
-       return mid->error;
+       if (!SSL_up_ref(ssl)) {
+               SSL_free(ssl);
+               return croak(mid, __func__, "SSL_up_ref");
+       }
+       // On error: free 'ssl' twice
+       stream *rstream = openssl_stream(ssl);
+       if (rstream == NULL || mnstr_errnr(rstream) != MNSTR_NO__ERROR) {
+               SSL_free(ssl); // drops first ref
+               SSL_free(ssl); // drops second ref
+               return croak(mid, __func__, "openssl_stream: %s", 
mnstr_peek_error(rstream));
+       }
+       // On error: free 'ssl' and close 'rstream'.
+       stream *wstream = openssl_stream(ssl);
+       if (wstream == NULL || mnstr_errnr(wstream) != MNSTR_NO__ERROR) {
+               mnstr_close(rstream);
+               SSL_free(ssl);
+               return croak(mid, __func__, "openssl_stream: %s", 
mnstr_peek_error(wstream));
+       }
+       // On error: free 'rstream' and 'wstream'.
+       msg = mapi_set_streams(mid, rstream, wstream);
+       if (msg != MOK) {
+               mnstr_close(rstream);
+               mnstr_close(wstream);
+               return msg;
+       }
+       // 'rstream' and 'wstream' are part of 'mid' now.
+
+       return MOK;
 }
diff --git a/common/stream/CMakeLists.txt b/common/stream/CMakeLists.txt
--- a/common/stream/CMakeLists.txt
+++ b/common/stream/CMakeLists.txt
@@ -39,6 +39,7 @@ target_sources(stream
   fwf.c
   iconv_stream.c
   text_stream.c
+  $<$<BOOL:${HAVE_OPENSSL}>:openssl_stream.c>
   pump.c
   stream.h
   stream_internal.h
diff --git a/common/stream/openssl_stream.c b/common/stream/openssl_stream.c
new file mode 100644
--- /dev/null
+++ b/common/stream/openssl_stream.c
@@ -0,0 +1,21 @@
+/*
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0.  If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright 1997 - July 2008 CWI, August 2008 - 2023 MonetDB B.V.
+ */
+
+#include "monetdb_config.h"
+#include "stream.h"
+#include "stream_internal.h"
+
+stream *
+openssl_stream(SSL *ssl)
+{
+       (void)ssl;
+       mnstr_set_open_error(NULL, 0, "not implemented yet");
+       return NULL;
+}
diff --git a/common/stream/stream.h b/common/stream/stream.h
--- a/common/stream/stream.h
+++ b/common/stream/stream.h
@@ -31,6 +31,11 @@
 #include <signal.h>
 #include <limits.h>
 
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#endif
+
+
 /* avoid using "#ifdef WIN32" so that this file does not need our config.h */
 #if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)
 # ifndef LIBSTREAM
@@ -272,5 +277,9 @@ stream_export stream *mapi_request_downl
 // write-only
 stream_export stream *byte_counting_stream(stream *wrapped, uint64_t *counter);
 
+#ifdef HAVE_OPENSSL
+stream_export stream *openssl_stream(SSL *ssl);
+#endif
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to