[CRYPT32] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / dll / win32 / crypt32 / cert.c
index c1728d5..0065ba6 100644 (file)
  *
  */
 
+#include <assert.h>
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "wine/winternl.h"
+#define CRYPT_OID_INFO_HAS_EXTRA_FIELDS
+#include "wincrypt.h"
+#include "snmp.h"
+#include "bcrypt.h"
+#include "winnls.h"
+#include "rpc.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
 #include "crypt32_private.h"
 
-#include <rpc.h>
-
 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 
 /* Internal version of CertGetCertificateContextProperty that gets properties
@@ -518,14 +533,19 @@ void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
     provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
     data += provNameLen;
 
-    info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
-    data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
-
-    for (i = 0; i < info->cProvParam; i++)
+    if (info->cProvParam)
     {
-        info->rgProvParam[i].pbData = data;
-        data += info->rgProvParam[i].cbData;
+        info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
+        data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
+
+        for (i = 0; i < info->cProvParam; i++)
+        {
+            info->rgProvParam[i].pbData = data;
+            data += info->rgProvParam[i].cbData;
+        }
     }
+    else
+        info->rgProvParam = NULL;
 }
 
 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
@@ -685,6 +705,7 @@ static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
         case CERT_ENROLLMENT_PROP_ID:
         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
+        case CERT_OCSP_RESPONSE_PROP_ID:
         case CERT_RENEWAL_PROP_ID:
         {
             if (pvData)
@@ -975,10 +996,9 @@ static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
 {
     CRYPT_KEY_PROV_INFO copy;
     WCHAR containerW[MAX_PATH];
-    BOOL matches = FALSE;
+    BOOL matches;
 
-    MultiByteToWideChar(CP_ACP, 0, container, -1,
-     containerW, sizeof(containerW) / sizeof(containerW[0]));
+    MultiByteToWideChar(CP_ACP, 0, container, -1, containerW, ARRAY_SIZE(containerW));
     /* 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.
@@ -1133,7 +1153,7 @@ static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
  DWORD dwFlags, void *pvReserved)
 {
-    BOOL matches = FALSE;
+    BOOL matches;
 
     TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
 
@@ -1228,6 +1248,12 @@ BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
 
     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
 
+    /* RSA public key data should start with ASN_SEQUENCE,
+     * otherwise it's not a RSA_CSP_PUBLICKEYBLOB.
+     */
+    if (!pPublicKey1->PublicKey.cbData || pPublicKey1->PublicKey.pbData[0] != ASN_SEQUENCE)
+        dwCertEncodingType = 0;
+
     switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
     {
     case 0:    /* Seems to mean "raw binary bits" */
@@ -1253,32 +1279,21 @@ BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
         ret = FALSE;
         if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
                     pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
-                    0, NULL, &length))
+                    CRYPT_DECODE_ALLOC_FLAG, &pblob1, &length))
         {
-            pblob1 = CryptMemAlloc(length);
             if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
-                    pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
-                    0, pblob1, &length))
+                        pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
+                        CRYPT_DECODE_ALLOC_FLAG, &pblob2, &length))
             {
-                if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
-                            pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
-                            0, NULL, &length))
-                {
-                    pblob2 = CryptMemAlloc(length);
-                    if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
-                            pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
-                            0, pblob2, &length))
-                    {
-                        /* The RSAPUBKEY structure directly follows the BLOBHEADER */
-                        RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
-                                  *pk2 = (LPVOID)(pblob2 + 1);
-                        ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
-                                 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
-                    }
-                    CryptMemFree(pblob2);
-                }
+                /* The RSAPUBKEY structure directly follows the BLOBHEADER */
+                RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
+                          *pk2 = (LPVOID)(pblob2 + 1);
+                ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
+                         && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
+
+                LocalFree(pblob2);
             }
-            CryptMemFree(pblob1);
+            LocalFree(pblob1);
         }
 
         break;
@@ -1307,9 +1322,30 @@ DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
     }
     else
     {
+        PCCRYPT_OID_INFO info;
         DWORD size;
         PBYTE buf;
-        BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
+        BOOL ret;
+
+        info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pPublicKey->Algorithm.pszObjId, 0);
+        if (info)
+        {
+            HCRYPTKEY key;
+
+            TRACE("public key algid %#x (%s)\n", info->u.Algid, debugstr_a(pPublicKey->Algorithm.pszObjId));
+
+            ret = CryptImportPublicKeyInfo(I_CryptGetDefaultCryptProv(info->u.Algid), dwCertEncodingType, pPublicKey, &key);
+            if (ret)
+            {
+                size = sizeof(len);
+                ret = CryptGetKeyParam(key, KP_KEYLEN, (BYTE *)&len, &size, 0);
+                CryptDestroyKey(key);
+                return len;
+            }
+            /* fallback to RSA */
+        }
+
+        ret = CryptDecodeObjectEx(dwCertEncodingType,
          RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
          pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
          &size);
@@ -1780,7 +1816,7 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
     }
 
     if (find)
-        ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext);
+        ret = find(hCertStore, dwType, dwFlags, pvPara, pPrevCertContext);
     else if (compare)
         ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
          compare, dwType, dwFlags, pvPara);
@@ -1874,6 +1910,12 @@ PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
             CertFreeCertificateContext(ret);
             ret = NULL;
         }
+        if (CRYPT_IsCertificateSelfSigned(pSubjectContext))
+        {
+            CertFreeCertificateContext(ret);
+            ret = NULL;
+            SetLastError(CRYPT_E_SELF_SIGNED);
+        }
     }
     TRACE("returning %p\n", ret);
     return ret;
@@ -2153,7 +2195,7 @@ BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
 
     if (!hCryptProv)
-        hCryptProv = CRYPT_GetDefaultProvider();
+        hCryptProv = I_CryptGetDefaultCryptProv(0);
     if (!Algid)
         Algid = CALG_SHA1;
     if (ret)
@@ -2182,7 +2224,7 @@ BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
      dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
 
     if (!hCryptProv)
-        hCryptProv = CRYPT_GetDefaultProvider();
+        hCryptProv = I_CryptGetDefaultCryptProv(0);
     if (!Algid)
         Algid = CALG_MD5;
     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
@@ -2234,7 +2276,7 @@ BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
         HCRYPTHASH hHash;
 
         if (!hCryptProv)
-            hCryptProv = CRYPT_GetDefaultProvider();
+            hCryptProv = I_CryptGetDefaultCryptProv(0);
         oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
          info->SignatureAlgorithm.pszObjId, 0);
         if (!oidInfo)
@@ -2283,7 +2325,7 @@ BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
     if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
     {
         if (!hCryptProv)
-            hCryptProv = CRYPT_GetDefaultProvider();
+            hCryptProv = I_CryptGetDefaultCryptProv(0);
         ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
         if (ret)
         {
@@ -2393,22 +2435,13 @@ BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
 }
 
-static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
- DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
- const CERT_SIGNED_CONTENT_INFO *signedCert)
+static BOOL CRYPT_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
+    CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
 {
     BOOL ret;
     HCRYPTKEY key;
-    PCCRYPT_OID_INFO info;
     ALG_ID pubKeyID, hashID;
 
-    info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
-     signedCert->SignatureAlgorithm.pszObjId, 0);
-    if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
-    {
-        SetLastError(NTE_BAD_ALGID);
-        return FALSE;
-    }
     hashID = info->u.Algid;
     if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
         pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
@@ -2416,7 +2449,7 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptP
         pubKeyID = hashID;
     /* Load the default provider if necessary */
     if (!hCryptProv)
-        hCryptProv = CRYPT_GetDefaultProvider();
+        hCryptProv = I_CryptGetDefaultCryptProv(0);
     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
      pubKeyInfo, pubKeyID, 0, NULL, &key);
     if (ret)
@@ -2438,6 +2471,249 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptP
     return ret;
 }
 
+static BOOL CNG_CalcHash(const WCHAR *algorithm, const CERT_SIGNED_CONTENT_INFO *signedCert,
+        BYTE **hash_value, DWORD *hash_len)
+{
+    BCRYPT_HASH_HANDLE hash = NULL;
+    BCRYPT_ALG_HANDLE alg = NULL;
+    NTSTATUS status;
+    DWORD size;
+
+    if ((status = BCryptOpenAlgorithmProvider(&alg, algorithm, NULL, 0)))
+        goto done;
+
+    if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0)))
+        goto done;
+
+    if ((status = BCryptHashData(hash, signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, 0)))
+        goto done;
+
+    if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)hash_len, sizeof(*hash_len), &size, 0)))
+        goto done;
+
+    if (!(*hash_value = CryptMemAlloc(*hash_len)))
+    {
+        status = STATUS_NO_MEMORY;
+        goto done;
+    }
+
+    if ((status = BCryptFinishHash(hash, *hash_value, *hash_len, 0)))
+    {
+        CryptMemFree(*hash_value);
+        goto done;
+    }
+
+done:
+    if (hash) BCryptDestroyHash(hash);
+    if (alg)  BCryptCloseAlgorithmProvider(alg, 0);
+    if (status) SetLastError(RtlNtStatusToDosError(status));
+    return status == 0;
+}
+
+static BOOL CNG_ImportECCPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
+{
+    DWORD blob_magic, ecckey_len, size;
+    BCRYPT_ALG_HANDLE alg = NULL;
+    BCRYPT_ECCKEY_BLOB *ecckey;
+    const WCHAR *sign_algo;
+    char **ecc_curve;
+    NTSTATUS status;
+
+    if (!pubKeyInfo->PublicKey.cbData)
+    {
+        SetLastError(NTE_BAD_ALGID);
+        return FALSE;
+    }
+
+    if (pubKeyInfo->PublicKey.pbData[0] != 0x4)
+    {
+        FIXME("Compressed ECC curves (%02x) not yet supported\n", pubKeyInfo->PublicKey.pbData[0]);
+        SetLastError(NTE_BAD_ALGID);
+        return FALSE;
+    }
+
+    if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER, pubKeyInfo->Algorithm.Parameters.pbData,
+            pubKeyInfo->Algorithm.Parameters.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_curve, &size))
+        return FALSE;
+
+    if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P256))
+    {
+        sign_algo = BCRYPT_ECDSA_P256_ALGORITHM;
+        blob_magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
+    }
+    else if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P384))
+    {
+        sign_algo = BCRYPT_ECDSA_P384_ALGORITHM;
+        blob_magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
+    }
+    else
+    {
+        FIXME("Unsupported ecc curve type: %s\n", *ecc_curve);
+        sign_algo = NULL;
+        blob_magic = 0;
+    }
+    LocalFree(ecc_curve);
+
+    if (!sign_algo)
+    {
+        SetLastError(NTE_BAD_ALGID);
+        return FALSE;
+    }
+
+    if ((status = BCryptOpenAlgorithmProvider(&alg, sign_algo, NULL, 0)))
+        goto done;
+
+    ecckey_len = sizeof(BCRYPT_ECCKEY_BLOB) + pubKeyInfo->PublicKey.cbData - 1;
+    if (!(ecckey = CryptMemAlloc(ecckey_len)))
+    {
+        status = STATUS_NO_MEMORY;
+        goto done;
+    }
+
+    ecckey->dwMagic = blob_magic;
+    ecckey->cbKey = (pubKeyInfo->PublicKey.cbData - 1) / 2;
+    memcpy(ecckey + 1, pubKeyInfo->PublicKey.pbData + 1, pubKeyInfo->PublicKey.cbData - 1);
+
+    status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, key, (BYTE*)ecckey, ecckey_len, 0);
+    CryptMemFree(ecckey);
+
+done:
+    if (alg) BCryptCloseAlgorithmProvider(alg, 0);
+    if (status) SetLastError(RtlNtStatusToDosError(status));
+    return !status;
+}
+
+static BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
+{
+    if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
+        return CNG_ImportECCPubKey(pubKeyInfo, key);
+
+    FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
+    SetLastError(NTE_BAD_ALGID);
+    return FALSE;
+}
+
+static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE **sig_value, DWORD *sig_len)
+{
+    CERT_ECC_SIGNATURE *ecc_sig;
+    DWORD size;
+    int i;
+
+    if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE, encoded_sig, encoded_size,
+            CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_sig, &size))
+        return FALSE;
+
+    if (!ecc_sig->r.cbData || !ecc_sig->s.cbData)
+    {
+        LocalFree(ecc_sig);
+        SetLastError(ERROR_INVALID_DATA);
+        return FALSE;
+    }
+
+    *sig_len = ecc_sig->r.cbData + ecc_sig->s.cbData;
+    if (!(*sig_value = CryptMemAlloc(*sig_len)))
+    {
+        LocalFree(ecc_sig);
+        SetLastError(ERROR_OUTOFMEMORY);
+        return FALSE;
+    }
+
+    for (i = 0; i < ecc_sig->r.cbData; i++)
+        (*sig_value)[i] = ecc_sig->r.pbData[ecc_sig->r.cbData - i - 1];
+    for (i = 0; i < ecc_sig->s.cbData; i++)
+        (*sig_value)[ecc_sig->r.cbData + i] = ecc_sig->s.pbData[ecc_sig->s.cbData - i - 1];
+
+    LocalFree(ecc_sig);
+    return TRUE;
+}
+
+static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert,
+    BYTE **sig_value, DWORD *sig_len)
+{
+    BYTE *encoded_sig;
+    BOOL ret = FALSE;
+    int i;
+
+    if (!signedCert->Signature.cbData)
+    {
+        SetLastError(ERROR_INVALID_DATA);
+        return FALSE;
+    }
+
+    if (!(encoded_sig = CryptMemAlloc(signedCert->Signature.cbData)))
+    {
+        SetLastError(ERROR_OUTOFMEMORY);
+        return FALSE;
+    }
+
+    for (i = 0; i < signedCert->Signature.cbData; i++)
+        encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1];
+
+    if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
+        ret = CNG_PrepareSignatureECC(encoded_sig, signedCert->Signature.cbData, sig_value, sig_len);
+    else
+    {
+        FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
+        SetLastError(NTE_BAD_ALGID);
+    }
+
+    CryptMemFree(encoded_sig);
+    return ret;
+}
+
+static BOOL CNG_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
+    CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
+{
+    BCRYPT_KEY_HANDLE key = NULL;
+    BYTE *hash_value = NULL, *sig_value;
+    DWORD hash_len, sig_len;
+    NTSTATUS status;
+    BOOL ret;
+
+    ret = CNG_ImportPubKey(pubKeyInfo, &key);
+    if (ret)
+    {
+        ret = CNG_CalcHash(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len);
+        if (ret)
+        {
+            ret = CNG_PrepareSignature(pubKeyInfo, signedCert, &sig_value, &sig_len);
+            if (ret)
+            {
+                status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0);
+                if (status)
+                {
+                    FIXME("Failed to verify signature: %08x\n", status);
+                    SetLastError(RtlNtStatusToDosError(status));
+                    ret = FALSE;
+                }
+                CryptMemFree(sig_value);
+            }
+            CryptMemFree(hash_value);
+        }
+        BCryptDestroyKey(key);
+    }
+
+    return ret;
+}
+
+static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
+    CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert)
+{
+    CCRYPT_OID_INFO *info;
+
+    info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, signedCert->SignatureAlgorithm.pszObjId, 0);
+    if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
+    {
+        SetLastError(NTE_BAD_ALGID);
+        return FALSE;
+    }
+
+    if (info->u.Algid == CALG_OID_INFO_CNG_ONLY)
+        return CNG_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
+    else
+        return CRYPT_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
+}
+
 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
@@ -2872,7 +3148,7 @@ static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
 
 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
 {
-    BOOL set = FALSE;
+    BOOL set;
     DWORD indexIndex = bit / BITS_PER_DWORD;
 
     assert(field->cIndexes);
@@ -3084,7 +3360,6 @@ static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
                 CryptMemFree(szProvider);
             }
         }
-        size = sizeof(info.dwKeySpec);
         /* in case no CRYPT_KEY_PROV_INFO given,
          *  we always use AT_SIGNATURE key spec
          */
@@ -3432,3 +3707,11 @@ const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
         return NULL;
     }
 }
+
+BOOL WINAPI CryptSetKeyIdentifierProperty(const CRYPT_HASH_BLOB *pKeyIdentifier, DWORD dwPropId,
+    DWORD dwFlags, LPCWSTR pwszComputerName, void *pvReserved, const void *pvData)
+{
+    FIXME("(%p, 0x%x, 0x%x, %s, %p, %p): stub\n", pKeyIdentifier, dwPropId, dwFlags,
+        debugstr_w(pwszComputerName), pvReserved, pvData);
+    return FALSE;
+}