Module: wine Branch: master Commit: 0706ba1114dc5c6a24d1ae21334bc88415c0d359 URL: http://source.winehq.org/git/wine.git/?a=commit;h=0706ba1114dc5c6a24d1ae2133...
Author: Jacek Caban jacek@codeweavers.com Date: Thu Mar 2 13:45:53 2017 +0100
secur32: Added support for SECPKG_ATTR_ENDPOINT_BINDINGS in schannel.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/secur32/schannel.c | 78 +++++++++++++++++++++++++++++++++++-------- dlls/secur32/tests/schannel.c | 42 +++++++++++++++++++++++ 2 files changed, 107 insertions(+), 13 deletions(-)
diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 71f219c..6914837 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -23,6 +23,7 @@ #include <stdarg.h> #include <errno.h>
+#define NONAMELESSUNION #include "windef.h" #include "winbase.h" #include "winreg.h" @@ -961,6 +962,23 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextA( return ret; }
+static SECURITY_STATUS ensure_remote_cert(struct schan_context *ctx) +{ + HCERTSTORE cert_store; + SECURITY_STATUS status; + + if(ctx->cert) + return SEC_E_OK; + + cert_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); + if(!cert_store) + return GetLastError(); + + status = schan_imp_get_session_peer_certificate(ctx->session, cert_store, &ctx->cert); + CertCloseStore(cert_store, 0); + return status; +} + static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( PCtxtHandle context_handle, ULONG attribute, PVOID buffer) { @@ -1001,20 +1019,11 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( case SECPKG_ATTR_REMOTE_CERT_CONTEXT: { PCCERT_CONTEXT *cert = buffer; + SECURITY_STATUS status;
- if (!ctx->cert) { - HCERTSTORE cert_store; - SECURITY_STATUS status; - - cert_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); - if(!cert_store) - return GetLastError(); - - status = schan_imp_get_session_peer_certificate(ctx->session, cert_store, &ctx->cert); - CertCloseStore(cert_store, 0); - if(status != SEC_E_OK) - return status; - } + status = ensure_remote_cert(ctx); + if(status != SEC_E_OK) + return status;
*cert = CertDuplicateCertificateContext(ctx->cert); return SEC_E_OK; @@ -1024,6 +1033,47 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( SecPkgContext_ConnectionInfo *info = buffer; return schan_imp_get_connection_info(ctx->session, info); } + case SECPKG_ATTR_ENDPOINT_BINDINGS: + { + SecPkgContext_Bindings *bindings = buffer; + CCRYPT_OID_INFO *info; + ALG_ID hash_alg = CALG_SHA_256; + BYTE hash[1024]; + DWORD hash_size; + SECURITY_STATUS status; + char *p; + BOOL r; + + static const char prefix[] = "tls-server-end-point:"; + + status = ensure_remote_cert(ctx); + if(status != SEC_E_OK) + return status; + + /* RFC 5929 */ + info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, ctx->cert->pCertInfo->SignatureAlgorithm.pszObjId, 0); + if(info && info->u.Algid != CALG_SHA1 && info->u.Algid != CALG_MD5) + hash_alg = info->u.Algid; + + hash_size = sizeof(hash); + r = CryptHashCertificate(0, hash_alg, 0, ctx->cert->pbCertEncoded, ctx->cert->cbCertEncoded, hash, &hash_size); + if(!r) + return GetLastError(); + + bindings->BindingsLength = sizeof(*bindings->Bindings) + sizeof(prefix)-1 + hash_size; + bindings->Bindings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bindings->BindingsLength); + if(!bindings->Bindings) + return SEC_E_INSUFFICIENT_MEMORY; + + bindings->Bindings->cbApplicationDataLength = sizeof(prefix)-1 + hash_size; + bindings->Bindings->dwApplicationDataOffset = sizeof(*bindings->Bindings); + + p = (char*)(bindings->Bindings+1); + memcpy(p, prefix, sizeof(prefix)-1); + p += sizeof(prefix)-1; + memcpy(p, hash, hash_size); + return SEC_E_OK; + }
default: FIXME("Unhandled attribute %#x\n", attribute); @@ -1045,6 +1095,8 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesA( return schan_QueryContextAttributesW(context_handle, attribute, buffer); case SECPKG_ATTR_CONNECTION_INFO: return schan_QueryContextAttributesW(context_handle, attribute, buffer); + case SECPKG_ATTR_ENDPOINT_BINDINGS: + return schan_QueryContextAttributesW(context_handle, attribute, buffer);
default: FIXME("Unhandled attribute %#x\n", attribute); diff --git a/dlls/secur32/tests/schannel.c b/dlls/secur32/tests/schannel.c index a858488..b52510d 100644 --- a/dlls/secur32/tests/schannel.c +++ b/dlls/secur32/tests/schannel.c @@ -870,7 +870,49 @@ todo_wine status = pQueryContextAttributesA(&context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); ok(status == SEC_E_OK, "QueryContextAttributesW(SECPKG_ATTR_REMOTE_CERT_CONTEXT) failed: %08x\n", status); if(status == SEC_E_OK) { + SecPkgContext_Bindings bindings = {0xdeadbeef, (void*)0xdeadbeef}; + test_remote_cert(cert); + + status = pQueryContextAttributesA(&context, SECPKG_ATTR_ENDPOINT_BINDINGS, &bindings); + ok(status == SEC_E_OK || broken(status == SEC_E_UNSUPPORTED_FUNCTION), + "QueryContextAttributesW(SECPKG_ATTR_ENDPOINT_BINDINGS) failed: %08x\n", status); + if(status == SEC_E_OK) { + static const char prefix[] = "tls-server-end-point:"; + const char *p; + BYTE hash[64]; + DWORD hash_size; + + ok(bindings.BindingsLength == sizeof(*bindings.Bindings) + sizeof(prefix)-1 + 32 /* hash size */, + "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), "missing prefix\n"); + p += sizeof(prefix)-1; + + hash_size = sizeof(hash); + ret = CryptHashCertificate(0, CALG_SHA_256, 0, cert->pbCertEncoded, cert->cbCertEncoded, hash, &hash_size); + if(ret) { + ok(hash_size == 32, "hash_size = %u\n", hash_size); + ok(!memcmp(hash, p, hash_size), "unexpected hash part\n"); + }else { + win_skip("SHA 256 hash not supported.\n"); + } + + FreeContextBuffer(bindings.Bindings); + }else { + win_skip("SECPKG_ATTR_ENDPOINT_BINDINGS not supported\n"); + } + CertFreeCertificateContext(cert); }