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..95e1fc24c45 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,41 @@ 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); + return SEC_E_INTERNAL_ERROR; + } + + 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 +1051,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 +1070,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); }