[PATCH] secur32: implement the SECPKG_ATTR_UNIQUE_BINDINGS context attribute

Damjan Jovanovic damjan.jov at gmail.com
Tue Jan 26 03:14:11 CST 2021


.NET's System.Data.SqlClient needs this to connect to MSSQL Server.

A MacOSX implementation doesn't appear to be possible.

Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
 dlls/secur32/schannel.c        |  7 ++++++
 dlls/secur32/schannel_gnutls.c | 41 ++++++++++++++++++++++++++++++++++
 dlls/secur32/schannel_macosx.c |  6 +++++
 dlls/secur32/secur32_priv.h    |  2 ++
 dlls/secur32/tests/schannel.c  | 26 +++++++++++++++++++++
 5 files changed, 82 insertions(+)
-------------- next part --------------
diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index e76a3e46c34..2d135a85227 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -1115,6 +1115,11 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
             memcpy(p, hash, hash_size);
             return SEC_E_OK;
         }
+        case SECPKG_ATTR_UNIQUE_BINDINGS:
+        {
+            SecPkgContext_Bindings *bindings = buffer;
+            return schan_imp_get_unique_channel_binding(ctx->session, bindings);
+        }
         case SECPKG_ATTR_APPLICATION_PROTOCOL:
         {
             SecPkgContext_ApplicationProtocol *protocol = buffer;
@@ -1154,6 +1159,8 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesA(
             return schan_QueryContextAttributesW(context_handle, attribute, buffer);
         case SECPKG_ATTR_ENDPOINT_BINDINGS:
             return schan_QueryContextAttributesW(context_handle, attribute, buffer);
+        case SECPKG_ATTR_UNIQUE_BINDINGS:
+            return schan_QueryContextAttributesW(context_handle, attribute, buffer);
         case SECPKG_ATTR_APPLICATION_PROTOCOL:
             return schan_QueryContextAttributesW(context_handle, attribute, buffer);
 
diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c
index 784c1ffe6e8..df2d45651a8 100644
--- a/dlls/secur32/schannel_gnutls.c
+++ b/dlls/secur32/schannel_gnutls.c
@@ -77,6 +77,7 @@ MAKE_FUNCPTR(gnutls_cipher_get);
 MAKE_FUNCPTR(gnutls_cipher_get_key_size);
 MAKE_FUNCPTR(gnutls_credentials_set);
 MAKE_FUNCPTR(gnutls_deinit);
+static gnutls_free_function *pgnutls_free;
 MAKE_FUNCPTR(gnutls_global_deinit);
 MAKE_FUNCPTR(gnutls_global_init);
 MAKE_FUNCPTR(gnutls_global_set_log_function);
@@ -95,6 +96,7 @@ MAKE_FUNCPTR(gnutls_record_get_max_size);
 MAKE_FUNCPTR(gnutls_record_recv);
 MAKE_FUNCPTR(gnutls_record_send);
 MAKE_FUNCPTR(gnutls_server_name_set);
+MAKE_FUNCPTR(gnutls_session_channel_binding);
 MAKE_FUNCPTR(gnutls_transport_get_ptr);
 MAKE_FUNCPTR(gnutls_transport_set_errno);
 MAKE_FUNCPTR(gnutls_transport_set_ptr);
@@ -507,6 +509,43 @@ SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
     return SEC_E_OK;
 }
 
+SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
+                                                     SecPkgContext_Bindings *bindings)
+{
+    static const char prefix[] = "tls-unique:";
+    gnutls_datum_t datum;
+    int rc;
+    SECURITY_STATUS ret;
+    char *p;
+    gnutls_session_t s = (gnutls_session_t)session;
+
+    rc = pgnutls_session_channel_binding(s, GNUTLS_CB_TLS_UNIQUE, &datum);
+    if (rc)
+    {
+        pgnutls_perror(rc);
+        ret = SEC_E_INTERNAL_ERROR;
+    }
+    else
+    {
+        bindings->BindingsLength = sizeof(SEC_CHANNEL_BINDINGS) + sizeof(prefix)-1 + datum.size;
+        bindings->Bindings = heap_alloc_zero(bindings->BindingsLength);
+        if (!bindings->Bindings)
+            ret = SEC_E_INSUFFICIENT_MEMORY;
+        else
+        {
+            bindings->Bindings->cbApplicationDataLength = sizeof(prefix)-1 + datum.size;
+            bindings->Bindings->dwApplicationDataOffset = sizeof(SEC_CHANNEL_BINDINGS);
+            p = (char*)(bindings->Bindings+1);
+            memcpy(p, prefix, sizeof(prefix)-1);
+            p += sizeof(prefix)-1;
+            memcpy(p, datum.data, datum.size);
+            ret = SEC_E_OK;
+        }
+    }
+    (*pgnutls_free)(datum.data);
+    return ret;
+}
+
 ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session)
 {
     gnutls_session_t s = (gnutls_session_t)session;
@@ -1014,6 +1053,7 @@ BOOL schan_imp_init(void)
     LOAD_FUNCPTR(gnutls_cipher_get_key_size)
     LOAD_FUNCPTR(gnutls_credentials_set)
     LOAD_FUNCPTR(gnutls_deinit)
+    LOAD_FUNCPTR(gnutls_free)
     LOAD_FUNCPTR(gnutls_global_deinit)
     LOAD_FUNCPTR(gnutls_global_init)
     LOAD_FUNCPTR(gnutls_global_set_log_function)
@@ -1032,6 +1072,7 @@ BOOL schan_imp_init(void)
     LOAD_FUNCPTR(gnutls_record_recv);
     LOAD_FUNCPTR(gnutls_record_send);
     LOAD_FUNCPTR(gnutls_server_name_set)
+    LOAD_FUNCPTR(gnutls_session_channel_binding)
     LOAD_FUNCPTR(gnutls_transport_get_ptr)
     LOAD_FUNCPTR(gnutls_transport_set_errno)
     LOAD_FUNCPTR(gnutls_transport_set_ptr)
diff --git a/dlls/secur32/schannel_macosx.c b/dlls/secur32/schannel_macosx.c
index d725c9d22c2..8a2bea79ad7 100644
--- a/dlls/secur32/schannel_macosx.c
+++ b/dlls/secur32/schannel_macosx.c
@@ -1039,6 +1039,12 @@ SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
     return SEC_E_OK;
 }
 
+SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
+                                                     SecPkgContext_Bindings *bindings)
+{
+    return SEC_E_UNSUPPORTED_FUNCTION;
+}
+
 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
 static void schan_imp_cf_release(const void *arg, void *ctx)
 {
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index c34d1d32566..ce8d55d1eb6 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -237,6 +237,8 @@ extern unsigned int schan_imp_get_max_message_size(schan_imp_session session) DE
 extern ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) DECLSPEC_HIDDEN;
 extern SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
                                                      SecPkgContext_ConnectionInfo *info) DECLSPEC_HIDDEN;
+extern SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
+                                                            SecPkgContext_Bindings *bindings) DECLSPEC_HIDDEN;
 extern SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE,
                                                               PCCERT_CONTEXT *cert) DECLSPEC_HIDDEN;
 extern SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
diff --git a/dlls/secur32/tests/schannel.c b/dlls/secur32/tests/schannel.c
index 30022437bc0..99adf0bbc19 100644
--- a/dlls/secur32/tests/schannel.c
+++ b/dlls/secur32/tests/schannel.c
@@ -925,6 +925,32 @@ todo_wine
             win_skip("SECPKG_ATTR_ENDPOINT_BINDINGS not supported\n");
         }
 
+        status = pQueryContextAttributesA(&context, SECPKG_ATTR_UNIQUE_BINDINGS, &bindings);
+        ok(status == SEC_E_OK || broken(status == SEC_E_UNSUPPORTED_FUNCTION),
+           "QueryContextAttributesW(SECPKG_ATTR_UNIQUE_BINDINGS) failed: %08x\n", status);
+        if(status == SEC_E_OK) {
+            const char *p;
+            static const char prefix[] = "tls-unique:";
+
+            ok(bindings.BindingsLength > sizeof(*bindings.Bindings) + sizeof(prefix)-1,
+               "bindings.BindingsLength = %u\n", bindings.BindingsLength);
+            ok(!bindings.Bindings->dwInitiatorAddrType, "dwInitiatorAddrType = %x\n", bindings.Bindings->dwInitiatorAddrType);
+            ok(!bindings.Bindings->cbInitiatorLength, "cbInitiatorLength = %x\n", bindings.Bindings->cbInitiatorLength);
+            ok(!bindings.Bindings->dwInitiatorOffset, "dwInitiatorOffset = %x\n", bindings.Bindings->dwInitiatorOffset);
+            ok(!bindings.Bindings->dwAcceptorAddrType, "dwAcceptorAddrType = %x\n", bindings.Bindings->dwAcceptorAddrType);
+            ok(!bindings.Bindings->cbAcceptorLength, "cbAcceptorLength = %x\n", bindings.Bindings->cbAcceptorLength);
+            ok(!bindings.Bindings->dwAcceptorOffset, "dwAcceptorOffset = %x\n", bindings.Bindings->dwAcceptorOffset);
+            ok(sizeof(*bindings.Bindings) + bindings.Bindings->cbApplicationDataLength == bindings.BindingsLength,
+               "cbApplicationDataLength = %x\n", bindings.Bindings->cbApplicationDataLength);
+            ok(bindings.Bindings->dwApplicationDataOffset == sizeof(*bindings.Bindings),
+               "dwApplicationDataOffset = %x\n", bindings.Bindings->dwApplicationDataOffset);
+            p = (const char*)(bindings.Bindings+1);
+            ok(!memcmp(p, prefix, sizeof(prefix)-1), "wrong prefix\n");
+            FreeContextBuffer(bindings.Bindings);
+        } else {
+            win_skip("SECPKG_ATTR_UNIQUE_BINDINGS not supported\n");
+        }
+
         CertFreeCertificateContext(cert);
     }
 


More information about the wine-devel mailing list