Juan Lang : crypt32: Implement CryptFindCertificateKeyProvInfo.
Alexandre Julliard
julliard at winehq.org
Wed Jan 28 08:02:55 CST 2009
Module: wine
Branch: master
Commit: 1352f6d316da3a95b73ca3f31eb44190a20adca5
URL: http://source.winehq.org/git/wine.git/?a=commit;h=1352f6d316da3a95b73ca3f31eb44190a20adca5
Author: Juan Lang <juan.lang at gmail.com>
Date: Tue Jan 27 09:01:06 2009 -0800
crypt32: Implement CryptFindCertificateKeyProvInfo.
---
dlls/crypt32/cert.c | 213 +++++++++++++++++++++++++++++++++++++++++++++
dlls/crypt32/crypt32.spec | 1 +
2 files changed, 214 insertions(+), 0 deletions(-)
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c
index 5c2c786..c677556 100644
--- a/dlls/crypt32/cert.c
+++ b/dlls/crypt32/cert.c
@@ -27,6 +27,7 @@
#include "winnls.h"
#include "rpc.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
#include "crypt32_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
@@ -718,6 +719,218 @@ BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
return ret;
}
+static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
+ const CRYPT_KEY_PROV_INFO *keyProvInfo)
+{
+ HCRYPTPROV csp;
+ BOOL matches = FALSE;
+
+ if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
+ keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
+ {
+ DWORD size;
+
+ /* Need to sign something to verify the sig. What to sign? Why not
+ * the certificate itself?
+ */
+ if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
+ pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
+ &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
+ {
+ BYTE *certEncoded = CryptMemAlloc(size);
+
+ if (certEncoded)
+ {
+ if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
+ pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
+ pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
+ NULL, certEncoded, &size))
+ {
+ if (size == pCert->cbCertEncoded &&
+ !memcmp(certEncoded, pCert->pbCertEncoded, size))
+ matches = TRUE;
+ }
+ CryptMemFree(certEncoded);
+ }
+ }
+ CryptReleaseContext(csp, 0);
+ }
+ return matches;
+}
+
+static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
+ CRYPT_KEY_PROV_INFO *keyProvInfo)
+{
+ CRYPT_KEY_PROV_INFO copy;
+ WCHAR containerW[MAX_PATH];
+ BOOL matches = FALSE;
+
+ MultiByteToWideChar(CP_ACP, 0, container, -1,
+ containerW, sizeof(containerW) / sizeof(containerW[0]));
+ /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
+ * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
+ * name.
+ */
+ memcpy(©, keyProvInfo, sizeof(copy));
+ copy.pwszContainerName = containerW;
+ matches = key_prov_info_matches_cert(pCert, ©);
+ if (matches)
+ {
+ keyProvInfo->pwszContainerName =
+ CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
+ if (keyProvInfo->pwszContainerName)
+ {
+ strcpyW(keyProvInfo->pwszContainerName, containerW);
+ keyProvInfo->dwKeySpec = AT_SIGNATURE;
+ }
+ else
+ matches = FALSE;
+ }
+ return matches;
+}
+
+/* Searches the provider named keyProvInfo.pwszProvName for a container whose
+ * private key matches pCert's public key. Upon success, updates keyProvInfo
+ * with the matching container's info (free keyProvInfo.pwszContainerName upon
+ * success.)
+ * Returns TRUE if found, FALSE if not.
+ */
+static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
+ CRYPT_KEY_PROV_INFO *keyProvInfo)
+{
+ HCRYPTPROV defProvider;
+ BOOL ret, found = FALSE;
+ char containerA[MAX_PATH];
+
+ assert(keyProvInfo->pwszContainerName == NULL);
+ if ((ret = CryptAcquireContextW(&defProvider, NULL,
+ keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
+ keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
+ {
+ DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
+
+ while (ret && !found)
+ {
+ DWORD size = sizeof(containerA);
+
+ ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
+ (BYTE *)containerA, &size, enumFlags);
+ if (ret)
+ found = container_matches_cert(pCert, containerA, keyProvInfo);
+ if (enumFlags & CRYPT_FIRST)
+ {
+ enumFlags &= ~CRYPT_FIRST;
+ enumFlags |= CRYPT_NEXT;
+ }
+ }
+ CryptReleaseContext(defProvider, 0);
+ }
+ return found;
+}
+
+static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
+{
+ BOOL found = FALSE, ret = TRUE;
+ DWORD index = 0, cbProvName = 0;
+ CRYPT_KEY_PROV_INFO keyProvInfo;
+
+ TRACE("(%p, %08x)\n", pCert, dwFlags);
+
+ memset(&keyProvInfo, 0, sizeof(keyProvInfo));
+ while (ret && !found)
+ {
+ DWORD size = 0;
+
+ ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
+ NULL, &size);
+ if (ret)
+ {
+ if (size <= cbProvName)
+ ret = CryptEnumProvidersW(index, NULL, 0,
+ &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
+ else
+ {
+ CryptMemFree(keyProvInfo.pwszProvName);
+ keyProvInfo.pwszProvName = CryptMemAlloc(size);
+ if (keyProvInfo.pwszProvName)
+ {
+ cbProvName = size;
+ ret = CryptEnumProvidersW(index, NULL, 0,
+ &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
+ if (ret)
+ {
+ if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
+ keyProvInfo.dwFlags |= CRYPT_SILENT;
+ if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
+ !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
+ CRYPT_FIND_MACHINE_KEYSET_FLAG)))
+ {
+ keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
+ found = find_key_prov_info_in_provider(pCert,
+ &keyProvInfo);
+ }
+ if (!found)
+ {
+ if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
+ !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
+ CRYPT_FIND_MACHINE_KEYSET_FLAG)))
+ {
+ keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
+ keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
+ found = find_key_prov_info_in_provider(pCert,
+ &keyProvInfo);
+ }
+ }
+ }
+ }
+ else
+ ret = FALSE;
+ }
+ index++;
+ }
+ }
+ if (found)
+ CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
+ 0, &keyProvInfo);
+ CryptMemFree(keyProvInfo.pwszProvName);
+ CryptMemFree(keyProvInfo.pwszContainerName);
+ return found;
+}
+
+static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
+{
+ BOOL matches = FALSE;
+ DWORD size;
+
+ if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
+ NULL, &size))
+ {
+ CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
+
+ if (keyProvInfo)
+ {
+ if (CertGetCertificateContextProperty(pCert,
+ CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
+ matches = key_prov_info_matches_cert(pCert, keyProvInfo);
+ CryptMemFree(keyProvInfo);
+ }
+ }
+ return matches;
+}
+
+BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
+ DWORD dwFlags, void *pvReserved)
+{
+ BOOL matches = FALSE;
+
+ TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
+
+ matches = cert_prov_info_matches_cert(pCert);
+ if (!matches)
+ matches = find_matching_provider(pCert, dwFlags);
+ return matches;
+}
+
BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
PCERT_INFO pCertId1, PCERT_INFO pCertId2)
{
diff --git a/dlls/crypt32/crypt32.spec b/dlls/crypt32/crypt32.spec
index ea2b6fa..3591d17 100644
--- a/dlls/crypt32/crypt32.spec
+++ b/dlls/crypt32/crypt32.spec
@@ -118,6 +118,7 @@
@ stub CryptExportPKCS8
@ stdcall CryptExportPublicKeyInfo(long long long ptr ptr)
@ stdcall CryptExportPublicKeyInfoEx(long long long str long ptr ptr ptr)
+@ stdcall CryptFindCertificateKeyProvInfo(ptr long ptr)
@ stdcall CryptFindLocalizedName(wstr)
@ stdcall CryptFindOIDInfo(long ptr long)
@ stdcall CryptFormatObject(long long long ptr str ptr long ptr ptr)
More information about the wine-cvs
mailing list