From 2fbe80ad8936537c80685ba584b79e600f6b6085 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Thu, 17 Dec 2009 08:54:54 -0800 Subject: [PATCH] wintrust: Check authority key identifer extension to determine if a certificate is self-signed. --- dlls/wintrust/wintrust_main.c | 111 +++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/dlls/wintrust/wintrust_main.c b/dlls/wintrust/wintrust_main.c index c61f6e0f2d6..1c87b6ee07f 100644 --- a/dlls/wintrust/wintrust_main.c +++ b/dlls/wintrust/wintrust_main.c @@ -77,11 +77,118 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) */ BOOL WINAPI TrustIsCertificateSelfSigned( PCCERT_CONTEXT cert ) { + PCERT_EXTENSION ext; + DWORD size; BOOL ret; TRACE("%p\n", cert); - ret = CertCompareCertificateName(cert->dwCertEncodingType, - &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer); + if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, + cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) + { + CERT_AUTHORITY_KEY_ID2_INFO *info; + + ret = CryptDecodeObjectEx(cert->dwCertEncodingType, + X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &info, &size); + if (ret) + { + if (info->AuthorityCertIssuer.cAltEntry && + info->AuthorityCertSerialNumber.cbData) + { + PCERT_ALT_NAME_ENTRY directoryName = NULL; + DWORD i; + + for (i = 0; !directoryName && + i < info->AuthorityCertIssuer.cAltEntry; i++) + if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice + == CERT_ALT_NAME_DIRECTORY_NAME) + directoryName = + &info->AuthorityCertIssuer.rgAltEntry[i]; + if (directoryName) + { + ret = CertCompareCertificateName(cert->dwCertEncodingType, + &directoryName->u.DirectoryName, &cert->pCertInfo->Issuer) + && CertCompareIntegerBlob(&info->AuthorityCertSerialNumber, + &cert->pCertInfo->SerialNumber); + } + else + { + FIXME("no supported name type in authority key id2\n"); + ret = FALSE; + } + } + else if (info->KeyId.cbData) + { + ret = CertGetCertificateContextProperty(cert, + CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); + if (ret && size == info->KeyId.cbData) + { + LPBYTE buf = CryptMemAlloc(size); + + if (buf) + { + CertGetCertificateContextProperty(cert, + CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); + ret = !memcmp(buf, info->KeyId.pbData, size); + CryptMemFree(buf); + } + else + ret = FALSE; + } + else + ret = FALSE; + } + LocalFree(info); + } + } + else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, + cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) + { + CERT_AUTHORITY_KEY_ID_INFO *info; + + ret = CryptDecodeObjectEx(cert->dwCertEncodingType, + X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &info, &size); + if (ret) + { + if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) + { + ret = CertCompareCertificateName(cert->dwCertEncodingType, + &info->CertIssuer, &cert->pCertInfo->Issuer) && + CertCompareIntegerBlob(&info->CertSerialNumber, + &cert->pCertInfo->SerialNumber); + } + else if (info->KeyId.cbData) + { + ret = CertGetCertificateContextProperty(cert, + CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); + if (ret && size == info->KeyId.cbData) + { + LPBYTE buf = CryptMemAlloc(size); + + if (buf) + { + CertGetCertificateContextProperty(cert, + CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); + ret = !memcmp(buf, info->KeyId.pbData, size); + CryptMemFree(buf); + } + else + ret = FALSE; + } + else + ret = FALSE; + } + else + ret = FALSE; + LocalFree(info); + } + } + else + ret = CertCompareCertificateName(cert->dwCertEncodingType, + &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer); return ret; }