s4:lib/tls: add tstream_tls_channel_bindings()
authorStefan Metzmacher <metze@samba.org>
Thu, 28 Sep 2023 10:34:35 +0000 (12:34 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Apr 2024 23:50:33 +0000 (23:50 +0000)
This is based on GNUTLS_CB_TLS_SERVER_END_POINT
and is the value that is required for channel bindings
in LDAP of active directory domain controllers.

For gnutls versions before 3.7.2 we basically
copied the code from the GNUTLS_CB_TLS_SERVER_END_POINT
implementation as it only uses public gnutls functions
and it was easy to re-implement.

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.h
source4/lib/tls/tls_tstream.c

index 5634cce516c2d065c5b4667ed535fcd12c36f6bf..03063204e853f4150c9869eb89ade8d64d798c74 100644 (file)
@@ -81,6 +81,8 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
 
 bool tstream_tls_params_enabled(struct tstream_tls_params *params);
 
+const DATA_BLOB *tstream_tls_channel_bindings(struct tstream_context *tls_tstream);
+
 struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
                                             struct tevent_context *ev,
                                             struct tstream_context *plain_stream,
index 42b43020b4d377e39bf084a7fa8e2e273f19d04d..f6ba7bdc1d255774688af9d7b401d0708d8e9b69 100644 (file)
@@ -70,6 +70,8 @@ struct tstream_tls {
        enum tls_verify_peer_state verify_peer;
        const char *peer_name;
 
+       DATA_BLOB channel_bindings;
+
        struct tevent_context *current_ev;
 
        struct tevent_immediate *retry_im;
@@ -890,6 +892,63 @@ bool tstream_tls_params_enabled(struct tstream_tls_params *tls_params)
        return tlsp->tls_enabled;
 }
 
+static NTSTATUS tstream_tls_setup_channel_bindings(struct tstream_tls *tlss)
+{
+       gnutls_datum_t cb = { .size = 0 };
+       int ret;
+
+#ifdef HAVE_GNUTLS_CB_TLS_SERVER_END_POINT
+       ret = gnutls_session_channel_binding(tlss->tls_session,
+                                            GNUTLS_CB_TLS_SERVER_END_POINT,
+                                            &cb);
+#else /* not HAVE_GNUTLS_CB_TLS_SERVER_END_POINT */
+       ret = legacy_gnutls_server_end_point_cb(tlss->tls_session,
+                                               tlss->is_server,
+                                               &cb);
+#endif /* not HAVE_GNUTLS_CB_TLS_SERVER_END_POINT */
+       if (ret != GNUTLS_E_SUCCESS) {
+               return gnutls_error_to_ntstatus(ret,
+                               NT_STATUS_CRYPTO_SYSTEM_INVALID);
+       }
+
+       if (cb.size != 0) {
+               /*
+                * Looking at the OpenLDAP implementation
+                * for LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT
+                * revealed that we need to prefix it with
+                * 'tls-server-end-point:'
+                */
+               const char endpoint_prefix[] = "tls-server-end-point:";
+               size_t prefix_size = strlen(endpoint_prefix);
+               size_t size = prefix_size + cb.size;
+
+               tlss->channel_bindings = data_blob_talloc_named(tlss, NULL, size,
+                                                               "tls_channel_bindings");
+               if (tlss->channel_bindings.data == NULL) {
+                       gnutls_free(cb.data);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               memcpy(tlss->channel_bindings.data, endpoint_prefix, prefix_size);
+               memcpy(tlss->channel_bindings.data + prefix_size, cb.data, cb.size);
+               gnutls_free(cb.data);
+       }
+
+       return NT_STATUS_OK;
+}
+
+const DATA_BLOB *tstream_tls_channel_bindings(struct tstream_context *tls_tstream)
+{
+       struct tstream_tls *tlss =
+               talloc_get_type(_tstream_context_data(tls_tstream),
+               struct tstream_tls);
+
+       if (tlss == NULL) {
+               return NULL;
+       }
+
+       return &tlss->channel_bindings;
+}
+
 NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
                                   const char *ca_file,
                                   const char *crl_file,
@@ -1574,6 +1633,13 @@ static void tstream_tls_retry_handshake(struct tstream_context *stream)
                return;
        }
 
+       status = tstream_tls_setup_channel_bindings(tlss);
+       if (!NT_STATUS_IS_OK(status)) {
+               tlss->error = EIO;
+               tevent_req_error(req, tlss->error);
+               return;
+       }
+
        if (tlss->push.subreq != NULL || tlss->pull.subreq != NULL) {
                tlss->waiting_flush.mgmt_req = req;
                return;