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(&copy, keyProvInfo, sizeof(copy));
+    copy.pwszContainerName = containerW;
+    matches = key_prov_info_matches_cert(pCert, &copy);
+    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