s4:lib/tls: split out tstream_tls_prepare_gnutls()
authorStefan Metzmacher <metze@samba.org>
Mon, 12 Feb 2024 11:35:02 +0000 (12:35 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Apr 2024 23:50:33 +0000 (23:50 +0000)
Review with: git show --patience

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15621

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/lib/tls/tls_tstream.c
source4/lib/tls/wscript_build

index 347c47ed48eb14bdd30c258a371e61dce461f80b..9a69a0154032efd4233b5f65a8f885e29067ef68 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
+#include "lib/crypto/gnutls_helpers.h"
 
 #define DH_BITS 2048
 
@@ -63,6 +64,8 @@ struct tstream_tls {
 
        gnutls_session_t tls_session;
 
+       bool is_server;
+
        enum tls_verify_peer_state verify_peer;
        const char *peer_name;
 
@@ -983,40 +986,28 @@ NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
-struct tstream_tls_connect_state {
-       struct tstream_context *tls_stream;
-};
-
-struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
-                                            struct tevent_context *ev,
-                                            struct tstream_context *plain_stream,
-                                            struct tstream_tls_params *_tls_params,
-                                            const char *location)
+static NTSTATUS tstream_tls_prepare_gnutls(struct tstream_tls_params *_tlsp,
+                                          struct tstream_tls *tlss)
 {
-       struct tevent_req *req;
-       struct tstream_tls_connect_state *state;
-       const char *error_pos;
-       struct tstream_tls *tlss;
-       struct tstream_tls_params_internal *tls_params = NULL;
+       struct tstream_tls_params_internal *tlsp = NULL;
        int ret;
-       unsigned int flags = GNUTLS_CLIENT;
-
-       req = tevent_req_create(mem_ctx, &state,
-                               struct tstream_tls_connect_state);
-       if (req == NULL) {
-               return NULL;
-       }
+       unsigned int flags;
 
-       state->tls_stream = tstream_context_create(state,
-                                                  &tstream_tls_ops,
-                                                  &tlss,
-                                                  struct tstream_tls,
-                                                  location);
-       if (tevent_req_nomem(state->tls_stream, req)) {
-               return tevent_req_post(req, ev);
+       if (tlss->is_server) {
+               flags = GNUTLS_SERVER;
+       } else {
+               flags = GNUTLS_CLIENT;
+#ifdef GNUTLS_NO_TICKETS
+               /*
+                * tls_tstream can't properly handle 'New Session Ticket'
+                * messages sent 'after' the client sends the 'Finished'
+                * message.  GNUTLS_NO_TICKETS was introduced in GnuTLS 3.5.6.
+                * This flag is to indicate the session Flag session should not
+                * use resumption with session tickets.
+                */
+               flags |= GNUTLS_NO_TICKETS;
+#endif
        }
-       ZERO_STRUCTP(tlss);
-       talloc_set_destructor(tlss, tstream_tls_destructor);
 
        /*
         * Note we need to make sure x509_cred and dh_params
@@ -1028,71 +1019,109 @@ struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
         *
         * Note: here we use talloc_reference() in a way
         *       that does not expose it to the caller.
-        *
         */
-       tls_params = talloc_reference(tlss, _tls_params->internal);
-       if (tevent_req_nomem(tls_params, req)) {
-               return tevent_req_post(req, ev);
+       tlsp = talloc_reference(tlss, _tlsp->internal);
+       if (tlsp == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
 
-       tlss->plain_stream = plain_stream;
-       tlss->verify_peer = tls_params->verify_peer;
-       if (tls_params->peer_name != NULL) {
-               tlss->peer_name = talloc_strdup(tlss, tls_params->peer_name);
-               if (tevent_req_nomem(tlss->peer_name, req)) {
-                       return tevent_req_post(req, ev);
+       tlss->verify_peer = tlsp->verify_peer;
+       if (tlsp->peer_name != NULL) {
+               tlss->peer_name = talloc_strdup(tlss, tlsp->peer_name);
+               if (tlss->peer_name == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
        }
 
-       tlss->current_ev = ev;
-       tlss->retry_im = tevent_create_immediate(tlss);
-       if (tevent_req_nomem(tlss->retry_im, req)) {
-               return tevent_req_post(req, ev);
+       if (tlss->current_ev != NULL) {
+               tlss->retry_im = tevent_create_immediate(tlss);
+               if (tlss->retry_im == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
 
-#ifdef GNUTLS_NO_TICKETS
-       /*
-        * tls_tstream can't properly handle 'New Session Ticket' messages
-        * sent 'after' the client sends the 'Finished' message.
-        * GNUTLS_NO_TICKETS was introduced in GnuTLS 3.5.6.  This flag is to
-        * indicate the session Flag session should not use resumption with
-        * session tickets.
-        */
-       flags |= GNUTLS_NO_TICKETS;
-#endif
-
        ret = gnutls_init(&tlss->tls_session, flags);
        if (ret != GNUTLS_E_SUCCESS) {
-               DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
-               tevent_req_error(req, EINVAL);
-               return tevent_req_post(req, ev);
+               return gnutls_error_to_ntstatus(ret,
+                       NT_STATUS_CRYPTO_SYSTEM_INVALID);
        }
 
        ret = gnutls_set_default_priority(tlss->tls_session);
        if (ret != GNUTLS_E_SUCCESS) {
-               DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
-                       __location__, gnutls_strerror(ret));
-               tevent_req_error(req, EINVAL);
-               return tevent_req_post(req, ev);
+               return gnutls_error_to_ntstatus(ret,
+                       NT_STATUS_CRYPTO_SYSTEM_INVALID);
        }
 
-       if (strlen(tls_params->tls_priority) > 0) {
+       if (strlen(tlsp->tls_priority) > 0) {
+               const char *error_pos = NULL;
+
                ret = gnutls_priority_set_direct(tlss->tls_session,
-                                                tls_params->tls_priority,
+                                                tlsp->tls_priority,
                                                 &error_pos);
                if (ret != GNUTLS_E_SUCCESS) {
-                       DEBUG(0,("TLS %s - %s.  Check 'tls priority' option at '%s'\n",
-                                __location__, gnutls_strerror(ret), error_pos));
-                       tevent_req_error(req, EINVAL);
-                       return tevent_req_post(req, ev);
+                       return gnutls_error_to_ntstatus(ret,
+                               NT_STATUS_CRYPTO_SYSTEM_INVALID);
                }
        }
 
        ret = gnutls_credentials_set(tlss->tls_session,
                                     GNUTLS_CRD_CERTIFICATE,
-                                    tls_params->x509_cred);
+                                    tlsp->x509_cred);
        if (ret != GNUTLS_E_SUCCESS) {
-               DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
+               return gnutls_error_to_ntstatus(ret,
+                               NT_STATUS_CRYPTO_SYSTEM_INVALID);
+       }
+
+       if (tlss->is_server) {
+               gnutls_certificate_server_set_request(tlss->tls_session,
+                                                     GNUTLS_CERT_REQUEST);
+               gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
+       }
+
+       return NT_STATUS_OK;
+}
+
+struct tstream_tls_connect_state {
+       struct tstream_context *tls_stream;
+};
+
+struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct tstream_context *plain_stream,
+                                            struct tstream_tls_params *_tls_params,
+                                            const char *location)
+{
+       struct tevent_req *req;
+       struct tstream_tls_connect_state *state;
+       struct tstream_tls *tlss;
+       NTSTATUS status;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct tstream_tls_connect_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->tls_stream = tstream_context_create(state,
+                                                  &tstream_tls_ops,
+                                                  &tlss,
+                                                  struct tstream_tls,
+                                                  location);
+       if (tevent_req_nomem(state->tls_stream, req)) {
+               return tevent_req_post(req, ev);
+       }
+       ZERO_STRUCTP(tlss);
+       talloc_set_destructor(tlss, tstream_tls_destructor);
+       tlss->plain_stream = plain_stream;
+       tlss->is_server = false;
+       tlss->current_ev = ev;
+
+       status = tstream_tls_prepare_gnutls(_tls_params, tlss);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+               tevent_req_oom(req);
+               return tevent_req_post(req, ev);
+       }
+       if (!NT_STATUS_IS_OK(status)) {
                tevent_req_error(req, EINVAL);
                return tevent_req_post(req, ev);
        }
@@ -1313,9 +1342,7 @@ struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *req;
        struct tstream_tls_accept_state *state;
        struct tstream_tls *tlss;
-       const char *error_pos;
-       struct tstream_tls_params_internal *tlsp = NULL;
-       int ret;
+       NTSTATUS status;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct tstream_tls_accept_state);
@@ -1333,70 +1360,20 @@ struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
        }
        ZERO_STRUCTP(tlss);
        talloc_set_destructor(tlss, tstream_tls_destructor);
-
-       /*
-        * Note we need to make sure x509_cred and dh_params
-        * from tstream_tls_params_internal stay alive for
-        * the whole lifetime of this session!
-        *
-        * See 'man gnutls_credentials_set' and
-        * 'man gnutls_certificate_set_dh_params'.
-        *
-        * Note: here we use talloc_reference() in a way
-        *       that does not expose it to the caller.
-        */
-       tlsp = talloc_reference(tlss, _tlsp->internal);
-       if (tevent_req_nomem(tlsp, req)) {
-               return tevent_req_post(req, ev);
-       }
-
        tlss->plain_stream = plain_stream;
-
+       tlss->is_server = true;
        tlss->current_ev = ev;
-       tlss->retry_im = tevent_create_immediate(tlss);
-       if (tevent_req_nomem(tlss->retry_im, req)) {
-               return tevent_req_post(req, ev);
-       }
 
-       ret = gnutls_init(&tlss->tls_session, GNUTLS_SERVER);
-       if (ret != GNUTLS_E_SUCCESS) {
-               DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
-               tevent_req_error(req, EINVAL);
+       status = tstream_tls_prepare_gnutls(_tlsp, tlss);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+               tevent_req_oom(req);
                return tevent_req_post(req, ev);
        }
-
-       ret = gnutls_set_default_priority(tlss->tls_session);
-       if (ret != GNUTLS_E_SUCCESS) {
-               DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
-                       __location__, gnutls_strerror(ret));
+       if (!NT_STATUS_IS_OK(status)) {
                tevent_req_error(req, EINVAL);
                return tevent_req_post(req, ev);
        }
 
-       if (strlen(tlsp->tls_priority) > 0) {
-               ret = gnutls_priority_set_direct(tlss->tls_session,
-                                                tlsp->tls_priority,
-                                                &error_pos);
-               if (ret != GNUTLS_E_SUCCESS) {
-                       DEBUG(0,("TLS %s - %s.  Check 'tls priority' option at '%s'\n",
-                                __location__, gnutls_strerror(ret), error_pos));
-                       tevent_req_error(req, EINVAL);
-                       return tevent_req_post(req, ev);
-               }
-       }
-
-       ret = gnutls_credentials_set(tlss->tls_session, GNUTLS_CRD_CERTIFICATE,
-                                    tlsp->x509_cred);
-       if (ret != GNUTLS_E_SUCCESS) {
-               DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
-               tevent_req_error(req, EINVAL);
-               return tevent_req_post(req, ev);
-       }
-
-       gnutls_certificate_server_set_request(tlss->tls_session,
-                                             GNUTLS_CERT_REQUEST);
-       gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
-
        gnutls_transport_set_ptr(tlss->tls_session,
                                 (gnutls_transport_ptr_t)state->tls_stream);
        gnutls_transport_set_pull_function(tlss->tls_session,
index 7980a633574b8972e990cb0847590db761ed0ae8..8fe77da8489257fbbe7395a323cf7a279ef10084 100644 (file)
@@ -8,6 +8,7 @@ bld.SAMBA_SUBSYSTEM('LIBTLS',
                     public_deps='''
                                 talloc
                                 gnutls
+                                GNUTLS_HELPERS
                                 samba-hostconfig
                                 LIBTSOCKET
                                 tevent