From b1c2a48e3b86736cc7730c6d2c08b54c1f2d0c57 Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Sat, 10 May 2008 18:43:43 +0000 Subject: [PATCH] =?UTF-8?q?Samuel=20Serapi=C3=B3n=20(samdwise51=20AT=20gma?= =?UTF-8?q?il=20DOT=20com):=20-=20Winesync=20of=20crypt32=20=20=20The=20fu?= =?UTF-8?q?nction=20import=5Fcerts=5Ffrom=5Fdir=20had=20to=20be=20killed,?= =?UTF-8?q?=20because=20it=20uses=20UNIX-only=20functions.=20(see=20"crypt?= =?UTF-8?q?32=5Fros.diff")=20-=20This=20gets=20MSN=20Messenger=20a=20bit?= =?UTF-8?q?=20more=20to=20work?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit svn path=/trunk/; revision=33417 --- reactos/dll/win32/crypt32/cert.c | 721 +++-- reactos/dll/win32/crypt32/chain.c | 1701 ++++++++++- reactos/dll/win32/crypt32/collectionstore.c | 480 +++ reactos/dll/win32/crypt32/context.c | 6 +- reactos/dll/win32/crypt32/crl.c | 39 +- reactos/dll/win32/crypt32/crypt32.rbuild | 14 +- reactos/dll/win32/crypt32/crypt32.rc | 10 +- reactos/dll/win32/crypt32/crypt32.spec | 41 +- reactos/dll/win32/crypt32/crypt32_De.rc | 10 +- reactos/dll/win32/crypt32/crypt32_En.rc | 10 +- reactos/dll/win32/crypt32/crypt32_Fr.rc | 22 +- reactos/dll/win32/crypt32/crypt32_Ko.rc | 10 +- reactos/dll/win32/crypt32/crypt32_Nl.rc | 174 ++ reactos/dll/win32/crypt32/crypt32_No.rc | 10 +- reactos/dll/win32/crypt32/crypt32_Sv.rc | 169 ++ reactos/dll/win32/crypt32/crypt32_private.h | 180 +- reactos/dll/win32/crypt32/crypt32_ros.diff | 39 +- reactos/dll/win32/crypt32/cryptres.h | 5 + reactos/dll/win32/crypt32/decode.c | 2917 +++++++++++++------ reactos/dll/win32/crypt32/encode.c | 1195 ++++++-- reactos/dll/win32/crypt32/filestore.c | 389 +++ reactos/dll/win32/crypt32/main.c | 85 +- reactos/dll/win32/crypt32/msg.c | 2614 +++++++++++++++++ reactos/dll/win32/crypt32/object.c | 522 ++++ reactos/dll/win32/crypt32/oid.c | 286 +- reactos/dll/win32/crypt32/protectdata.c | 140 +- reactos/dll/win32/crypt32/provstore.c | 300 ++ reactos/dll/win32/crypt32/regstore.c | 550 ++++ reactos/dll/win32/crypt32/rootstore.c | 514 ++++ reactos/dll/win32/crypt32/serialize.c | 314 +- reactos/dll/win32/crypt32/sip.c | 231 +- reactos/dll/win32/crypt32/store.c | 1984 +++---------- reactos/dll/win32/crypt32/str.c | 192 +- reactos/include/psdk/i_cryptasn1tls.h | 40 + reactos/include/psdk/wincrypt.h | 164 +- 35 files changed, 12733 insertions(+), 3345 deletions(-) create mode 100644 reactos/dll/win32/crypt32/collectionstore.c create mode 100644 reactos/dll/win32/crypt32/crypt32_Nl.rc create mode 100644 reactos/dll/win32/crypt32/crypt32_Sv.rc create mode 100644 reactos/dll/win32/crypt32/filestore.c create mode 100644 reactos/dll/win32/crypt32/msg.c create mode 100644 reactos/dll/win32/crypt32/object.c create mode 100644 reactos/dll/win32/crypt32/provstore.c create mode 100644 reactos/dll/win32/crypt32/regstore.c create mode 100644 reactos/dll/win32/crypt32/rootstore.c create mode 100644 reactos/include/psdk/i_cryptasn1tls.h diff --git a/reactos/dll/win32/crypt32/cert.c b/reactos/dll/win32/crypt32/cert.c index 056096b339a..41d399814f0 100644 --- a/reactos/dll/win32/crypt32/cert.c +++ b/reactos/dll/win32/crypt32/cert.c @@ -158,7 +158,7 @@ static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId, { BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, pcbData); - if (ret) + if (ret && pvData) { CRYPT_DATA_BLOB blob = { *pcbData, pvData }; @@ -167,6 +167,27 @@ static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId, return ret; } +static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb, + DWORD cb) +{ + BOOL ret = TRUE; + + if (!pvData) + *pcbData = cb; + else if (*pcbData < cb) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = cb; + ret = FALSE; + } + else + { + memcpy(pvData, pb, cb); + *pcbData = cb; + } + return ret; +} + static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId, void *pvData, DWORD *pcbData) { @@ -183,24 +204,7 @@ static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId, else ret = FALSE; if (ret) - { - if (!pvData) - { - *pcbData = blob.cbData; - ret = TRUE; - } - else if (*pcbData < blob.cbData) - { - SetLastError(ERROR_MORE_DATA); - *pcbData = blob.cbData; - } - else - { - memcpy(pvData, blob.pbData, blob.cbData); - *pcbData = blob.cbData; - ret = TRUE; - } - } + ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData); else { /* Implicit properties */ @@ -238,6 +242,32 @@ static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId, FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n"); SetLastError(CRYPT_E_NOT_FOUND); break; + case CERT_KEY_IDENTIFIER_PROP_ID: + { + PCERT_EXTENSION ext = CertFindExtension( + szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension, + pCertContext->pCertInfo->rgExtension); + + if (ext) + { + CRYPT_DATA_BLOB value; + DWORD size = sizeof(value); + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, + szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData, + ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value, + &size); + if (ret) + { + ret = CertContext_CopyParam(pvData, pcbData, value.pbData, + value.cbData); + CertContext_SetProperty(context, dwPropId, 0, &value); + } + } + else + SetLastError(ERROR_INVALID_DATA); + break; + } default: SetLastError(CRYPT_E_NOT_FOUND); } @@ -286,30 +316,16 @@ BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, ret = FALSE; break; case CERT_ACCESS_STATE_PROP_ID: - if (!pvData) - { - *pcbData = sizeof(DWORD); - ret = TRUE; - } - else if (*pcbData < sizeof(DWORD)) - { - SetLastError(ERROR_MORE_DATA); - *pcbData = sizeof(DWORD); - ret = FALSE; - } + if (pCertContext->hCertStore) + ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId, + pvData, pcbData); else { - *(DWORD *)pvData = - CertStore_GetAccessState(pCertContext->hCertStore); - ret = TRUE; + DWORD state = 0; + + ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state)); } break; - case CERT_KEY_IDENTIFIER_PROP_ID: - ret = CertContext_GetProperty((void *)pCertContext, dwPropId, - pvData, pcbData); - if (!ret) - SetLastError(ERROR_INVALID_DATA); - break; case CERT_KEY_PROV_HANDLE_PROP_ID: { CERT_KEY_CONTEXT keyContext; @@ -318,24 +334,8 @@ BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext, ret = CertContext_GetProperty((void *)pCertContext, CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size); if (ret) - { - if (!pvData) - { - *pcbData = sizeof(HCRYPTPROV); - ret = TRUE; - } - else if (*pcbData < sizeof(HCRYPTPROV)) - { - SetLastError(ERROR_MORE_DATA); - *pcbData = sizeof(HCRYPTPROV); - ret = FALSE; - } - else - { - *(HCRYPTPROV *)pvData = keyContext.hCryptProv; - ret = TRUE; - } - } + ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv, + sizeof(keyContext.hCryptProv)); break; } case CERT_KEY_PROV_INFO_PROP_ID: @@ -496,8 +496,14 @@ static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId, { const CERT_KEY_CONTEXT *keyContext = (const CERT_KEY_CONTEXT *)pvData; - ret = ContextPropertyList_SetProperty(properties, dwPropId, - (const BYTE *)keyContext, keyContext->cbSize); + if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT)) + { + SetLastError(E_INVALIDARG); + ret = FALSE; + } + else + ret = ContextPropertyList_SetProperty(properties, dwPropId, + (const BYTE *)keyContext, keyContext->cbSize); } else { @@ -623,8 +629,8 @@ static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert, } BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert, - DWORD dwFlags, void *pvReserved, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec, - BOOL *pfCallerFreeProv) + DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv, + DWORD *pdwKeySpec, BOOL *pfCallerFreeProv) { BOOL ret = FALSE, cache = FALSE; PCRYPT_KEY_PROV_INFO info = NULL; @@ -700,11 +706,15 @@ BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert, BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType, PCERT_INFO pCertId1, PCERT_INFO pCertId2) { + BOOL ret; + TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2); - return CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer, + ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer, &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber, &pCertId2->SerialNumber); + TRACE("returning %d\n", ret); + return ret; } BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType, @@ -724,6 +734,7 @@ BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType, } else ret = FALSE; + TRACE("returning %d\n", ret); return ret; } @@ -760,12 +771,13 @@ BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1, if (cb1 == cb2) { if (cb1) - ret = !memcmp(pInt1->pbData, pInt1->pbData, cb1); + ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1); else ret = TRUE; } else ret = FALSE; + TRACE("returning %d\n", ret); return ret; } @@ -819,8 +831,7 @@ DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType, if (ret) { - RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)((LPBYTE)buf + - sizeof(BLOBHEADER)); + RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER)); len = rsaPubKey->bitlen; LocalFree(buf); @@ -899,16 +910,185 @@ static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, const void *pvPara) { CERT_INFO *pCertInfo = (CERT_INFO *)pvPara; + BOOL ret; - return CertCompareCertificateName(pCertContext->dwCertEncodingType, + /* Matching serial number and subject match.. */ + ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject); + if (ret) + ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber, + &pCertInfo->SerialNumber); + else + { + /* failing that, if the serial number and issuer match, we match */ + ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber, + &pCertInfo->SerialNumber); + if (ret) + ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, + &pCertInfo->Issuer, &pCertContext->pCertInfo->Issuer); + } + TRACE("returning %d\n", ret); + return ret; } -static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, - DWORD dwType, DWORD dwFlags, const void *pvPara) +static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) { - return compare_cert_by_subject_cert(pCertContext, dwType, dwFlags, - ((PCCERT_CONTEXT)pvPara)->pCertInfo); + CERT_ID *id = (CERT_ID *)pvPara; + BOOL ret; + + switch (id->dwIdChoice) + { + case CERT_ID_ISSUER_SERIAL_NUMBER: + ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, + &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer); + if (ret) + ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber, + &id->u.IssuerSerialNumber.SerialNumber); + break; + case CERT_ID_SHA1_HASH: + ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags, + &id->u.HashId); + break; + case CERT_ID_KEY_IDENTIFIER: + { + DWORD size = 0; + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); + if (ret && size == id->u.KeyId.cbData) + { + LPBYTE buf = CryptMemAlloc(size); + + if (buf) + { + CertGetCertificateContextProperty(pCertContext, + CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); + ret = !memcmp(buf, id->u.KeyId.pbData, size); + CryptMemFree(buf); + } + } + else + ret = FALSE; + break; + } + default: + ret = FALSE; + break; + } + return ret; +} + +static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + BOOL ret = FALSE; + PCCERT_CONTEXT subject = (PCCERT_CONTEXT)pvPara; + PCERT_EXTENSION ext; + DWORD size; + + if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, + subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) + { + CERT_AUTHORITY_KEY_ID_INFO *info; + + ret = CryptDecodeObjectEx(subject->dwCertEncodingType, + X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &info, &size); + if (ret) + { + CERT_ID id; + + if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) + { + id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer, + sizeof(CERT_NAME_BLOB)); + memcpy(&id.u.IssuerSerialNumber.SerialNumber, + &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB)); + ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags, + &id); + } + else if (info->KeyId.cbData) + { + id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); + ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags, + &id); + } + else + ret = FALSE; + LocalFree(info); + } + } + else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, + subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) + { + CERT_AUTHORITY_KEY_ID2_INFO *info; + + ret = CryptDecodeObjectEx(subject->dwCertEncodingType, + X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &info, &size); + if (ret) + { + CERT_ID id; + + 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) + { + id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + memcpy(&id.u.IssuerSerialNumber.Issuer, + &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB)); + memcpy(&id.u.IssuerSerialNumber.SerialNumber, + &info->AuthorityCertSerialNumber, + sizeof(CRYPT_INTEGER_BLOB)); + ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags, + &id); + } + else + { + FIXME("no supported name type in authority key id2\n"); + ret = FALSE; + } + } + else if (info->KeyId.cbData) + { + id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); + ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags, + &id); + } + else + ret = FALSE; + LocalFree(info); + } + } + else + ret = compare_cert_by_name(pCertContext, + CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, dwFlags, + &subject->pCertInfo->Issuer); + return ret; +} + +static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + PCCERT_CONTEXT toCompare = (PCCERT_CONTEXT)pvPara; + return CertCompareCertificate(pCertContext->dwCertEncodingType, + pCertContext->pCertInfo, toCompare->pCertInfo); } PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, @@ -918,7 +1098,7 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, PCCERT_CONTEXT ret; CertCompareFunc compare; - TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType, + TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType, dwFlags, dwType, pvPara, pPrevCertContext); switch (dwType >> CERT_COMPARE_SHIFT) @@ -938,9 +1118,15 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, case CERT_COMPARE_SUBJECT_CERT: compare = compare_cert_by_subject_cert; break; + case CERT_COMPARE_CERT_ID: + compare = compare_cert_by_cert_id; + break; case CERT_COMPARE_ISSUER_OF: compare = compare_cert_by_issuer; break; + case CERT_COMPARE_EXISTING: + compare = compare_existing_cert; + break; default: FIXME("find type %08x unimplemented\n", dwType); compare = NULL; @@ -964,6 +1150,7 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, SetLastError(CRYPT_E_NOT_FOUND); ret = NULL; } + TRACE("returning %p\n", ret); return ret; } @@ -1050,7 +1237,89 @@ PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore, ret = NULL; } } + TRACE("returning %p\n", ret); + return ret; +} +typedef struct _OLD_CERT_REVOCATION_STATUS { + DWORD cbSize; + DWORD dwIndex; + DWORD dwError; + DWORD dwReason; +} OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS; + +typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD, + void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS); + +BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType, + DWORD cContext, PVOID rgpvContext[], DWORD dwFlags, + PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus) +{ + BOOL ret; + + TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType, + cContext, rgpvContext, dwFlags, pRevPara, pRevStatus); + + if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) && + pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS)) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (cContext) + { + static HCRYPTOIDFUNCSET set = NULL; + DWORD size; + + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0); + ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size); + if (ret) + { + if (size == 1) + { + /* empty list */ + SetLastError(CRYPT_E_NO_REVOCATION_DLL); + ret = FALSE; + } + else + { + LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr; + + if (dllList) + { + ret = CryptGetDefaultOIDDllList(set, dwEncodingType, + dllList, &size); + if (ret) + { + for (ptr = dllList; ret && *ptr; + ptr += lstrlenW(ptr) + 1) + { + CertVerifyRevocationFunc func; + HCRYPTOIDFUNCADDR hFunc; + + ret = CryptGetDefaultOIDFunctionAddress(set, + dwEncodingType, ptr, 0, (void **)&func, &hFunc); + if (ret) + { + ret = func(dwEncodingType, dwRevType, cContext, + rgpvContext, dwFlags, pRevPara, pRevStatus); + CryptFreeOIDFunctionAddress(hFunc, 0); + } + } + } + CryptMemFree(dllList); + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + } + } + else + ret = TRUE; return ret; } @@ -1128,10 +1397,7 @@ LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify, if (!pTimeToVerify) { - SYSTEMTIME sysTime; - - GetSystemTime(&sysTime); - SystemTimeToFileTime(&sysTime, &fileTime); + GetSystemTimeAsFileTime(&fileTime); pTimeToVerify = &fileTime; } if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0) @@ -1152,7 +1418,7 @@ BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo, && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0; } -BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid, +BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid, DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash, DWORD *pcbComputedHash) { @@ -1181,7 +1447,7 @@ BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid, return ret; } -BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV hCryptProv, ALG_ID Algid, +BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid, DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, BYTE *pbComputedHash, DWORD *pcbComputedHash) { @@ -1219,8 +1485,8 @@ BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV hCryptProv, ALG_ID Algid, return ret; } -BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec, - DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned, +BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, + DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned, DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature) { @@ -1278,10 +1544,10 @@ BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec, return ret; } -BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV hCryptProv, +BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, - const void *pvHashAuxInfo, PBYTE pbEncoded, DWORD *pcbEncoded) + const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded) { BOOL ret; DWORD encodedSize, hashSize; @@ -1339,7 +1605,7 @@ BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV hCryptProv, return ret; } -BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv, +BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, PCERT_PUBLIC_KEY_INFO pPublicKey) { @@ -1348,7 +1614,7 @@ BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv, CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL); } -static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv, +static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert) { @@ -1358,38 +1624,17 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv, ALG_ID pubKeyID, hashID; info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, - pubKeyInfo->Algorithm.pszObjId, 0); - if (!info || (info->dwGroupId != CRYPT_PUBKEY_ALG_OID_GROUP_ID && - info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)) + signedCert->SignatureAlgorithm.pszObjId, 0); + if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID) { SetLastError(NTE_BAD_ALGID); return FALSE; } - if (info->dwGroupId == CRYPT_PUBKEY_ALG_OID_GROUP_ID) - { - switch (info->u.Algid) - { - case CALG_RSA_KEYX: - pubKeyID = CALG_RSA_SIGN; - hashID = CALG_SHA1; - break; - case CALG_RSA_SIGN: - pubKeyID = CALG_RSA_SIGN; - hashID = CALG_SHA1; - break; - default: - FIXME("unimplemented for %s\n", pubKeyInfo->Algorithm.pszObjId); - return FALSE; - } - } + hashID = info->u.Algid; + if (info->ExtraInfo.cbData >= sizeof(ALG_ID)) + pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData; else - { - hashID = info->u.Algid; - if (info->ExtraInfo.cbData >= sizeof(ALG_ID)) - pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData; - else - pubKeyID = hashID; - } + pubKeyID = hashID; /* Load the default provider if necessary */ if (!hCryptProv) hCryptProv = CRYPT_GetDefaultProvider(); @@ -1414,7 +1659,7 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv, return ret; } -BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv, +BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject, DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved) { @@ -1657,29 +1902,43 @@ BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size); if (ret) { - PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size + - sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1); + DWORD i; + BOOL exists = FALSE; - if (newUsage) + /* Make sure usage doesn't already exist */ + for (i = 0; !exists && i < usage->cUsageIdentifier; i++) { - LPSTR nextOID; - DWORD i; + if (!strcmp(usage->rgpszUsageIdentifier[i], + pszUsageIdentifier)) + exists = TRUE; + } + if (!exists) + { + PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size + + sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1); - newUsage->rgpszUsageIdentifier = - (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE)); - nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier + - (usage->cUsageIdentifier + 1) * sizeof(LPSTR)); - for (i = 0; i < usage->cUsageIdentifier; i++) + if (newUsage) { + LPSTR nextOID; + + newUsage->rgpszUsageIdentifier = (LPSTR *) + ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE)); + nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier + + (usage->cUsageIdentifier + 1) * sizeof(LPSTR)); + for (i = 0; i < usage->cUsageIdentifier; i++) + { + newUsage->rgpszUsageIdentifier[i] = nextOID; + strcpy(nextOID, usage->rgpszUsageIdentifier[i]); + nextOID += strlen(nextOID) + 1; + } newUsage->rgpszUsageIdentifier[i] = nextOID; - strcpy(nextOID, usage->rgpszUsageIdentifier[i]); - nextOID += strlen(nextOID) + 1; + strcpy(nextOID, pszUsageIdentifier); + newUsage->cUsageIdentifier = i + 1; + ret = CertSetEnhancedKeyUsage(pCertContext, newUsage); + CryptMemFree(newUsage); } - newUsage->rgpszUsageIdentifier[i] = nextOID; - strcpy(nextOID, pszUsageIdentifier); - newUsage->cUsageIdentifier = i + 1; - ret = CertSetEnhancedKeyUsage(pCertContext, newUsage); - CryptMemFree(newUsage); + else + ret = FALSE; } } CryptMemFree(usage); @@ -1766,18 +2025,57 @@ BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext, return ret; } +struct BitField +{ + DWORD cIndexes; + DWORD *indexes; +}; + +#define BITS_PER_DWORD (sizeof(DWORD) * 8) + +static void CRYPT_SetBitInField(struct BitField *field, DWORD bit) +{ + DWORD indexIndex = bit / BITS_PER_DWORD; + + if (indexIndex + 1 > field->cIndexes) + { + if (field->cIndexes) + field->indexes = CryptMemRealloc(field->indexes, + (indexIndex + 1) * sizeof(DWORD)); + else + field->indexes = CryptMemAlloc(sizeof(DWORD)); + if (field->indexes) + { + field->indexes[indexIndex] = 0; + field->cIndexes = indexIndex + 1; + } + } + if (field->indexes) + field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD); +} + +static BOOL CRYPT_IsBitInFieldSet(struct BitField *field, DWORD bit) +{ + BOOL set = FALSE; + DWORD indexIndex = bit / BITS_PER_DWORD; + + assert(field->cIndexes); + set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD)); + return set; +} + BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, - int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs) + int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs) { BOOL ret = TRUE; DWORD i, cbOIDs = 0; BOOL allUsagesValid = TRUE; CERT_ENHKEY_USAGE validUsages = { 0, NULL }; - TRACE("(%d, %p, %p, %p, %d)\n", cCerts, *rghCerts, cNumOIDSs, + TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs, rghOIDs, *pcbOIDs); - for (i = 0; ret && i < cCerts; i++) + for (i = 0; i < cCerts; i++) { CERT_ENHKEY_USAGE usage; DWORD size = sizeof(usage); @@ -1819,12 +2117,11 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, nextOID += lstrlenA(nextOID) + 1; } } - else - ret = FALSE; } else { - DWORD j, k, validIndexes = 0, numRemoved = 0; + struct BitField validIndexes = { 0, NULL }; + DWORD j, k, numRemoved = 0; /* Merge: build a bitmap of all the indexes of * validUsages.rgpszUsageIdentifier that are in pUsage. @@ -1836,7 +2133,7 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, if (!strcmp(pUsage->rgpszUsageIdentifier[j], validUsages.rgpszUsageIdentifier[k])) { - validIndexes |= (1 << k); + CRYPT_SetBitInField(&validIndexes, k); break; } } @@ -1846,11 +2143,11 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, */ for (j = 0; j < validUsages.cUsageIdentifier; j++) { - if (!(validIndexes & (1 << j))) + if (!CRYPT_IsBitInFieldSet(&validIndexes, j)) { if (j < validUsages.cUsageIdentifier - 1) { - memcpy(&validUsages.rgpszUsageIdentifier[j], + memmove(&validUsages.rgpszUsageIdentifier[j], &validUsages.rgpszUsageIdentifier[j + numRemoved + 1], (validUsages.cUsageIdentifier - numRemoved @@ -1858,52 +2155,54 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts, cbOIDs -= lstrlenA( validUsages.rgpszUsageIdentifier[j]) + 1 + sizeof(LPSTR); + validUsages.cUsageIdentifier--; numRemoved++; } else validUsages.cUsageIdentifier--; } } + CryptMemFree(validIndexes.indexes); } } CryptMemFree(pUsage); } - else - ret = FALSE; } } - if (ret) + ret = TRUE; + if (allUsagesValid) { - if (allUsagesValid) + *cNumOIDs = -1; + *pcbOIDs = 0; + } + else + { + *cNumOIDs = validUsages.cUsageIdentifier; + if (!rghOIDs) + *pcbOIDs = cbOIDs; + else if (*pcbOIDs < cbOIDs) { - *cNumOIDSs = -1; - *pcbOIDs = 0; + *pcbOIDs = cbOIDs; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; } else { - if (!rghOIDs || *pcbOIDs < cbOIDs) - { - *pcbOIDs = cbOIDs; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs + - validUsages.cUsageIdentifier * sizeof(LPSTR)); + LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs + + validUsages.cUsageIdentifier * sizeof(LPSTR)); - *pcbOIDs = cbOIDs; - *cNumOIDSs = validUsages.cUsageIdentifier; - for (i = 0; i < validUsages.cUsageIdentifier; i++) - { - rghOIDs[i] = nextOID; - lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]); - nextOID += lstrlenA(nextOID) + 1; - } + *pcbOIDs = cbOIDs; + for (i = 0; i < validUsages.cUsageIdentifier; i++) + { + rghOIDs[i] = nextOID; + lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]); + nextOID += lstrlenA(nextOID) + 1; } } } CryptMemFree(validUsages.rgpszUsageIdentifier); + TRACE("cNumOIDs: %d\n", *cNumOIDs); + TRACE("returning %d\n", ret); return ret; } @@ -1970,10 +2269,10 @@ static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context, } } size = sizeof(info.dwKeySpec); - ret = CryptGetProvParam(hProv, PP_KEYSPEC, (LPBYTE)&info.dwKeySpec, - &size, 0); - if (!ret) - info.dwKeySpec = AT_SIGNATURE; + /* in case no CRYPT_KEY_PROV_INFO given, + * we always use AT_SIGNATURE key spec + */ + info.dwKeySpec = AT_SIGNATURE; size = sizeof(info.dwProvType); ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType, &size, 0); @@ -1996,19 +2295,19 @@ static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context, * in blob, using the crypto provider hProv and the signature algorithm sigAlgo. */ static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob, - HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo) + HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo) { PCCERT_CONTEXT context = NULL; BOOL ret; DWORD sigSize = 0; - ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING, + ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING, blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize); if (ret) { LPBYTE sig = CryptMemAlloc(sigSize); - ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING, + ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING, blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize); if (ret) { @@ -2108,7 +2407,7 @@ static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNu info->rgExtension = NULL; } } - + typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *); typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **); typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **); @@ -2159,7 +2458,7 @@ static HCRYPTPROV CRYPT_CreateKeyProv(void) return hProv; } -PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv, +PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv, PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags, PCRYPT_KEY_PROV_INFO pKeyProvInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime, @@ -2168,24 +2467,80 @@ PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv, PCCERT_CONTEXT context = NULL; BOOL ret, releaseContext = FALSE; PCERT_PUBLIC_KEY_INFO pubKey = NULL; - DWORD pubKeySize = 0; + DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE; TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv, pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime, pExtensions, pExtensions); - if (!hProv) + if(!pSubjectIssuerBlob) { - hProv = CRYPT_CreateKeyProv(); - releaseContext = TRUE; + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; } - CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL, + if (!hProv) + { + if (!pKeyProvInfo) + { + hProv = CRYPT_CreateKeyProv(); + releaseContext = TRUE; + } + else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID) + { + SetLastError(NTE_BAD_FLAGS); + return NULL; + } + else + { + HCRYPTKEY hKey = 0; + /* acquire the context using the given information*/ + ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName, + pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType, + pKeyProvInfo->dwFlags); + if (!ret) + { + if(GetLastError() != NTE_BAD_KEYSET) + return NULL; + /* create the key set */ + ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName, + pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType, + pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET); + if (!ret) + return NULL; + } + dwKeySpec = pKeyProvInfo->dwKeySpec; + /* check if the key is here */ + ret = CryptGetUserKey(hProv,dwKeySpec,&hKey); + if(!ret) + { + if (NTE_NO_KEY == GetLastError()) + { /* generate the key */ + ret = CryptGenKey(hProv,dwKeySpec,0,&hKey); + } + if (!ret) + { + CryptReleaseContext(hProv,0); + SetLastError(NTE_BAD_KEYSET); + return NULL; + } + } + CryptDestroyKey(hKey); + releaseContext = TRUE; + } + } + else if (pKeyProvInfo) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL, &pubKeySize); pubKey = CryptMemAlloc(pubKeySize); if (pubKey) { - ret = CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, + ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, pubKey, &pubKeySize); if (ret) { @@ -2203,7 +2558,7 @@ PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv, if (ret) { if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN)) - context = CRYPT_CreateSignedCert(&blob, hProv, + context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec, &info.SignatureAlgorithm); else context = CertCreateCertificateContext(X509_ASN_ENCODING, @@ -2219,3 +2574,15 @@ PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv, CryptReleaseContext(hProv, 0); return context; } + +BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType, + void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags, + PCTL_VERIFY_USAGE_PARA pVerifyUsagePara, + PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus) +{ + FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType, + dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara, + pVerifyUsageStatus); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} diff --git a/reactos/dll/win32/crypt32/chain.c b/reactos/dll/win32/crypt32/chain.c index 03267db076e..a13a8960918 100644 --- a/reactos/dll/win32/crypt32/chain.c +++ b/reactos/dll/win32/crypt32/chain.c @@ -17,14 +17,22 @@ * */ #include +#define NONAMELESSUNION #include "windef.h" #include "winbase.h" +#define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS +#define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS #include "wincrypt.h" #include "wine/debug.h" +#include "wine/unicode.h" #include "crypt32_private.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); +#define DEFAULT_CYCLE_MODULUS 7 + +static HCERTCHAINENGINE CRYPT_defaultChainEngine; + /* This represents a subset of a certificate chain engine: it doesn't include * the "hOther" store described by MSDN, because I'm not sure how that's used. * It also doesn't include the "hTrust" store, because I don't yet implement @@ -100,12 +108,48 @@ static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store) return ret; } -BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig, - HCERTCHAINENGINE *phChainEngine) +HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root, + PCERT_CHAIN_ENGINE_CONFIG pConfig) { static const WCHAR caW[] = { 'C','A',0 }; static const WCHAR myW[] = { 'M','y',0 }; static const WCHAR trustW[] = { 'T','r','u','s','t',0 }; + PCertificateChainEngine engine = + CryptMemAlloc(sizeof(CertificateChainEngine)); + + if (engine) + { + HCERTSTORE worldStores[4]; + + engine->ref = 1; + engine->hRoot = root; + engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + worldStores[0] = CertDuplicateStore(engine->hRoot); + worldStores[1] = CertOpenSystemStoreW(0, caW); + worldStores[2] = CertOpenSystemStoreW(0, myW); + worldStores[3] = CertOpenSystemStoreW(0, trustW); + CRYPT_AddStoresToCollection(engine->hWorld, + sizeof(worldStores) / sizeof(worldStores[0]), worldStores); + CRYPT_AddStoresToCollection(engine->hWorld, + pConfig->cAdditionalStore, pConfig->rghAdditionalStore); + CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]), + worldStores); + engine->dwFlags = pConfig->dwFlags; + engine->dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout; + engine->MaximumCachedCertificates = + pConfig->MaximumCachedCertificates; + if (pConfig->CycleDetectionModulus) + engine->CycleDetectionModulus = pConfig->CycleDetectionModulus; + else + engine->CycleDetectionModulus = DEFAULT_CYCLE_MODULUS; + } + return (HCERTCHAINENGINE)engine; +} + +BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig, + HCERTCHAINENGINE *phChainEngine) +{ BOOL ret; TRACE("(%p, %p)\n", pConfig, phChainEngine); @@ -119,36 +163,17 @@ BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig, ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot); if (ret) { - PCertificateChainEngine engine = - CryptMemAlloc(sizeof(CertificateChainEngine)); + HCERTSTORE root; + HCERTCHAINENGINE engine; + if (pConfig->hRestrictedRoot) + root = CertDuplicateStore(pConfig->hRestrictedRoot); + else + root = CertOpenSystemStoreW(0, rootW); + engine = CRYPT_CreateChainEngine(root, pConfig); if (engine) { - HCERTSTORE worldStores[4]; - - engine->ref = 1; - if (pConfig->hRestrictedRoot) - engine->hRoot = CertDuplicateStore(pConfig->hRestrictedRoot); - else - engine->hRoot = CertOpenSystemStoreW(0, rootW); - engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, - CERT_STORE_CREATE_NEW_FLAG, NULL); - worldStores[0] = CertDuplicateStore(engine->hRoot); - worldStores[1] = CertOpenSystemStoreW(0, caW); - worldStores[2] = CertOpenSystemStoreW(0, myW); - worldStores[3] = CertOpenSystemStoreW(0, trustW); - CRYPT_AddStoresToCollection(engine->hWorld, - sizeof(worldStores) / sizeof(worldStores[0]), worldStores); - CRYPT_AddStoresToCollection(engine->hWorld, - pConfig->cAdditionalStore, pConfig->rghAdditionalStore); - CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]), - worldStores); - engine->dwFlags = pConfig->dwFlags; - engine->dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout; - engine->MaximumCachedCertificates = - pConfig->MaximumCachedCertificates; - engine->CycleDetectionModulus = pConfig->CycleDetectionModulus; - *phChainEngine = (HCERTCHAINENGINE)engine; + *phChainEngine = engine; ret = TRUE; } else @@ -157,7 +182,7 @@ BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig, return ret; } -void WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine) +VOID WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine) { PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine; @@ -170,3 +195,1619 @@ void WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine) CryptMemFree(engine); } } + +static HCERTCHAINENGINE CRYPT_GetDefaultChainEngine(void) +{ + if (!CRYPT_defaultChainEngine) + { + CERT_CHAIN_ENGINE_CONFIG config = { 0 }; + HCERTCHAINENGINE engine; + + config.cbSize = sizeof(config); + CertCreateCertificateChainEngine(&config, &engine); + InterlockedCompareExchangePointer(&CRYPT_defaultChainEngine, engine, + NULL); + if (CRYPT_defaultChainEngine != engine) + CertFreeCertificateChainEngine(engine); + } + return CRYPT_defaultChainEngine; +} + +void default_chain_engine_free(void) +{ + CertFreeCertificateChainEngine(CRYPT_defaultChainEngine); +} + +typedef struct _CertificateChain +{ + CERT_CHAIN_CONTEXT context; + HCERTSTORE world; + LONG ref; +} CertificateChain, *PCertificateChain; + +static inline BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert) +{ + return CertCompareCertificateName(cert->dwCertEncodingType, + &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer); +} + +static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element) +{ + CertFreeCertificateContext(element->pCertContext); + CryptMemFree(element); +} + +static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain) +{ + DWORD i, j, cyclicCertIndex = 0; + + /* O(n^2) - I don't think there's a faster way */ + for (i = 0; !cyclicCertIndex && i < chain->cElement; i++) + for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++) + if (CertCompareCertificate(X509_ASN_ENCODING, + chain->rgpElement[i]->pCertContext->pCertInfo, + chain->rgpElement[j]->pCertContext->pCertInfo)) + cyclicCertIndex = j; + if (cyclicCertIndex) + { + chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus + |= CERT_TRUST_IS_CYCLIC; + /* Release remaining certs */ + for (i = cyclicCertIndex + 1; i < chain->cElement; i++) + CRYPT_FreeChainElement(chain->rgpElement[i]); + /* Truncate chain */ + chain->cElement = cyclicCertIndex + 1; + } +} + +/* Checks whether the chain is cyclic by examining the last element's status */ +static inline BOOL CRYPT_IsSimpleChainCyclic(PCERT_SIMPLE_CHAIN chain) +{ + if (chain->cElement) + return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus + & CERT_TRUST_IS_CYCLIC; + else + return FALSE; +} + +static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS *chainStatus, + CERT_TRUST_STATUS *elementStatus) +{ + /* Any error that applies to an element also applies to a chain.. */ + chainStatus->dwErrorStatus |= elementStatus->dwErrorStatus; + /* but the bottom nibble of an element's info status doesn't apply to the + * chain. + */ + chainStatus->dwInfoStatus |= (elementStatus->dwInfoStatus & 0xfffffff0); +} + +static BOOL CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine, + PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD subjectInfoStatus) +{ + BOOL ret = FALSE; + PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT)); + + if (element) + { + if (!chain->cElement) + chain->rgpElement = CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT)); + else + chain->rgpElement = CryptMemRealloc(chain->rgpElement, + (chain->cElement + 1) * sizeof(PCERT_CHAIN_ELEMENT)); + if (chain->rgpElement) + { + chain->rgpElement[chain->cElement++] = element; + memset(element, 0, sizeof(CERT_CHAIN_ELEMENT)); + element->cbSize = sizeof(CERT_CHAIN_ELEMENT); + element->pCertContext = CertDuplicateCertificateContext(cert); + if (chain->cElement > 1) + chain->rgpElement[chain->cElement - 2]->TrustStatus.dwInfoStatus + = subjectInfoStatus; + /* FIXME: initialize the rest of element */ + if (chain->cElement % engine->CycleDetectionModulus) + CRYPT_CheckSimpleChainForCycles(chain); + CRYPT_CombineTrustStatus(&chain->TrustStatus, + &element->TrustStatus); + ret = TRUE; + } + else + CryptMemFree(element); + } + return ret; +} + +static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain) +{ + DWORD i; + + for (i = 0; i < chain->cElement; i++) + CRYPT_FreeChainElement(chain->rgpElement[i]); + CryptMemFree(chain->rgpElement); + CryptMemFree(chain); +} + +static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot, + PCERT_CHAIN_ELEMENT rootElement) +{ + BYTE hash[20]; + DWORD size = sizeof(hash); + CRYPT_HASH_BLOB blob = { sizeof(hash), hash }; + PCCERT_CONTEXT trustedRoot; + + CertGetCertificateContextProperty(rootElement->pCertContext, + CERT_HASH_PROP_ID, hash, &size); + trustedRoot = CertFindCertificateInStore(hRoot, + rootElement->pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, + &blob, NULL); + if (!trustedRoot) + rootElement->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_UNTRUSTED_ROOT; + else + CertFreeCertificateContext(trustedRoot); +} + +static void CRYPT_CheckRootCert(HCERTCHAINENGINE hRoot, + PCERT_CHAIN_ELEMENT rootElement) +{ + PCCERT_CONTEXT root = rootElement->pCertContext; + + if (!CryptVerifyCertificateSignatureEx(0, root->dwCertEncodingType, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root, + CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL)) + { + TRACE("Last certificate's signature is invalid\n"); + rootElement->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_NOT_SIGNATURE_VALID; + } + CRYPT_CheckTrustedStatus(hRoot, rootElement); +} + +/* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS + * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a + * CERT_BASIC_CONSTRAINTS2_INFO. If it neither extension is present, sets + * constraints->fCA to defaultIfNotSpecified. + * Returns FALSE if the extension is present but couldn't be decoded. + */ +static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert, + CERT_BASIC_CONSTRAINTS2_INFO *constraints, BOOL defaultIfNotSpecified) +{ + BOOL ret = TRUE; + PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS, + cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); + + constraints->fPathLenConstraint = FALSE; + if (ext) + { + CERT_BASIC_CONSTRAINTS_INFO *info; + DWORD size = 0; + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS, + ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, + NULL, (LPBYTE)&info, &size); + if (ret) + { + if (info->SubjectType.cbData == 1) + constraints->fCA = + info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG; + LocalFree(info); + } + } + else + { + ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2, + cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); + if (ext) + { + DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO); + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, + szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData, + 0, NULL, constraints, &size); + } + else + constraints->fCA = defaultIfNotSpecified; + } + return ret; +} + +/* Checks element's basic constraints to see if it can act as a CA, with + * remainingCAs CAs left in this chain. Updates chainConstraints with the + * element's constraints, if: + * 1. chainConstraints doesn't have a path length constraint, or + * 2. element's path length constraint is smaller than chainConstraints's + * Sets *pathLengthConstraintViolated to TRUE if a path length violation + * occurs. + * Returns TRUE if the element can be a CA, and the length of the remaining + * chain is valid. + */ +static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert, + CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs, + BOOL *pathLengthConstraintViolated) +{ + BOOL validBasicConstraints; + CERT_BASIC_CONSTRAINTS2_INFO constraints; + + if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert, + &constraints, TRUE))) + { + if (!constraints.fCA) + { + TRACE("chain element %d can't be a CA\n", remainingCAs + 1); + validBasicConstraints = FALSE; + } + else if (constraints.fPathLenConstraint) + { + /* If the element has path length constraints, they apply to the + * entire remaining chain. + */ + if (!chainConstraints->fPathLenConstraint || + constraints.dwPathLenConstraint < + chainConstraints->dwPathLenConstraint) + { + TRACE("setting path length constraint to %d\n", + chainConstraints->dwPathLenConstraint); + chainConstraints->fPathLenConstraint = TRUE; + chainConstraints->dwPathLenConstraint = + constraints.dwPathLenConstraint; + } + } + } + if (chainConstraints->fPathLenConstraint && + remainingCAs > chainConstraints->dwPathLenConstraint) + { + TRACE("remaining CAs %d exceed max path length %d\n", remainingCAs, + chainConstraints->dwPathLenConstraint); + validBasicConstraints = FALSE; + *pathLengthConstraintViolated = TRUE; + } + return validBasicConstraints; +} + +static BOOL url_matches(LPCWSTR constraint, LPCWSTR name, + DWORD *trustErrorStatus) +{ + BOOL match = FALSE; + + TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name)); + + if (!constraint) + *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; + else if (!name) + ; /* no match */ + else if (constraint[0] == '.') + { + if (lstrlenW(name) > lstrlenW(constraint)) + match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint), + constraint); + } + else + match = !lstrcmpiW(constraint, name); + return match; +} + +static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name, + DWORD *trustErrorStatus) +{ + BOOL match = FALSE; + LPCWSTR at; + + TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name)); + + if (!constraint) + *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; + else if (!name) + ; /* no match */ + else if ((at = strchrW(constraint, '@'))) + match = !lstrcmpiW(constraint, name); + else + { + if ((at = strchrW(name, '@'))) + match = url_matches(constraint, at + 1, trustErrorStatus); + else + match = !lstrcmpiW(constraint, name); + } + return match; +} + +static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name, + DWORD *trustErrorStatus) +{ + BOOL match = FALSE; + + TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name)); + + if (!constraint) + *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; + else if (!name) + ; /* no match */ + else if (lstrlenW(name) >= lstrlenW(constraint)) + match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint), + constraint); + /* else: name is too short, no match */ + + return match; +} + +static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint, + const CRYPT_DATA_BLOB *name, DWORD *trustErrorStatus) +{ + BOOL match = FALSE; + + TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData, + name->cbData, name->pbData); + + if (constraint->cbData != sizeof(DWORD) * 2) + *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; + else if (name->cbData == sizeof(DWORD)) + { + DWORD subnet, mask, addr; + + memcpy(&subnet, constraint->pbData, sizeof(subnet)); + memcpy(&mask, constraint->pbData + sizeof(subnet), sizeof(mask)); + memcpy(&addr, name->pbData, sizeof(addr)); + /* These are really in big-endian order, but for equality matching we + * don't need to swap to host order + */ + match = (subnet & mask) == (addr & mask); + } + /* else: name is wrong size, no match */ + + return match; +} + +static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY *constraint, + const CERT_ALT_NAME_INFO *subjectName, DWORD *trustErrorStatus, + DWORD errorIfFound, DWORD errorIfNotFound) +{ + DWORD i; + BOOL defined = FALSE, match = FALSE; + + for (i = 0; i < subjectName->cAltEntry; i++) + { + if (subjectName->rgAltEntry[i].dwAltNameChoice == + constraint->dwAltNameChoice) + { + defined = TRUE; + switch (constraint->dwAltNameChoice) + { + case CERT_ALT_NAME_RFC822_NAME: + match = rfc822_name_matches(constraint->u.pwszURL, + subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus); + break; + case CERT_ALT_NAME_DNS_NAME: + match = dns_name_matches(constraint->u.pwszURL, + subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus); + break; + case CERT_ALT_NAME_URL: + match = url_matches(constraint->u.pwszURL, + subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus); + break; + case CERT_ALT_NAME_IP_ADDRESS: + match = ip_address_matches(&constraint->u.IPAddress, + &subjectName->rgAltEntry[i].u.IPAddress, trustErrorStatus); + break; + case CERT_ALT_NAME_DIRECTORY_NAME: + default: + ERR("name choice %d unsupported in this context\n", + constraint->dwAltNameChoice); + *trustErrorStatus |= + CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT; + } + } + } + /* Microsoft's implementation of name constraint checking appears at odds + * with RFC 3280: + * According to MSDN, CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT is set + * when a name constraint is present, but that name form is not defined in + * the end certificate. According to RFC 3280, "if no name of the type is + * in the certificate, the name is acceptable." + * I follow Microsoft here. + */ + if (!defined) + *trustErrorStatus |= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT; + *trustErrorStatus |= match ? errorIfFound : errorIfNotFound; +} + +static void CRYPT_CheckNameConstraints( + const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert, + DWORD *trustErrorStatus) +{ + /* If there aren't any existing constraints, don't bother checking */ + if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree) + { + CERT_EXTENSION *ext; + + if ((ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, cert->cExtension, + cert->rgExtension))) + { + CERT_ALT_NAME_INFO *subjectName; + DWORD size; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, + ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &subjectName, &size)) + { + DWORD i; + + for (i = 0; i < nameConstraints->cExcludedSubtree; i++) + CRYPT_FindMatchingNameEntry( + &nameConstraints->rgExcludedSubtree[i].Base, subjectName, + trustErrorStatus, + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, 0); + for (i = 0; i < nameConstraints->cPermittedSubtree; i++) + CRYPT_FindMatchingNameEntry( + &nameConstraints->rgPermittedSubtree[i].Base, subjectName, + trustErrorStatus, + 0, CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT); + LocalFree(subjectName); + } + } + else + { + /* See above comment on CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT. + * I match Microsoft's implementation here as well. + */ + *trustErrorStatus |= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT; + if (nameConstraints->cPermittedSubtree) + *trustErrorStatus |= + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; + if (nameConstraints->cExcludedSubtree) + *trustErrorStatus |= + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; + } + } +} + +/* Gets cert's name constraints, if any. Free with LocalFree. */ +static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert) +{ + CERT_NAME_CONSTRAINTS_INFO *info = NULL; + + CERT_EXTENSION *ext; + + if ((ext = CertFindExtension(szOID_NAME_CONSTRAINTS, cert->cExtension, + cert->rgExtension))) + { + DWORD size; + + CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS, + ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info, + &size); + } + return info; +} + +static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain) +{ + int i, j; + + /* Microsoft's implementation appears to violate RFC 3280: according to + * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's + * name constraint is violated in the end cert. According to RFC 3280, + * the constraints should be checked against every subsequent certificate + * in the chain, not just the end cert. + * Microsoft's implementation also sets the name constraint errors on the + * certs whose constraints were violated, not on the certs that violated + * them. + * In order to be error-compatible with Microsoft's implementation, while + * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name + * constraints. + */ + for (i = chain->cElement - 1; i > 0; i--) + { + CERT_NAME_CONSTRAINTS_INFO *nameConstraints; + + if ((nameConstraints = CRYPT_GetNameConstraints( + chain->rgpElement[i]->pCertContext->pCertInfo))) + { + for (j = i - 1; j >= 0; j--) + { + DWORD errorStatus = 0; + + /* According to RFC 3280, self-signed certs don't have name + * constraints checked unless they're the end cert. + */ + if (j == 0 || !CRYPT_IsCertificateSelfSigned( + chain->rgpElement[j]->pCertContext)) + { + CRYPT_CheckNameConstraints(nameConstraints, + chain->rgpElement[i]->pCertContext->pCertInfo, + &errorStatus); + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + errorStatus; + } + } + LocalFree(nameConstraints); + } + } +} + +static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine, + PCERT_SIMPLE_CHAIN chain, LPFILETIME time) +{ + PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1]; + int i; + BOOL pathLengthConstraintViolated = FALSE; + CERT_BASIC_CONSTRAINTS2_INFO constraints = { TRUE, FALSE, 0 }; + + for (i = chain->cElement - 1; i >= 0; i--) + { + if (CertVerifyTimeValidity(time, + chain->rgpElement[i]->pCertContext->pCertInfo) != 0) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_NOT_TIME_VALID; + if (i != 0) + { + /* Check the signature of the cert this issued */ + if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, + (void *)chain->rgpElement[i - 1]->pCertContext, + CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, + (void *)chain->rgpElement[i]->pCertContext, 0, NULL)) + chain->rgpElement[i - 1]->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_NOT_SIGNATURE_VALID; + /* Once a path length constraint has been violated, every remaining + * CA cert's basic constraints is considered invalid. + */ + if (pathLengthConstraintViolated) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_INVALID_BASIC_CONSTRAINTS; + else if (!CRYPT_CheckBasicConstraintsForCA( + chain->rgpElement[i]->pCertContext, &constraints, i - 1, + &pathLengthConstraintViolated)) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_INVALID_BASIC_CONSTRAINTS; + else if (constraints.fPathLenConstraint && + constraints.dwPathLenConstraint) + { + /* This one's valid - decrement max length */ + constraints.dwPathLenConstraint--; + } + } + /* FIXME: check valid usages */ + CRYPT_CombineTrustStatus(&chain->TrustStatus, + &chain->rgpElement[i]->TrustStatus); + } + CRYPT_CheckChainNameConstraints(chain); + if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext)) + { + rootElement->TrustStatus.dwInfoStatus |= + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER; + CRYPT_CheckRootCert(engine->hRoot, rootElement); + } + CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus); +} + +static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject, + PCCERT_CONTEXT prevIssuer, DWORD *infoStatus) +{ + PCCERT_CONTEXT issuer = NULL; + PCERT_EXTENSION ext; + DWORD size; + + *infoStatus = 0; + if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, + subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) + { + CERT_AUTHORITY_KEY_ID_INFO *info; + BOOL ret; + + ret = CryptDecodeObjectEx(subject->dwCertEncodingType, + X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &info, &size); + if (ret) + { + CERT_ID id; + + if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) + { + id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer, + sizeof(CERT_NAME_BLOB)); + memcpy(&id.u.IssuerSerialNumber.SerialNumber, + &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB)); + issuer = CertFindCertificateInStore(store, + subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, + prevIssuer); + if (issuer) + *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER; + } + else if (info->KeyId.cbData) + { + id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); + issuer = CertFindCertificateInStore(store, + subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, + prevIssuer); + if (issuer) + *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER; + } + LocalFree(info); + } + } + else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, + subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) + { + CERT_AUTHORITY_KEY_ID2_INFO *info; + BOOL ret; + + ret = CryptDecodeObjectEx(subject->dwCertEncodingType, + X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &info, &size); + if (ret) + { + CERT_ID id; + + 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) + { + id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + memcpy(&id.u.IssuerSerialNumber.Issuer, + &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB)); + memcpy(&id.u.IssuerSerialNumber.SerialNumber, + &info->AuthorityCertSerialNumber, + sizeof(CRYPT_INTEGER_BLOB)); + issuer = CertFindCertificateInStore(store, + subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, + prevIssuer); + if (issuer) + *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER; + } + else + FIXME("no supported name type in authority key id2\n"); + } + else if (info->KeyId.cbData) + { + id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); + issuer = CertFindCertificateInStore(store, + subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id, + prevIssuer); + if (issuer) + *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER; + } + LocalFree(info); + } + } + else + { + issuer = CertFindCertificateInStore(store, + subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME, + &subject->pCertInfo->Issuer, prevIssuer); + if (issuer) + *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER; + } + return issuer; +} + +/* Builds a simple chain by finding an issuer for the last cert in the chain, + * until reaching a self-signed cert, or until no issuer can be found. + */ +static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine, + HCERTSTORE world, PCERT_SIMPLE_CHAIN chain) +{ + BOOL ret = TRUE; + PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext; + + while (ret && !CRYPT_IsSimpleChainCyclic(chain) && + !CRYPT_IsCertificateSelfSigned(cert)) + { + DWORD infoStatus; + PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL, &infoStatus); + + if (issuer) + { + ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, infoStatus); + /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to + * close the enumeration that found it + */ + CertFreeCertificateContext(issuer); + cert = issuer; + } + else + { + TRACE("Couldn't find issuer, halting chain creation\n"); + break; + } + } + return ret; +} + +static BOOL CRYPT_GetSimpleChainForCert(PCertificateChainEngine engine, + HCERTSTORE world, PCCERT_CONTEXT cert, LPFILETIME pTime, + PCERT_SIMPLE_CHAIN *ppChain) +{ + BOOL ret = FALSE; + PCERT_SIMPLE_CHAIN chain; + + TRACE("(%p, %p, %p, %p)\n", engine, world, cert, pTime); + + chain = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN)); + if (chain) + { + memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN)); + chain->cbSize = sizeof(CERT_SIMPLE_CHAIN); + ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0); + if (ret) + { + ret = CRYPT_BuildSimpleChain(engine, world, chain); + if (ret) + CRYPT_CheckSimpleChain(engine, chain, pTime); + } + if (!ret) + { + CRYPT_FreeSimpleChain(chain); + chain = NULL; + } + *ppChain = chain; + } + return ret; +} + +static BOOL CRYPT_BuildCandidateChainFromCert(HCERTCHAINENGINE hChainEngine, + PCCERT_CONTEXT cert, LPFILETIME pTime, HCERTSTORE hAdditionalStore, + PCertificateChain *ppChain) +{ + PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine; + PCERT_SIMPLE_CHAIN simpleChain = NULL; + HCERTSTORE world; + BOOL ret; + + world = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddStoreToCollection(world, engine->hWorld, 0, 0); + if (hAdditionalStore) + CertAddStoreToCollection(world, hAdditionalStore, 0, 0); + /* FIXME: only simple chains are supported for now, as CTLs aren't + * supported yet. + */ + if ((ret = CRYPT_GetSimpleChainForCert(engine, world, cert, pTime, + &simpleChain))) + { + PCertificateChain chain = CryptMemAlloc(sizeof(CertificateChain)); + + if (chain) + { + chain->ref = 1; + chain->world = world; + chain->context.cbSize = sizeof(CERT_CHAIN_CONTEXT); + chain->context.TrustStatus = simpleChain->TrustStatus; + chain->context.cChain = 1; + chain->context.rgpChain = CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN)); + chain->context.rgpChain[0] = simpleChain; + chain->context.cLowerQualityChainContext = 0; + chain->context.rgpLowerQualityChainContext = NULL; + chain->context.fHasRevocationFreshnessTime = FALSE; + chain->context.dwRevocationFreshnessTime = 0; + } + else + ret = FALSE; + *ppChain = chain; + } + return ret; +} + +/* Makes and returns a copy of chain, up to and including element iElement. */ +static PCERT_SIMPLE_CHAIN CRYPT_CopySimpleChainToElement( + PCERT_SIMPLE_CHAIN chain, DWORD iElement) +{ + PCERT_SIMPLE_CHAIN copy = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN)); + + if (copy) + { + memset(copy, 0, sizeof(CERT_SIMPLE_CHAIN)); + copy->cbSize = sizeof(CERT_SIMPLE_CHAIN); + copy->rgpElement = + CryptMemAlloc((iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT)); + if (copy->rgpElement) + { + DWORD i; + BOOL ret = TRUE; + + memset(copy->rgpElement, 0, + (iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT)); + for (i = 0; ret && i <= iElement; i++) + { + PCERT_CHAIN_ELEMENT element = + CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT)); + + if (element) + { + *element = *chain->rgpElement[i]; + element->pCertContext = CertDuplicateCertificateContext( + chain->rgpElement[i]->pCertContext); + /* Reset the trust status of the copied element, it'll get + * rechecked after the new chain is done. + */ + memset(&element->TrustStatus, 0, sizeof(CERT_TRUST_STATUS)); + copy->rgpElement[copy->cElement++] = element; + } + else + ret = FALSE; + } + if (!ret) + { + for (i = 0; i <= iElement; i++) + CryptMemFree(copy->rgpElement[i]); + CryptMemFree(copy->rgpElement); + CryptMemFree(copy); + copy = NULL; + } + } + else + { + CryptMemFree(copy); + copy = NULL; + } + } + return copy; +} + +static void CRYPT_FreeLowerQualityChains(PCertificateChain chain) +{ + DWORD i; + + for (i = 0; i < chain->context.cLowerQualityChainContext; i++) + CertFreeCertificateChain(chain->context.rgpLowerQualityChainContext[i]); + CryptMemFree(chain->context.rgpLowerQualityChainContext); + chain->context.cLowerQualityChainContext = 0; + chain->context.rgpLowerQualityChainContext = NULL; +} + +static void CRYPT_FreeChainContext(PCertificateChain chain) +{ + DWORD i; + + CRYPT_FreeLowerQualityChains(chain); + for (i = 0; i < chain->context.cChain; i++) + CRYPT_FreeSimpleChain(chain->context.rgpChain[i]); + CryptMemFree(chain->context.rgpChain); + CertCloseStore(chain->world, 0); + CryptMemFree(chain); +} + +/* Makes and returns a copy of chain, up to and including element iElement of + * simple chain iChain. + */ +static PCertificateChain CRYPT_CopyChainToElement(PCertificateChain chain, + DWORD iChain, DWORD iElement) +{ + PCertificateChain copy = CryptMemAlloc(sizeof(CertificateChain)); + + if (copy) + { + copy->ref = 1; + copy->world = CertDuplicateStore(chain->world); + copy->context.cbSize = sizeof(CERT_CHAIN_CONTEXT); + /* Leave the trust status of the copied chain unset, it'll get + * rechecked after the new chain is done. + */ + memset(©->context.TrustStatus, 0, sizeof(CERT_TRUST_STATUS)); + copy->context.cLowerQualityChainContext = 0; + copy->context.rgpLowerQualityChainContext = NULL; + copy->context.fHasRevocationFreshnessTime = FALSE; + copy->context.dwRevocationFreshnessTime = 0; + copy->context.rgpChain = CryptMemAlloc( + (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN)); + if (copy->context.rgpChain) + { + BOOL ret = TRUE; + DWORD i; + + memset(copy->context.rgpChain, 0, + (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN)); + if (iChain) + { + for (i = 0; ret && iChain && i < iChain - 1; i++) + { + copy->context.rgpChain[i] = + CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i], + chain->context.rgpChain[i]->cElement - 1); + if (!copy->context.rgpChain[i]) + ret = FALSE; + } + } + else + i = 0; + if (ret) + { + copy->context.rgpChain[i] = + CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i], + iElement); + if (!copy->context.rgpChain[i]) + ret = FALSE; + } + if (!ret) + { + CRYPT_FreeChainContext(copy); + copy = NULL; + } + else + copy->context.cChain = iChain + 1; + } + else + { + CryptMemFree(copy); + copy = NULL; + } + } + return copy; +} + +static PCertificateChain CRYPT_BuildAlternateContextFromChain( + HCERTCHAINENGINE hChainEngine, LPFILETIME pTime, HCERTSTORE hAdditionalStore, + PCertificateChain chain) +{ + PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine; + PCertificateChain alternate; + + TRACE("(%p, %p, %p, %p)\n", hChainEngine, pTime, hAdditionalStore, chain); + + /* Always start with the last "lower quality" chain to ensure a consistent + * order of alternate creation: + */ + if (chain->context.cLowerQualityChainContext) + chain = (PCertificateChain)chain->context.rgpLowerQualityChainContext[ + chain->context.cLowerQualityChainContext - 1]; + /* A chain with only one element can't have any alternates */ + if (chain->context.cChain <= 1 && chain->context.rgpChain[0]->cElement <= 1) + alternate = NULL; + else + { + DWORD i, j, infoStatus; + PCCERT_CONTEXT alternateIssuer = NULL; + + alternate = NULL; + for (i = 0; !alternateIssuer && i < chain->context.cChain; i++) + for (j = 0; !alternateIssuer && + j < chain->context.rgpChain[i]->cElement - 1; j++) + { + PCCERT_CONTEXT subject = + chain->context.rgpChain[i]->rgpElement[j]->pCertContext; + PCCERT_CONTEXT prevIssuer = CertDuplicateCertificateContext( + chain->context.rgpChain[i]->rgpElement[j + 1]->pCertContext); + + alternateIssuer = CRYPT_GetIssuer(prevIssuer->hCertStore, + subject, prevIssuer, &infoStatus); + } + if (alternateIssuer) + { + i--; + j--; + alternate = CRYPT_CopyChainToElement(chain, i, j); + if (alternate) + { + BOOL ret = CRYPT_AddCertToSimpleChain(engine, + alternate->context.rgpChain[i], alternateIssuer, infoStatus); + + /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it + * to close the enumeration that found it + */ + CertFreeCertificateContext(alternateIssuer); + if (ret) + { + ret = CRYPT_BuildSimpleChain(engine, alternate->world, + alternate->context.rgpChain[i]); + if (ret) + CRYPT_CheckSimpleChain(engine, + alternate->context.rgpChain[i], pTime); + CRYPT_CombineTrustStatus(&alternate->context.TrustStatus, + &alternate->context.rgpChain[i]->TrustStatus); + } + if (!ret) + { + CRYPT_FreeChainContext(alternate); + alternate = NULL; + } + } + } + } + TRACE("%p\n", alternate); + return alternate; +} + +#define CHAIN_QUALITY_SIGNATURE_VALID 8 +#define CHAIN_QUALITY_TIME_VALID 4 +#define CHAIN_QUALITY_COMPLETE_CHAIN 2 +#define CHAIN_QUALITY_TRUSTED_ROOT 1 + +#define CHAIN_QUALITY_HIGHEST \ + CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \ + CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_TRUSTED_ROOT + +#define IS_TRUST_ERROR_SET(TrustStatus, bits) \ + (TrustStatus)->dwErrorStatus & (bits) + +static DWORD CRYPT_ChainQuality(PCertificateChain chain) +{ + DWORD quality = CHAIN_QUALITY_HIGHEST; + + if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, + CERT_TRUST_IS_UNTRUSTED_ROOT)) + quality &= ~CHAIN_QUALITY_TRUSTED_ROOT; + if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, + CERT_TRUST_IS_PARTIAL_CHAIN)) + if (chain->context.TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) + quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN; + if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, + CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED)) + quality &= ~CHAIN_QUALITY_TIME_VALID; + if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, + CERT_TRUST_IS_NOT_SIGNATURE_VALID)) + quality &= ~CHAIN_QUALITY_SIGNATURE_VALID; + return quality; +} + +/* Chooses the highest quality chain among chain and its "lower quality" + * alternate chains. Returns the highest quality chain, with all other + * chains as lower quality chains of it. + */ +static PCertificateChain CRYPT_ChooseHighestQualityChain( + PCertificateChain chain) +{ + DWORD i; + + /* There are always only two chains being considered: chain, and an + * alternate at chain->rgpLowerQualityChainContext[i]. If the alternate + * has a higher quality than chain, the alternate gets assigned the lower + * quality contexts, with chain taking the alternate's place among the + * lower quality contexts. + */ + for (i = 0; i < chain->context.cLowerQualityChainContext; i++) + { + PCertificateChain alternate = + (PCertificateChain)chain->context.rgpLowerQualityChainContext[i]; + + if (CRYPT_ChainQuality(alternate) > CRYPT_ChainQuality(chain)) + { + alternate->context.cLowerQualityChainContext = + chain->context.cLowerQualityChainContext; + alternate->context.rgpLowerQualityChainContext = + chain->context.rgpLowerQualityChainContext; + alternate->context.rgpLowerQualityChainContext[i] = + (PCCERT_CHAIN_CONTEXT)chain; + chain->context.cLowerQualityChainContext = 0; + chain->context.rgpLowerQualityChainContext = NULL; + chain = alternate; + } + } + return chain; +} + +static BOOL CRYPT_AddAlternateChainToChain(PCertificateChain chain, + PCertificateChain alternate) +{ + BOOL ret; + + if (chain->context.cLowerQualityChainContext) + chain->context.rgpLowerQualityChainContext = + CryptMemRealloc(chain->context.rgpLowerQualityChainContext, + (chain->context.cLowerQualityChainContext + 1) * + sizeof(PCCERT_CHAIN_CONTEXT)); + else + chain->context.rgpLowerQualityChainContext = + CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT)); + if (chain->context.rgpLowerQualityChainContext) + { + chain->context.rgpLowerQualityChainContext[ + chain->context.cLowerQualityChainContext++] = + (PCCERT_CHAIN_CONTEXT)alternate; + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +static PCERT_CHAIN_ELEMENT CRYPT_FindIthElementInChain( + PCERT_CHAIN_CONTEXT chain, DWORD i) +{ + DWORD j, iElement; + PCERT_CHAIN_ELEMENT element = NULL; + + for (j = 0, iElement = 0; !element && j < chain->cChain; j++) + { + if (iElement + chain->rgpChain[j]->cElement < i) + iElement += chain->rgpChain[j]->cElement; + else + element = chain->rgpChain[j]->rgpElement[i - iElement]; + } + return element; +} + +typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS { + DWORD cbSize; + CERT_USAGE_MATCH RequestedUsage; +} CERT_CHAIN_PARA_NO_EXTRA_FIELDS, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS; + +static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, + LPFILETIME pTime, PCERT_CHAIN_PARA pChainPara, DWORD chainFlags) +{ + DWORD cContext; + + if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT) + cContext = 1; + else if ((chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) || + (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)) + { + DWORD i; + + for (i = 0, cContext = 0; i < chain->cChain; i++) + { + if (i < chain->cChain - 1 || + chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) + cContext += chain->rgpChain[i]->cElement; + else + cContext += chain->rgpChain[i]->cElement - 1; + } + } + else + cContext = 0; + if (cContext) + { + PCCERT_CONTEXT *contexts = + CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT *)); + + if (contexts) + { + DWORD i, j, iContext, revocationFlags; + CERT_REVOCATION_PARA revocationPara = { sizeof(revocationPara), 0 }; + CERT_REVOCATION_STATUS revocationStatus = + { sizeof(revocationStatus), 0 }; + BOOL ret; + + for (i = 0, iContext = 0; iContext < cContext && i < chain->cChain; + i++) + { + for (j = 0; iContext < cContext && + j < chain->rgpChain[i]->cElement; j++) + contexts[iContext++] = + chain->rgpChain[i]->rgpElement[j]->pCertContext; + } + revocationFlags = CERT_VERIFY_REV_CHAIN_FLAG; + if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY) + revocationFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION; + if (chainFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT) + revocationFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG; + revocationPara.pftTimeToUse = pTime; + if (pChainPara->cbSize == sizeof(CERT_CHAIN_PARA)) + { + revocationPara.dwUrlRetrievalTimeout = + pChainPara->dwUrlRetrievalTimeout; + revocationPara.fCheckFreshnessTime = + pChainPara->fCheckRevocationFreshnessTime; + revocationPara.dwFreshnessTime = + pChainPara->dwRevocationFreshnessTime; + } + ret = CertVerifyRevocation(X509_ASN_ENCODING, + CERT_CONTEXT_REVOCATION_TYPE, cContext, (void **)contexts, + revocationFlags, &revocationPara, &revocationStatus); + if (!ret) + { + PCERT_CHAIN_ELEMENT element = + CRYPT_FindIthElementInChain(chain, revocationStatus.dwIndex); + DWORD error; + + switch (revocationStatus.dwError) + { + case CRYPT_E_NO_REVOCATION_CHECK: + case CRYPT_E_NO_REVOCATION_DLL: + case CRYPT_E_NOT_IN_REVOCATION_DATABASE: + error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN; + break; + case CRYPT_E_REVOCATION_OFFLINE: + error = CERT_TRUST_IS_OFFLINE_REVOCATION; + break; + case CRYPT_E_REVOKED: + error = CERT_TRUST_IS_REVOKED; + break; + default: + WARN("unmapped error %08x\n", revocationStatus.dwError); + error = 0; + } + if (element) + { + /* FIXME: set element's pRevocationInfo member */ + element->TrustStatus.dwErrorStatus |= error; + } + chain->TrustStatus.dwErrorStatus |= error; + } + CryptMemFree(contexts); + } + } +} + +BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, + PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore, + PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved, + PCCERT_CHAIN_CONTEXT* ppChainContext) +{ + BOOL ret; + PCertificateChain chain = NULL; + + TRACE("(%p, %p, %p, %p, %p, %08x, %p, %p)\n", hChainEngine, pCertContext, + pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, ppChainContext); + + if (ppChainContext) + *ppChainContext = NULL; + if (!pChainPara) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!pCertContext->pCertInfo->SignatureAlgorithm.pszObjId) + { + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + if (pChainPara->cbSize != sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) && + pChainPara->cbSize != sizeof(CERT_CHAIN_PARA)) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!hChainEngine) + hChainEngine = CRYPT_GetDefaultChainEngine(); + /* FIXME: what about HCCE_LOCAL_MACHINE? */ + ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime, + hAdditionalStore, &chain); + if (ret) + { + PCertificateChain alternate = NULL; + PCERT_CHAIN_CONTEXT pChain; + + do { + alternate = CRYPT_BuildAlternateContextFromChain(hChainEngine, + pTime, hAdditionalStore, chain); + + /* Alternate contexts are added as "lower quality" contexts of + * chain, to avoid loops in alternate chain creation. + * The highest-quality chain is chosen at the end. + */ + if (alternate) + ret = CRYPT_AddAlternateChainToChain(chain, alternate); + } while (ret && alternate); + chain = CRYPT_ChooseHighestQualityChain(chain); + if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS)) + CRYPT_FreeLowerQualityChains(chain); + pChain = (PCERT_CHAIN_CONTEXT)chain; + CRYPT_VerifyChainRevocation(pChain, pTime, pChainPara, dwFlags); + if (ppChainContext) + *ppChainContext = pChain; + else + CertFreeCertificateChain(pChain); + } + TRACE("returning %d\n", ret); + return ret; +} + +PCCERT_CHAIN_CONTEXT WINAPI CertDuplicateCertificateChain( + PCCERT_CHAIN_CONTEXT pChainContext) +{ + PCertificateChain chain = (PCertificateChain)pChainContext; + + TRACE("(%p)\n", pChainContext); + + if (chain) + InterlockedIncrement(&chain->ref); + return pChainContext; +} + +VOID WINAPI CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext) +{ + PCertificateChain chain = (PCertificateChain)pChainContext; + + TRACE("(%p)\n", pChainContext); + + if (chain) + { + if (InterlockedDecrement(&chain->ref) == 0) + CRYPT_FreeChainContext(chain); + } +} + +static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error, + LONG *iChain, LONG *iElement) +{ + DWORD i, j; + + for (i = 0; i < chain->cChain; i++) + for (j = 0; j < chain->rgpChain[i]->cElement; j++) + if (chain->rgpChain[i]->rgpElement[j]->TrustStatus.dwErrorStatus & + error) + { + *iChain = i; + *iElement = j; + return; + } +} + +static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID, + PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, + PCERT_CHAIN_POLICY_STATUS pPolicyStatus) +{ + pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1; + if (pChainContext->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_SIGNATURE_VALID) + { + pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE; + find_element_with_error(pChainContext, + CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex, + &pPolicyStatus->lElementIndex); + } + else if (pChainContext->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_UNTRUSTED_ROOT) + { + pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT; + find_element_with_error(pChainContext, + CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex, + &pPolicyStatus->lElementIndex); + } + else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC) + { + pPolicyStatus->dwError = CERT_E_CHAINING; + find_element_with_error(pChainContext, CERT_TRUST_IS_CYCLIC, + &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex); + /* For a cyclic chain, which element is a cycle isn't meaningful */ + pPolicyStatus->lElementIndex = -1; + } + else + pPolicyStatus->dwError = NO_ERROR; + return TRUE; +} + +static BYTE msTestPubKey1[] = { +0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9, +0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7, +0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f, +0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10, +0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 }; +static BYTE msTestPubKey2[] = { +0x30,0x48,0x02,0x41,0x00,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7, +0xd9,0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1, +0xf7,0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46, +0x5f,0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a, +0x10,0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 }; +static BYTE msTestPubKey3[] = { +0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5, +0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8, +0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6, +0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18, +0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 }; + +static BOOL WINAPI verify_authenticode_policy(LPCSTR szPolicyOID, + PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, + PCERT_CHAIN_POLICY_STATUS pPolicyStatus) +{ + BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara, + pPolicyStatus); + + if (ret && pPolicyStatus->dwError == CERT_E_UNTRUSTEDROOT) + { + CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } }; + BOOL isMSTestRoot = FALSE; + PCCERT_CONTEXT failingCert = + pChainContext->rgpChain[pPolicyStatus->lChainIndex]-> + rgpElement[pPolicyStatus->lElementIndex]->pCertContext; + DWORD i; + CRYPT_DATA_BLOB keyBlobs[] = { + { sizeof(msTestPubKey1), msTestPubKey1 }, + { sizeof(msTestPubKey2), msTestPubKey2 }, + { sizeof(msTestPubKey3), msTestPubKey3 }, + }; + + /* Check whether the root is an MS test root */ + for (i = 0; !isMSTestRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]); + i++) + { + msPubKey.PublicKey.cbData = keyBlobs[i].cbData; + msPubKey.PublicKey.pbData = keyBlobs[i].pbData; + if (CertComparePublicKeyInfo( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &failingCert->pCertInfo->SubjectPublicKeyInfo, &msPubKey)) + isMSTestRoot = TRUE; + } + if (isMSTestRoot) + pPolicyStatus->dwError = CERT_E_UNTRUSTEDTESTROOT; + } + return ret; +} + +static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID, + PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, + PCERT_CHAIN_POLICY_STATUS pPolicyStatus) +{ + pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1; + if (pChainContext->TrustStatus.dwErrorStatus & + CERT_TRUST_INVALID_BASIC_CONSTRAINTS) + { + pPolicyStatus->dwError = TRUST_E_BASIC_CONSTRAINTS; + find_element_with_error(pChainContext, + CERT_TRUST_INVALID_BASIC_CONSTRAINTS, &pPolicyStatus->lChainIndex, + &pPolicyStatus->lElementIndex); + } + else + pPolicyStatus->dwError = NO_ERROR; + return TRUE; +} + +static BYTE msPubKey1[] = { +0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e, +0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d, +0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29, +0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16, +0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60, +0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5, +0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d, +0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61, +0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e, +0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94, +0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb, +0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a, +0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d, +0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb, +0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08, +0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43, +0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf, +0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 }; +static BYTE msPubKey2[] = { +0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6, +0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25, +0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2, +0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54, +0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62, +0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a, +0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7, +0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84, +0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9, +0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91, +0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52, +0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80, +0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18, +0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07, +0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef, +0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0, +0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30, +0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 }; +static BYTE msPubKey3[] = { +0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4, +0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7, +0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94, +0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04, +0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d, +0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09, +0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae, +0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7, +0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f, +0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94, +0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d, +0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05, +0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e, +0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d, +0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b, +0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67, +0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08, +0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5, +0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64, +0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38, +0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0, +0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9, +0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28, +0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc, +0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45, +0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde, +0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04, +0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89, +0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11, +0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32, +0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40, +0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41, +0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1, +0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5, +0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00, +0x01 }; + +static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID, + PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, + PCERT_CHAIN_POLICY_STATUS pPolicyStatus) +{ + BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara, + pPolicyStatus); + + if (ret && !pPolicyStatus->dwError) + { + CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } }; + BOOL isMSRoot = FALSE; + DWORD i; + CRYPT_DATA_BLOB keyBlobs[] = { + { sizeof(msPubKey1), msPubKey1 }, + { sizeof(msPubKey2), msPubKey2 }, + { sizeof(msPubKey3), msPubKey3 }, + }; + PCERT_SIMPLE_CHAIN rootChain = + pChainContext->rgpChain[pChainContext->cChain -1 ]; + PCCERT_CONTEXT root = + rootChain->rgpElement[rootChain->cElement - 1]->pCertContext; + + for (i = 0; !isMSRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]); + i++) + { + msPubKey.PublicKey.cbData = keyBlobs[i].cbData; + msPubKey.PublicKey.pbData = keyBlobs[i].pbData; + if (CertComparePublicKeyInfo( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &root->pCertInfo->SubjectPublicKeyInfo, &msPubKey)) + isMSRoot = TRUE; + } + if (isMSRoot) + pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = 0; + } + return ret; +} + +typedef BOOL (WINAPI *CertVerifyCertificateChainPolicyFunc)(LPCSTR szPolicyOID, + PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, + PCERT_CHAIN_POLICY_STATUS pPolicyStatus); + +BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID, + PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, + PCERT_CHAIN_POLICY_STATUS pPolicyStatus) +{ + static HCRYPTOIDFUNCSET set = NULL; + BOOL ret = FALSE; + CertVerifyCertificateChainPolicyFunc verifyPolicy = NULL; + HCRYPTOIDFUNCADDR hFunc = NULL; + + TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID), pChainContext, + pPolicyPara, pPolicyStatus); + + if (!HIWORD(szPolicyOID)) + { + switch (LOWORD(szPolicyOID)) + { + case LOWORD(CERT_CHAIN_POLICY_BASE): + verifyPolicy = verify_base_policy; + break; + case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE): + verifyPolicy = verify_authenticode_policy; + break; + case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS): + verifyPolicy = verify_basic_constraints_policy; + break; + case LOWORD(CERT_CHAIN_POLICY_MICROSOFT_ROOT): + verifyPolicy = verify_ms_root_policy; + break; + default: + FIXME("unimplemented for %d\n", LOWORD(szPolicyOID)); + } + } + if (!verifyPolicy) + { + if (!set) + set = CryptInitOIDFunctionSet( + CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC, 0); + CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, szPolicyOID, 0, + (void **)&verifyPolicy, hFunc); + } + if (verifyPolicy) + ret = verifyPolicy(szPolicyOID, pChainContext, pPolicyPara, + pPolicyStatus); + if (hFunc) + CryptFreeOIDFunctionAddress(hFunc, 0); + return ret; +} diff --git a/reactos/dll/win32/crypt32/collectionstore.c b/reactos/dll/win32/crypt32/collectionstore.c new file mode 100644 index 00000000000..9bf6d1daa7c --- /dev/null +++ b/reactos/dll/win32/crypt32/collectionstore.c @@ -0,0 +1,480 @@ +/* + * Copyright 2004-2007 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +typedef struct _WINE_STORE_LIST_ENTRY +{ + PWINECRYPT_CERTSTORE store; + DWORD dwUpdateFlags; + DWORD dwPriority; + struct list entry; +} WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY; + +typedef struct _WINE_COLLECTIONSTORE +{ + WINECRYPT_CERTSTORE hdr; + CRITICAL_SECTION cs; + struct list stores; +} WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE; + +static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + PWINE_STORE_LIST_ENTRY entry, next; + + TRACE("(%p, %08x)\n", store, dwFlags); + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY, + entry) + { + TRACE("closing %p\n", entry); + CertCloseStore((HCERTSTORE)entry->store, dwFlags); + CryptMemFree(entry); + } + cs->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&cs->cs); + CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store); +} + +static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store, + PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize, + BOOL addRef) +{ + void *ret = Context_CreateLinkContext(contextSize, child, + sizeof(PWINE_STORE_LIST_ENTRY), addRef); + + if (ret) + *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize) + = storeEntry; + + return ret; +} + +static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store, + unsigned int contextFuncsOffset, void *context, void *toReplace, unsigned int contextSize, + void **pChildContext) +{ + BOOL ret; + void *childContext = NULL; + PWINE_STORE_LIST_ENTRY storeEntry = NULL; + + TRACE("(%p, %d, %p, %p, %d)\n", store, contextFuncsOffset, context, + toReplace, contextSize); + + ret = FALSE; + if (toReplace) + { + void *existingLinked = Context_GetLinkedContext(toReplace, contextSize); + PCONTEXT_FUNCS contextFuncs; + + storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace, + contextSize); + contextFuncs = (PCONTEXT_FUNCS)((LPBYTE)storeEntry->store + + contextFuncsOffset); + ret = contextFuncs->addContext(storeEntry->store, context, + existingLinked, childContext); + } + else + { + PWINE_STORE_LIST_ENTRY entry, next; + + EnterCriticalSection(&store->cs); + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores, + WINE_STORE_LIST_ENTRY, entry) + { + if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG) + { + PCONTEXT_FUNCS contextFuncs = (PCONTEXT_FUNCS)( + (LPBYTE)entry->store + contextFuncsOffset); + + storeEntry = entry; + ret = contextFuncs->addContext(entry->store, context, NULL, + (const void **)&childContext); + break; + } + } + LeaveCriticalSection(&store->cs); + if (!storeEntry) + SetLastError(E_ACCESSDENIED); + } + *pChildContext = childContext; + return ret; +} + +/* Advances a collection enumeration by one context, if possible, where + * advancing means: + * - calling the current store's enumeration function once, and returning + * the enumerated context if one is returned + * - moving to the next store if the current store has no more items, and + * recursively calling itself to get the next item. + * Returns NULL if the collection contains no more items or on error. + * Assumes the collection store's lock is held. + */ +static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store, + PWINE_STORE_LIST_ENTRY storeEntry, PCONTEXT_FUNCS contextFuncs, + PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize) +{ + void *ret, *child; + struct list *storeNext = list_next(&store->stores, &storeEntry->entry); + + TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev); + + if (pPrev) + { + /* Ref-counting funny business: "duplicate" (addref) the child, because + * the free(pPrev) below can cause the ref count to become negative. + */ + child = Context_GetLinkedContext(pPrev, contextSize); + contextInterface->duplicate(child); + child = contextFuncs->enumContext(storeEntry->store, child); + contextInterface->free(pPrev); + pPrev = NULL; + } + else + child = contextFuncs->enumContext(storeEntry->store, NULL); + if (child) + ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child, + contextSize, FALSE); + else + { + if (storeNext) + { + /* We always want the same function pointers (from certs, crls) + * in the next store, so use the same offset into the next store. + */ + size_t offset = (LPBYTE)contextFuncs - (LPBYTE)storeEntry->store; + PWINE_STORE_LIST_ENTRY storeNextEntry = + LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry); + PCONTEXT_FUNCS storeNextContexts = + (PCONTEXT_FUNCS)((LPBYTE)storeNextEntry->store + offset); + + ret = CRYPT_CollectionAdvanceEnum(store, storeNextEntry, + storeNextContexts, contextInterface, NULL, contextSize); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + } + TRACE("returning %p\n", ret); + return ret; +} + +static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert, + void *toReplace, const void **ppStoreContext) +{ + BOOL ret; + void *childContext = NULL; + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + + ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs), + cert, toReplace, sizeof(CERT_CONTEXT), &childContext); + if (ppStoreContext && childContext) + { + PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *) + Context_GetExtra(childContext, sizeof(CERT_CONTEXT)); + PCERT_CONTEXT context = + CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext, + sizeof(CERT_CONTEXT), TRUE); + + if (context) + context->hCertStore = store; + *ppStoreContext = context; + } + CertFreeCertificateContext((PCCERT_CONTEXT)childContext); + return ret; +} + +static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + void *ret; + + TRACE("(%p, %p)\n", store, pPrev); + + EnterCriticalSection(&cs->cs); + if (pPrev) + { + PWINE_STORE_LIST_ENTRY storeEntry = + *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev, + sizeof(CERT_CONTEXT)); + + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + &storeEntry->store->certs, pCertInterface, pPrev, + sizeof(CERT_CONTEXT)); + } + else + { + if (!list_empty(&cs->stores)) + { + PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next, + WINE_STORE_LIST_ENTRY, entry); + + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + &storeEntry->store->certs, pCertInterface, NULL, + sizeof(CERT_CONTEXT)); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + } + LeaveCriticalSection(&cs->cs); + if (ret) + ((PCERT_CONTEXT)ret)->hCertStore = store; + TRACE("returning %p\n", ret); + return ret; +} + +static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store, + void *pCertContext) +{ + BOOL ret; + + TRACE("(%p, %p)\n", store, pCertContext); + + ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT) + Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT))); + return ret; +} + +static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl, + void *toReplace, const void **ppStoreContext) +{ + BOOL ret; + void *childContext = NULL; + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + + ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls), + crl, toReplace, sizeof(CRL_CONTEXT), &childContext); + if (ppStoreContext && childContext) + { + PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *) + Context_GetExtra(childContext, sizeof(CRL_CONTEXT)); + PCRL_CONTEXT context = + CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext, + sizeof(CRL_CONTEXT), TRUE); + + if (context) + context->hCertStore = store; + *ppStoreContext = context; + } + CertFreeCRLContext((PCCRL_CONTEXT)childContext); + return ret; +} + +static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev) +{ + PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; + void *ret; + + TRACE("(%p, %p)\n", store, pPrev); + + EnterCriticalSection(&cs->cs); + if (pPrev) + { + PWINE_STORE_LIST_ENTRY storeEntry = + *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev, + sizeof(CRL_CONTEXT)); + + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + &storeEntry->store->crls, pCRLInterface, pPrev, sizeof(CRL_CONTEXT)); + } + else + { + if (!list_empty(&cs->stores)) + { + PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next, + WINE_STORE_LIST_ENTRY, entry); + + ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, + &storeEntry->store->crls, pCRLInterface, NULL, + sizeof(CRL_CONTEXT)); + } + else + { + SetLastError(CRYPT_E_NOT_FOUND); + ret = NULL; + } + } + LeaveCriticalSection(&cs->cs); + if (ret) + ((PCRL_CONTEXT)ret)->hCertStore = store; + TRACE("returning %p\n", ret); + return ret; +} + +static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store, + void *pCrlContext) +{ + BOOL ret; + + TRACE("(%p, %p)\n", store, pCrlContext); + + ret = CertDeleteCRLFromStore((PCCRL_CONTEXT) + Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT))); + return ret; +} + +PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + PWINE_COLLECTIONSTORE store; + + if (dwFlags & CERT_STORE_DELETE_FLAG) + { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + store = NULL; + } + else + { + store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE)); + if (store) + { + memset(store, 0, sizeof(WINE_COLLECTIONSTORE)); + CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeCollection); + store->hdr.closeStore = CRYPT_CollectionCloseStore; + store->hdr.certs.addContext = CRYPT_CollectionAddCert; + store->hdr.certs.enumContext = CRYPT_CollectionEnumCert; + store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert; + store->hdr.crls.addContext = CRYPT_CollectionAddCRL; + store->hdr.crls.enumContext = CRYPT_CollectionEnumCRL; + store->hdr.crls.deleteContext = CRYPT_CollectionDeleteCRL; + InitializeCriticalSection(&store->cs); + store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs"); + list_init(&store->stores); + } + } + return (PWINECRYPT_CERTSTORE)store; +} + +BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, + HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority) +{ + PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; + WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; + PWINE_STORE_LIST_ENTRY entry; + BOOL ret; + + TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore, + dwUpdateFlags, dwPriority); + + if (!collection || !sibling) + return TRUE; + if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (collection->hdr.type != StoreTypeCollection) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + + entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY)); + if (entry) + { + InterlockedIncrement(&sibling->ref); + TRACE("sibling %p's ref count is %d\n", sibling, sibling->ref); + entry->store = sibling; + entry->dwUpdateFlags = dwUpdateFlags; + entry->dwPriority = dwPriority; + list_init(&entry->entry); + TRACE("%p: adding %p, priority %d\n", collection, entry, dwPriority); + EnterCriticalSection(&collection->cs); + if (dwPriority) + { + PWINE_STORE_LIST_ENTRY cursor; + BOOL added = FALSE; + + LIST_FOR_EACH_ENTRY(cursor, &collection->stores, + WINE_STORE_LIST_ENTRY, entry) + { + if (cursor->dwPriority < dwPriority) + { + list_add_before(&cursor->entry, &entry->entry); + added = TRUE; + break; + } + } + if (!added) + list_add_tail(&collection->stores, &entry->entry); + } + else + list_add_tail(&collection->stores, &entry->entry); + LeaveCriticalSection(&collection->cs); + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore, + HCERTSTORE hSiblingStore) +{ + PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; + WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; + PWINE_STORE_LIST_ENTRY store, next; + + TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore); + + if (!collection || !sibling) + return; + if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(E_INVALIDARG); + return; + } + if (collection->hdr.type != StoreTypeCollection) + return; + if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(E_INVALIDARG); + return; + } + EnterCriticalSection(&collection->cs); + LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores, + WINE_STORE_LIST_ENTRY, entry) + { + if (store->store == sibling) + { + list_remove(&store->entry); + CertCloseStore(store->store, 0); + CryptMemFree(store); + break; + } + } + LeaveCriticalSection(&collection->cs); +} diff --git a/reactos/dll/win32/crypt32/context.c b/reactos/dll/win32/crypt32/context.c index ab57c5709b8..a5b749f86af 100644 --- a/reactos/dll/win32/crypt32/context.c +++ b/reactos/dll/win32/crypt32/context.c @@ -71,6 +71,7 @@ void *Context_CreateDataContext(size_t contextSize) ret = NULL; } } + TRACE("returning %p\n", ret); return ret; } @@ -96,6 +97,7 @@ void *Context_CreateLinkContext(unsigned int contextSize, void *linked, unsigned InterlockedIncrement(&linkedBase->ref); TRACE("%p's ref count is %d\n", context, linkContext->ref); } + TRACE("returning %p\n", context); return context; } @@ -123,7 +125,7 @@ void *Context_GetLinkedContext(void *context, size_t contextSize) contextSize); } -PCONTEXT_PROPERTY_LIST Context_GetProperties(void *context, size_t contextSize) +PCONTEXT_PROPERTY_LIST Context_GetProperties(const void *context, size_t contextSize) { PBASE_CONTEXT ptr = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); @@ -242,7 +244,7 @@ void *ContextList_Add(struct ContextList *list, void *toLink, void *toReplace) list->contextInterface->free(toReplace); } else - list_add_tail(&list->contexts, entry); + list_add_head(&list->contexts, entry); LeaveCriticalSection(&list->cs); } return context; diff --git a/reactos/dll/win32/crypt32/crl.c b/reactos/dll/win32/crypt32/crl.c index 32c4f3aa797..9caf46d6033 100644 --- a/reactos/dll/win32/crypt32/crl.c +++ b/reactos/dll/win32/crypt32/crl.c @@ -266,10 +266,10 @@ DWORD WINAPI CertEnumCRLContextProperties(PCCRL_CONTEXT pCRLContext, return ret; } -static BOOL WINAPI CRLContext_SetProperty(void *context, DWORD dwPropId, - DWORD dwFlags, const void *pvData); +static BOOL CRLContext_SetProperty(PCCRL_CONTEXT context, DWORD dwPropId, + DWORD dwFlags, const void *pvData); -static BOOL CRLContext_GetHashProp(void *context, DWORD dwPropId, +static BOOL CRLContext_GetHashProp(PCCRL_CONTEXT context, DWORD dwPropId, ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, DWORD *pcbData) { @@ -284,10 +284,9 @@ static BOOL CRLContext_GetHashProp(void *context, DWORD dwPropId, return ret; } -static BOOL WINAPI CRLContext_GetProperty(void *context, DWORD dwPropId, - void *pvData, DWORD *pcbData) +static BOOL CRLContext_GetProperty(PCCRL_CONTEXT context, DWORD dwPropId, + void *pvData, DWORD *pcbData) { - PCCRL_CONTEXT pCRLContext = (PCCRL_CONTEXT)context; PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(context, sizeof(CRL_CONTEXT)); BOOL ret; @@ -302,20 +301,17 @@ static BOOL WINAPI CRLContext_GetProperty(void *context, DWORD dwPropId, if (ret) { if (!pvData) - { *pcbData = blob.cbData; - ret = TRUE; - } else if (*pcbData < blob.cbData) { SetLastError(ERROR_MORE_DATA); *pcbData = blob.cbData; + ret = FALSE; } else { memcpy(pvData, blob.pbData, blob.cbData); *pcbData = blob.cbData; - ret = TRUE; } } else @@ -325,12 +321,12 @@ static BOOL WINAPI CRLContext_GetProperty(void *context, DWORD dwPropId, { case CERT_SHA1_HASH_PROP_ID: ret = CRLContext_GetHashProp(context, dwPropId, CALG_SHA1, - pCRLContext->pbCrlEncoded, pCRLContext->cbCrlEncoded, pvData, + context->pbCrlEncoded, context->cbCrlEncoded, pvData, pcbData); break; case CERT_MD5_HASH_PROP_ID: ret = CRLContext_GetHashProp(context, dwPropId, CALG_MD5, - pCRLContext->pbCrlEncoded, pCRLContext->cbCrlEncoded, pvData, + context->pbCrlEncoded, context->cbCrlEncoded, pvData, pcbData); break; default: @@ -371,19 +367,22 @@ BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext, } else { - *(DWORD *)pvData = - CertStore_GetAccessState(pCRLContext->hCertStore); + if (pCRLContext->hCertStore) + ret = CertGetStoreProperty(pCRLContext->hCertStore, dwPropId, + pvData, pcbData); + else + *(DWORD *)pvData = 0; ret = TRUE; } break; default: - ret = CRLContext_GetProperty((void *)pCRLContext, dwPropId, pvData, + ret = CRLContext_GetProperty(pCRLContext, dwPropId, pvData, pcbData); } return ret; } -static BOOL WINAPI CRLContext_SetProperty(void *context, DWORD dwPropId, +static BOOL CRLContext_SetProperty(PCCRL_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData) { PCONTEXT_PROPERTY_LIST properties = @@ -460,8 +459,7 @@ BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext, SetLastError(E_INVALIDARG); return FALSE; } - ret = CRLContext_SetProperty((void *)pCRLContext, dwPropId, dwFlags, - pvData); + ret = CRLContext_SetProperty(pCRLContext, dwPropId, dwFlags, pvData); TRACE("returning %d\n", ret); return ret; } @@ -519,10 +517,7 @@ LONG WINAPI CertVerifyCRLTimeValidity(LPFILETIME pTimeToVerify, if (!pTimeToVerify) { - SYSTEMTIME sysTime; - - GetSystemTime(&sysTime); - SystemTimeToFileTime(&sysTime, &fileTime); + GetSystemTimeAsFileTime(&fileTime); pTimeToVerify = &fileTime; } if ((ret = CompareFileTime(pTimeToVerify, &pCrlInfo->ThisUpdate)) >= 0) diff --git a/reactos/dll/win32/crypt32/crypt32.rbuild b/reactos/dll/win32/crypt32/crypt32.rbuild index c641672fad2..75fbcd315a5 100644 --- a/reactos/dll/win32/crypt32/crypt32.rbuild +++ b/reactos/dll/win32/crypt32/crypt32.rbuild @@ -5,28 +5,36 @@ 0x600 - 0x501 + 0x600 0x501 wine user32 advapi32 kernel32 ntdll + imagehlp base64.c cert.c chain.c - crl.c + collectionstore.c context.c + crl.c decode.c encode.c + filestore.c + main.c + msg.c + object.c oid.c proplist.c protectdata.c + provstore.c + regstore.c + rootstore.c serialize.c sip.c store.c str.c - main.c crypt32.rc crypt32.spec diff --git a/reactos/dll/win32/crypt32/crypt32.rc b/reactos/dll/win32/crypt32/crypt32.rc index 675469368a0..af0d77cfa9b 100644 --- a/reactos/dll/win32/crypt32/crypt32.rc +++ b/reactos/dll/win32/crypt32/crypt32.rc @@ -17,21 +17,17 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ - -#define REACTOS_VERSION_DLL -#define REACTOS_STR_FILE_DESCRIPTION "CryptoAPI Library\0" -#define REACTOS_STR_INTERNAL_NAME "crypt32\0" -#define REACTOS_STR_ORIGINAL_FILENAME "crypt32.dll\0" - #include "windef.h" #include "winbase.h" #include "winuser.h" #include "cryptres.h" -#include +#include "version.rc" #include "crypt32_De.rc" #include "crypt32_En.rc" #include "crypt32_Fr.rc" #include "crypt32_Ko.rc" +#include "crypt32_Nl.rc" #include "crypt32_No.rc" +#include "crypt32_Sv.rc" diff --git a/reactos/dll/win32/crypt32/crypt32.spec b/reactos/dll/win32/crypt32/crypt32.spec index 7ee23f4e683..b7f45d06b16 100644 --- a/reactos/dll/win32/crypt32/crypt32.spec +++ b/reactos/dll/win32/crypt32/crypt32.spec @@ -26,6 +26,7 @@ @ stdcall CertDeleteCertificateFromStore(ptr) @ stdcall CertDuplicateCRLContext(ptr) @ stdcall CertDuplicateCTLContext(ptr) +@ stdcall CertDuplicateCertificateChain(ptr) @ stdcall CertDuplicateCertificateContext(ptr) @ stdcall CertDuplicateStore(ptr) @ stdcall CertEnumCRLContextProperties(ptr long) @@ -34,6 +35,7 @@ @ stdcall CertEnumCTLsInStore(ptr ptr) @ stdcall CertEnumCertificateContextProperties(ptr long) @ stdcall CertEnumCertificatesInStore(long ptr) +@ stdcall CertEnumSystemStore(long ptr ptr ptr) @ stdcall CertFindAttribute(str long ptr) @ stdcall CertFindCRLInStore(long long long long ptr ptr) @ stub CertFindCTLInStore @@ -44,13 +46,13 @@ @ stub CertFindSubjectInCTL @ stdcall CertFreeCRLContext(ptr) @ stdcall CertFreeCTLContext(ptr) -@ stub CertFreeCertificateChain +@ stdcall CertFreeCertificateChain(ptr) @ stdcall CertFreeCertificateChainEngine(ptr) @ stdcall CertFreeCertificateContext(ptr) @ stdcall CertGetCRLContextProperty(ptr long ptr ptr) @ stdcall CertGetCRLFromStore(ptr ptr ptr ptr) @ stdcall CertGetCTLContextProperty(ptr long ptr ptr) -@ stub CertGetCertificateChain +@ stdcall CertGetCertificateChain(ptr ptr ptr ptr ptr long ptr ptr) @ stdcall CertGetCertificateContextProperty(ptr long ptr ptr) @ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr) @ stub CertGetIntendedKeyUsage @@ -58,6 +60,7 @@ @ stdcall CertGetNameStringA(ptr long long ptr ptr long) @ stdcall CertGetNameStringW(ptr long long ptr ptr long) @ stdcall CertGetPublicKeyLength(long ptr) +@ stdcall CertGetStoreProperty(long long ptr ptr) @ stdcall CertGetSubjectCertificateFromStore(ptr long ptr) @ stdcall CertGetValidUsages(long ptr ptr ptr ptr) @ stub CertIsRDNAttrsInCertificateName @@ -80,12 +83,14 @@ @ stdcall CertSetCTLContextProperty(ptr long long ptr) @ stdcall CertSetCertificateContextProperty(ptr long long ptr) @ stdcall CertSetEnhancedKeyUsage(ptr ptr) +@ stdcall CertSetStoreProperty(ptr long long ptr) @ stdcall CertStrToNameA(long str long ptr ptr ptr ptr) @ stdcall CertStrToNameW(long wstr long ptr ptr ptr ptr) +@ stdcall CertVerifyCertificateChainPolicy(str ptr ptr ptr) @ stdcall CertVerifyCRLRevocation(long ptr long ptr) @ stdcall CertVerifyCRLTimeValidity(ptr ptr) -@ stub CertVerifyCTLUsage -@ stub CertVerifyRevocation +@ stdcall CertVerifyCTLUsage(long long ptr ptr long ptr ptr) +@ stdcall CertVerifyRevocation(long long long ptr long ptr ptr) @ stdcall CertVerifySubjectCertificateContext(ptr ptr ptr) @ stdcall CertVerifyTimeValidity(ptr ptr) @ stdcall CertVerifyValidityNesting(ptr ptr) @@ -112,14 +117,15 @@ @ stub CryptExportPKCS8 @ stdcall CryptExportPublicKeyInfo(long long long ptr ptr) @ stdcall CryptExportPublicKeyInfoEx(long long long str long ptr ptr ptr) +@ stdcall CryptFindLocalizedName(wstr) @ stdcall CryptFindOIDInfo(long ptr long) @ stdcall CryptFormatObject(long long long ptr str ptr long ptr ptr) @ stdcall CryptFreeOIDFunctionAddress(long long) @ stub CryptGetAsyncParam @ stdcall CryptGetDefaultOIDDllList(long long ptr ptr) @ stdcall CryptGetDefaultOIDFunctionAddress(long long wstr long ptr ptr) -@ stub CryptGetMessageCertificates -@ stub CryptGetMessageSignerCount +@ stdcall CryptGetMessageCertificates(long ptr long ptr long) +@ stdcall CryptGetMessageSignerCount(long ptr long) @ stdcall CryptGetOIDFunctionAddress(long long str long ptr ptr) @ stdcall CryptGetOIDFunctionValue(long str str wstr ptr ptr ptr) @ stdcall CryptHashCertificate(long long long ptr long ptr ptr) @@ -136,17 +142,18 @@ @ stdcall CryptMemFree(ptr) @ stdcall CryptMemRealloc(ptr long) @ stub CryptMsgCalculateEncodedLength -@ stub CryptMsgClose -@ stub CryptMsgControl +@ stdcall CryptMsgClose(ptr) +@ stdcall CryptMsgControl(ptr long long ptr) @ stub CryptMsgCountersign @ stub CryptMsgCountersignEncoded +@ stdcall CryptMsgDuplicate(ptr) @ stub CryptMsgEncodeAndSignCTL @ stub CryptMsgGetAndVerifySigner -@ stub CryptMsgGetParam -@ stub CryptMsgOpenToDecode -@ stub CryptMsgOpenToEncode +@ stdcall CryptMsgGetParam(ptr long long ptr ptr) +@ stdcall CryptMsgOpenToDecode(long long long long ptr ptr) +@ stdcall CryptMsgOpenToEncode(long long long ptr str ptr) @ stub CryptMsgSignCTL -@ stub CryptMsgUpdate +@ stdcall CryptMsgUpdate(ptr ptr long long) @ stub CryptMsgVerifyCountersignatureEncoded @ stdcall CryptProtectData(ptr wstr ptr ptr ptr long ptr) @ stdcall CryptQueryObject(long ptr long long long ptr ptr ptr ptr ptr ptr) @@ -183,25 +190,29 @@ @ stdcall CryptVerifyMessageSignature(ptr long ptr long ptr ptr ptr) @ stub CryptVerifyMessageSignatureWithKey @ stub CryptVerifySignatureU +@ stdcall I_CertUpdateStore(ptr ptr long long) @ stdcall I_CryptAllocTls() @ stdcall I_CryptCreateLruCache(ptr ptr) -@ stub I_CryptCreateLruEntry +@ stdcall I_CryptCreateLruEntry(ptr long long) @ stdcall I_CryptDetachTls(long) +@ stdcall I_CryptFindLruEntry(long long) @ stdcall I_CryptFindLruEntryData(long long long) @ stdcall I_CryptFlushLruCache(ptr long long) @ stdcall I_CryptFreeLruCache(ptr long long) @ stdcall I_CryptFreeTls(long long) +@ stdcall I_CryptGetAsn1Decoder(long) +@ stdcall I_CryptGetAsn1Encoder(long) @ stdcall I_CryptGetDefaultCryptProv(long) @ stub I_CryptGetDefaultCryptProvForEncrypt @ stdcall I_CryptGetOssGlobal(long) @ stdcall I_CryptGetTls(long) @ stub I_CryptInsertLruEntry -@ stdcall I_CryptInstallAsn1Module(long long long) +@ stdcall I_CryptInstallAsn1Module(ptr long ptr) @ stdcall I_CryptInstallOssGlobal(long long long) @ stdcall I_CryptReadTrustedPublisherDWORDValueFromRegistry(wstr ptr) @ stub I_CryptReleaseLruEntry @ stdcall I_CryptSetTls(long ptr) -@ stdcall I_CryptUninstallAsn1Module(ptr) +@ stdcall I_CryptUninstallAsn1Module(long) @ stub I_CryptUninstallOssGlobal @ stub PFXExportCertStore @ stub PFXImportCertStore diff --git a/reactos/dll/win32/crypt32/crypt32_De.rc b/reactos/dll/win32/crypt32/crypt32_De.rc index 6c109edd839..40d07194a7c 100644 --- a/reactos/dll/win32/crypt32/crypt32_De.rc +++ b/reactos/dll/win32/crypt32/crypt32_De.rc @@ -97,7 +97,7 @@ STRINGTABLE DISCARDABLE IDS_CROSS_CERT_DIST_POINTS "Verteilungspunkte für Kreuzzertifikate" IDS_APPLICATION_POLICIES "Anwendungsrichtlinien" IDS_APPLICATION_POLICY_MAPPINGS "Anwendungsrichtlinienzuordnungen" - IDS_APPLICATION_POLICY_CONSTRAINTS "Anweungsungsrichtlinieneinschränkungen" + IDS_APPLICATION_POLICY_CONSTRAINTS "Anwendungsungsrichtlinieneinschränkungen" IDS_CMC_DATA "CMC Daten" IDS_CMC_RESPONSE "CMC Antwort" IDS_UNSIGNED_CMC_REQUEST "Unsignierte CMC Antwort" @@ -164,3 +164,11 @@ STRINGTABLE DISCARDABLE IDS_LIFETIME_SIGNING "Lebensdauersignatur" IDS_ANY_CERT_POLICY "Alle ausgegebenen Richtlinien" } + +STRINGTABLE DISCARDABLE +{ + IDS_LOCALIZEDNAME_ROOT "Vertrauenswürdige Stammzertifizierungsstellen" + IDS_LOCALIZEDNAME_MY "Persönlich" + IDS_LOCALIZEDNAME_CA "Zwischenzertifizierungsstellen" + IDS_LOCALIZEDNAME_ADDRESSBOOK "Andere Personen" +} diff --git a/reactos/dll/win32/crypt32/crypt32_En.rc b/reactos/dll/win32/crypt32/crypt32_En.rc index 273dcc8946b..38e3b2e91f9 100644 --- a/reactos/dll/win32/crypt32/crypt32_En.rc +++ b/reactos/dll/win32/crypt32/crypt32_En.rc @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT STRINGTABLE DISCARDABLE { @@ -164,3 +164,11 @@ STRINGTABLE DISCARDABLE IDS_LIFETIME_SIGNING "Lifetime Signing" IDS_ANY_CERT_POLICY "All issuance policies" } + +STRINGTABLE DISCARDABLE +{ + IDS_LOCALIZEDNAME_ROOT "Trusted Root Certification Authorities" + IDS_LOCALIZEDNAME_MY "Personal" + IDS_LOCALIZEDNAME_CA "Intermediate Certification Authorities" + IDS_LOCALIZEDNAME_ADDRESSBOOK "Other People" +} diff --git a/reactos/dll/win32/crypt32/crypt32_Fr.rc b/reactos/dll/win32/crypt32/crypt32_Fr.rc index f77a77ddfb1..06a11f9e39a 100644 --- a/reactos/dll/win32/crypt32/crypt32_Fr.rc +++ b/reactos/dll/win32/crypt32/crypt32_Fr.rc @@ -1,7 +1,7 @@ /* * crypt32 dll French resources * - * Copyright 2006 Jonathan Ernst + * Copyright 2006-2008 Jonathan Ernst * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,13 +22,13 @@ LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL STRINGTABLE DISCARDABLE { - IDS_AUTHORITY_KEY_ID "Authority Key Identifier" - IDS_KEY_ATTRIBUTES "Key Attributes" - IDS_KEY_USAGE_RESTRICTION "Key Usage Restriction" + IDS_AUTHORITY_KEY_ID "Identifiant de l'authorité de la clé" + IDS_KEY_ATTRIBUTES "Attributs de la clé" + IDS_KEY_USAGE_RESTRICTION "Restrictions de l'utilisation de la clé" IDS_SUBJECT_ALT_NAME "Subject Alternative Name" IDS_ISSUER_ALT_NAME "Issuer Alternative Name" IDS_BASIC_CONSTRAINTS "Basic Constraints" - IDS_KEY_USAGE "Key Usage" + IDS_KEY_USAGE "Utilisation de la clé" IDS_CERT_POLICIES "Certificate Policies" IDS_SUBJECT_KEY_IDENTIFIER "Subject Key Identifier" IDS_CRL_REASON_CODE "CRL Reason Code" @@ -49,7 +49,7 @@ STRINGTABLE DISCARDABLE IDS_SMIME_CAPABILITIES "SMIME Capabilities" IDS_PREFER_SIGNED_DATA "Prefer Signed Data" IDS_CPS "CPS" - IDS_USER_NOTICE "User Notice" + IDS_USER_NOTICE "Notice utilisateur" IDS_OCSP "On-line Certificate Status Protocol" IDS_CA_ISSUER "Certification Authority Issuer" IDS_CERT_TEMPLATE_NAME "Certification Template Name" @@ -157,10 +157,18 @@ STRINGTABLE DISCARDABLE IDS_DOCUMENT_SIGNING "Signature de document" IDS_IPSEC_IKE_INTERMEDIATE "IP security IKE intermediate" IDS_FILE_RECOVERY "Récupération de fichier" - IDS_ROOT_LIST_SIGNER "Root List Signer" + IDS_ROOT_LIST_SIGNER "Signataires de la liste racine" IDS_ANY_APPLICATION_POLICIES "All application policies" IDS_DS_EMAIL_REPLICATION "Directory Service Email Replication" IDS_ENROLLMENT_AGENT "Certificate Request Agent" IDS_LIFETIME_SIGNING "Lifetime Signing" IDS_ANY_CERT_POLICY "All issuance policies" } + +STRINGTABLE DISCARDABLE +{ + IDS_LOCALIZEDNAME_ROOT "Autorités de certification de confiance" + IDS_LOCALIZEDNAME_MY "Personnel" + IDS_LOCALIZEDNAME_CA "Autorités intermédiaires" + IDS_LOCALIZEDNAME_ADDRESSBOOK "Autres personnes" +} diff --git a/reactos/dll/win32/crypt32/crypt32_Ko.rc b/reactos/dll/win32/crypt32/crypt32_Ko.rc index 418e04514b7..cdb89fcb04c 100644 --- a/reactos/dll/win32/crypt32/crypt32_Ko.rc +++ b/reactos/dll/win32/crypt32/crypt32_Ko.rc @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT +LANGUAGE LANG_KOREAN, SUBLANG_NEUTRAL STRINGTABLE DISCARDABLE { @@ -165,3 +165,11 @@ STRINGTABLE DISCARDABLE IDS_LIFETIME_SIGNING "Æò»ý ¼­¸í" IDS_ANY_CERT_POLICY "¸ðµç ¹èÆ÷ ¹æħ" } + +STRINGTABLE DISCARDABLE +{ + IDS_LOCALIZEDNAME_ROOT "½Åȸ ÇÒ ¼ö ÀÖ´Â ·çÆ® °Ë»çÁõ±â°ü" + IDS_LOCALIZEDNAME_MY "°³ÀÎÀû" + IDS_LOCALIZEDNAME_CA "Áß°£ °ËÁõ ±â°ü¤¤Intermediate Certification Authorities" + IDS_LOCALIZEDNAME_ADDRESSBOOK "´Ù¸¥ »ç¶÷" +} diff --git a/reactos/dll/win32/crypt32/crypt32_Nl.rc b/reactos/dll/win32/crypt32/crypt32_Nl.rc new file mode 100644 index 00000000000..b98f21302c6 --- /dev/null +++ b/reactos/dll/win32/crypt32/crypt32_Nl.rc @@ -0,0 +1,174 @@ +/* + * Dutch crypt32 dll resources + * + * Copyright (C) 2008 Frans Kool + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL + +STRINGTABLE DISCARDABLE +{ + IDS_AUTHORITY_KEY_ID "Autoriteits Sleutel Identificatie nummer" + IDS_KEY_ATTRIBUTES "Sleutel Attributen" + IDS_KEY_USAGE_RESTRICTION "Sleutel Gebruiksbeperkingen" + IDS_SUBJECT_ALT_NAME "Onderwerp's Alternatieve Naam" + IDS_ISSUER_ALT_NAME "Verstrekker's Alternatieve Naam" + IDS_BASIC_CONSTRAINTS "Basis Beperkingen" + IDS_KEY_USAGE "Sleutel Gebruik" + IDS_CERT_POLICIES "Certificaat Beleid" + IDS_SUBJECT_KEY_IDENTIFIER "Onderwerp's Sleutel Identificatie nummer" + IDS_CRL_REASON_CODE "CRL Reden Code" + IDS_CRL_DIST_POINTS "CRL Distributie Locaties" + IDS_ENHANCED_KEY_USAGE "Uitgebreid Sleutel Gebruik" + IDS_AUTHORITY_INFO_ACCESS "Autoriteits Informatie Toegang" + IDS_CERT_EXTENSIONS "Certificaat Extensies" + IDS_NEXT_UPDATE_LOCATION "Volgende Update Locatie" + IDS_YES_OR_NO_TRUST "Wel of Geen Vertrouwen" + IDS_EMAIL_ADDRESS "Email Adres" + IDS_UNSTRUCTURED_NAME "Ongestructureerde Naam" + IDS_CONTENT_TYPE "Inhoud Type" + IDS_MESSAGE_DIGEST "Boodschap Samenvatting" + IDS_SIGNING_TIME "Tijd van Ondertekening" + IDS_COUNTER_SIGN "Counter Sign" + IDS_CHALLENGE_PASSWORD "Geheime Vraag Wachtwoord" + IDS_UNSTRUCTURED_ADDRESS "Ongestructureerd Adres" + IDS_SMIME_CAPABILITIES "SMIME Mogelijkheden" + IDS_PREFER_SIGNED_DATA "Prefereer Getekende Data" + IDS_CPS "CPS" + IDS_USER_NOTICE "Gebruikers Mededeling" + IDS_OCSP "On-line Certificaat Status Protocol" + IDS_CA_ISSUER "Certificatie Autoriteits Verstrekker" + IDS_CERT_TEMPLATE_NAME "Certificatie Template Naam" + IDS_CERT_TYPE "Type Certificaat" + IDS_CERT_MANIFOLD "Certificaat Verspreider" + IDS_NETSCAPE_CERT_TYPE "Netscape Certificaat Type" + IDS_NETSCAPE_BASE_URL "Netscape Basis URL" + IDS_NETSCAPE_REVOCATION_URL "Netscape Terugroep URL" + IDS_NETSCAPE_CA_REVOCATION_URL "Netscape CA Terugroep URL" + IDS_NETSCAPE_CERT_RENEWAL_URL "Netscape Cert Verversings URL" + IDS_NETSCAPE_CA_POLICY_URL "Netscape CA Beleids URL" + IDS_NETSCAPE_SSL_SERVER_NAME "Netscape SSL Server Naam" + IDS_NETSCAPE_COMMENT "Netscape Commentaar" + IDS_SPC_SP_AGENCY_INFO "SpcSpAgencyInfo" + IDS_SPC_FINANCIAL_CRITERIA "SpcFinancialCriteria" + IDS_SPC_MINIMAL_CRITERIA "SpcMinimalCriteria" + IDS_COUNTRY "Land/Regio" + IDS_ORGANIZATION "Organisatie" + IDS_ORGANIZATIONAL_UNIT "Organisatie Onderdeel" + IDS_COMMON_NAME "Gemeenschappelijke Naam" + IDS_LOCALITY "Localiteit" + IDS_STATE_OR_PROVINCE "Staat of Provincie" + IDS_TITLE "Titel" + IDS_GIVEN_NAME "Voornaam" + IDS_INITIALS "Initialen" + IDS_SUR_NAME "Achternaam" + IDS_DOMAIN_COMPONENT "Domein Component" + IDS_STREET_ADDRESS "Straat/Adres" + IDS_SERIAL_NUMBER "Registratie Nummer" + IDS_CA_VERSION "CA Versie" + IDS_CROSS_CA_VERSION "Cross CA Versie" + IDS_SERIALIZED_SIG_SERIAL_NUMBER "Geautomatiseerde Handtekening Serienummer" + IDS_PRINCIPAL_NAME "Hoofd Naam" + IDS_WINDOWS_PRODUCT_UPDATE "Windows Produkt Update" + IDS_ENROLLMENT_NAME_VALUE_PAIR "Inschrijvingsnaam Waarde Paar" + IDS_OS_VERSION "OS Versie" + IDS_ENROLLMENT_CSP "Inschrijving CSP" + IDS_CRL_NUMBER "CRL Nummer" + IDS_DELTA_CRL_INDICATOR "Delta CRL Indicatie" + IDS_ISSUING_DIST_POINT "Verstrekkend Distributie Punt" + IDS_FRESHEST_CRL "Nieuwste CRL" + IDS_NAME_CONSTRAINTS "Beperkingen op Naam" + IDS_POLICY_MAPPINGS "Beleids Mappingen" + IDS_POLICY_CONSTRAINTS "Beperkingen op Beleid" + IDS_CROSS_CERT_DIST_POINTS "Trans-Certificaat Distributie Punten" + IDS_APPLICATION_POLICIES "Applicatie Beleid" + IDS_APPLICATION_POLICY_MAPPINGS "Applicatie Beleids Mappingen" + IDS_APPLICATION_POLICY_CONSTRAINTS "Applicatie Beperkingen op Beleid" + IDS_CMC_DATA "CMC Data" + IDS_CMC_RESPONSE "CMC Antwoord" + IDS_UNSIGNED_CMC_REQUEST "Ongetekend CMC Verzoek" + IDS_CMC_STATUS_INFO "CMC Status Informatie" + IDS_CMC_EXTENSIONS "CMC Extensies" + IDS_CMC_ATTRIBUTES "CMC Attributen" + IDS_PKCS_7_DATA "PKCS 7 Data" + IDS_PKCS_7_SIGNED "PKCS 7 Ondertekend" + IDS_PKCS_7_ENVELOPED "PKCS 7 Omsloten" + IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 Getekend Omsloten" + IDS_PKCS_7_DIGESTED "PKCS 7 Samengevat" + IDS_PKCS_7_ENCRYPTED "PKCS 7 Gecodeerd" + IDS_PREVIOUS_CA_CERT_HASH "Vorige CA Certificaat Hash" + IDS_CRL_VIRTUAL_BASE "Virtueel Basis CRL Nummer" + IDS_CRL_NEXT_PUBLISH "Volgende CRL Publicatie" + IDS_CA_EXCHANGE "CA Coderings Certificaat" + IDS_KEY_RECOVERY_AGENT "Sleutel Herstel Agent" + IDS_CERTIFICATE_TEMPLATE "Certificaat Template Information" + IDS_ENTERPRISE_ROOT_OID "Ondernemings Basis OID" + IDS_RDN_DUMMY_SIGNER "Dummie Tekenaar" + IDS_ARCHIVED_KEY_ATTR "Gecodeerde Persoonlijke Sleutel" + IDS_CRL_SELF_CDP "Gepubliseerde CRL Locaties" + IDS_REQUIRE_CERT_CHAIN_POLICY "Afdwingen Certificaat Keten Beleid" + IDS_TRANSACTION_ID "Transactie Nummer" + IDS_SENDER_NONCE "Zender Nonce" + IDS_RECIPIENT_NONCE "Ontvanger Nonce" + IDS_REG_INFO "Registratie Informatie" + IDS_GET_CERTIFICATE "Haal Certificaat op" + IDS_GET_CRL "Haal CRL op" + IDS_REVOKE_REQUEST "Trek Verzoek In" + IDS_QUERY_PENDING "Verzoek in behandeling" + IDS_SORTED_CTL "Certificaat Vertrouwenslijst" + IDS_ARCHIVED_KEY_CERT_HASH "Gearchiveerde Sleutel Certificaat Hash" + IDS_PRIVATE_KEY_USAGE_PERIOD "Prive Sleutel Gebruik Periode" + IDS_CLIENT_INFORMATION "Cliënt Informatie" + IDS_SERVER_AUTHENTICATION "Server Authentificatie" + IDS_CLIENT_AUTHENTICATION "Cliënt Authentificatie" + IDS_CODE_SIGNING "Code Ondertekenen" + IDS_SECURE_EMAIL "Beveiligde Email" + IDS_TIME_STAMPING "Tijd Stempel Toekennen" + IDS_MICROSOFT_TRUST_LIST_SIGNING "Microsoft Trust Lijst Ondertekenen" + IDS_MICROSOFT_TIME_STAMPING "Microsoft Tijd Stempel Toekennen" + IDS_IPSEC_END_SYSTEM "IP beveiliging eind systeem" + IDS_IPSEC_TUNNEL "IP beveiliging tunnel afsluiting" + IDS_IPSEC_USER "IP beveiliging gebruiker" + IDS_EFS "Versleutelen Bestand Systeem" + IDS_WHQL_CRYPTO "Windows Hardware Driver Verificatie" + IDS_NT5_CRYPTO "Windows Systeem Component Verificatie" + IDS_OEM_WHQL_CRYPTO "OEM Windows Systeem Component Verificatie" + IDS_EMBEDDED_NT_CRYPTO "Ingebed Windows Systeem Componenten Verificatie" + IDS_KEY_PACK_LICENSES "Sleutel Verzameling Licenties" + IDS_LICENSE_SERVER "Licentie Server Verificatie" + IDS_SMART_CARD_LOGON "Smart Card Aanmelden" + IDS_DIGITAL_RIGHTS "Digitale Rechten" + IDS_QUALIFIED_SUBORDINATION "Gekwalificeerde Ondergeschiktheid" + IDS_KEY_RECOVERY "Sleutel Herstellen" + IDS_DOCUMENT_SIGNING "Document Ondertekenen" + IDS_IPSEC_IKE_INTERMEDIATE "IP beveiliging IKE tussenpersoon" + IDS_FILE_RECOVERY "Bestand Herstellen" + IDS_ROOT_LIST_SIGNER "Basis Lijst Ondertekenaar" + IDS_ANY_APPLICATION_POLICIES "Alle applicaties beleid" + IDS_DS_EMAIL_REPLICATION "Directory Service Email Replicatie" + IDS_ENROLLMENT_AGENT "Certificaat Verzoek Agent" + IDS_LIFETIME_SIGNING "Levensduur Ondertekenen" + IDS_ANY_CERT_POLICY "Alle uitgifte beleid" +} + +STRINGTABLE DISCARDABLE +{ + IDS_LOCALIZEDNAME_ROOT "Vertrouwde Basis Certificatie Autoriteiten" + IDS_LOCALIZEDNAME_MY "Persoonlijk" + IDS_LOCALIZEDNAME_CA "Certificatie Tussen-Autoriteiten" + IDS_LOCALIZEDNAME_ADDRESSBOOK "Overige Personen" +} diff --git a/reactos/dll/win32/crypt32/crypt32_No.rc b/reactos/dll/win32/crypt32/crypt32_No.rc index 02ce5d78e1e..18de84b8c4b 100644 --- a/reactos/dll/win32/crypt32/crypt32_No.rc +++ b/reactos/dll/win32/crypt32/crypt32_No.rc @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL +LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL STRINGTABLE DISCARDABLE { @@ -164,3 +164,11 @@ STRINGTABLE DISCARDABLE IDS_LIFETIME_SIGNING "Livstidsignering" IDS_ANY_CERT_POLICY "Alle framgangsmåter for utsteding" } + +STRINGTABLE DISCARDABLE +{ + IDS_LOCALIZEDNAME_ROOT "Klarerte rotsertifiseringsinstanser" + IDS_LOCALIZEDNAME_MY "Personlig" + IDS_LOCALIZEDNAME_CA "Mellomliggende sertifiseringsinstanser" + IDS_LOCALIZEDNAME_ADDRESSBOOK "Andre personer" +} diff --git a/reactos/dll/win32/crypt32/crypt32_Sv.rc b/reactos/dll/win32/crypt32/crypt32_Sv.rc new file mode 100644 index 00000000000..33167d1f1fb --- /dev/null +++ b/reactos/dll/win32/crypt32/crypt32_Sv.rc @@ -0,0 +1,169 @@ +/* + * crypt32 dll resources + * + * Copyright (C) 2007 Daniel Nylander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#pragma code_page(65001) + +LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_AUTHORITY_KEY_ID "Authority Key Identifier" + IDS_KEY_ATTRIBUTES "Nyckelattribut" + IDS_KEY_USAGE_RESTRICTION "Key Usage Restriction" + IDS_SUBJECT_ALT_NAME "Subject Alternative Name" + IDS_ISSUER_ALT_NAME "Issuer Alternative Name" + IDS_BASIC_CONSTRAINTS "Basic Constraints" + IDS_KEY_USAGE "Nyckelanvändning" + IDS_CERT_POLICIES "Certificate Policies" + IDS_SUBJECT_KEY_IDENTIFIER "Subject Key Identifier" + IDS_CRL_REASON_CODE "CRL Reason Code" + IDS_CRL_DIST_POINTS "CRL Distribution Points" + IDS_ENHANCED_KEY_USAGE "Enhanced Key Usage" + IDS_AUTHORITY_INFO_ACCESS "Authority Information Access" + IDS_CERT_EXTENSIONS "Certificate Extensions" + IDS_NEXT_UPDATE_LOCATION "Next Update Location" + IDS_YES_OR_NO_TRUST "Yes or No Trust" + IDS_EMAIL_ADDRESS "E-postadress" + IDS_UNSTRUCTURED_NAME "Unstructured Name" + IDS_CONTENT_TYPE "InnehÃ¥llstyp" + IDS_MESSAGE_DIGEST "Message Digest" + IDS_SIGNING_TIME "Signing Time" + IDS_COUNTER_SIGN "Counter Sign" + IDS_CHALLENGE_PASSWORD "Challenge Password" + IDS_UNSTRUCTURED_ADDRESS "Unstructured Address" + IDS_SMIME_CAPABILITIES "SMIME Capabilities" + IDS_PREFER_SIGNED_DATA "Prefer Signed Data" + IDS_CPS "CPS" + IDS_USER_NOTICE "User Notice" + IDS_OCSP "On-line Certificate Status Protocol" + IDS_CA_ISSUER "Certification Authority Issuer" + IDS_CERT_TEMPLATE_NAME "Certification Template Name" + IDS_CERT_TYPE "Certificate Type" + IDS_CERT_MANIFOLD "Certificate Manifold" + IDS_NETSCAPE_CERT_TYPE "Netscape Cert Type" + IDS_NETSCAPE_BASE_URL "Netscape Base URL" + IDS_NETSCAPE_REVOCATION_URL "Netscape Revocation URL" + IDS_NETSCAPE_CA_REVOCATION_URL "Netscape CA Revocation URL" + IDS_NETSCAPE_CERT_RENEWAL_URL "Netscape Cert Renewal URL" + IDS_NETSCAPE_CA_POLICY_URL "Netscape CA Policy URL" + IDS_NETSCAPE_SSL_SERVER_NAME "Netscape SSL ServerName" + IDS_NETSCAPE_COMMENT "Netscape Comment" + IDS_SPC_SP_AGENCY_INFO "SpcSpAgencyInfo" + IDS_SPC_FINANCIAL_CRITERIA "SpcFinancialCriteria" + IDS_SPC_MINIMAL_CRITERIA "SpcMinimalCriteria" + IDS_COUNTRY "Land/Region" + IDS_ORGANIZATION "Organisation" + IDS_ORGANIZATIONAL_UNIT "Organizational Unit" + IDS_COMMON_NAME "Common Name" + IDS_LOCALITY "Plats" + IDS_STATE_OR_PROVINCE "Län eller region" + IDS_TITLE "Titel" + IDS_GIVEN_NAME "Förnamn" + IDS_INITIALS "Initialer" + IDS_SUR_NAME "Efternamn" + IDS_DOMAIN_COMPONENT "Domain Component" + IDS_STREET_ADDRESS "Postadress" + IDS_SERIAL_NUMBER "Serienummer" + IDS_CA_VERSION "CA Version" + IDS_CROSS_CA_VERSION "Cross CA Version" + IDS_SERIALIZED_SIG_SERIAL_NUMBER "Serialized Signature Serial Number" + IDS_PRINCIPAL_NAME "Principal Name" + IDS_WINDOWS_PRODUCT_UPDATE "Windows Product Update" + IDS_ENROLLMENT_NAME_VALUE_PAIR "Enrollment Name Value Pair" + IDS_OS_VERSION "OS Version" + IDS_ENROLLMENT_CSP "Enrollment CSP" + IDS_CRL_NUMBER "CRL Number" + IDS_DELTA_CRL_INDICATOR "Delta CRL Indicator" + IDS_ISSUING_DIST_POINT "Issuing Distribution Point" + IDS_FRESHEST_CRL "Freshest CRL" + IDS_NAME_CONSTRAINTS "Name Constraints" + IDS_POLICY_MAPPINGS "Policy Mappings" + IDS_POLICY_CONSTRAINTS "Policy Constraints" + IDS_CROSS_CERT_DIST_POINTS "Cross-Certificate Distribution Points" + IDS_APPLICATION_POLICIES "Application Policies" + IDS_APPLICATION_POLICY_MAPPINGS "Application Policy Mappings" + IDS_APPLICATION_POLICY_CONSTRAINTS "Application Policy Constraints" + IDS_CMC_DATA "CMC Data" + IDS_CMC_RESPONSE "CMC Response" + IDS_UNSIGNED_CMC_REQUEST "Unsigned CMC Request" + IDS_CMC_STATUS_INFO "CMC Status Info" + IDS_CMC_EXTENSIONS "CMC Extensions" + IDS_CMC_ATTRIBUTES "CMC Attributes" + IDS_PKCS_7_DATA "PKCS 7 Data" + IDS_PKCS_7_SIGNED "PKCS 7 Signed" + IDS_PKCS_7_ENVELOPED "PKCS 7 Enveloped" + IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 Signed Enveloped" + IDS_PKCS_7_DIGESTED "PKCS 7 Digested" + IDS_PKCS_7_ENCRYPTED "PKCS 7 Encrypted" + IDS_PREVIOUS_CA_CERT_HASH "Previous CA Certificate Hash" + IDS_CRL_VIRTUAL_BASE "Virtual Base CRL Number" + IDS_CRL_NEXT_PUBLISH "Next CRL Publish" + IDS_CA_EXCHANGE "CA Encryption Certificate" + IDS_KEY_RECOVERY_AGENT "Key Recovery Agent" + IDS_CERTIFICATE_TEMPLATE "Certificate Template Information" + IDS_ENTERPRISE_ROOT_OID "Enterprise Root OID" + IDS_RDN_DUMMY_SIGNER "Dummy Signer" + IDS_ARCHIVED_KEY_ATTR "Encrypted Private Key" + IDS_CRL_SELF_CDP "Published CRL Locations" + IDS_REQUIRE_CERT_CHAIN_POLICY "Enforce Certificate Chain Policy" + IDS_TRANSACTION_ID "Transaction Id" + IDS_SENDER_NONCE "Sender Nonce" + IDS_RECIPIENT_NONCE "Recipient Nonce" + IDS_REG_INFO "Reg Info" + IDS_GET_CERTIFICATE "Get Certificate" + IDS_GET_CRL "Get CRL" + IDS_REVOKE_REQUEST "Revoke Request" + IDS_QUERY_PENDING "Query Pending" + IDS_SORTED_CTL "Certificate Trust List" + IDS_ARCHIVED_KEY_CERT_HASH "Archived Key Certificate Hash" + IDS_PRIVATE_KEY_USAGE_PERIOD "Private Key Usage Period" + IDS_CLIENT_INFORMATION "Client Information" + IDS_SERVER_AUTHENTICATION "Server Authentication" + IDS_CLIENT_AUTHENTICATION "Client Authentication" + IDS_CODE_SIGNING "Code Signing" + IDS_SECURE_EMAIL "Säker e-post" + IDS_TIME_STAMPING "Time Stamping" + IDS_MICROSOFT_TRUST_LIST_SIGNING "Microsoft Trust List Signing" + IDS_MICROSOFT_TIME_STAMPING "Microsoft Time Stamping" + IDS_IPSEC_END_SYSTEM "IP security end system" + IDS_IPSEC_TUNNEL "IP security tunnel termination" + IDS_IPSEC_USER "IP security user" + IDS_EFS "Encrypting File System" + IDS_WHQL_CRYPTO "Windows Hardware Driver Verification" + IDS_NT5_CRYPTO "Windows System Component Verification" + IDS_OEM_WHQL_CRYPTO "OEM Windows System Component Verification" + IDS_EMBEDDED_NT_CRYPTO "Embedded Windows System Component Verification" + IDS_KEY_PACK_LICENSES "Key Pack Licenses" + IDS_LICENSE_SERVER "License Server Verification" + IDS_SMART_CARD_LOGON "Smart Card Logon" + IDS_DIGITAL_RIGHTS "Digital Rights" + IDS_QUALIFIED_SUBORDINATION "Qualified Subordination" + IDS_KEY_RECOVERY "Key Recovery" + IDS_DOCUMENT_SIGNING "Document Signing" + IDS_IPSEC_IKE_INTERMEDIATE "IP security IKE intermediate" + IDS_FILE_RECOVERY "File Recovery" + IDS_ROOT_LIST_SIGNER "Root List Signer" + IDS_ANY_APPLICATION_POLICIES "All application policies" + IDS_DS_EMAIL_REPLICATION "Directory Service Email Replication" + IDS_ENROLLMENT_AGENT "Certificate Request Agent" + IDS_LIFETIME_SIGNING "Lifetime Signing" + IDS_ANY_CERT_POLICY "All issuance policies" +} + +#pragma code_page(default) diff --git a/reactos/dll/win32/crypt32/crypt32_private.h b/reactos/dll/win32/crypt32/crypt32_private.h index 8aa544b2f06..18384dcc9f1 100644 --- a/reactos/dll/win32/crypt32/crypt32_private.h +++ b/reactos/dll/win32/crypt32/crypt32_private.h @@ -38,6 +38,81 @@ #define ASN_UNIVERSALSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1c) #define ASN_BMPSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e) +BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded); + +typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *, + DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *); + +struct AsnEncodeSequenceItem +{ + const void *pvStructInfo; + CryptEncodeObjectExFunc encodeFunc; + DWORD size; /* used during encoding, not for your use */ +}; + +BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType, + struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); + +struct AsnConstructedItem +{ + BYTE tag; + const void *pvStructInfo; + CryptEncodeObjectExFunc encodeFunc; +}; + +BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); +BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); +BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); + +typedef struct _CRYPT_DIGESTED_DATA +{ + DWORD version; + CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm; + CRYPT_CONTENT_INFO ContentInfo; + CRYPT_HASH_BLOB hash; +} CRYPT_DIGESTED_DATA; + +BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData, + void *pvData, DWORD *pcbData); + +typedef struct _CRYPT_SIGNED_INFO +{ + DWORD version; + DWORD cCertEncoded; + PCERT_BLOB rgCertEncoded; + DWORD cCrlEncoded; + PCRL_BLOB rgCrlEncoded; + CRYPT_CONTENT_INFO content; + DWORD cSignerInfo; + PCMSG_SIGNER_INFO rgSignerInfo; +} CRYPT_SIGNED_INFO; + +BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *, void *pvData, + DWORD *pcbData); + +BOOL CRYPT_AsnDecodePKCSSignedInfo(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, + CRYPT_SIGNED_INFO *signedInfo, DWORD *pcbSignedInfo); + +/* Helper function to check *pcbEncoded, set it to the required size, and + * optionally to allocate memory. Assumes pbEncoded is not NULL. + * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a + * pointer to the newly allocated memory. + */ +BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, + BYTE *pbEncoded, DWORD *pcbEncoded, DWORD bytesNeeded); + +BOOL CRYPT_AsnDecodePKCSDigestedData(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, + CRYPT_DIGESTED_DATA *digestedData, DWORD *pcbDigestedData); + /* The following aren't defined in wincrypt.h, as they're "reserved" */ #define CERT_CERT_PROP_ID 32 #define CERT_CRL_PROP_ID 33 @@ -50,6 +125,9 @@ HCRYPTPROV CRYPT_GetDefaultProvider(void); void crypt_oid_init(HINSTANCE hinst); void crypt_oid_free(void); +void crypt_sip_free(void); +void root_store_free(void); +void default_chain_engine_free(void); /* Some typedefs that make it easier to abstract which type of context we're * working with. @@ -95,6 +173,94 @@ extern PCWINE_CONTEXT_INTERFACE pCertInterface; extern PCWINE_CONTEXT_INTERFACE pCRLInterface; extern PCWINE_CONTEXT_INTERFACE pCTLInterface; +/* (Internal) certificate store types and functions */ +struct WINE_CRYPTCERTSTORE; + +typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara); + +/* Called to enumerate the next context in a store. */ +typedef void * (*EnumFunc)(struct WINE_CRYPTCERTSTORE *store, void *pPrev); + +/* Called to add a context to a store. If toReplace is not NULL, + * context replaces toReplace in the store, and access checks should not be + * performed. Otherwise context is a new context, and it should only be + * added if the store allows it. If ppStoreContext is not NULL, the added + * context should be returned in *ppStoreContext. + */ +typedef BOOL (*AddFunc)(struct WINE_CRYPTCERTSTORE *store, void *context, + void *toReplace, const void **ppStoreContext); + +typedef BOOL (*DeleteFunc)(struct WINE_CRYPTCERTSTORE *store, void *context); + +typedef struct _CONTEXT_FUNCS +{ + AddFunc addContext; + EnumFunc enumContext; + DeleteFunc deleteContext; +} CONTEXT_FUNCS, *PCONTEXT_FUNCS; + +typedef enum _CertStoreType { + StoreTypeMem, + StoreTypeCollection, + StoreTypeProvider, +} CertStoreType; + +struct _CONTEXT_PROPERTY_LIST; +typedef struct _CONTEXT_PROPERTY_LIST *PCONTEXT_PROPERTY_LIST; + +#define WINE_CRYPTCERTSTORE_MAGIC 0x74726563 + +/* A cert store is polymorphic through the use of function pointers. A type + * is still needed to distinguish collection stores from other types. + * On the function pointers: + * - closeStore is called when the store's ref count becomes 0 + * - control is optional, but should be implemented by any store that supports + * persistence + */ +typedef struct WINE_CRYPTCERTSTORE +{ + DWORD dwMagic; + LONG ref; + DWORD dwOpenFlags; + CertStoreType type; + PFN_CERT_STORE_PROV_CLOSE closeStore; + CONTEXT_FUNCS certs; + CONTEXT_FUNCS crls; + PFN_CERT_STORE_PROV_CONTROL control; /* optional */ + PCONTEXT_PROPERTY_LIST properties; +} WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE; + +void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags, + CertStoreType type); +void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store); +BOOL WINAPI I_CertUpdateStore(HCERTSTORE store1, HCERTSTORE store2, DWORD unk0, + DWORD unk1); + +PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara); +PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(DWORD dwFlags, + PWINECRYPT_CERTSTORE memStore, const CERT_STORE_PROV_INFO *pProvInfo); +PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider, + DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, + const void *pvPara); +PWINECRYPT_CERTSTORE CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, + const void *pvPara); +PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, + const void *pvPara); +PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara); +PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara); +PWINECRYPT_CERTSTORE CRYPT_RootOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags); + +/* Allocates and initializes a certificate chain engine, but without creating + * the root store. Instead, it uses root, and assumes the caller has done any + * checking necessary. + */ +HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root, + PCERT_CHAIN_ENGINE_CONFIG pConfig); + /* Helper function for store reading functions and * CertAddSerializedElementToStore. Returns a context of the appropriate type * if it can, or NULL otherwise. Doesn't validate any of the properties in @@ -104,15 +270,12 @@ extern PCWINE_CONTEXT_INTERFACE pCTLInterface; const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType); -/* Writes contexts from the memory store to the file. */ -BOOL CRYPT_WriteSerializedFile(HANDLE file, HCERTSTORE store); - /* Reads contexts serialized in the file into the memory store. Returns FALSE * if the file is not of the expected format. */ -BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store); +BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store); -/* Fixes up the the pointers in info, where info is assumed to be a +/* Fixes up the pointers in info, where info is assumed to be a * CRYPT_KEY_PROV_INFO, followed by its container name, provider name, and any * provider parameters, in a contiguous buffer, but where info's pointers are * assumed to be invalid. Upon return, info's pointers point to the @@ -120,8 +283,6 @@ BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store); */ void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info); -DWORD CertStore_GetAccessState(HCERTSTORE hCertStore); - /** * Context functions */ @@ -153,13 +314,10 @@ void *Context_GetLinkedContext(void *context, size_t contextSize); void Context_CopyProperties(const void *to, const void *from, size_t contextSize); -struct _CONTEXT_PROPERTY_LIST; -typedef struct _CONTEXT_PROPERTY_LIST *PCONTEXT_PROPERTY_LIST; - /* Returns context's properties, or the linked context's properties if context * is a link context. */ -PCONTEXT_PROPERTY_LIST Context_GetProperties(void *context, size_t contextSize); +PCONTEXT_PROPERTY_LIST Context_GetProperties(const void *context, size_t contextSize); void Context_AddRef(void *context, size_t contextSize); diff --git a/reactos/dll/win32/crypt32/crypt32_ros.diff b/reactos/dll/win32/crypt32/crypt32_ros.diff index a392a8692c3..02696926e87 100644 --- a/reactos/dll/win32/crypt32/crypt32_ros.diff +++ b/reactos/dll/win32/crypt32/crypt32_ros.diff @@ -1,24 +1,19 @@ -Index: crypt32.rc -=================================================================== ---- crypt32.rc (revision 22838) -+++ crypt32.rc (working copy) -@@ -17,12 +17,18 @@ - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -+ -+#define REACTOS_VERSION_DLL -+#define REACTOS_STR_FILE_DESCRIPTION "CryptoAPI Library\0" -+#define REACTOS_STR_INTERNAL_NAME "crypt32\0" -+#define REACTOS_STR_ORIGINAL_FILENAME "crypt32.dll\0" -+ - #include "windef.h" - #include "winbase.h" - #include "winuser.h" - #include "cryptres.h" +--- D:/Wine-CVS/wine/dlls/crypt32/rootstore.c Sat Feb 16 22:49:56 2008 ++++ D:/ReactOS-Trunk/reactos/dll/win32/crypt32/rootstore.c Sat May 10 20:30:25 2008 +@@ -317,7 +317,7 @@ + DIR *dir; --#include "version.rc" -+#include + TRACE("(%s, %p)\n", debugstr_a(path), store); +- ++ /* UNIX functions = bad for reactos + dir = opendir(path); + if (dir) + { +@@ -340,6 +340,7 @@ + CryptMemFree(filebuf); + } + } ++ */ + return ret; + } - #include "crypt32_De.rc" - #include "crypt32_En.rc" diff --git a/reactos/dll/win32/crypt32/cryptres.h b/reactos/dll/win32/crypt32/cryptres.h index 1f0a95ea43d..32c81690e2c 100644 --- a/reactos/dll/win32/crypt32/cryptres.h +++ b/reactos/dll/win32/crypt32/cryptres.h @@ -160,4 +160,9 @@ #define IDS_LIFETIME_SIGNING 1139 #define IDS_ANY_CERT_POLICY 1140 +#define IDS_LOCALIZEDNAME_ROOT 1141 +#define IDS_LOCALIZEDNAME_MY 1142 +#define IDS_LOCALIZEDNAME_CA 1143 +#define IDS_LOCALIZEDNAME_ADDRESSBOOK 1144 + #endif /* ndef __WINE_CRYPTRES_H__ */ diff --git a/reactos/dll/win32/crypt32/decode.c b/reactos/dll/win32/crypt32/decode.c index e6ca94c7c17..47b0ba6515e 100644 --- a/reactos/dll/win32/crypt32/decode.c +++ b/reactos/dll/win32/crypt32/decode.c @@ -1,5 +1,5 @@ /* - * Copyright 2005 Juan Lang + * Copyright 2005-2007 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,8 +17,8 @@ * * This file implements ASN.1 DER decoding of a limited set of types. * It isn't a full ASN.1 implementation. Microsoft implements BER - * encoding of many of the basic types in msasn1.dll, but that interface is - * undocumented, so I implement them here. + * encoding of many of the basic types in msasn1.dll, but that interface isn't + * implemented, so I implement them here. * * References: * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski @@ -27,10 +27,12 @@ * * RFC3280, http://www.faqs.org/rfcs/rfc3280.html * - * MSDN, especially: - * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp + * MSDN, especially "Constants for CryptEncodeObject and CryptDecodeObject" */ +#include "config.h" +#include "wine/port.h" + #include #include #include @@ -40,10 +42,8 @@ #include "windef.h" #include "winbase.h" -#include "excpt.h" #include "wincrypt.h" #include "winnls.h" -#include "winreg.h" #include "snmp.h" #include "wine/debug.h" #include "wine/exception.h" @@ -55,7 +55,8 @@ #define ASN_FLAGS_MASK 0xe0 #define ASN_TYPE_MASK 0x1f -WINE_DEFAULT_DEBUG_CHANNEL(crypt); +WINE_DEFAULT_DEBUG_CHANNEL(cryptasn); +WINE_DECLARE_DEBUG_CHANNEL(crypt); struct GenericArray { @@ -68,111 +69,60 @@ typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *, typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *, DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *); -/* Prototypes for built-in decoders. They follow the Ex style prototypes. - * The dwCertEncodingType and lpszStructType are ignored by the built-in - * functions, but the parameters are retained to simplify CryptDecodeObjectEx, - * since it must call functions in external DLLs that follow these signatures. +/* Internal decoders don't do memory allocation or exception handling, and + * they report how many bytes they decoded. */ -static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +typedef BOOL (*InternalDecodeFunc)(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded); + +static BOOL CRYPT_AsnDecodeChoiceOfTimeInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded); +static BOOL CRYPT_AsnDecodePubKeyInfoInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded); /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of * time, doesn't do memory allocation, and doesn't do exception handling. - * (This isn't intended to be the externally-called one.) */ -static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Assumes algo->Parameters.pbData is set ahead of time. Internal func. */ -static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Internal function */ -static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +static BOOL CRYPT_AsnDecodeExtensionsInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded); +/* Assumes algo->Parameters.pbData is set ahead of time. */ +static BOOL CRYPT_AsnDecodeAlgorithmId(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded); +static BOOL CRYPT_AsnDecodeBool(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded); /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */ -static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -/* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData - * member has been initialized, doesn't do exception handling, and doesn't do - * memory allocation. - */ -static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); -static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +static BOOL CRYPT_AsnDecodeOctetsInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded); +static BOOL CRYPT_AsnDecodeBitsInternal(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded); +static BOOL CRYPT_AsnDecodeIntInternal(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded); /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData * member has been initialized, doesn't do exception handling, and doesn't do * memory allocation. Also doesn't check tag, assumes the caller has checked * it. */ -static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +static BOOL CRYPT_AsnDecodeIntegerInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded); /* Like CRYPT_AsnDecodeInteger, but unsigned. */ -static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal( - DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, - void *pvStructInfo, DWORD *pcbStructInfo); - -BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType, - const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, - DWORD *pcbStructInfo) -{ - static HCRYPTOIDFUNCSET set = NULL; - BOOL ret = FALSE; - CryptDecodeObjectFunc pCryptDecodeObject; - HCRYPTOIDFUNCADDR hFunc; - - TRACE("(0x%08x, %s, %p, %d, 0x%08x, %p, %p)\n", dwCertEncodingType, - debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags, - pvStructInfo, pcbStructInfo); - - if (!pvStructInfo && !pcbStructInfo) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* Try registered DLL first.. */ - if (!set) - set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0); - CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, - (void **)&pCryptDecodeObject, &hFunc); - if (pCryptDecodeObject) - { - ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType, - pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo); - CryptFreeOIDFunctionAddress(hFunc, 0); - } - else - { - /* If not, use CryptDecodeObjectEx */ - ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded, - cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo); - } - return ret; -} +static BOOL CRYPT_AsnDecodeUnsignedIntegerInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded); /* Gets the number of length bytes from the given (leading) length byte */ -#define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f)) +#define GET_LEN_BYTES(b) ((b) <= 0x80 ? 1 : 1 + ((b) & 0x7f)) /* Helper function to get the encoded length of the data starting at pbEncoded, * where pbEncoded[0] is the tag. If the data are too short to contain a * length or if the length is too large for cbEncoded, sets an appropriate - * error code and returns FALSE. + * error code and returns FALSE. If the encoded length is unknown due to + * indefinite length encoding, *len is set to CMSG_INDEFINITE_LENGTH. */ -static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, +static BOOL CRYPT_GetLengthIndefinite(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len) { BOOL ret; @@ -195,6 +145,11 @@ static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, ret = TRUE; } } + else if (pbEncoded[1] == 0x80) + { + *len = CMSG_INDEFINITE_LENGTH; + ret = TRUE; + } else { BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]); @@ -234,6 +189,20 @@ static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, return ret; } +/* Like CRYPT_GetLengthIndefinite, but disallows indefinite-length encoding. */ +static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len) +{ + BOOL ret; + + if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, len)) && + *len == CMSG_INDEFINITE_LENGTH) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + return ret; +} + /* Helper function to check *pcbStructInfo, set it to the required size, and * optionally to allocate memory. Assumes pvStructInfo is not NULL. * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a @@ -265,6 +234,35 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, return ret; } +static void CRYPT_FreeSpace(PCRYPT_DECODE_PARA pDecodePara, LPVOID pv) +{ + if (pDecodePara && pDecodePara->pfnFree) + pDecodePara->pfnFree(pv); + else + LocalFree(pv); +} + +/* Helper function to check *pcbStructInfo and set it to the required size. + * Assumes pvStructInfo is not NULL. + */ +static BOOL CRYPT_DecodeCheckSpace(DWORD *pcbStructInfo, DWORD bytesNeeded) +{ + BOOL ret; + + if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbStructInfo = bytesNeeded; + ret = TRUE; + } + return ret; +} + /* tag: * The expected tag of the item. If tag is 0, decodeFunc is called * regardless of the tag value seen. @@ -280,47 +278,62 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags, * If true, and the tag doesn't match the expected tag for this item, * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is * filled with 0 for this member. - * hasPointer, pointerOffset, minSize: + * hasPointer, pointerOffset: * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to - * the offset within the (outer) struct of the data pointer (or to the + * the offset within the struct of the data pointer (or to the * first data pointer, if more than one exist). * size: * Used by CRYPT_AsnDecodeSequence, not for your use. */ struct AsnDecodeSequenceItem { - BYTE tag; - DWORD offset; - CryptDecodeObjectExFunc decodeFunc; - DWORD minSize; - BOOL optional; - BOOL hasPointer; - DWORD pointerOffset; - DWORD size; + BYTE tag; + DWORD offset; + InternalDecodeFunc decodeFunc; + DWORD minSize; + BOOL optional; + BOOL hasPointer; + DWORD pointerOffset; + DWORD size; }; -static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, - struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData) +/* Decodes the items in a sequence, where the items are described in items, + * the encoded data are in pbEncoded with length cbEncoded. Decodes into + * pvStructInfo. nextData is a pointer to the memory location at which the + * first decoded item with a dynamic pointer should point. + * Upon decoding, *cbDecoded is the total number of bytes decoded. + * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set. + */ +static BOOL CRYPT_AsnDecodeSequenceItems(struct AsnDecodeSequenceItem items[], + DWORD cItem, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + void *pvStructInfo, BYTE *nextData, DWORD *cbDecoded) { BOOL ret; - DWORD i; - const BYTE *ptr; + DWORD i, decoded = 0; + const BYTE *ptr = pbEncoded; + + TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded, + cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded); - ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]); for (i = 0, ret = TRUE; ret && i < cItem; i++) { if (cbEncoded - (ptr - pbEncoded) != 0) { - DWORD nextItemLen; + DWORD itemLen; - if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), - &nextItemLen))) + if ((ret = CRYPT_GetLengthIndefinite(ptr, + cbEncoded - (ptr - pbEncoded), &itemLen))) { - BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]); + BYTE itemLenBytes = GET_LEN_BYTES(ptr[1]); if (ptr[0] == items[i].tag || !items[i].tag) { + DWORD itemEncodedLen; + + if (itemLen == CMSG_INDEFINITE_LENGTH) + itemEncodedLen = cbEncoded - (ptr - pbEncoded); + else + itemEncodedLen = 1 + itemLenBytes + itemLen; if (nextData && pvStructInfo && items[i].hasPointer) { TRACE("Setting next pointer to %p\n", @@ -330,31 +343,56 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, } if (items[i].decodeFunc) { + DWORD itemDecoded; + if (pvStructInfo) TRACE("decoding item %d\n", i); else TRACE("sizing item %d\n", i); - ret = items[i].decodeFunc(dwCertEncodingType, - NULL, ptr, 1 + nextItemLenBytes + nextItemLen, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, + ret = items[i].decodeFunc(ptr, itemEncodedLen, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset - : NULL, &items[i].size); + : NULL, &items[i].size, &itemDecoded); if (ret) { + /* Account for alignment padding */ + if (items[i].size % sizeof(DWORD_PTR)) + items[i].size += sizeof(DWORD_PTR) - + items[i].size % sizeof(DWORD_PTR); + TRACE("item %d size: %d\n", i, items[i].size); if (nextData && items[i].hasPointer && items[i].size > items[i].minSize) - { nextData += items[i].size - items[i].minSize; - /* align nextData to DWORD boundaries */ - if (items[i].size % sizeof(DWORD)) - nextData += sizeof(DWORD) - items[i].size % - sizeof(DWORD); + if (itemDecoded > itemEncodedLen) + { + WARN("decoded length %d exceeds encoded %d\n", + itemDecoded, itemEncodedLen); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + if (itemLen == CMSG_INDEFINITE_LENGTH) + { + if (itemDecoded > itemEncodedLen - 2 || + *(ptr + itemDecoded) != 0 || + *(ptr + itemDecoded + 1) != 0) + { + TRACE("expected 0 TLV\n"); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + itemDecoded += 2; + } + if (ret) + { + ptr += itemDecoded; + decoded += itemDecoded; + TRACE("item %d: decoded %d bytes\n", i, + itemDecoded); + } } - /* Account for alignment padding */ - if (items[i].size % sizeof(DWORD)) - items[i].size += sizeof(DWORD) - - items[i].size % sizeof(DWORD); - ptr += 1 + nextItemLenBytes + nextItemLen; } else if (items[i].optional && GetLastError() == CRYPT_E_ASN1_BADTAG) @@ -368,8 +406,19 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, TRACE("item %d failed: %08x\n", i, GetLastError()); } + else if (itemLen == CMSG_INDEFINITE_LENGTH) + { + ERR("can't use indefinite length encoding without a decoder\n"); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } else + { + TRACE("item %d: decoded %d bytes\n", i, itemEncodedLen); + ptr += itemEncodedLen; + decoded += itemEncodedLen; items[i].size = items[i].minSize; + } } else if (items[i].optional) { @@ -378,8 +427,8 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, } else { - TRACE("tag %02x doesn't match expected %02x\n", - ptr[0], items[i].tag); + TRACE("item %d: tag %02x doesn't match expected %02x\n", + i, ptr[0], items[i].tag); SetLastError(CRYPT_E_ASN1_BADTAG); ret = FALSE; } @@ -397,13 +446,9 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, ret = FALSE; } } - if (cbEncoded - (ptr - pbEncoded) != 0) - { - TRACE("%d remaining bytes, failing\n", cbEncoded - - (ptr - pbEncoded)); - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } + if (cbDecoded) + *cbDecoded = decoded; + TRACE("returning %d\n", ret); return ret; } @@ -413,13 +458,11 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, * startingPointer is an optional pointer to the first place where dynamic * data will be stored. If you know the starting offset, you may pass it * here. Otherwise, pass NULL, and one will be inferred from the items. - * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set. - * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT. */ -static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, - struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, - void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer) +static BOOL CRYPT_AsnDecodeSequence(struct AsnDecodeSequenceItem items[], + DWORD cItem, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded, void *startingPointer) { BOOL ret; @@ -431,21 +474,66 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, { DWORD dataLen; - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen))) { - DWORD i; + DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded; + const BYTE *ptr = pbEncoded + 1 + lenBytes; + BOOL indefinite = FALSE; - ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded, - cbEncoded, dwFlags, NULL, NULL); + cbEncoded -= 1 + lenBytes; + if (dataLen == CMSG_INDEFINITE_LENGTH) + { + dataLen = cbEncoded; + indefinite = TRUE; + } + else if (cbEncoded < dataLen) + { + TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen, + cbEncoded); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } if (ret) { - DWORD bytesNeeded = 0, structSize = 0; + ret = CRYPT_AsnDecodeSequenceItems(items, cItem, + ptr, dataLen, dwFlags, NULL, NULL, &cbDecoded); + if (ret && dataLen == CMSG_INDEFINITE_LENGTH) + { + if (cbDecoded > cbEncoded - 2) + { + /* Not enough space for 0 TLV */ + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else if (*(ptr + cbDecoded) != 0 || + *(ptr + cbDecoded + 1) != 0) + { + TRACE("expected 0 TLV\n"); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + cbDecoded += 2; + } + } + if (ret && !indefinite && cbDecoded != dataLen) + { + TRACE("expected %d decoded, got %d, failing\n", dataLen, + cbDecoded); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + if (ret) + { + DWORD i, bytesNeeded = 0, structSize = 0; for (i = 0; i < cItem; i++) { bytesNeeded += items[i].size; structSize += items[i].minSize; } + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + cbDecoded; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, @@ -460,8 +548,11 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, else nextData = (BYTE *)pvStructInfo + structSize; memset(pvStructInfo, 0, structSize); - ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, - pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData); + ret = CRYPT_AsnDecodeSequenceItems(items, cItem, + ptr, dataLen, dwFlags, pvStructInfo, nextData, + &cbDecoded); + if (!ret && (dwFlags & CRYPT_DECODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pDecodePara, pvStructInfo); } } } @@ -477,7 +568,8 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, /* tag: * The expected tag of the entire encoded array (usually a variant - * of ASN_SETOF or ASN_SEQUENCEOF.) + * of ASN_SETOF or ASN_SEQUENCEOF.) If tag is 0, decodeFunc is called + * regardless of the tag seen. * decodeFunc: * used to decode each item in the array * itemSize: @@ -489,11 +581,11 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, */ struct AsnArrayDescriptor { - BYTE tag; - CryptDecodeObjectExFunc decodeFunc; - DWORD itemSize; - BOOL hasPointer; - DWORD pointerOffset; + BYTE tag; + InternalDecodeFunc decodeFunc; + DWORD itemSize; + BOOL hasPointer; + DWORD pointerOffset; }; struct AsnArrayItemSize @@ -509,7 +601,7 @@ struct AsnArrayItemSize static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo, - void *startingPointer) + DWORD *pcbDecoded, void *startingPointer) { BOOL ret = TRUE; @@ -517,73 +609,96 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo, startingPointer); - if (pbEncoded[0] == arrayDesc->tag) + if (!arrayDesc->tag || pbEncoded[0] == arrayDesc->tag) { DWORD dataLen; - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen))) { - DWORD bytesNeeded, cItems = 0; + DWORD bytesNeeded, cItems = 0, decoded; BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); /* There can be arbitrarily many items, but there is often only one. */ struct AsnArrayItemSize itemSize = { 0 }, *itemSizes = &itemSize; + decoded = 1 + lenBytes; bytesNeeded = sizeof(struct GenericArray); if (dataLen) { const BYTE *ptr; + BOOL doneDecoding = FALSE; - for (ptr = pbEncoded + 1 + lenBytes; ret && - ptr - pbEncoded - 1 - lenBytes < dataLen; ) + for (ptr = pbEncoded + 1 + lenBytes; ret && !doneDecoding; ) { - DWORD itemLenBytes, itemDataLen, size; - - itemLenBytes = GET_LEN_BYTES(ptr[1]); - /* Each item decoded may not tolerate extraneous bytes, so - * get the length of the next element and pass it directly. - */ - ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), - &itemDataLen); - if (ret) - ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr, - 1 + itemLenBytes + itemDataLen, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, - &size); - if (ret) + if (dataLen == CMSG_INDEFINITE_LENGTH) { - DWORD nextLen; + if (ptr[0] == 0) + { + doneDecoding = TRUE; + if (ptr[1] != 0) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + decoded += 2; + } + } + else if (ptr - pbEncoded - 1 - lenBytes >= dataLen) + doneDecoding = TRUE; + if (!doneDecoding) + { + DWORD itemEncoded, itemDataLen, itemDecoded, size = 0; - cItems++; - if (itemSizes != &itemSize) - itemSizes = CryptMemRealloc(itemSizes, - cItems * sizeof(struct AsnArrayItemSize)); - else + /* Each item decoded may not tolerate extraneous bytes, + * so get the length of the next element if known. + */ + if ((ret = CRYPT_GetLengthIndefinite(ptr, + cbEncoded - (ptr - pbEncoded), &itemDataLen))) { - itemSizes = - CryptMemAlloc( - cItems * sizeof(struct AsnArrayItemSize)); + if (itemDataLen == CMSG_INDEFINITE_LENGTH) + itemEncoded = cbEncoded - (ptr - pbEncoded); + else + itemEncoded = 1 + GET_LEN_BYTES(ptr[1]) + + itemDataLen; + } + if (ret) + ret = arrayDesc->decodeFunc(ptr, itemEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &size, + &itemDecoded); + if (ret) + { + cItems++; + if (itemSizes != &itemSize) + itemSizes = CryptMemRealloc(itemSizes, + cItems * sizeof(struct AsnArrayItemSize)); + else if (cItems > 1) + { + itemSizes = + CryptMemAlloc( + cItems * sizeof(struct AsnArrayItemSize)); + if (itemSizes) + memcpy(itemSizes, &itemSize, + sizeof(itemSize)); + } if (itemSizes) - memcpy(itemSizes, &itemSize, sizeof(itemSize)); + { + decoded += itemDecoded; + itemSizes[cItems - 1].encodedLen = itemEncoded; + itemSizes[cItems - 1].size = size; + bytesNeeded += size; + ptr += itemEncoded; + } + else + ret = FALSE; } - if (itemSizes) - { - itemSizes[cItems - 1].encodedLen = 1 + itemLenBytes - + itemDataLen; - itemSizes[cItems - 1].size = size; - bytesNeeded += size; - ret = CRYPT_GetLen(ptr, - cbEncoded - (ptr - pbEncoded), &nextLen); - if (ret) - ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]); - } - else - ret = FALSE; } } } if (ret) { + if (pcbDecoded) + *pcbDecoded = decoded; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, @@ -603,31 +718,30 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, else array->rgItems = (BYTE *)array + sizeof(struct GenericArray); - nextData = (BYTE *)array->rgItems + + nextData = array->rgItems + array->cItems * arrayDesc->itemSize; for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cItems && ptr - pbEncoded - 1 - lenBytes < dataLen; i++) { + DWORD itemDecoded; + if (arrayDesc->hasPointer) *(BYTE **)(array->rgItems + i * arrayDesc->itemSize + arrayDesc->pointerOffset) = nextData; - ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr, + ret = arrayDesc->decodeFunc(ptr, itemSizes[i].encodedLen, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, array->rgItems + i * arrayDesc->itemSize, - &itemSizes[i].size); + &itemSizes[i].size, &itemDecoded); if (ret) { - DWORD nextLen; - nextData += itemSizes[i].size - arrayDesc->itemSize; - ret = CRYPT_GetLen(ptr, - cbEncoded - (ptr - pbEncoded), &nextLen); - if (ret) - ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]); + ptr += itemDecoded; } } + if (!ret && (dwFlags & CRYPT_DECODE_ALLOC_FLAG)) + CRYPT_FreeSpace(pDecodePara, pvStructInfo); } } if (itemSizes != &itemSize) @@ -648,9 +762,8 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData * set! */ -static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeDerBlob(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; DWORD dataLen; @@ -659,14 +772,15 @@ static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType, { BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB); - + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) bytesNeeded += 1 + lenBytes + dataLen; + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, bytesNeeded))) + else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, bytesNeeded))) { CRYPT_DER_BLOB *blob; @@ -695,21 +809,21 @@ static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType, } /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */ -static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeBitsSwapBytes(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; - TRACE("(%p, %d, 0x%08x, %p, %p, %d)\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("(%p, %d, 0x%08x, %p, %d, %p)\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in- * place. */ - ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType, - pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara, - pvStructInfo, pcbStructInfo); + ret = CRYPT_AsnDecodeBitsInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pvStructInfo, pcbStructInfo, + pcbDecoded); if (ret && pvStructInfo) { CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo; @@ -757,9 +871,9 @@ static BOOL WINAPI CRYPT_AsnDecodeCertSignedContent(DWORD dwCertEncodingType, if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG) items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -772,10 +886,8 @@ static BOOL WINAPI CRYPT_AsnDecodeCertSignedContent(DWORD dwCertEncodingType, return ret; } -/* Internal function */ -static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeCertVersion(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; DWORD dataLen; @@ -784,36 +896,35 @@ static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType, { BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, - pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo); + ret = CRYPT_AsnDecodeIntInternal(pbEncoded + 1 + lenBytes, dataLen, + dwFlags, pvStructInfo, pcbStructInfo, NULL); + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; } return ret; } -static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeValidity(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; struct AsnDecodeSequenceItem items[] = { { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore), - CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, + CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 }, { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter), - CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 }, + CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 }, }; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, NULL); return ret; } -/* Internal function */ -static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeCertExtensions(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; DWORD dataLen; @@ -822,9 +933,10 @@ static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType, { BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, - X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo); + ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded + 1 + lenBytes, + dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL); + if (ret && pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; } return ret; } @@ -870,9 +982,27 @@ static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType, TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo); - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, + NULL, NULL); + if (ret && pvStructInfo) + { + CERT_INFO *info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + info = *(CERT_INFO **)pvStructInfo; + else + info = (CERT_INFO *)pvStructInfo; + if (!info->SerialNumber.cbData || !info->Issuer.cbData || + !info->Subject.cbData) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + /* Don't need to deallocate, because it should have failed on the + * first pass (and no memory was allocated.) + */ + ret = FALSE; + } + } TRACE("Returning %d (%08x)\n", ret, GetLastError()); return ret; @@ -882,28 +1012,32 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { - BOOL ret = TRUE; + BOOL ret = FALSE; TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo); __TRY { - PCERT_SIGNED_CONTENT_INFO signedCert = NULL; DWORD size = 0; - /* First try to decode it as a signed cert. */ - ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, X509_CERT, - pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, - (BYTE *)&signedCert, &size); - if (ret) + /* Unless told not to, first try to decode it as a signed cert. */ + if (!(dwFlags & CRYPT_DECODE_TO_BE_SIGNED_FLAG)) { - size = 0; - ret = CRYPT_AsnDecodeCertInfo(dwCertEncodingType, - X509_CERT_TO_BE_SIGNED, signedCert->ToBeSigned.pbData, - signedCert->ToBeSigned.cbData, dwFlags, pDecodePara, pvStructInfo, - pcbStructInfo); - LocalFree(signedCert); + PCERT_SIGNED_CONTENT_INFO signedCert = NULL; + + ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, + X509_CERT, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&signedCert, &size); + if (ret) + { + size = 0; + ret = CRYPT_AsnDecodeCertInfo(dwCertEncodingType, + X509_CERT_TO_BE_SIGNED, signedCert->ToBeSigned.pbData, + signedCert->ToBeSigned.cbData, dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo); + LocalFree(signedCert); + } } /* Failing that, try it as an unsigned cert */ if (!ret) @@ -917,7 +1051,6 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, __EXCEPT_PAGE_FAULT { SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; } __ENDTRY @@ -925,17 +1058,16 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; struct AsnDecodeSequenceItem items[] = { { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY, SerialNumber.pbData), 0 }, - { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime, - sizeof(FILETIME), FALSE, FALSE, 0 }, + { 0, offsetof(CRL_ENTRY, RevocationDate), + CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 }, { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY, rgExtension), 0 }, @@ -945,18 +1077,23 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType, TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, entry, *pcbStructInfo); - ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, entry, pcbStructInfo, pcbDecoded, + entry ? entry->SerialNumber.pbData : NULL); + if (ret && entry && !entry->SerialNumber.cbData) + { + WARN("empty CRL entry serial number\n"); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } return ret; } /* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has * been set prior to calling. */ -static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeCRLEntries(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, @@ -964,11 +1101,11 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType, offsetof(CRL_ENTRY, SerialNumber.pbData) }; struct GenericArray *entries = (struct GenericArray *)pvStructInfo; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, entries ? entries->rgItems : NULL); TRACE("Returning %d (%08x)\n", ret, GetLastError()); return ret; @@ -980,16 +1117,16 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType, { struct AsnDecodeSequenceItem items[] = { { ASN_INTEGER, offsetof(CRL_INFO, dwVersion), - CRYPT_AsnDecodeInt, sizeof(DWORD), TRUE, FALSE, 0, 0 }, + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), TRUE, FALSE, 0, 0 }, { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 }, { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO, Issuer.pbData) }, - { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime, + { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 }, - { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime, + { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), TRUE, FALSE, 0 }, { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE, @@ -1003,9 +1140,9 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType, TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo); - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, + NULL, NULL); TRACE("Returning %d (%08x)\n", ret, GetLastError()); return ret; @@ -1015,28 +1152,32 @@ static BOOL WINAPI CRYPT_AsnDecodeCRL(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { - BOOL ret = TRUE; + BOOL ret = FALSE; TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo); __TRY { - PCERT_SIGNED_CONTENT_INFO signedCrl = NULL; DWORD size = 0; - /* First try to decode it as a signed crl. */ - ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, X509_CERT, - pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, - (BYTE *)&signedCrl, &size); - if (ret) + /* Unless told not to, first try to decode it as a signed crl. */ + if (!(dwFlags & CRYPT_DECODE_TO_BE_SIGNED_FLAG)) { - size = 0; - ret = CRYPT_AsnDecodeCRLInfo(dwCertEncodingType, - X509_CERT_CRL_TO_BE_SIGNED, signedCrl->ToBeSigned.pbData, - signedCrl->ToBeSigned.cbData, dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo); - LocalFree(signedCrl); + PCERT_SIGNED_CONTENT_INFO signedCrl = NULL; + + ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, + X509_CERT, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&signedCrl, &size); + if (ret) + { + size = 0; + ret = CRYPT_AsnDecodeCRLInfo(dwCertEncodingType, + X509_CERT_CRL_TO_BE_SIGNED, signedCrl->ToBeSigned.pbData, + signedCrl->ToBeSigned.cbData, dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo); + LocalFree(signedCrl); + } } /* Failing that, try it as an unsigned crl */ if (!ret) @@ -1050,7 +1191,6 @@ static BOOL WINAPI CRYPT_AsnDecodeCRL(DWORD dwCertEncodingType, __EXCEPT_PAGE_FAULT { SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; } __ENDTRY @@ -1058,42 +1198,87 @@ static BOOL WINAPI CRYPT_AsnDecodeCRL(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeOidInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeOidIgnoreTag(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret = TRUE; + DWORD dataLen; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); - if (pbEncoded[0] == ASN_OBJECTIDENTIFIER) + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { - DWORD dataLen; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + DWORD bytesNeeded = sizeof(LPSTR); - if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + if (dataLen) { - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - DWORD bytesNeeded = sizeof(LPSTR); + /* The largest possible string for the first two components + * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough. + */ + char firstTwo[6]; + const BYTE *ptr; + snprintf(firstTwo, sizeof(firstTwo), "%d.%d", + pbEncoded[1 + lenBytes] / 40, + pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) + * 40); + bytesNeeded += strlen(firstTwo) + 1; + for (ptr = pbEncoded + 2 + lenBytes; ret && + ptr - pbEncoded - 1 - lenBytes < dataLen; ) + { + /* large enough for ".4000000" */ + char str[9]; + int val = 0; + + while (ptr - pbEncoded - 1 - lenBytes < dataLen && + (*ptr & 0x80)) + { + val <<= 7; + val |= *ptr & 0x7f; + ptr++; + } + if (ptr - pbEncoded - 1 - lenBytes >= dataLen || + (*ptr & 0x80)) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + val <<= 7; + val |= *ptr++; + snprintf(str, sizeof(str), ".%d", val); + bytesNeeded += strlen(str); + } + } + } + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { if (dataLen) { - /* The largest possible string for the first two components - * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough. - */ - char firstTwo[6]; const BYTE *ptr; + LPSTR pszObjId = *(LPSTR *)pvStructInfo; - snprintf(firstTwo, sizeof(firstTwo), "%d.%d", - pbEncoded[1 + lenBytes] / 40, - pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) - * 40); - bytesNeeded += strlen(firstTwo) + 1; + *pszObjId = 0; + sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40, + pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / + 40) * 40); + pszObjId += strlen(pszObjId); for (ptr = pbEncoded + 2 + lenBytes; ret && ptr - pbEncoded - 1 - lenBytes < dataLen; ) { - /* large enough for ".4000000" */ - char str[9]; int val = 0; while (ptr - pbEncoded - 1 - lenBytes < dataLen && @@ -1103,78 +1288,48 @@ static BOOL WINAPI CRYPT_AsnDecodeOidInternal(DWORD dwCertEncodingType, val |= *ptr & 0x7f; ptr++; } - if (ptr - pbEncoded - 1 - lenBytes >= dataLen || - (*ptr & 0x80)) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - val <<= 7; - val |= *ptr++; - snprintf(str, sizeof(str), ".%d", val); - bytesNeeded += strlen(str); - } + val <<= 7; + val |= *ptr++; + sprintf(pszObjId, ".%d", val); + pszObjId += strlen(pszObjId); } } - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - *pcbStructInfo = bytesNeeded; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } else - { - if (dataLen) - { - const BYTE *ptr; - LPSTR pszObjId = *(LPSTR *)pvStructInfo; - - *pszObjId = 0; - sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40, - pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / - 40) * 40); - pszObjId += strlen(pszObjId); - for (ptr = pbEncoded + 2 + lenBytes; ret && - ptr - pbEncoded - 1 - lenBytes < dataLen; ) - { - int val = 0; - - while (ptr - pbEncoded - 1 - lenBytes < dataLen && - (*ptr & 0x80)) - { - val <<= 7; - val |= *ptr & 0x7f; - ptr++; - } - val <<= 7; - val |= *ptr++; - sprintf(pszObjId, ".%d", val); - pszObjId += strlen(pszObjId); - } - } - else - *(LPSTR *)pvStructInfo = NULL; - *pcbStructInfo = bytesNeeded; - } + *(LPSTR *)pvStructInfo = NULL; + *pcbStructInfo = bytesNeeded; } } return ret; } +static BOOL CRYPT_AsnDecodeOidInternal(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) +{ + BOOL ret; + + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + if (pbEncoded[0] == ASN_OBJECTIDENTIFIER) + ret = CRYPT_AsnDecodeOidIgnoreTag(pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pcbStructInfo, pcbDecoded); + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + return ret; +} + /* Warning: assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set * ahead of time! */ -static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { struct AsnDecodeSequenceItem items[] = { { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId), - CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_EXTENSION, pszObjId), 0 }, { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 }, @@ -1190,9 +1345,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType, if (ext) TRACE("ext->pszObjId is %p\n", ext->pszObjId); - ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, - ext, pcbStructInfo, ext ? ext->pszObjId : NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, ext, pcbStructInfo, + pcbDecoded, ext ? ext->pszObjId : NULL); if (ext) TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId, debugstr_a(ext->pszObjId)); @@ -1200,9 +1355,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeExtensionsInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret = TRUE; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, @@ -1210,11 +1365,12 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType, offsetof(CERT_EXTENSION, pszObjId) }; PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, + exts ? exts->rgExtension : NULL); return ret; } @@ -1226,9 +1382,8 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType, __TRY { - ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo); + ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL); if (ret && pvStructInfo) { ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, @@ -1242,10 +1397,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType, exts = (CERT_EXTENSIONS *)pvStructInfo; exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts + sizeof(CERT_EXTENSIONS)); - ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - pcbStructInfo); + ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + pcbStructInfo, NULL); } } } @@ -1262,9 +1416,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType, * order to avoid overwriting memory. (In some cases, it may change it, if it * doesn't copy anything to memory.) Be sure to set it correctly! */ -static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeNameValueInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret = TRUE; DWORD dataLen; @@ -1340,6 +1494,8 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType, return FALSE; } + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!value) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -1394,7 +1550,7 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType, LPWSTR str = (LPWSTR)value->Value.pbData; value->Value.cbData = MultiByteToWideChar(CP_UTF8, 0, - (LPCSTR)pbEncoded + 1 + lenBytes, dataLen, + (LPCSTR)pbEncoded + 1 + lenBytes, dataLen, str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * 2; break; } @@ -1418,9 +1574,8 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType, __TRY { - ret = CRYPT_AsnDecodeNameValueInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo); + ret = CRYPT_AsnDecodeNameValueInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL); if (ret && pvStructInfo) { ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, @@ -1433,10 +1588,9 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType, pvStructInfo = *(BYTE **)pvStructInfo; value = (CERT_NAME_VALUE *)pvStructInfo; value->Value.pbData = ((BYTE *)value + sizeof(CERT_NAME_VALUE)); - ret = CRYPT_AsnDecodeNameValueInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - pcbStructInfo); + ret = CRYPT_AsnDecodeNameValueInternal( pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + pcbStructInfo, NULL); } } } @@ -1449,10 +1603,9 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValueInternal( - DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, - void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeUnicodeNameValueInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret = TRUE; DWORD dataLen; @@ -1515,6 +1668,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValueInternal( return FALSE; } + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!value) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -1584,9 +1739,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValue(DWORD dwCertEncodingType, __TRY { - ret = CRYPT_AsnDecodeUnicodeNameValueInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo); + ret = CRYPT_AsnDecodeUnicodeNameValueInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL); if (ret && pvStructInfo) { ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, @@ -1599,10 +1753,9 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValue(DWORD dwCertEncodingType, pvStructInfo = *(BYTE **)pvStructInfo; value = (CERT_NAME_VALUE *)pvStructInfo; value->Value.pbData = ((BYTE *)value + sizeof(CERT_NAME_VALUE)); - ret = CRYPT_AsnDecodeUnicodeNameValueInternal( - dwCertEncodingType, lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - pcbStructInfo); + ret = CRYPT_AsnDecodeUnicodeNameValueInternal(pbEncoded, + cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + pcbStructInfo, NULL); } } } @@ -1615,14 +1768,13 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValue(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; struct AsnDecodeSequenceItem items[] = { { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId), - CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_RDN_ATTR, pszObjId), 0 }, { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValueInternal, sizeof(CERT_NAME_VALUE), @@ -1635,9 +1787,9 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, if (attr) TRACE("attr->pszObjId is %p\n", attr->pszObjId); - ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, - attr, pcbStructInfo, attr ? attr->pszObjId : NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, attr, pcbStructInfo, pcbDecoded, + attr ? attr->pszObjId : NULL); if (attr) { TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId, @@ -1648,9 +1800,8 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret = TRUE; struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, @@ -1659,7 +1810,8 @@ static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType, PCERT_RDN rdn = (PCERT_RDN)pvStructInfo; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, + rdn ? rdn->rgRDNAttr : NULL); return ret; } @@ -1676,7 +1828,7 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType, offsetof(CERT_RDN, rgRDNAttr) }; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -1687,14 +1839,14 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdnAttr(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeUnicodeRdnAttr(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; struct AsnDecodeSequenceItem items[] = { { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId), - CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_RDN_ATTR, pszObjId), 0 }, { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeUnicodeNameValueInternal, sizeof(CERT_NAME_VALUE), @@ -1707,9 +1859,9 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdnAttr(DWORD dwCertEncodingType, if (attr) TRACE("attr->pszObjId is %p\n", attr->pszObjId); - ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL, - attr, pcbStructInfo, attr ? attr->pszObjId : NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, attr, pcbStructInfo, pcbDecoded, + attr ? attr->pszObjId : NULL); if (attr) { TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId, @@ -1720,9 +1872,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdnAttr(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdn(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeUnicodeRdn(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret = TRUE; struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, @@ -1731,7 +1882,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdn(DWORD dwCertEncodingType, PCERT_RDN rdn = (PCERT_RDN)pvStructInfo; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, + rdn ? rdn->rgRDNAttr : NULL); return ret; } @@ -1748,7 +1900,7 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeName(DWORD dwCertEncodingType, offsetof(CERT_RDN, rgRDNAttr) }; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -1759,65 +1911,275 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeName(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_FindEncodedLen(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD *pcbDecoded) { - BOOL ret = TRUE; - DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB); + BOOL ret = TRUE, done = FALSE; + DWORD indefiniteNestingLevels = 0, decoded = 0; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("(%p, %d)\n", pbEncoded, cbEncoded); - if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) - bytesNeeded += cbEncoded; - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) + do { + DWORD dataLen; + + if (!cbEncoded) + done = TRUE; + else if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, + &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + if (dataLen == CMSG_INDEFINITE_LENGTH) + { + indefiniteNestingLevels++; + pbEncoded += 1 + lenBytes; + cbEncoded -= 1 + lenBytes; + decoded += 1 + lenBytes; + TRACE("indefiniteNestingLevels = %d\n", + indefiniteNestingLevels); + } + else + { + if (pbEncoded[0] == 0 && pbEncoded[1] == 0 && + indefiniteNestingLevels) + { + indefiniteNestingLevels--; + TRACE("indefiniteNestingLevels = %d\n", + indefiniteNestingLevels); + } + pbEncoded += 1 + lenBytes + dataLen; + cbEncoded -= 1 + lenBytes + dataLen; + decoded += 1 + lenBytes + dataLen; + if (!indefiniteNestingLevels) + done = TRUE; + } + } + } while (ret && !done); + /* If we haven't found all 0 TLVs, we haven't found the end */ + if (ret && indefiniteNestingLevels) { - SetLastError(ERROR_MORE_DATA); - *pcbStructInfo = bytesNeeded; + SetLastError(CRYPT_E_ASN1_EOD); ret = FALSE; } - else - { - PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo; + if (ret) + *pcbDecoded = decoded; + TRACE("returning %d (%d)\n", ret, ret ? *pcbDecoded : 0); + return ret; +} - *pcbStructInfo = bytesNeeded; - blob->cbData = cbEncoded; - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - blob->pbData = (LPBYTE)pbEncoded; +static BOOL CRYPT_AsnDecodeCopyBytes(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = TRUE; + DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB), encodedLen = 0; + + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + if ((ret = CRYPT_FindEncodedLen(pbEncoded, cbEncoded, &encodedLen))) + { + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += encodedLen; + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbStructInfo = bytesNeeded; + ret = FALSE; + } else { - assert(blob->pbData); - memcpy(blob->pbData, pbEncoded, blob->cbData); + PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo; + + *pcbStructInfo = bytesNeeded; + blob->cbData = encodedLen; + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) + blob->pbData = (LPBYTE)pbEncoded; + else + { + assert(blob->pbData); + memcpy(blob->pbData, pbEncoded, blob->cbData); + } } + if (pcbDecoded) + *pcbDecoded = encodedLen; } return ret; } -static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, +static BOOL CRYPT_DecodeDERArray(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { 0, CRYPT_AsnDecodeCopyBytes, + sizeof(CRYPT_DER_BLOB), TRUE, offsetof(CRYPT_DER_BLOB, pbData) }; + struct GenericArray *array = (struct GenericArray *)pvStructInfo; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, + array ? array->rgItems : NULL); + return ret; +} + +static BOOL CRYPT_AsnDecodePKCSAttributeInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnDecodeSequenceItem items[] = { + { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE, pszObjId), + CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE, + offsetof(CRYPT_ATTRIBUTE, pszObjId), 0 }, + { ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CRYPT_ATTRIBUTE, cValue), + CRYPT_DecodeDERArray, sizeof(struct GenericArray), FALSE, TRUE, + offsetof(CRYPT_ATTRIBUTE, rgValue), 0 }, + }; + PCRYPT_ATTRIBUTE attr = (PCRYPT_ATTRIBUTE)pvStructInfo; + + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, attr ? attr->pszObjId : NULL); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePKCSAttribute(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + DWORD bytesNeeded; + + ret = CRYPT_AsnDecodePKCSAttributeInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL); + if (ret) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + PCRYPT_ATTRIBUTE attr; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + attr = (PCRYPT_ATTRIBUTE)pvStructInfo; + attr->pszObjId = (LPSTR)((BYTE *)pvStructInfo + + sizeof(CRYPT_ATTRIBUTE)); + ret = CRYPT_AsnDecodePKCSAttributeInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, &bytesNeeded, + NULL); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_AsnDecodePKCSAttributesInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + struct AsnArrayDescriptor arrayDesc = { 0, + CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE), TRUE, + offsetof(CRYPT_ATTRIBUTE, pszObjId) }; + PCRYPT_ATTRIBUTES attrs = (PCRYPT_ATTRIBUTES)pvStructInfo; + BOOL ret; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, attrs ? attrs->rgAttr : + NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePKCSAttributes(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + DWORD bytesNeeded; + + if (!cbEncoded) + SetLastError(CRYPT_E_ASN1_EOD); + else if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF)) + SetLastError(CRYPT_E_ASN1_CORRUPT); + else if ((ret = CRYPT_AsnDecodePKCSAttributesInternal(pbEncoded, + cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, + NULL))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + PCRYPT_ATTRIBUTES attrs; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + attrs = (PCRYPT_ATTRIBUTES)pvStructInfo; + attrs->rgAttr = (PCRYPT_ATTRIBUTE)((BYTE *)pvStructInfo + + sizeof(CRYPT_ATTRIBUTES)); + ret = CRYPT_AsnDecodePKCSAttributesInternal(pbEncoded, + cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_AsnDecodeAlgorithmId(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { CRYPT_ALGORITHM_IDENTIFIER *algo = (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo; BOOL ret = TRUE; struct AsnDecodeSequenceItem items[] = { { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), - CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 }, { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters), - CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, + CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 }, }; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, algo ? algo->pszObjId : NULL); if (ret && pvStructInfo) { TRACE("pszObjId is %p (%s)\n", algo->pszObjId, @@ -1826,9 +2188,9 @@ static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodePubKeyInfoInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret = TRUE; struct AsnDecodeSequenceItem items[] = { @@ -1842,10 +2204,9 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType, }; PCERT_PUBLIC_KEY_INFO info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, info ? - info->Algorithm.Parameters.pbData : NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, info ? info->Algorithm.Parameters.pbData : NULL); return ret; } @@ -1859,9 +2220,8 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, { DWORD bytesNeeded; - if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL))) { if (!pvStructInfo) *pcbStructInfo = bytesNeeded; @@ -1875,10 +2235,9 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo; info->Algorithm.Parameters.pbData = (BYTE *)pvStructInfo + sizeof(CERT_PUBLIC_KEY_INFO); - ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); + ret = CRYPT_AsnDecodePubKeyInfoInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); } } } @@ -1891,9 +2250,8 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeBool(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; @@ -1912,6 +2270,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, SetLastError(CRYPT_E_ASN1_CORRUPT); return FALSE; } + if (pcbDecoded) + *pcbDecoded = 3; if (!pvStructInfo) { *pcbStructInfo = sizeof(BOOL); @@ -1932,27 +2292,21 @@ static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo; DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY); BOOL ret; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); if (cbEncoded < 2) { SetLastError(CRYPT_E_ASN1_CORRUPT); return FALSE; } - if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT) - { - SetLastError(CRYPT_E_ASN1_BADTAG); - return FALSE; - } lenBytes = GET_LEN_BYTES(pbEncoded[1]); if (1 + lenBytes > cbEncoded) { @@ -1968,28 +2322,41 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, case 6: /* uniformResourceIdentifier */ bytesNeeded += (dataLen + 1) * sizeof(WCHAR); break; + case 4: /* directoryName */ case 7: /* iPAddress */ bytesNeeded += dataLen; break; case 8: /* registeredID */ - /* FIXME: decode as OID */ + ret = CRYPT_AsnDecodeOidIgnoreTag(pbEncoded, cbEncoded, 0, NULL, + &dataLen, NULL); + if (ret) + { + /* FIXME: ugly, shouldn't need to know internals of OID decode + * function to use it. + */ + bytesNeeded += dataLen - sizeof(LPSTR); + } + break; case 0: /* otherName */ - case 4: /* directoryName */ - FIXME("stub\n"); + FIXME("%d: stub\n", pbEncoded[0] & ASN_TYPE_MASK); SetLastError(CRYPT_E_ASN1_BADTAG); ret = FALSE; break; case 3: /* x400Address, unimplemented */ case 5: /* ediPartyName, unimplemented */ + TRACE("type %d unimplemented\n", pbEncoded[0] & ASN_TYPE_MASK); SetLastError(CRYPT_E_ASN1_BADTAG); ret = FALSE; break; default: + TRACE("type %d bad\n", pbEncoded[0] & ASN_TYPE_MASK); SetLastError(CRYPT_E_ASN1_CORRUPT); ret = FALSE; } if (ret) { + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!entry) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -2019,6 +2386,11 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, debugstr_w(entry->u.pwszURL)); break; } + case 4: /* directoryName */ + entry->dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME; + /* The data are memory-equivalent with the IPAddress case, + * fall-through + */ case 7: /* iPAddress */ /* The next data pointer is in the pwszURL spot, that is, * the first 4 bytes. Need to move it to the next spot. @@ -2028,6 +2400,10 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes, dataLen); break; + case 8: /* registeredID */ + ret = CRYPT_AsnDecodeOidIgnoreTag(pbEncoded, cbEncoded, 0, + &entry->u.pszRegisteredID, &dataLen, NULL); + break; } } } @@ -2035,23 +2411,61 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeAltNameInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret = TRUE; - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + struct AsnArrayDescriptor arrayDesc = { 0, CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); if (info) TRACE("info->rgAltEntry is %p\n", info->rgAltEntry); ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, + info ? info->rgAltEntry : NULL); + return ret; +} + +/* Like CRYPT_AsnDecodeIntegerInternal, but swaps the bytes */ +static BOOL CRYPT_AsnDecodeIntegerSwapBytes(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + + TRACE("(%p, %d, 0x%08x, %p, %d, %p)\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in- + * place. + */ + ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pvStructInfo, pcbStructInfo, + pcbDecoded); + if (ret && pvStructInfo) + { + CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo; + + if (blob->cbData) + { + DWORD i; + BYTE temp; + + for (i = 0; i < blob->cbData / 2; i++) + { + temp = blob->pbData[i]; + blob->pbData[i] = blob->pbData[blob->cbData - i - 1]; + blob->pbData[blob->cbData - i - 1] = temp; + } + } + } + TRACE("returning %d (%08x)\n", ret, GetLastError()); return ret; } @@ -2065,7 +2479,7 @@ static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType, { struct AsnDecodeSequenceItem items[] = { { ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId), - CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_DATA_BLOB), + CRYPT_AsnDecodeIntegerSwapBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId.pbData), 0 }, { ASN_CONTEXT | ASN_CONSTRUCTOR| 1, offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer), @@ -2077,9 +2491,9 @@ static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType, offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertSerialNumber.pbData), 0 }, }; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -2090,6 +2504,187 @@ static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId2(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId), + CRYPT_AsnDecodeIntegerSwapBytes, sizeof(CRYPT_DATA_BLOB), + TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId.pbData), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR| 1, + offsetof(CERT_AUTHORITY_KEY_ID2_INFO, AuthorityCertIssuer), + CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, + TRUE, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, + AuthorityCertIssuer.rgAltEntry), 0 }, + { ASN_CONTEXT | 2, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, + AuthorityCertSerialNumber), CRYPT_AsnDecodeIntegerInternal, + sizeof(CRYPT_INTEGER_BLOB), TRUE, TRUE, + offsetof(CERT_AUTHORITY_KEY_ID2_INFO, + AuthorityCertSerialNumber.pbData), 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +static BOOL CRYPT_AsnDecodePKCSContent(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) +{ + BOOL ret; + DWORD dataLen; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + /* The caller has already checked the tag, no need to check it again. + * Check the outer length is valid: + */ + if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + DWORD innerLen; + + pbEncoded += 1 + lenBytes; + cbEncoded -= 1 + lenBytes; + if (dataLen == CMSG_INDEFINITE_LENGTH) + cbEncoded -= 2; /* space for 0 TLV */ + /* Check the inner length is valid: */ + if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &innerLen))) + { + DWORD decodedLen; + + ret = CRYPT_AsnDecodeCopyBytes(pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pcbStructInfo, &decodedLen); + if (dataLen == CMSG_INDEFINITE_LENGTH) + { + if (*(pbEncoded + decodedLen) != 0 || + *(pbEncoded + decodedLen + 1) != 0) + { + TRACE("expected 0 TLV, got {%02x,%02x}\n", + *(pbEncoded + decodedLen), + *(pbEncoded + decodedLen + 1)); + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + decodedLen += 2; + } + if (ret && pcbDecoded) + { + *pcbDecoded = 1 + lenBytes + decodedLen; + TRACE("decoded %d bytes\n", *pcbDecoded); + } + } + } + return ret; +} + +static BOOL CRYPT_AsnDecodePKCSContentInfoInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + CRYPT_CONTENT_INFO *info = (CRYPT_CONTENT_INFO *)pvStructInfo; + struct AsnDecodeSequenceItem items[] = { + { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_CONTENT_INFO, pszObjId), + CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE, + offsetof(CRYPT_CONTENT_INFO, pszObjId), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, + offsetof(CRYPT_CONTENT_INFO, Content), CRYPT_AsnDecodePKCSContent, + sizeof(CRYPT_DER_BLOB), TRUE, TRUE, + offsetof(CRYPT_CONTENT_INFO, Content.pbData), 0 }, + }; + BOOL ret; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, info ? info->pszObjId : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePKCSContentInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + ret = CRYPT_AsnDecodePKCSContentInfoInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL); + if (ret && pvStructInfo) + { + ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, *pcbStructInfo); + if (ret) + { + CRYPT_CONTENT_INFO *info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = (CRYPT_CONTENT_INFO *)pvStructInfo; + info->pszObjId = (LPSTR)((BYTE *)info + + sizeof(CRYPT_CONTENT_INFO)); + ret = CRYPT_AsnDecodePKCSContentInfoInternal(pbEncoded, + cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + pcbStructInfo, NULL); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +BOOL CRYPT_AsnDecodePKCSDigestedData(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, + CRYPT_DIGESTED_DATA *digestedData, DWORD *pcbDigestedData) +{ + BOOL ret; + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(CRYPT_DIGESTED_DATA, version), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + { ASN_SEQUENCEOF, offsetof(CRYPT_DIGESTED_DATA, DigestAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CRYPT_DIGESTED_DATA, DigestAlgorithm.pszObjId), + 0 }, + { ASN_SEQUENCEOF, offsetof(CRYPT_DIGESTED_DATA, ContentInfo), + CRYPT_AsnDecodePKCSContentInfoInternal, + sizeof(CRYPT_CONTENT_INFO), FALSE, TRUE, offsetof(CRYPT_DIGESTED_DATA, + ContentInfo.pszObjId), 0 }, + { ASN_OCTETSTRING, offsetof(CRYPT_DIGESTED_DATA, hash), + CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_HASH_BLOB), FALSE, TRUE, + offsetof(CRYPT_DIGESTED_DATA, hash.pbData), 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, digestedData, pcbDigestedData, + NULL, NULL); + return ret; +} + static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -2101,12 +2696,28 @@ static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType, __TRY { - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, - CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, - offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; + DWORD bytesNeeded; - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + if ((ret = CRYPT_AsnDecodeAltNameInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL))) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CERT_ALT_NAME_INFO *name; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + name = (CERT_ALT_NAME_INFO *)pvStructInfo; + name->rgAltEntry = (PCERT_ALT_NAME_ENTRY) + ((BYTE *)pvStructInfo + sizeof(CERT_ALT_NAME_INFO)); + ret = CRYPT_AsnDecodeAltNameInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); + } + } } __EXCEPT_PAGE_FAULT { @@ -2123,57 +2734,48 @@ struct PATH_LEN_CONSTRAINT DWORD dwPathLenConstraint; }; -static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodePathLenConstraint(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret = TRUE; + DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT), size; - TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); - if (cbEncoded) + if (!pvStructInfo) { - if (pbEncoded[0] == ASN_INTEGER) - { - DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT); + ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags, NULL, + &size, pcbDecoded); + *pcbStructInfo = bytesNeeded; + } + else if (*pcbStructInfo < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbStructInfo = bytesNeeded; + ret = FALSE; + } + else + { + struct PATH_LEN_CONSTRAINT *constraint = + (struct PATH_LEN_CONSTRAINT *)pvStructInfo; - if (!pvStructInfo) - *pcbStructInfo = bytesNeeded; - else if (*pcbStructInfo < bytesNeeded) - { - SetLastError(ERROR_MORE_DATA); - *pcbStructInfo = bytesNeeded; - ret = FALSE; - } - else - { - struct PATH_LEN_CONSTRAINT *constraint = - (struct PATH_LEN_CONSTRAINT *)pvStructInfo; - DWORD size = sizeof(constraint->dwPathLenConstraint); - - ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER, - pbEncoded, cbEncoded, 0, NULL, - &constraint->dwPathLenConstraint, &size); - if (ret) - constraint->fPathLenConstraint = TRUE; - TRACE("got an int, dwPathLenConstraint is %d\n", - constraint->dwPathLenConstraint); - } - } - else - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } + size = sizeof(constraint->dwPathLenConstraint); + ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags, + &constraint->dwPathLenConstraint, &size, pcbDecoded); + if (ret) + constraint->fPathLenConstraint = TRUE; + TRACE("got an int, dwPathLenConstraint is %d\n", + constraint->dwPathLenConstraint); } TRACE("returning %d (%08x)\n", ret, GetLastError()); return ret; } -static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeSubtreeConstraints(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, @@ -2181,11 +2783,11 @@ static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType, offsetof(CERT_NAME_BLOB, pbData) }; struct GenericArray *entries = (struct GenericArray *)pvStructInfo; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, entries ? entries->rgItems : NULL); TRACE("Returning %d (%08x)\n", ret, GetLastError()); return ret; @@ -2201,7 +2803,7 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType, { struct AsnDecodeSequenceItem items[] = { { ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType), - CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, + CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 }, { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO, fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint, @@ -2212,9 +2814,9 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType, offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 }, }; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -2241,9 +2843,9 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType, sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, }; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -2276,14 +2878,14 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData), 0 }, { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp), - CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, }; struct DECODED_RSA_PUB_KEY *decodedKey = NULL; DWORD size = 0; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, - CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, + &size, NULL, NULL); if (ret) { DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + @@ -2328,22 +2930,26 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeOctetsInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; DWORD bytesNeeded, dataLen; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) bytesNeeded = sizeof(CRYPT_DATA_BLOB); else bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB); + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -2355,7 +2961,6 @@ static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType, else { CRYPT_DATA_BLOB *blob; - BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); blob = (CRYPT_DATA_BLOB *)pvStructInfo; blob->cbData = dataLen; @@ -2396,9 +3001,8 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, SetLastError(CRYPT_E_ASN1_BADTAG); ret = FALSE; } - else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + else if ((ret = CRYPT_AsnDecodeOctetsInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL))) { if (!pvStructInfo) *pcbStructInfo = bytesNeeded; @@ -2411,10 +3015,9 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, pvStructInfo = *(BYTE **)pvStructInfo; blob = (CRYPT_DATA_BLOB *)pvStructInfo; blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB); - ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); + ret = CRYPT_AsnDecodeOctetsInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); } } } @@ -2427,18 +3030,18 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeBitsInternal(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; - TRACE("(%p, %d, 0x%08x, %p, %p, %d)\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); + TRACE("(%p, %d, 0x%08x, %p, %d, %p)\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); if (pbEncoded[0] == ASN_BITSTRING) { DWORD bytesNeeded, dataLen; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { @@ -2446,6 +3049,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, bytesNeeded = sizeof(CRYPT_BIT_BLOB); else bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB); + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -2460,12 +3065,10 @@ static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, blob = (CRYPT_BIT_BLOB *)pvStructInfo; blob->cbData = dataLen - 1; - blob->cUnusedBits = *(pbEncoded + 1 + - GET_LEN_BYTES(pbEncoded[1])); + blob->cUnusedBits = *(pbEncoded + 1 + lenBytes); if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) { - blob->pbData = (BYTE *)pbEncoded + 2 + - GET_LEN_BYTES(pbEncoded[1]); + blob->pbData = (BYTE *)pbEncoded + 2 + lenBytes; } else { @@ -2474,8 +3077,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, { BYTE mask = 0xff << blob->cUnusedBits; - memcpy(blob->pbData, pbEncoded + 2 + - GET_LEN_BYTES(pbEncoded[1]), blob->cbData); + memcpy(blob->pbData, pbEncoded + 2 + lenBytes, + blob->cbData); blob->pbData[blob->cbData - 1] &= mask; } } @@ -2504,9 +3107,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, { DWORD bytesNeeded; - if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + if ((ret = CRYPT_AsnDecodeBitsInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL))) { if (!pvStructInfo) *pcbStructInfo = bytesNeeded; @@ -2519,10 +3121,9 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, pvStructInfo = *(BYTE **)pvStructInfo; blob = (CRYPT_BIT_BLOB *)pvStructInfo; blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB); - ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); + ret = CRYPT_AsnDecodeBitsInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); } } } @@ -2536,59 +3137,83 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, return ret; } +/* Ignores tag. Only allows integers 4 bytes or smaller in size. */ +static BOOL CRYPT_AsnDecodeIntInternal(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) +{ + BOOL ret; + BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)]; + CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf; + DWORD size = sizeof(buf); + + blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB); + ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded, 0, &buf, + &size, pcbDecoded); + if (ret) + { + if (!pvStructInfo) + *pcbStructInfo = sizeof(int); + else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, sizeof(int)))) + { + int val, i; + + if (blob->pbData[blob->cbData - 1] & 0x80) + { + /* initialize to a negative value to sign-extend */ + val = -1; + } + else + val = 0; + for (i = 0; i < blob->cbData; i++) + { + val <<= 8; + val |= blob->pbData[blob->cbData - i - 1]; + } + memcpy(pvStructInfo, &val, sizeof(int)); + } + } + else if (GetLastError() == ERROR_MORE_DATA) + SetLastError(CRYPT_E_ASN1_LARGE); + return ret; +} + static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { BOOL ret; - if (!pvStructInfo) - { - *pcbStructInfo = sizeof(int); - return TRUE; - } __TRY { - BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)]; - CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf; - DWORD size = sizeof(buf); + DWORD bytesNeeded; - blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB); - if (pbEncoded[0] != ASN_INTEGER) + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else if (pbEncoded[0] != ASN_INTEGER) { SetLastError(CRYPT_E_ASN1_BADTAG); ret = FALSE; } else - ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, - X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, - &size); + ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL); if (ret) { - if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo, sizeof(int)))) + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) { - int val, i; - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) pvStructInfo = *(BYTE **)pvStructInfo; - if (blob->pbData[blob->cbData - 1] & 0x80) - { - /* initialize to a negative value to sign-extend */ - val = -1; - } - else - val = 0; - for (i = 0; i < blob->cbData; i++) - { - val <<= 8; - val |= blob->pbData[blob->cbData - i - 1]; - } - memcpy(pvStructInfo, &val, sizeof(int)); + ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); } } - else if (GetLastError() == ERROR_MORE_DATA) - SetLastError(CRYPT_E_ASN1_LARGE); } __EXCEPT_PAGE_FAULT { @@ -2599,9 +3224,9 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeIntegerInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; DWORD bytesNeeded, dataLen; @@ -2611,6 +3236,8 @@ static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType, BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB); + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -2656,9 +3283,8 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType, ret = FALSE; } else - ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded); + ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL); if (ret) { if (!pvStructInfo) @@ -2673,10 +3299,9 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType, blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB); - ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); + ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); } } } @@ -2689,10 +3314,9 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal( - DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, - void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeUnsignedIntegerInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; @@ -2704,6 +3328,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal( { BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB); if (!pvStructInfo) *pcbStructInfo = bytesNeeded; @@ -2756,9 +3382,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType, { DWORD bytesNeeded; - if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded))) + if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL))) { if (!pvStructInfo) *pcbStructInfo = bytesNeeded; @@ -2772,10 +3397,9 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType, blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB); - ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, - dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo, - &bytesNeeded); + ret = CRYPT_AsnDecodeUnsignedIntegerInternal(pbEncoded, + cbEncoded, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); } } } @@ -2882,251 +3506,254 @@ static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType, static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len, SYSTEMTIME *sysTime) { - BOOL ret; + BOOL ret = TRUE; - __TRY + if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-')) { - ret = TRUE; - if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-')) - { - WORD hours, minutes = 0; - BYTE sign = *pbEncoded++; + WORD hours, minutes = 0; + BYTE sign = *pbEncoded++; - len--; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours); - if (ret && hours >= 24) + len--; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours); + if (ret && hours >= 24) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else if (len >= 2) + { + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes); + if (ret && minutes >= 60) { SetLastError(CRYPT_E_ASN1_CORRUPT); ret = FALSE; } - else if (len >= 2) + } + if (ret) + { + if (sign == '+') { - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes); - if (ret && minutes >= 60) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } + sysTime->wHour += hours; + sysTime->wMinute += minutes; } - if (ret) + else { - if (sign == '+') + if (hours > sysTime->wHour) { - sysTime->wHour += hours; - sysTime->wMinute += minutes; + sysTime->wDay--; + sysTime->wHour = 24 - (hours - sysTime->wHour); } else + sysTime->wHour -= hours; + if (minutes > sysTime->wMinute) { - if (hours > sysTime->wHour) - { - sysTime->wDay--; - sysTime->wHour = 24 - (hours - sysTime->wHour); - } - else - sysTime->wHour -= hours; - if (minutes > sysTime->wMinute) - { - sysTime->wHour--; - sysTime->wMinute = 60 - (minutes - sysTime->wMinute); - } - else - sysTime->wMinute -= minutes; + sysTime->wHour--; + sysTime->wMinute = 60 - (minutes - sysTime->wMinute); } + else + sysTime->wMinute -= minutes; } } } - __EXCEPT_PAGE_FAULT - { - SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; - } - __ENDTRY return ret; } #define MIN_ENCODED_TIME_LENGTH 10 +static BOOL CRYPT_AsnDecodeUtcTimeInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = FALSE; + + if (pbEncoded[0] == ASN_UTCTIME) + { + if (cbEncoded <= 1) + SetLastError(CRYPT_E_ASN1_EOD); + else if (pbEncoded[1] > 0x7f) + { + /* long-form date strings really can't be valid */ + SetLastError(CRYPT_E_ASN1_CORRUPT); + } + else + { + SYSTEMTIME sysTime = { 0 }; + BYTE len = pbEncoded[1]; + + if (len < MIN_ENCODED_TIME_LENGTH) + SetLastError(CRYPT_E_ASN1_CORRUPT); + else + { + ret = TRUE; + if (pcbDecoded) + *pcbDecoded = 2 + len; + pbEncoded += 2; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear); + if (sysTime.wYear >= 50) + sysTime.wYear += 1900; + else + sysTime.wYear += 2000; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute); + if (ret && len > 0) + { + if (len >= 2 && isdigit(*pbEncoded) && + isdigit(*(pbEncoded + 1))) + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, + sysTime.wSecond); + else if (isdigit(*pbEncoded)) + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, + sysTime.wSecond); + if (ret) + ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, + &sysTime); + } + if (ret) + { + if (!pvStructInfo) + *pcbStructInfo = sizeof(FILETIME); + else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, + sizeof(FILETIME)))) + ret = SystemTimeToFileTime(&sysTime, + (FILETIME *)pvStructInfo); + } + } + } + } + else + SetLastError(CRYPT_E_ASN1_BADTAG); + return ret; +} + static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { - BOOL ret; + BOOL ret = FALSE; - if (!pvStructInfo) - { - *pcbStructInfo = sizeof(FILETIME); - return TRUE; - } __TRY { - ret = TRUE; - if (pbEncoded[0] == ASN_UTCTIME) - { - if (cbEncoded <= 1) - { - SetLastError(CRYPT_E_ASN1_EOD); - ret = FALSE; - } - else if (pbEncoded[1] > 0x7f) - { - /* long-form date strings really can't be valid */ - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - SYSTEMTIME sysTime = { 0 }; - BYTE len = pbEncoded[1]; + DWORD bytesNeeded; - if (len < MIN_ENCODED_TIME_LENGTH) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - pbEncoded += 2; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear); - if (sysTime.wYear >= 50) - sysTime.wYear += 1900; - else - sysTime.wYear += 2000; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute); - if (ret && len > 0) - { - if (len >= 2 && isdigit(*pbEncoded) && - isdigit(*(pbEncoded + 1))) - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, - sysTime.wSecond); - else if (isdigit(*pbEncoded)) - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, - sysTime.wSecond); - if (ret) - ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, - &sysTime); - } - if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, - sizeof(FILETIME)))) - { - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - ret = SystemTimeToFileTime(&sysTime, - (FILETIME *)pvStructInfo); - } - } - } - } - else + ret = CRYPT_AsnDecodeUtcTimeInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL); + if (ret) { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded))) + { + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + ret = CRYPT_AsnDecodeUtcTimeInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); + } } } __EXCEPT_PAGE_FAULT { SetLastError(STATUS_ACCESS_VIOLATION); - ret = FALSE; } __ENDTRY return ret; } -static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeGeneralizedTime(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { - BOOL ret; + BOOL ret = FALSE; - if (!pvStructInfo) + if (pbEncoded[0] == ASN_GENERALTIME) { - *pcbStructInfo = sizeof(FILETIME); - return TRUE; - } - __TRY - { - ret = TRUE; - if (pbEncoded[0] == ASN_GENERALTIME) + if (cbEncoded <= 1) + SetLastError(CRYPT_E_ASN1_EOD); + else if (pbEncoded[1] > 0x7f) { - if (cbEncoded <= 1) - { - SetLastError(CRYPT_E_ASN1_EOD); - ret = FALSE; - } - else if (pbEncoded[1] > 0x7f) - { - /* long-form date strings really can't be valid */ - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - BYTE len = pbEncoded[1]; - - if (len < MIN_ENCODED_TIME_LENGTH) - { - SetLastError(CRYPT_E_ASN1_CORRUPT); - ret = FALSE; - } - else - { - SYSTEMTIME sysTime = { 0 }; - - pbEncoded += 2; - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); - if (ret && len > 0) - { - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, - sysTime.wMinute); - if (ret && len > 0) - CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, - sysTime.wSecond); - if (ret && len > 0 && (*pbEncoded == '.' || - *pbEncoded == ',')) - { - BYTE digits; - - pbEncoded++; - len--; - /* workaround macro weirdness */ - digits = min(len, 3); - CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits, - sysTime.wMilliseconds); - } - if (ret) - ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, - &sysTime); - } - if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, - sizeof(FILETIME)))) - { - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - ret = SystemTimeToFileTime(&sysTime, - (FILETIME *)pvStructInfo); - } - } - } + /* long-form date strings really can't be valid */ + SetLastError(CRYPT_E_ASN1_CORRUPT); } else { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; + BYTE len = pbEncoded[1]; + + if (len < MIN_ENCODED_TIME_LENGTH) + SetLastError(CRYPT_E_ASN1_CORRUPT); + else + { + SYSTEMTIME sysTime = { 0 }; + + ret = TRUE; + if (pcbDecoded) + *pcbDecoded = 2 + len; + pbEncoded += 2; + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour); + if (ret && len > 0) + { + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, + sysTime.wMinute); + if (ret && len > 0) + CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, + sysTime.wSecond); + if (ret && len > 0 && (*pbEncoded == '.' || + *pbEncoded == ',')) + { + BYTE digits; + + pbEncoded++; + len--; + /* workaround macro weirdness */ + digits = min(len, 3); + CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits, + sysTime.wMilliseconds); + } + if (ret) + ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, + &sysTime); + } + if (ret) + { + if (!pvStructInfo) + *pcbStructInfo = sizeof(FILETIME); + else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, + sizeof(FILETIME)))) + ret = SystemTimeToFileTime(&sysTime, + (FILETIME *)pvStructInfo); + } + } } } - __EXCEPT_PAGE_FAULT + else + SetLastError(CRYPT_E_ASN1_BADTAG); + return ret; +} + +static BOOL CRYPT_AsnDecodeChoiceOfTimeInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + InternalDecodeFunc decode = NULL; + + if (pbEncoded[0] == ASN_UTCTIME) + decode = CRYPT_AsnDecodeUtcTimeInternal; + else if (pbEncoded[0] == ASN_GENERALTIME) + decode = CRYPT_AsnDecodeGeneralizedTime; + if (decode) + ret = decode(pbEncoded, cbEncoded, dwFlags, pvStructInfo, + pcbStructInfo, pcbDecoded); + else { - SetLastError(STATUS_ACCESS_VIOLATION); + SetLastError(CRYPT_E_ASN1_BADTAG); ret = FALSE; } - __ENDTRY return ret; } @@ -3138,18 +3765,23 @@ static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType, __TRY { - if (pbEncoded[0] == ASN_UTCTIME) - ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType, - pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, - pcbStructInfo); - else if (pbEncoded[0] == ASN_GENERALTIME) - ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType, - lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara, - pvStructInfo, pcbStructInfo); - else + DWORD bytesNeeded; + + ret = CRYPT_AsnDecodeChoiceOfTimeInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL); + if (ret) { - SetLastError(CRYPT_E_ASN1_BADTAG); - ret = FALSE; + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + ret = CRYPT_AsnDecodeChoiceOfTimeInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + &bytesNeeded, NULL); + } } } __EXCEPT_PAGE_FAULT @@ -3264,9 +3896,9 @@ static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeDistPointName(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeDistPointName(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { BOOL ret; @@ -3288,11 +3920,13 @@ static BOOL WINAPI CRYPT_AsnDecodeDistPointName(DWORD dwCertEncodingType, ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, - 0, NULL, NULL, &nameLen, NULL); + 0, NULL, NULL, &nameLen, NULL, NULL); bytesNeeded = sizeof(CRL_DIST_POINT_NAME) + nameLen; } else bytesNeeded = sizeof(CRL_DIST_POINT_NAME); + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -3310,7 +3944,7 @@ static BOOL WINAPI CRYPT_AsnDecodeDistPointName(DWORD dwCertEncodingType, name->dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, - 0, NULL, &name->u.FullName, pcbStructInfo, + 0, NULL, &name->u.FullName, pcbStructInfo, NULL, name->u.FullName.rgAltEntry); } else @@ -3326,9 +3960,8 @@ static BOOL WINAPI CRYPT_AsnDecodeDistPointName(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeDistPoint(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { struct AsnDecodeSequenceItem items[] = { { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT, @@ -3344,9 +3977,9 @@ static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType, }; BOOL ret; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, - dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, NULL); return ret; } @@ -3366,7 +3999,7 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType, offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) }; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -3392,7 +4025,7 @@ static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType, CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 }; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL); + pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -3434,9 +4067,9 @@ static BOOL WINAPI CRYPT_AsnDecodeIssuingDistPoint(DWORD dwCertEncodingType, fIndirectCRL), CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0 }, }; - ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, - sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, - dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -3447,129 +4080,404 @@ static BOOL WINAPI CRYPT_AsnDecodeIssuingDistPoint(DWORD dwCertEncodingType, return ret; } -BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, - const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, - PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +static BOOL CRYPT_AsnDecodeMaximum(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) { - static HCRYPTOIDFUNCSET set = NULL; BOOL ret = FALSE; - CryptDecodeObjectExFunc decodeFunc = NULL; - HCRYPTOIDFUNCADDR hFunc = NULL; - TRACE("(0x%08x, %s, %p, %d, 0x%08x, %p, %p, %p)\n", - dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded, - cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); - if (!pvStructInfo && !pcbStructInfo) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING - && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } if (!cbEncoded) { SetLastError(CRYPT_E_ASN1_EOD); return FALSE; } - if (cbEncoded > MAX_ENCODED_LEN) + if (pbEncoded[0] != (ASN_CONTEXT | 1)) { - SetLastError(CRYPT_E_ASN1_LARGE); + SetLastError(CRYPT_E_ASN1_BADTAG); return FALSE; } + /* The BOOL is implicit: if the integer is present, then it's TRUE */ + ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags, + pvStructInfo ? (BYTE *)pvStructInfo + sizeof(BOOL) : NULL, pcbStructInfo, + pcbDecoded); + if (ret && pvStructInfo) + *(BOOL *)pvStructInfo = TRUE; + TRACE("returning %d\n", ret); + return ret; +} - SetLastError(NOERROR); - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo) - *(BYTE **)pvStructInfo = NULL; +static BOOL CRYPT_AsnDecodeSubtree(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnDecodeSequenceItem items[] = { + { 0, offsetof(CERT_GENERAL_SUBTREE, Base), + CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, TRUE, + offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL), 0 }, + { ASN_CONTEXT | 0, offsetof(CERT_GENERAL_SUBTREE, dwMinimum), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), TRUE, FALSE, 0, 0 }, + { ASN_CONTEXT | 1, offsetof(CERT_GENERAL_SUBTREE, fMaximum), + CRYPT_AsnDecodeMaximum, sizeof(BOOL) + sizeof(DWORD), TRUE, FALSE, 0, + 0 }, + }; + CERT_GENERAL_SUBTREE *subtree = (CERT_GENERAL_SUBTREE *)pvStructInfo; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, subtree ? (BYTE *)subtree->Base.u.pwszURL : NULL); + if (pcbDecoded) + { + TRACE("%d\n", *pcbDecoded); + if (*pcbDecoded < cbEncoded) + TRACE("%02x %02x\n", *(pbEncoded + *pcbDecoded), + *(pbEncoded + *pcbDecoded + 1)); + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_AsnDecodeSubtreeArray(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { 0, + CRYPT_AsnDecodeSubtree, sizeof(CERT_GENERAL_SUBTREE), TRUE, + offsetof(CERT_GENERAL_SUBTREE, Base.u.pwszURL) }; + struct GenericArray *array = (struct GenericArray *)pvStructInfo; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, + array ? array->rgItems : NULL); + return ret; +} + + +static BOOL WINAPI CRYPT_AsnDecodeNameConstraints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, + offsetof(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree), + CRYPT_AsnDecodeSubtreeArray, sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CERT_NAME_CONSTRAINTS_INFO, rgPermittedSubtree), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 1, + offsetof(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree), + CRYPT_AsnDecodeSubtreeArray, sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CERT_NAME_CONSTRAINTS_INFO, rgExcludedSubtree), 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +static BOOL CRYPT_AsnDecodeIssuerSerialNumber(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnDecodeSequenceItem items[] = { + { 0, offsetof(CERT_ISSUER_SERIAL_NUMBER, Issuer), CRYPT_AsnDecodeDerBlob, + sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_ISSUER_SERIAL_NUMBER, + Issuer.pbData) }, + { ASN_INTEGER, offsetof(CERT_ISSUER_SERIAL_NUMBER, SerialNumber), + CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, + TRUE, offsetof(CERT_ISSUER_SERIAL_NUMBER, SerialNumber.pbData), 0 }, + }; + CERT_ISSUER_SERIAL_NUMBER *issuerSerial = + (CERT_ISSUER_SERIAL_NUMBER *)pvStructInfo; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, issuerSerial ? issuerSerial->Issuer.pbData : NULL); + if (ret && issuerSerial && !issuerSerial->SerialNumber.cbData) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_AsnDecodePKCSSignerInfoInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + CMSG_SIGNER_INFO *info = (CMSG_SIGNER_INFO *)pvStructInfo; + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(CMSG_SIGNER_INFO, dwVersion), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + { ASN_SEQUENCEOF, offsetof(CMSG_SIGNER_INFO, Issuer), + CRYPT_AsnDecodeIssuerSerialNumber, sizeof(CERT_ISSUER_SERIAL_NUMBER), + FALSE, TRUE, offsetof(CMSG_SIGNER_INFO, Issuer.pbData), 0 }, + { ASN_SEQUENCEOF, offsetof(CMSG_SIGNER_INFO, HashAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CMSG_SIGNER_INFO, HashAlgorithm.pszObjId), 0 }, + { ASN_CONSTRUCTOR | ASN_CONTEXT | 0, + offsetof(CMSG_SIGNER_INFO, AuthAttrs), + CRYPT_AsnDecodePKCSAttributesInternal, sizeof(CRYPT_ATTRIBUTES), + TRUE, TRUE, offsetof(CMSG_SIGNER_INFO, AuthAttrs.rgAttr), 0 }, + { ASN_SEQUENCEOF, offsetof(CMSG_SIGNER_INFO, HashEncryptionAlgorithm), + CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), + FALSE, TRUE, offsetof(CMSG_SIGNER_INFO, + HashEncryptionAlgorithm.pszObjId), 0 }, + { ASN_OCTETSTRING, offsetof(CMSG_SIGNER_INFO, EncryptedHash), + CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_DER_BLOB), + FALSE, TRUE, offsetof(CMSG_SIGNER_INFO, EncryptedHash.pbData), 0 }, + { ASN_CONSTRUCTOR | ASN_CONTEXT | 1, + offsetof(CMSG_SIGNER_INFO, UnauthAttrs), + CRYPT_AsnDecodePKCSAttributesInternal, sizeof(CRYPT_ATTRIBUTES), + TRUE, TRUE, offsetof(CMSG_SIGNER_INFO, UnauthAttrs.rgAttr), 0 }, + }; + BOOL ret; + + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, info ? info->Issuer.pbData : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePKCSSignerInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + ret = CRYPT_AsnDecodePKCSSignerInfoInternal(pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL); + if (ret && pvStructInfo) + { + ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, *pcbStructInfo); + if (ret) + { + CMSG_SIGNER_INFO *info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = (CMSG_SIGNER_INFO *)pvStructInfo; + info->Issuer.pbData = ((BYTE *)info + + sizeof(CMSG_SIGNER_INFO)); + ret = CRYPT_AsnDecodePKCSSignerInfoInternal(pbEncoded, + cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, + pcbStructInfo, NULL); + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_DecodeSignerArray(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, + CRYPT_AsnDecodePKCSSignerInfoInternal, sizeof(CMSG_SIGNER_INFO), TRUE, + offsetof(CMSG_SIGNER_INFO, Issuer.pbData) }; + struct GenericArray *array = (struct GenericArray *)pvStructInfo; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo, pcbDecoded); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, + NULL, pvStructInfo, pcbStructInfo, pcbDecoded, + array ? array->rgItems : NULL); + return ret; +} + +BOOL CRYPT_AsnDecodePKCSSignedInfo(const BYTE *pbEncoded, DWORD cbEncoded, + DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, + CRYPT_SIGNED_INFO *signedInfo, DWORD *pcbSignedInfo) +{ + BOOL ret = FALSE; + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(CRYPT_SIGNED_INFO, version), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + /* Placeholder for the hash algorithms - redundant with those in the + * signers, so just ignore them. + */ + { ASN_CONSTRUCTOR | ASN_SETOF, 0, NULL, 0, TRUE, FALSE, 0, 0 }, + { ASN_SEQUENCE, offsetof(CRYPT_SIGNED_INFO, content), + CRYPT_AsnDecodePKCSContentInfoInternal, sizeof(CRYPT_CONTENT_INFO), + FALSE, TRUE, offsetof(CRYPT_SIGNED_INFO, content.pszObjId), 0 }, + { ASN_CONSTRUCTOR | ASN_CONTEXT | 0, + offsetof(CRYPT_SIGNED_INFO, cCertEncoded), + CRYPT_DecodeDERArray, sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CRYPT_SIGNED_INFO, rgCertEncoded), 0 }, + { ASN_CONSTRUCTOR | ASN_CONTEXT | 1, + offsetof(CRYPT_SIGNED_INFO, cCrlEncoded), CRYPT_DecodeDERArray, + sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CRYPT_SIGNED_INFO, rgCrlEncoded), 0 }, + { ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CRYPT_SIGNED_INFO, cSignerInfo), + CRYPT_DecodeSignerArray, sizeof(struct GenericArray), TRUE, TRUE, + offsetof(CRYPT_SIGNED_INFO, rgSignerInfo), 0 }, + }; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, signedInfo, *pcbSignedInfo); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, signedInfo, pcbSignedInfo, + NULL, NULL); + TRACE("returning %d\n", ret); + return ret; +} + +static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, + LPCSTR lpszStructType) +{ + CryptDecodeObjectExFunc decodeFunc = NULL; + + if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING + && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } if (!HIWORD(lpszStructType)) { switch (LOWORD(lpszStructType)) { - case (WORD)X509_CERT: + case LOWORD(X509_CERT): decodeFunc = CRYPT_AsnDecodeCertSignedContent; break; - case (WORD)X509_CERT_TO_BE_SIGNED: + case LOWORD(X509_CERT_TO_BE_SIGNED): decodeFunc = CRYPT_AsnDecodeCert; break; - case (WORD)X509_CERT_CRL_TO_BE_SIGNED: + case LOWORD(X509_CERT_CRL_TO_BE_SIGNED): decodeFunc = CRYPT_AsnDecodeCRL; break; - case (WORD)X509_EXTENSIONS: + case LOWORD(X509_EXTENSIONS): decodeFunc = CRYPT_AsnDecodeExtensions; break; - case (WORD)X509_NAME_VALUE: + case LOWORD(X509_NAME_VALUE): decodeFunc = CRYPT_AsnDecodeNameValue; break; - case (WORD)X509_NAME: + case LOWORD(X509_NAME): decodeFunc = CRYPT_AsnDecodeName; break; - case (WORD)X509_PUBLIC_KEY_INFO: + case LOWORD(X509_PUBLIC_KEY_INFO): decodeFunc = CRYPT_AsnDecodePubKeyInfo; break; - case (WORD)X509_AUTHORITY_KEY_ID: + case LOWORD(X509_AUTHORITY_KEY_ID): decodeFunc = CRYPT_AsnDecodeAuthorityKeyId; break; - case (WORD)X509_ALTERNATE_NAME: + case LOWORD(X509_ALTERNATE_NAME): decodeFunc = CRYPT_AsnDecodeAltName; break; - case (WORD)X509_BASIC_CONSTRAINTS: + case LOWORD(X509_BASIC_CONSTRAINTS): decodeFunc = CRYPT_AsnDecodeBasicConstraints; break; - case (WORD)X509_BASIC_CONSTRAINTS2: + case LOWORD(X509_BASIC_CONSTRAINTS2): decodeFunc = CRYPT_AsnDecodeBasicConstraints2; break; - case (WORD)RSA_CSP_PUBLICKEYBLOB: + case LOWORD(RSA_CSP_PUBLICKEYBLOB): decodeFunc = CRYPT_AsnDecodeRsaPubKey; break; - case (WORD)X509_UNICODE_NAME: + case LOWORD(X509_UNICODE_NAME): decodeFunc = CRYPT_AsnDecodeUnicodeName; break; - case (WORD)X509_UNICODE_NAME_VALUE: + case LOWORD(PKCS_ATTRIBUTE): + decodeFunc = CRYPT_AsnDecodePKCSAttribute; + break; + case LOWORD(X509_UNICODE_NAME_VALUE): decodeFunc = CRYPT_AsnDecodeUnicodeNameValue; break; - case (WORD)X509_OCTET_STRING: + case LOWORD(X509_OCTET_STRING): decodeFunc = CRYPT_AsnDecodeOctets; break; - case (WORD)X509_BITS: - case (WORD)X509_KEY_USAGE: + case LOWORD(X509_BITS): + case LOWORD(X509_KEY_USAGE): decodeFunc = CRYPT_AsnDecodeBits; break; - case (WORD)X509_INTEGER: + case LOWORD(X509_INTEGER): decodeFunc = CRYPT_AsnDecodeInt; break; - case (WORD)X509_MULTI_BYTE_INTEGER: + case LOWORD(X509_MULTI_BYTE_INTEGER): decodeFunc = CRYPT_AsnDecodeInteger; break; - case (WORD)X509_MULTI_BYTE_UINT: + case LOWORD(X509_MULTI_BYTE_UINT): decodeFunc = CRYPT_AsnDecodeUnsignedInteger; break; - case (WORD)X509_ENUMERATED: + case LOWORD(X509_ENUMERATED): decodeFunc = CRYPT_AsnDecodeEnumerated; break; - case (WORD)X509_CHOICE_OF_TIME: + case LOWORD(X509_CHOICE_OF_TIME): decodeFunc = CRYPT_AsnDecodeChoiceOfTime; break; - case (WORD)X509_SEQUENCE_OF_ANY: + case LOWORD(X509_AUTHORITY_KEY_ID2): + decodeFunc = CRYPT_AsnDecodeAuthorityKeyId2; + break; + case LOWORD(PKCS_CONTENT_INFO): + decodeFunc = CRYPT_AsnDecodePKCSContentInfo; + break; + case LOWORD(X509_SEQUENCE_OF_ANY): decodeFunc = CRYPT_AsnDecodeSequenceOfAny; break; - case (WORD)PKCS_UTC_TIME: + case LOWORD(PKCS_UTC_TIME): decodeFunc = CRYPT_AsnDecodeUtcTime; break; - case (WORD)X509_CRL_DIST_POINTS: + case LOWORD(X509_CRL_DIST_POINTS): decodeFunc = CRYPT_AsnDecodeCRLDistPoints; break; - case (WORD)X509_ENHANCED_KEY_USAGE: + case LOWORD(X509_ENHANCED_KEY_USAGE): decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; break; - case (WORD)X509_ISSUING_DIST_POINT: + case LOWORD(PKCS_ATTRIBUTES): + decodeFunc = CRYPT_AsnDecodePKCSAttributes; + break; + case LOWORD(X509_ISSUING_DIST_POINT): decodeFunc = CRYPT_AsnDecodeIssuingDistPoint; break; - default: - FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); + case LOWORD(X509_NAME_CONSTRAINTS): + decodeFunc = CRYPT_AsnDecodeNameConstraints; + break; + case LOWORD(PKCS7_SIGNER_INFO): + decodeFunc = CRYPT_AsnDecodePKCSSignerInfo; + break; } } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) @@ -3578,6 +4486,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, decodeFunc = CRYPT_AsnDecodeUtcTime; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER)) decodeFunc = CRYPT_AsnDecodeAuthorityKeyId; + else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) + decodeFunc = CRYPT_AsnDecodeAuthorityKeyId2; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) decodeFunc = CRYPT_AsnDecodeEnumerated; else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) @@ -3604,22 +4514,159 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT)) decodeFunc = CRYPT_AsnDecodeIssuingDistPoint; - else - TRACE("OID %s not found or unimplemented, looking for DLL\n", + else if (!strcmp(lpszStructType, szOID_NAME_CONSTRAINTS)) + decodeFunc = CRYPT_AsnDecodeNameConstraints; + return decodeFunc; +} + +static CryptDecodeObjectFunc CRYPT_LoadDecoderFunc(DWORD dwCertEncodingType, + LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc) +{ + static HCRYPTOIDFUNCSET set = NULL; + CryptDecodeObjectFunc decodeFunc = NULL; + + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, + (void **)&decodeFunc, hFunc); + return decodeFunc; +} + +static CryptDecodeObjectExFunc CRYPT_LoadDecoderExFunc(DWORD dwCertEncodingType, + LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc) +{ + static HCRYPTOIDFUNCSET set = NULL; + CryptDecodeObjectExFunc decodeFunc = NULL; + + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, + (void **)&decodeFunc, hFunc); + return decodeFunc; +} + +BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType, + const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, + DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + CryptDecodeObjectFunc pCryptDecodeObject = NULL; + CryptDecodeObjectExFunc pCryptDecodeObjectEx = NULL; + HCRYPTOIDFUNCADDR hFunc = NULL; + + TRACE_(crypt)("(0x%08x, %s, %p, %d, 0x%08x, %p, %p)\n", dwCertEncodingType, + debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pcbStructInfo); + + if (!pvStructInfo && !pcbStructInfo) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + return FALSE; + } + if (cbEncoded > MAX_ENCODED_LEN) + { + SetLastError(CRYPT_E_ASN1_LARGE); + return FALSE; + } + + if (!(pCryptDecodeObjectEx = CRYPT_GetBuiltinDecoder(dwCertEncodingType, + lpszStructType))) + { + TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n", debugstr_a(lpszStructType)); + pCryptDecodeObject = CRYPT_LoadDecoderFunc(dwCertEncodingType, + lpszStructType, &hFunc); + if (!pCryptDecodeObject) + pCryptDecodeObjectEx = CRYPT_LoadDecoderExFunc(dwCertEncodingType, + lpszStructType, &hFunc); + } + if (pCryptDecodeObject) + ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType, + pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo); + else if (pCryptDecodeObjectEx) + ret = pCryptDecodeObjectEx(dwCertEncodingType, lpszStructType, + pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, + pvStructInfo, pcbStructInfo); + if (hFunc) + CryptFreeOIDFunctionAddress(hFunc, 0); + TRACE_(crypt)("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, + const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + CryptDecodeObjectExFunc decodeFunc; + HCRYPTOIDFUNCADDR hFunc = NULL; + + TRACE_(crypt)("(0x%08x, %s, %p, %d, 0x%08x, %p, %p, %p)\n", + dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded, + cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); + + if (!pvStructInfo && !pcbStructInfo) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + return FALSE; + } + if (cbEncoded > MAX_ENCODED_LEN) + { + SetLastError(CRYPT_E_ASN1_LARGE); + return FALSE; + } + + SetLastError(NOERROR); + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo) + *(BYTE **)pvStructInfo = NULL; + decodeFunc = CRYPT_GetBuiltinDecoder(dwCertEncodingType, lpszStructType); if (!decodeFunc) { - if (!set) - set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0); - CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, - (void **)&decodeFunc, &hFunc); + TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n", + debugstr_a(lpszStructType)); + decodeFunc = CRYPT_LoadDecoderExFunc(dwCertEncodingType, lpszStructType, + &hFunc); } if (decodeFunc) ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo); else - SetLastError(ERROR_FILE_NOT_FOUND); + { + CryptDecodeObjectFunc pCryptDecodeObject = + CRYPT_LoadDecoderFunc(dwCertEncodingType, lpszStructType, &hFunc); + + /* Try CryptDecodeObject function. Don't call CryptDecodeObject + * directly, as that could cause an infinite loop. + */ + if (pCryptDecodeObject) + { + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + { + ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType, + pbEncoded, cbEncoded, dwFlags, NULL, pcbStructInfo); + if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, *pcbStructInfo))) + ret = pCryptDecodeObject(dwCertEncodingType, + lpszStructType, pbEncoded, cbEncoded, dwFlags, + *(BYTE **)pvStructInfo, pcbStructInfo); + } + else + ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType, + pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo); + } + } if (hFunc) CryptFreeOIDFunctionAddress(hFunc, 0); + TRACE_(crypt)("returning %d\n", ret); return ret; } diff --git a/reactos/dll/win32/crypt32/encode.c b/reactos/dll/win32/crypt32/encode.c index cb80416cff8..9071e5c4918 100644 --- a/reactos/dll/win32/crypt32/encode.c +++ b/reactos/dll/win32/crypt32/encode.c @@ -1,5 +1,5 @@ /* - * Copyright 2005 Juan Lang + * Copyright 2005-2007 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,8 +17,8 @@ * * This file implements ASN.1 DER encoding of a limited set of types. * It isn't a full ASN.1 implementation. Microsoft implements BER - * encoding of many of the basic types in msasn1.dll, but that interface is - * undocumented, so I implement them here. + * encoding of many of the basic types in msasn1.dll, but that interface isn't + * implemented, so I implement them here. * * References: * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski @@ -27,10 +27,12 @@ * * RFC3280, http://www.faqs.org/rfcs/rfc3280.html * - * MSDN, especially: - * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp + * MSDN, especially "Constants for CryptEncodeObject and CryptDecodeObject" */ +#include "config.h" +#include "wine/port.h" + #include #include #include @@ -40,28 +42,25 @@ #include "windef.h" #include "winbase.h" -#include "excpt.h" #include "wincrypt.h" -#include "winreg.h" #include "snmp.h" #include "wine/debug.h" #include "wine/exception.h" #include "wine/unicode.h" #include "crypt32_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(crypt); +WINE_DEFAULT_DEBUG_CHANNEL(cryptasn); +WINE_DECLARE_DEBUG_CHANNEL(crypt); typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *, BYTE *, DWORD *); -typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *, - DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *); /* Prototypes for built-in encoders. They follow the Ex style prototypes. * The dwCertEncodingType and lpszStructType are ignored by the built-in * functions, but the parameters are retained to simplify CryptEncodeObjectEx, * since it must call functions in external DLLs that follow these signatures. */ -static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, +BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType, @@ -76,9 +75,6 @@ static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); -static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType, - LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, - PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); @@ -98,52 +94,8 @@ static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); -BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType, - const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded) -{ - static HCRYPTOIDFUNCSET set = NULL; - BOOL ret = FALSE; - HCRYPTOIDFUNCADDR hFunc; - CryptEncodeObjectFunc pCryptEncodeObject; - - TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, - debugstr_a(lpszStructType), pvStructInfo, pbEncoded, - pcbEncoded); - - if (!pbEncoded && !pcbEncoded) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* Try registered DLL first.. */ - if (!set) - set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0); - CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, - (void **)&pCryptEncodeObject, &hFunc); - if (pCryptEncodeObject) - { - ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType, - pvStructInfo, pbEncoded, pcbEncoded); - CryptFreeOIDFunctionAddress(hFunc, 0); - } - else - { - /* If not, use CryptEncodeObjectEx */ - ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType, - pvStructInfo, 0, NULL, pbEncoded, pcbEncoded); - } - return ret; -} - -/* Helper function to check *pcbEncoded, set it to the required size, and - * optionally to allocate memory. Assumes pbEncoded is not NULL. - * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a - * pointer to the newly allocated memory. - */ -static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, - PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded, - DWORD bytesNeeded) +BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, + BYTE *pbEncoded, DWORD *pcbEncoded, DWORD bytesNeeded) { BOOL ret = TRUE; @@ -169,7 +121,7 @@ static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, return ret; } -static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded) +BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded) { DWORD bytesNeeded, significantBytes = 0; @@ -211,14 +163,7 @@ static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded) return TRUE; } -struct AsnEncodeSequenceItem -{ - const void *pvStructInfo; - CryptEncodeObjectExFunc encodeFunc; - DWORD size; /* used during encoding, not for your use */ -}; - -static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType, +BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType, struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { @@ -272,14 +217,7 @@ static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType, return ret; } -struct AsnConstructedItem -{ - BYTE tag; - const void *pvStructInfo; - CryptEncodeObjectExFunc encodeFunc; -}; - -static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType, +BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { @@ -412,16 +350,44 @@ static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType, { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 }, }; + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded, + pcbEncoded); + return ret; +} + +/* Like CRYPT_AsnEncodeAlgorithmId, but encodes parameters as an asn.1 NULL + * if they are empty. + */ +static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams( + DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, + DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + const CRYPT_ALGORITHM_IDENTIFIER *algo = + (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo; + static const BYTE asn1Null[] = { ASN_NULL, 0 }; + static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null), + (LPBYTE)asn1Null }; + BOOL ret; + struct AsnEncodeSequenceItem items[2] = { + { algo->pszObjId, CRYPT_AsnEncodeOid, 0 }, + { NULL, CRYPT_CopyEncodedBlob, 0 }, + }; + + if (algo->Parameters.cbData) + items[1].pvStructInfo = &algo->Parameters; + else + items[1].pvStructInfo = &nullBlob; ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded, pcbEncoded); return ret; } -static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId( - DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, - DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, - DWORD *pcbEncoded) +static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { const CRYPT_ALGORITHM_IDENTIFIER *algo = (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo; @@ -485,7 +451,7 @@ static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType, if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG) items[2].encodeFunc = CRYPT_AsnEncodeBits; - ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded, pcbEncoded); } @@ -800,7 +766,7 @@ static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, +BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { @@ -950,8 +916,12 @@ static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value, LPCWSTR str = (LPCWSTR)value->Value.pbData; DWORD bytesNeeded, lenBytes, strLen; - strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) : - lstrlenW(str); + if (value->Value.cbData) + strLen = value->Value.cbData / sizeof(WCHAR); + else if (value->Value.pbData) + strLen = lstrlenW(str); + else + strLen = 0; CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes); bytesNeeded = 1 + lenBytes + strLen * 2; if (!pbEncoded) @@ -1167,92 +1137,175 @@ static int BLOBComp(const void *l, const void *r) return ret; } -/* This encodes as a SET OF, which in DER must be lexicographically sorted. +/* This encodes a SET OF, which in DER must be lexicographically sorted. */ +static BOOL WINAPI CRYPT_DEREncodeSet(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + const CRYPT_BLOB_ARRAY *set = (const CRYPT_BLOB_ARRAY *)pvStructInfo; + DWORD bytesNeeded = 0, lenBytes, i; + BOOL ret; + + for (i = 0; i < set->cBlob; i++) + bytesNeeded += set->rgBlob[i].cbData; + CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes); + bytesNeeded += 1 + lenBytes; + if (!pbEncoded) + { + *pcbEncoded = bytesNeeded; + ret = TRUE; + } + else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + qsort(set->rgBlob, set->cBlob, sizeof(CRYPT_DER_BLOB), BLOBComp); + *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + for (i = 0; ret && i < set->cBlob; i++) + { + memcpy(pbEncoded, set->rgBlob[i].pbData, set->rgBlob[i].cbData); + pbEncoded += set->rgBlob[i].cbData; + } + } + return ret; +} + +struct DERSetDescriptor +{ + DWORD cItems; + const void *items; + size_t itemSize; + size_t itemOffset; + CryptEncodeObjectExFunc encode; +}; + +static BOOL WINAPI CRYPT_DEREncodeItemsAsSet(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + const struct DERSetDescriptor *desc = + (const struct DERSetDescriptor *)pvStructInfo; + CRYPT_BLOB_ARRAY setOf = { 0, NULL }; + BOOL ret = TRUE; + DWORD i; + + if (desc->cItems) + { + setOf.rgBlob = CryptMemAlloc(desc->cItems * sizeof(CRYPT_DER_BLOB)); + if (!setOf.rgBlob) + ret = FALSE; + else + { + setOf.cBlob = desc->cItems; + memset(setOf.rgBlob, 0, setOf.cBlob * sizeof(CRYPT_DER_BLOB)); + } + } + for (i = 0; ret && i < setOf.cBlob; i++) + { + ret = desc->encode(dwCertEncodingType, lpszStructType, + (const BYTE *)desc->items + i * desc->itemSize + desc->itemOffset, + 0, NULL, NULL, &setOf.rgBlob[i].cbData); + if (ret) + { + setOf.rgBlob[i].pbData = CryptMemAlloc(setOf.rgBlob[i].cbData); + if (!setOf.rgBlob[i].pbData) + ret = FALSE; + else + ret = desc->encode(dwCertEncodingType, lpszStructType, + (const BYTE *)desc->items + i * desc->itemSize + + desc->itemOffset, 0, NULL, setOf.rgBlob[i].pbData, + &setOf.rgBlob[i].cbData); + } + /* Some functions propagate their errors through the size */ + if (!ret) + *pcbEncoded = setOf.rgBlob[i].cbData; + } + if (ret) + { + DWORD bytesNeeded = 0, lenBytes; + + for (i = 0; i < setOf.cBlob; i++) + bytesNeeded += setOf.rgBlob[i].cbData; + CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes); + bytesNeeded += 1 + lenBytes; + if (!pbEncoded) + *pcbEncoded = bytesNeeded; + else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + qsort(setOf.rgBlob, setOf.cBlob, sizeof(CRYPT_DER_BLOB), + BLOBComp); + *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + for (i = 0; i < setOf.cBlob; i++) + { + memcpy(pbEncoded, setOf.rgBlob[i].pbData, + setOf.rgBlob[i].cbData); + pbEncoded += setOf.rgBlob[i].cbData; + } + } + } + for (i = 0; i < setOf.cBlob; i++) + CryptMemFree(setOf.rgBlob[i].pbData); + CryptMemFree(setOf.rgBlob); + return ret; +} + static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn, CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded, DWORD *pcbEncoded) { BOOL ret; - CRYPT_DER_BLOB *blobs = NULL; + CRYPT_BLOB_ARRAY setOf = { 0, NULL }; __TRY { - DWORD bytesNeeded = 0, lenBytes, i; + DWORD i; - blobs = NULL; ret = TRUE; if (rdn->cRDNAttr) { - blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB)); - if (!blobs) + setOf.cBlob = rdn->cRDNAttr; + setOf.rgBlob = CryptMemAlloc(rdn->cRDNAttr * + sizeof(CRYPT_DER_BLOB)); + if (!setOf.rgBlob) ret = FALSE; else - memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB)); + memset(setOf.rgBlob, 0, setOf.cBlob * sizeof(CRYPT_DER_BLOB)); } for (i = 0; ret && i < rdn->cRDNAttr; i++) { + setOf.rgBlob[i].cbData = 0; ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i], - nameValueEncodeFunc, NULL, &blobs[i].cbData); + nameValueEncodeFunc, NULL, &setOf.rgBlob[i].cbData); if (ret) - bytesNeeded += blobs[i].cbData; - else + { + setOf.rgBlob[i].pbData = CryptMemAlloc(setOf.rgBlob[i].cbData); + if (!setOf.rgBlob[i].pbData) + ret = FALSE; + else + ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, + &rdn->rgRDNAttr[i], nameValueEncodeFunc, + setOf.rgBlob[i].pbData, &setOf.rgBlob[i].cbData); + } + if (!ret) { /* Have to propagate index of failing character */ - *pcbEncoded = blobs[i].cbData; + *pcbEncoded = setOf.rgBlob[i].cbData; } } if (ret) - { - CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes); - bytesNeeded += 1 + lenBytes; - if (pbEncoded) - { - if (*pcbEncoded < bytesNeeded) - { - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } - else - { - for (i = 0; ret && i < rdn->cRDNAttr; i++) - { - blobs[i].pbData = CryptMemAlloc(blobs[i].cbData); - if (!blobs[i].pbData) - ret = FALSE; - else - { - ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, - &rdn->rgRDNAttr[i], nameValueEncodeFunc, - blobs[i].pbData, &blobs[i].cbData); - if (!ret) - *pcbEncoded = blobs[i].cbData; - } - } - if (ret) - { - qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB), - BLOBComp); - *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF; - CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, - &lenBytes); - pbEncoded += lenBytes; - for (i = 0; ret && i < rdn->cRDNAttr; i++) - { - memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData); - pbEncoded += blobs[i].cbData; - } - } - } - } - if (ret) - *pcbEncoded = bytesNeeded; - } - if (blobs) - { - for (i = 0; i < rdn->cRDNAttr; i++) - CryptMemFree(blobs[i].pbData); - } + ret = CRYPT_DEREncodeSet(X509_ASN_ENCODING, NULL, &setOf, 0, NULL, + pbEncoded, pcbEncoded); + for (i = 0; i < setOf.cBlob; i++) + CryptMemFree(setOf.rgBlob[i].pbData); } __EXCEPT_PAGE_FAULT { @@ -1260,7 +1313,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn, ret = FALSE; } __ENDTRY - CryptMemFree(blobs); + CryptMemFree(setOf.rgBlob); return ret; } @@ -1351,6 +1404,130 @@ static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodePKCSAttribute(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + __TRY + { + const CRYPT_ATTRIBUTE *attr = (const CRYPT_ATTRIBUTE *)pvStructInfo; + + if (!attr->pszObjId) + SetLastError(E_INVALIDARG); + else + { + struct AsnEncodeSequenceItem items[2] = { + { attr->pszObjId, CRYPT_AsnEncodeOid, 0 }, + { &attr->cValue, CRYPT_DEREncodeSet, 0 }, + }; + + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded, + pcbEncoded); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodePKCSAttributes(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + __TRY + { + const CRYPT_ATTRIBUTES *attributes = + (const CRYPT_ATTRIBUTES *)pvStructInfo; + struct DERSetDescriptor desc = { attributes->cAttr, attributes->rgAttr, + sizeof(CRYPT_ATTRIBUTE), 0, CRYPT_AsnEncodePKCSAttribute }; + + ret = CRYPT_DEREncodeItemsAsSet(X509_ASN_ENCODING, lpszStructType, + &desc, dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +/* Like CRYPT_AsnEncodePKCSContentInfo, but allows the OID to be NULL */ +static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfoInternal( + DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, + DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + const CRYPT_CONTENT_INFO *info = (const CRYPT_CONTENT_INFO *)pvStructInfo; + struct AsnEncodeSequenceItem items[2] = { + { info->pszObjId, CRYPT_AsnEncodeOid, 0 }, + { NULL, NULL, 0 }, + }; + struct AsnConstructedItem constructed = { 0 }; + DWORD cItem = 1; + + if (info->Content.cbData) + { + constructed.tag = 0; + constructed.pvStructInfo = &info->Content; + constructed.encodeFunc = CRYPT_CopyEncodedBlob; + items[cItem].pvStructInfo = &constructed; + items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; + cItem++; + } + return CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded); +} + +BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData, + void *pvData, DWORD *pcbData) +{ + struct AsnEncodeSequenceItem items[] = { + { &digestedData->version, CRYPT_AsnEncodeInt, 0 }, + { &digestedData->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, + 0 }, + { &digestedData->ContentInfo, CRYPT_AsnEncodePKCSContentInfoInternal, 0 }, + { &digestedData->hash, CRYPT_AsnEncodeOctets, 0 }, + }; + + return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, + sizeof(items) / sizeof(items[0]), 0, NULL, pvData, pcbData); +} + +static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + __TRY + { + const CRYPT_CONTENT_INFO *info = + (const CRYPT_CONTENT_INFO *)pvStructInfo; + + if (!info->pszObjId) + SetLastError(E_INVALIDARG); + else + ret = CRYPT_AsnEncodePKCSContentInfoInternal(dwCertEncodingType, + lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded, + pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value, BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -1404,16 +1581,19 @@ static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value, pbEncoded, pcbEncoded, bytesNeeded))) { DWORD i; + BYTE *ptr; if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) - pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_NUMERICSTRING; - CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + ptr = *(BYTE **)pbEncoded; + else + ptr = pbEncoded; + *ptr++ = ASN_NUMERICSTRING; + CRYPT_EncodeLen(encodedLen, ptr, &lenBytes); + ptr += lenBytes; for (i = 0; ret && i < encodedLen; i++) { if (isdigitW(str[i])) - *pbEncoded++ = (BYTE)str[i]; + *ptr++ = (BYTE)str[i]; else { *pcbEncoded = i; @@ -1421,6 +1601,8 @@ static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value, ret = FALSE; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CryptMemFree(*(BYTE **)pbEncoded); } } return ret; @@ -1453,16 +1635,19 @@ static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value, pbEncoded, pcbEncoded, bytesNeeded))) { DWORD i; + BYTE *ptr; if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) - pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_PRINTABLESTRING; - CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + ptr = *(BYTE **)pbEncoded; + else + ptr = pbEncoded; + *ptr++ = ASN_PRINTABLESTRING; + CRYPT_EncodeLen(encodedLen, ptr, &lenBytes); + ptr += lenBytes; for (i = 0; ret && i < encodedLen; i++) { if (isprintableW(str[i])) - *pbEncoded++ = (BYTE)str[i]; + *ptr++ = (BYTE)str[i]; else { *pcbEncoded = i; @@ -1470,6 +1655,8 @@ static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value, ret = FALSE; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CryptMemFree(*(BYTE **)pbEncoded); } } return ret; @@ -1495,16 +1682,19 @@ static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value, pbEncoded, pcbEncoded, bytesNeeded))) { DWORD i; + BYTE *ptr; if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) - pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_IA5STRING; - CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; + ptr = *(BYTE **)pbEncoded; + else + ptr = pbEncoded; + *ptr++ = ASN_IA5STRING; + CRYPT_EncodeLen(encodedLen, ptr, &lenBytes); + ptr += lenBytes; for (i = 0; ret && i < encodedLen; i++) { if (str[i] <= 0x7f) - *pbEncoded++ = (BYTE)str[i]; + *ptr++ = (BYTE)str[i]; else { *pcbEncoded = i; @@ -1512,6 +1702,8 @@ static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value, ret = FALSE; } } + if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)) + CryptMemFree(*(BYTE **)pbEncoded); } } return ret; @@ -1722,11 +1914,15 @@ static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType, return ret; } -static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry, - BYTE *pbEncoded, DWORD *pcbEncoded) +static BOOL WINAPI CRYPT_AsnEncodeAltNameEntry(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { + const CERT_ALT_NAME_ENTRY *entry = + (const CERT_ALT_NAME_ENTRY *)pvStructInfo; BOOL ret; DWORD dataLen; + BYTE tag; ret = TRUE; switch (entry->dwAltNameChoice) @@ -1734,6 +1930,7 @@ static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry, case CERT_ALT_NAME_RFC822_NAME: case CERT_ALT_NAME_DNS_NAME: case CERT_ALT_NAME_URL: + tag = ASN_CONTEXT | (entry->dwAltNameChoice - 1); if (entry->u.pwszURL) { DWORD i; @@ -1753,13 +1950,24 @@ static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry, else dataLen = 0; break; + case CERT_ALT_NAME_DIRECTORY_NAME: + tag = ASN_CONTEXT | ASN_CONSTRUCTOR | (entry->dwAltNameChoice - 1); + dataLen = entry->u.DirectoryName.cbData; + break; case CERT_ALT_NAME_IP_ADDRESS: + tag = ASN_CONTEXT | (entry->dwAltNameChoice - 1); dataLen = entry->u.IPAddress.cbData; break; case CERT_ALT_NAME_REGISTERED_ID: - /* FIXME: encode OID */ + { + struct AsnEncodeTagSwappedItem swapped = + { ASN_CONTEXT | (entry->dwAltNameChoice - 1), entry->u.pszRegisteredID, + CRYPT_AsnEncodeOid }; + + return CRYPT_AsnEncodeSwapTag(0, NULL, &swapped, 0, NULL, pbEncoded, + pcbEncoded); + } case CERT_ALT_NAME_OTHER_NAME: - case CERT_ALT_NAME_DIRECTORY_NAME: FIXME("name type %d unimplemented\n", entry->dwAltNameChoice); return FALSE; default: @@ -1782,7 +1990,7 @@ static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry, } else { - *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1); + *pbEncoded++ = tag; CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); pbEncoded += lenBytes; switch (entry->dwAltNameChoice) @@ -1797,6 +2005,9 @@ static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry, *pbEncoded++ = (BYTE)entry->u.pwszURL[i]; break; } + case CERT_ALT_NAME_DIRECTORY_NAME: + memcpy(pbEncoded, entry->u.DirectoryName.pbData, dataLen); + break; case CERT_ALT_NAME_IP_ADDRESS: memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen); break; @@ -1809,6 +2020,45 @@ static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry, return ret; } +static BOOL WINAPI CRYPT_AsnEncodeIntegerSwapBytes(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo; + CRYPT_DATA_BLOB newBlob = { blob->cbData, NULL }; + + ret = TRUE; + if (newBlob.cbData) + { + newBlob.pbData = CryptMemAlloc(newBlob.cbData); + if (newBlob.pbData) + { + DWORD i; + + for (i = 0; i < newBlob.cbData; i++) + newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i]; + } + else + ret = FALSE; + } + if (ret) + ret = CRYPT_AsnEncodeInteger(dwCertEncodingType, lpszStructType, + &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded); + CryptMemFree(newBlob.pbData); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -1828,7 +2078,7 @@ static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType, { swapped[cSwapped].tag = ASN_CONTEXT | 0; swapped[cSwapped].pvStructInfo = &info->KeyId; - swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes; items[cItem].pvStructInfo = &swapped[cSwapped]; items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; cSwapped++; @@ -1885,8 +2135,8 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType, { DWORD len; - ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL, - &len); + ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType, NULL, + &info->rgAltEntry[i], 0, NULL, NULL, &len); if (ret) dataLen += len; else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING) @@ -1922,8 +2172,8 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType, { DWORD len = dataLen; - ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], - pbEncoded, &len); + ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType, + NULL, &info->rgAltEntry[i], 0, NULL, pbEncoded, &len); if (ret) { pbEncoded += len; @@ -1943,6 +2193,62 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const CERT_AUTHORITY_KEY_ID2_INFO *info = + (const CERT_AUTHORITY_KEY_ID2_INFO *)pvStructInfo; + struct AsnEncodeSequenceItem items[3] = { { 0 } }; + struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } }; + DWORD cItem = 0, cSwapped = 0; + + if (info->KeyId.cbData) + { + swapped[cSwapped].tag = ASN_CONTEXT | 0; + swapped[cSwapped].pvStructInfo = &info->KeyId; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (info->AuthorityCertIssuer.cAltEntry) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1; + swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (info->AuthorityCertSerialNumber.cbData) + { + swapped[cSwapped].tag = ASN_CONTEXT | 2; + swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags, + pEncodePara, pbEncoded, pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -2042,7 +2348,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType, ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER)); CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8, (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) }; - struct AsnEncodeSequenceItem items[] = { + struct AsnEncodeSequenceItem items[] = { { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 }, { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 }, }; @@ -2061,7 +2367,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType, +BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { @@ -2216,7 +2522,7 @@ static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType, return ret; } -static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType, +BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { @@ -2886,119 +3192,414 @@ static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType, return ret; } -BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, - const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, - void *pvEncoded, DWORD *pcbEncoded) +static BOOL WINAPI CRYPT_AsnEncodeGeneralSubtree(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { - static HCRYPTOIDFUNCSET set = NULL; - BOOL ret = FALSE; - CryptEncodeObjectExFunc encodeFunc = NULL; - HCRYPTOIDFUNCADDR hFunc = NULL; + BOOL ret; + const CERT_GENERAL_SUBTREE *subtree = + (const CERT_GENERAL_SUBTREE *)pvStructInfo; + struct AsnEncodeSequenceItem items[3] = { + { &subtree->Base, CRYPT_AsnEncodeAltNameEntry, 0 }, + { 0 } + }; + struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } }; + DWORD cItem = 1, cSwapped = 0; - TRACE("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType, - debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara, - pvEncoded, pcbEncoded); - - if (!pvEncoded && !pcbEncoded) + if (subtree->dwMinimum) { - SetLastError(ERROR_INVALID_PARAMETER); + swapped[cSwapped].tag = ASN_CONTEXT | 0; + swapped[cSwapped].pvStructInfo = &subtree->dwMinimum; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (subtree->fMaximum) + { + swapped[cSwapped].tag = ASN_CONTEXT | 1; + swapped[cSwapped].pvStructInfo = &subtree->dwMaximum; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, dwFlags, + pEncodePara, pbEncoded, pcbEncoded); + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodeNameConstraints(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + CRYPT_BLOB_ARRAY permitted = { 0, NULL }, excluded = { 0, NULL }; + + TRACE("%p\n", pvStructInfo); + + __TRY + { + const CERT_NAME_CONSTRAINTS_INFO *constraints = + (const CERT_NAME_CONSTRAINTS_INFO *)pvStructInfo; + struct AsnEncodeSequenceItem items[2] = { { 0 } }; + struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } }; + DWORD i, cItem = 0, cSwapped = 0; + + ret = TRUE; + if (constraints->cPermittedSubtree) + { + permitted.rgBlob = CryptMemAlloc( + constraints->cPermittedSubtree * sizeof(CRYPT_DER_BLOB)); + if (permitted.rgBlob) + { + permitted.cBlob = constraints->cPermittedSubtree; + memset(permitted.rgBlob, 0, + permitted.cBlob * sizeof(CRYPT_DER_BLOB)); + for (i = 0; ret && i < permitted.cBlob; i++) + ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType, + NULL, &constraints->rgPermittedSubtree[i], + CRYPT_ENCODE_ALLOC_FLAG, NULL, + (BYTE *)&permitted.rgBlob[i].pbData, + &permitted.rgBlob[i].cbData); + if (ret) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0; + swapped[cSwapped].pvStructInfo = &permitted; + swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + } + else + ret = FALSE; + } + if (constraints->cExcludedSubtree) + { + excluded.rgBlob = CryptMemAlloc( + constraints->cExcludedSubtree * sizeof(CRYPT_DER_BLOB)); + if (excluded.rgBlob) + { + excluded.cBlob = constraints->cExcludedSubtree; + memset(excluded.rgBlob, 0, + excluded.cBlob * sizeof(CRYPT_DER_BLOB)); + for (i = 0; ret && i < excluded.cBlob; i++) + ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType, + NULL, &constraints->rgExcludedSubtree[i], + CRYPT_ENCODE_ALLOC_FLAG, NULL, + (BYTE *)&excluded.rgBlob[i].pbData, + &excluded.rgBlob[i].cbData); + if (ret) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1; + swapped[cSwapped].pvStructInfo = &excluded; + swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + } + else + ret = FALSE; + } + if (ret) + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + for (i = 0; i < permitted.cBlob; i++) + LocalFree(permitted.rgBlob[i].pbData); + for (i = 0; i < excluded.cBlob; i++) + LocalFree(excluded.rgBlob[i].pbData); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + CryptMemFree(permitted.rgBlob); + CryptMemFree(excluded.rgBlob); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodeIssuerSerialNumber( + DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, + DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + BOOL ret; + const CERT_ISSUER_SERIAL_NUMBER *issuerSerial = + (const CERT_ISSUER_SERIAL_NUMBER *)pvStructInfo; + struct AsnEncodeSequenceItem items[] = { + { &issuerSerial->Issuer, CRYPT_CopyEncodedBlob, 0 }, + { &issuerSerial->SerialNumber, CRYPT_AsnEncodeInteger, 0 }, + }; + + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded, + pcbEncoded); + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodePKCSSignerInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + if (!(dwCertEncodingType & PKCS_7_ASN_ENCODING)) + { + SetLastError(E_INVALIDARG); return FALSE; } + + __TRY + { + const CMSG_SIGNER_INFO *info = (const CMSG_SIGNER_INFO *)pvStructInfo; + + if (!info->Issuer.cbData) + SetLastError(E_INVALIDARG); + else + { + struct AsnEncodeSequenceItem items[7] = { + { &info->dwVersion, CRYPT_AsnEncodeInt, 0 }, + { &info->Issuer, CRYPT_AsnEncodeIssuerSerialNumber, 0 }, + { &info->HashAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, + 0 }, + }; + struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } }; + DWORD cItem = 3, cSwapped = 0; + + if (info->AuthAttrs.cAttr) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0; + swapped[cSwapped].pvStructInfo = &info->AuthAttrs; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + items[cItem].pvStructInfo = &info->HashEncryptionAlgorithm; + items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams; + cItem++; + items[cItem].pvStructInfo = &info->EncryptedHash; + items[cItem].encodeFunc = CRYPT_AsnEncodeOctets; + cItem++; + if (info->UnauthAttrs.cAttr) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1; + swapped[cSwapped].pvStructInfo = &info->UnauthAttrs; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData, + DWORD *pcbData) +{ + struct AsnEncodeSequenceItem items[7] = { + { &signedInfo->version, CRYPT_AsnEncodeInt, 0 }, + }; + struct DERSetDescriptor digestAlgorithmsSet = { 0 }, certSet = { 0 }; + struct DERSetDescriptor crlSet = { 0 }, signerSet = { 0 }; + struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } }; + DWORD cItem = 1, cSwapped = 0; + BOOL ret = TRUE; + + if (signedInfo->cSignerInfo) + { + digestAlgorithmsSet.cItems = signedInfo->cSignerInfo; + digestAlgorithmsSet.items = signedInfo->rgSignerInfo; + digestAlgorithmsSet.itemSize = sizeof(CMSG_SIGNER_INFO); + digestAlgorithmsSet.itemOffset = + offsetof(CMSG_SIGNER_INFO, HashAlgorithm); + digestAlgorithmsSet.encode = CRYPT_AsnEncodeAlgorithmIdWithNullParams; + items[cItem].pvStructInfo = &digestAlgorithmsSet; + items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet; + cItem++; + } + items[cItem].pvStructInfo = &signedInfo->content; + items[cItem].encodeFunc = CRYPT_AsnEncodePKCSContentInfoInternal; + cItem++; + if (signedInfo->cCertEncoded) + { + certSet.cItems = signedInfo->cCertEncoded; + certSet.items = signedInfo->rgCertEncoded; + certSet.itemSize = sizeof(CERT_BLOB); + certSet.itemOffset = 0; + certSet.encode = CRYPT_CopyEncodedBlob; + swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 0; + swapped[cSwapped].pvStructInfo = &certSet; + swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (signedInfo->cCrlEncoded) + { + crlSet.cItems = signedInfo->cCrlEncoded; + crlSet.items = signedInfo->rgCrlEncoded; + crlSet.itemSize = sizeof(CRL_BLOB); + crlSet.itemOffset = 0; + crlSet.encode = CRYPT_CopyEncodedBlob; + swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 1; + swapped[cSwapped].pvStructInfo = &crlSet; + swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (ret && signedInfo->cSignerInfo) + { + signerSet.cItems = signedInfo->cSignerInfo; + signerSet.items = signedInfo->rgSignerInfo; + signerSet.itemSize = sizeof(CMSG_SIGNER_INFO); + signerSet.itemOffset = 0; + signerSet.encode = CRYPT_AsnEncodePKCSSignerInfo; + items[cItem].pvStructInfo = &signerSet; + items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet; + cItem++; + } + if (ret) + ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + items, cItem, 0, NULL, pvData, pcbData); + + return ret; +} + +static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, + LPCSTR lpszStructType) +{ + CryptEncodeObjectExFunc encodeFunc = NULL; + if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING) { SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; + return NULL; } - SetLastError(NOERROR); - if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded) - *(BYTE **)pvEncoded = NULL; if (!HIWORD(lpszStructType)) { switch (LOWORD(lpszStructType)) { - case (WORD)X509_CERT: + case LOWORD(X509_CERT): encodeFunc = CRYPT_AsnEncodeCert; break; - case (WORD)X509_CERT_TO_BE_SIGNED: + case LOWORD(X509_CERT_TO_BE_SIGNED): encodeFunc = CRYPT_AsnEncodeCertInfo; break; - case (WORD)X509_CERT_CRL_TO_BE_SIGNED: + case LOWORD(X509_CERT_CRL_TO_BE_SIGNED): encodeFunc = CRYPT_AsnEncodeCRLInfo; break; - case (WORD)X509_EXTENSIONS: + case LOWORD(X509_EXTENSIONS): encodeFunc = CRYPT_AsnEncodeExtensions; break; - case (WORD)X509_NAME_VALUE: + case LOWORD(X509_NAME_VALUE): encodeFunc = CRYPT_AsnEncodeNameValue; break; - case (WORD)X509_NAME: + case LOWORD(X509_NAME): encodeFunc = CRYPT_AsnEncodeName; break; - case (WORD)X509_PUBLIC_KEY_INFO: + case LOWORD(X509_PUBLIC_KEY_INFO): encodeFunc = CRYPT_AsnEncodePubKeyInfo; break; - case (WORD)X509_AUTHORITY_KEY_ID: + case LOWORD(X509_AUTHORITY_KEY_ID): encodeFunc = CRYPT_AsnEncodeAuthorityKeyId; break; - case (WORD)X509_ALTERNATE_NAME: + case LOWORD(X509_ALTERNATE_NAME): encodeFunc = CRYPT_AsnEncodeAltName; break; - case (WORD)X509_BASIC_CONSTRAINTS: + case LOWORD(X509_BASIC_CONSTRAINTS): encodeFunc = CRYPT_AsnEncodeBasicConstraints; break; - case (WORD)X509_BASIC_CONSTRAINTS2: + case LOWORD(X509_BASIC_CONSTRAINTS2): encodeFunc = CRYPT_AsnEncodeBasicConstraints2; break; - case (WORD)RSA_CSP_PUBLICKEYBLOB: + case LOWORD(RSA_CSP_PUBLICKEYBLOB): encodeFunc = CRYPT_AsnEncodeRsaPubKey; break; - case (WORD)X509_UNICODE_NAME: + case LOWORD(X509_UNICODE_NAME): encodeFunc = CRYPT_AsnEncodeUnicodeName; break; - case (WORD)X509_UNICODE_NAME_VALUE: + case LOWORD(PKCS_CONTENT_INFO): + encodeFunc = CRYPT_AsnEncodePKCSContentInfo; + break; + case LOWORD(PKCS_ATTRIBUTE): + encodeFunc = CRYPT_AsnEncodePKCSAttribute; + break; + case LOWORD(X509_UNICODE_NAME_VALUE): encodeFunc = CRYPT_AsnEncodeUnicodeNameValue; break; - case (WORD)X509_OCTET_STRING: + case LOWORD(X509_OCTET_STRING): encodeFunc = CRYPT_AsnEncodeOctets; break; - case (WORD)X509_BITS: - case (WORD)X509_KEY_USAGE: + case LOWORD(X509_BITS): + case LOWORD(X509_KEY_USAGE): encodeFunc = CRYPT_AsnEncodeBits; break; - case (WORD)X509_INTEGER: + case LOWORD(X509_INTEGER): encodeFunc = CRYPT_AsnEncodeInt; break; - case (WORD)X509_MULTI_BYTE_INTEGER: + case LOWORD(X509_MULTI_BYTE_INTEGER): encodeFunc = CRYPT_AsnEncodeInteger; break; - case (WORD)X509_MULTI_BYTE_UINT: + case LOWORD(X509_MULTI_BYTE_UINT): encodeFunc = CRYPT_AsnEncodeUnsignedInteger; break; - case (WORD)X509_ENUMERATED: + case LOWORD(X509_ENUMERATED): encodeFunc = CRYPT_AsnEncodeEnumerated; break; - case (WORD)X509_CHOICE_OF_TIME: + case LOWORD(X509_CHOICE_OF_TIME): encodeFunc = CRYPT_AsnEncodeChoiceOfTime; break; - case (WORD)X509_SEQUENCE_OF_ANY: + case LOWORD(X509_AUTHORITY_KEY_ID2): + encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2; + break; + case LOWORD(X509_SEQUENCE_OF_ANY): encodeFunc = CRYPT_AsnEncodeSequenceOfAny; break; - case (WORD)PKCS_UTC_TIME: + case LOWORD(PKCS_UTC_TIME): encodeFunc = CRYPT_AsnEncodeUtcTime; break; - case (WORD)X509_CRL_DIST_POINTS: + case LOWORD(X509_CRL_DIST_POINTS): encodeFunc = CRYPT_AsnEncodeCRLDistPoints; break; - case (WORD)X509_ENHANCED_KEY_USAGE: + case LOWORD(X509_ENHANCED_KEY_USAGE): encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage; break; - case (WORD)X509_ISSUING_DIST_POINT: + case LOWORD(PKCS_ATTRIBUTES): + encodeFunc = CRYPT_AsnEncodePKCSAttributes; + break; + case LOWORD(X509_ISSUING_DIST_POINT): encodeFunc = CRYPT_AsnEncodeIssuingDistPoint; break; - default: - FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); + case LOWORD(X509_NAME_CONSTRAINTS): + encodeFunc = CRYPT_AsnEncodeNameConstraints; + break; + case LOWORD(PKCS7_SIGNER_INFO): + encodeFunc = CRYPT_AsnEncodePKCSSignerInfo; + break; } } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) @@ -3007,6 +3608,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, encodeFunc = CRYPT_AsnEncodeUtcTime; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER)) encodeFunc = CRYPT_AsnEncodeAuthorityKeyId; + else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) + encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) encodeFunc = CRYPT_AsnEncodeEnumerated; else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) @@ -3033,34 +3636,146 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage; else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT)) encodeFunc = CRYPT_AsnEncodeIssuingDistPoint; - else - TRACE("OID %s not found or unimplemented, looking for DLL\n", + else if (!strcmp(lpszStructType, szOID_NAME_CONSTRAINTS)) + encodeFunc = CRYPT_AsnEncodeNameConstraints; + return encodeFunc; +} + +static CryptEncodeObjectFunc CRYPT_LoadEncoderFunc(DWORD dwCertEncodingType, + LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc) +{ + static HCRYPTOIDFUNCSET set = NULL; + CryptEncodeObjectFunc encodeFunc = NULL; + + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, + (void **)&encodeFunc, hFunc); + return encodeFunc; +} + +static CryptEncodeObjectExFunc CRYPT_LoadEncoderExFunc(DWORD dwCertEncodingType, + LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc) +{ + static HCRYPTOIDFUNCSET set = NULL; + CryptEncodeObjectExFunc encodeFunc = NULL; + + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, + (void **)&encodeFunc, hFunc); + return encodeFunc; +} + +BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType, + const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + HCRYPTOIDFUNCADDR hFunc = NULL; + CryptEncodeObjectFunc pCryptEncodeObject = NULL; + CryptEncodeObjectExFunc pCryptEncodeObjectEx = NULL; + + TRACE_(crypt)("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, + debugstr_a(lpszStructType), pvStructInfo, pbEncoded, + pcbEncoded); + + if (!pbEncoded && !pcbEncoded) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!(pCryptEncodeObjectEx = CRYPT_GetBuiltinEncoder(dwCertEncodingType, + lpszStructType))) + { + TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n", debugstr_a(lpszStructType)); + pCryptEncodeObject = CRYPT_LoadEncoderFunc(dwCertEncodingType, + lpszStructType, &hFunc); + if (!pCryptEncodeObject) + pCryptEncodeObjectEx = CRYPT_LoadEncoderExFunc(dwCertEncodingType, + lpszStructType, &hFunc); + } + if (pCryptEncodeObject) + ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType, + pvStructInfo, pbEncoded, pcbEncoded); + else if (pCryptEncodeObjectEx) + ret = pCryptEncodeObjectEx(dwCertEncodingType, lpszStructType, + pvStructInfo, 0, NULL, pbEncoded, pcbEncoded); + if (hFunc) + CryptFreeOIDFunctionAddress(hFunc, 0); + TRACE_(crypt)("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, + const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, + void *pvEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + HCRYPTOIDFUNCADDR hFunc = NULL; + CryptEncodeObjectExFunc encodeFunc = NULL; + + TRACE_(crypt)("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType, + debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara, + pvEncoded, pcbEncoded); + + if (!pvEncoded && !pcbEncoded) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + SetLastError(NOERROR); + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded) + *(BYTE **)pvEncoded = NULL; + encodeFunc = CRYPT_GetBuiltinEncoder(dwCertEncodingType, lpszStructType); if (!encodeFunc) { - if (!set) - set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0); - CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, - (void **)&encodeFunc, &hFunc); + TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n", + debugstr_a(lpszStructType)); + encodeFunc = CRYPT_LoadEncoderExFunc(dwCertEncodingType, lpszStructType, + &hFunc); } if (encodeFunc) ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo, dwFlags, pEncodePara, pvEncoded, pcbEncoded); else - SetLastError(ERROR_FILE_NOT_FOUND); + { + CryptEncodeObjectFunc pCryptEncodeObject = + CRYPT_LoadEncoderFunc(dwCertEncodingType, lpszStructType, &hFunc); + + if (pCryptEncodeObject) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + { + ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType, + pvStructInfo, NULL, pcbEncoded); + if (ret && (ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pvEncoded, pcbEncoded, *pcbEncoded))) + ret = pCryptEncodeObject(dwCertEncodingType, + lpszStructType, pvStructInfo, *(BYTE **)pvEncoded, + pcbEncoded); + } + else + ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType, + pvStructInfo, pvEncoded, pcbEncoded); + } + } if (hFunc) CryptFreeOIDFunctionAddress(hFunc, 0); + TRACE_(crypt)("returning %d\n", ret); return ret; } -BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec, +BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo) { return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType, NULL, 0, NULL, pInfo, pcbInfo); } -static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv, +static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo) { @@ -3068,9 +3783,9 @@ static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv, HCRYPTKEY key; static CHAR oid[] = szOID_RSA_RSA; - TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec, - dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo, - pInfo, pcbInfo); + TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv, + dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, + pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0); if (!pszPublicKeyObjId) pszPublicKeyObjId = oid; @@ -3135,11 +3850,11 @@ static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv, return ret; } -typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv, +typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo); -BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec, +BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo) { @@ -3148,9 +3863,9 @@ BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec, ExportPublicKeyInfoExFunc exportFunc = NULL; HCRYPTOIDFUNCADDR hFunc = NULL; - TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec, - dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo, - pInfo, pcbInfo); + TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv, + dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, + pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0); if (!hCryptProv) { @@ -3189,7 +3904,7 @@ static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv, BOOL ret; DWORD pubKeySize = 0; - TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv, + TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey); ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB, @@ -3227,7 +3942,7 @@ BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv, ImportPublicKeyInfoExFunc importFunc = NULL; HCRYPTOIDFUNCADDR hFunc = NULL; - TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv, + TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey); if (!set) diff --git a/reactos/dll/win32/crypt32/filestore.c b/reactos/dll/win32/crypt32/filestore.c new file mode 100644 index 00000000000..4c8c4a14a82 --- /dev/null +++ b/reactos/dll/win32/crypt32/filestore.c @@ -0,0 +1,389 @@ +/* + * Copyright 2004-2007 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "winnls.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +typedef struct _WINE_FILESTOREINFO +{ + DWORD dwOpenFlags; + HCERTSTORE memStore; + HANDLE file; + DWORD type; + BOOL dirty; +} WINE_FILESTOREINFO, *PWINE_FILESTOREINFO; + +static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; + + TRACE("(%p, %08x)\n", store, dwFlags); + if (store->dirty) + CertSaveStore(store->memStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + store->type, CERT_STORE_SAVE_TO_FILE, store->file, 0); + CertCloseStore(store->memStore, dwFlags); + CloseHandle(store->file); + CryptMemFree(store); +} + +static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; + + TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); + store->dirty = TRUE; + return TRUE; +} + +static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; + + TRACE("(%p, %p, %08x)\n", hCertStore, pCertContext, dwFlags); + store->dirty = TRUE; + return TRUE; +} + +static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT crl, DWORD dwFlags) +{ + PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; + + TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); + store->dirty = TRUE; + return TRUE; +} + +static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT pCrlContext, DWORD dwFlags) +{ + PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; + + TRACE("(%p, %p, %08x)\n", hCertStore, pCrlContext, dwFlags); + store->dirty = TRUE; + return TRUE; +} + +static BOOL CRYPT_ReadBlobFromFile(HANDLE file, PCERT_BLOB blob) +{ + BOOL ret = TRUE; + + blob->cbData = GetFileSize(file, NULL); + if (blob->cbData) + { + blob->pbData = CryptMemAlloc(blob->cbData); + if (blob->pbData) + { + DWORD read; + + ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL); + } + } + return ret; +} + +static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; + BOOL ret; + + TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + switch (dwCtrlType) + { + case CERT_STORE_CTRL_RESYNC: + store->dirty = FALSE; + if (store->type == CERT_STORE_SAVE_AS_STORE) + { + HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + /* FIXME: if I could translate a handle to a path, I could use + * CryptQueryObject instead, but there's no API to do so yet. + */ + ret = CRYPT_ReadSerializedStoreFromFile(store->file, memStore); + if (ret) + I_CertUpdateStore(store->memStore, memStore, 0, 0); + CertCloseStore(memStore, 0); + } + else if (store->type == CERT_STORE_SAVE_AS_PKCS7) + { + CERT_BLOB blob = { 0, NULL }; + + ret = CRYPT_ReadBlobFromFile(store->file, &blob); + if (ret) + { + HCERTSTORE messageStore; + + ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, + CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, + &messageStore, NULL, NULL); + I_CertUpdateStore(store->memStore, messageStore, 0, 0); + CertCloseStore(messageStore, 0); + CryptMemFree(blob.pbData); + } + } + else + { + WARN("unknown type %d\n", store->type); + ret = FALSE; + } + break; + case CERT_STORE_CTRL_COMMIT: + if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) + { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + ret = FALSE; + } + else if (store->dirty) + ret = CertSaveStore(store->memStore, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + store->type, CERT_STORE_SAVE_TO_FILE, store->file, 0); + else + ret = TRUE; + break; + default: + FIXME("%d: stub\n", dwCtrlType); + ret = FALSE; + } + return ret; +} + +static void *fileProvFuncs[] = { + CRYPT_FileCloseStore, + NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ + CRYPT_FileWriteCert, + CRYPT_FileDeleteCert, + NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ + CRYPT_FileWriteCRL, + CRYPT_FileDeleteCRL, + NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ + CRYPT_FileControl, +}; + +static PWINECRYPT_CERTSTORE CRYPT_CreateFileStore(DWORD dwFlags, + HCERTSTORE memStore, HANDLE file, DWORD type) +{ + PWINECRYPT_CERTSTORE store = NULL; + PWINE_FILESTOREINFO info = CryptMemAlloc(sizeof(WINE_FILESTOREINFO)); + + if (info) + { + CERT_STORE_PROV_INFO provInfo = { 0 }; + + info->dwOpenFlags = dwFlags; + info->memStore = memStore; + info->file = file; + info->type = type; + info->dirty = FALSE; + provInfo.cbSize = sizeof(provInfo); + provInfo.cStoreProvFunc = sizeof(fileProvFuncs) / + sizeof(fileProvFuncs[0]); + provInfo.rgpvStoreProvFunc = fileProvFuncs; + provInfo.hStoreProv = info; + store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); + } + return store; +} + +PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, + const void *pvPara) +{ + PWINECRYPT_CERTSTORE store = NULL; + HANDLE file = (HANDLE)pvPara; + + TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); + + if (!pvPara) + { + SetLastError(ERROR_INVALID_HANDLE); + return NULL; + } + if (dwFlags & CERT_STORE_DELETE_FLAG) + { + SetLastError(E_INVALIDARG); + return NULL; + } + if ((dwFlags & CERT_STORE_READONLY_FLAG) && + (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) + { + SetLastError(E_INVALIDARG); + return NULL; + } + + if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, + GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ? + GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0)) + { + HCERTSTORE memStore; + + memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (memStore) + { + if (CRYPT_ReadSerializedStoreFromFile(file, memStore)) + { + store = CRYPT_CreateFileStore(dwFlags, memStore, file, + CERT_STORE_SAVE_AS_STORE); + /* File store doesn't need crypto provider, so close it */ + if (hCryptProv && + !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) + CryptReleaseContext(hCryptProv, 0); + } + } + } + TRACE("returning %p\n", store); + return store; +} + +PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + HCERTSTORE store = 0; + LPCWSTR fileName = (LPCWSTR)pvPara; + DWORD access, create; + HANDLE file; + + TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName)); + + if (!fileName) + { + SetLastError(ERROR_PATH_NOT_FOUND); + return NULL; + } + if ((dwFlags & CERT_STORE_READONLY_FLAG) && + (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) + { + SetLastError(E_INVALIDARG); + return NULL; + } + + access = GENERIC_READ; + if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG) + access |= GENERIC_WRITE; + if (dwFlags & CERT_STORE_CREATE_NEW_FLAG) + create = CREATE_NEW; + else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG) + create = OPEN_EXISTING; + else + create = OPEN_ALWAYS; + file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create, + FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + HCERTSTORE memStore = NULL; + DWORD size = GetFileSize(file, NULL), type = 0; + + /* If the file isn't empty, try to get the type from the file itself */ + if (size) + { + DWORD contentType; + BOOL ret; + + /* Close the file so CryptQueryObject can succeed.. */ + CloseHandle(file); + ret = CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName, + CERT_QUERY_CONTENT_FLAG_CERT | + CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, + CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, &contentType, NULL, + &memStore, NULL, NULL); + if (ret) + { + if (contentType == CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) + type = CERT_STORE_SAVE_AS_PKCS7; + else + type = CERT_STORE_SAVE_AS_STORE; + /* and reopen the file. */ + file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, + create, FILE_ATTRIBUTE_NORMAL, NULL); + } + } + else + { + static const WCHAR spc[] = { 's','p','c',0 }; + static const WCHAR p7c[] = { 'p','7','c',0 }; + LPCWSTR ext = strrchrW(fileName, '.'); + + if (ext) + { + ext++; + if (!lstrcmpiW(ext, spc) || !lstrcmpiW(ext, p7c)) + type = CERT_STORE_SAVE_AS_PKCS7; + } + if (!type) + type = CERT_STORE_SAVE_AS_STORE; + memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + } + if (memStore) + { + store = CRYPT_CreateFileStore(dwFlags, memStore, file, type); + /* File store doesn't need crypto provider, so close it */ + if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) + CryptReleaseContext(hCryptProv, 0); + } + } + return (PWINECRYPT_CERTSTORE)store; +} + +PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv, + DWORD dwFlags, const void *pvPara) +{ + int len; + PWINECRYPT_CERTSTORE ret = NULL; + + TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, + debugstr_a((LPCSTR)pvPara)); + + if (!pvPara) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0); + if (len) + { + LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); + + if (storeName) + { + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len); + ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName); + CryptMemFree(storeName); + } + } + return ret; +} diff --git a/reactos/dll/win32/crypt32/main.c b/reactos/dll/win32/crypt32/main.c index cda762dd79b..922dd1955a7 100644 --- a/reactos/dll/win32/crypt32/main.c +++ b/reactos/dll/win32/crypt32/main.c @@ -25,10 +25,8 @@ #include "winbase.h" #include "wincrypt.h" #include "winreg.h" -#include "winnls.h" -#include "mssip.h" #include "winuser.h" -#include "advpub.h" +#include "i_cryptasn1tls.h" #include "crypt32_private.h" #include "wine/debug.h" @@ -46,7 +44,13 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) break; case DLL_PROCESS_DETACH: crypt_oid_free(); - if (hDefProv) CryptReleaseContext(hDefProv, 0); + crypt_sip_free(); + root_store_free(); + default_chain_engine_free(); + /* Don't release the default provider on process shutdown, there's + * no guarantee the provider dll hasn't already been unloaded. + */ + if (hDefProv && !pvReserved) CryptReleaseContext(hDefProv, 0); break; } return TRUE; @@ -55,8 +59,16 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) HCRYPTPROV CRYPT_GetDefaultProvider(void) { if (!hDefProv) - CryptAcquireContextW(&hDefProv, NULL, MS_ENHANCED_PROV_W, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + { + HCRYPTPROV prov; + + CryptAcquireContextW(&prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + InterlockedCompareExchangePointer((PVOID *)&hDefProv, (PVOID)prov, + NULL); + if (hDefProv != prov) + CryptReleaseContext(prov, 0); + } return hDefProv; } @@ -75,12 +87,24 @@ BOOL WINAPI I_CryptCreateLruCache(void *unknown, HLRUCACHE *out) return TRUE; } +BOOL WINAPI I_CryptFindLruEntry(DWORD unk0, DWORD unk1) +{ + FIXME("(%08x, %08x): stub!\n", unk0, unk1); + return FALSE; +} + BOOL WINAPI I_CryptFindLruEntryData(DWORD unk0, DWORD unk1, DWORD unk2) { FIXME("(%08x, %08x, %08x): stub!\n", unk0, unk1, unk2); return FALSE; } +BOOL WINAPI I_CryptCreateLruEntry(HLRUCACHE h, DWORD unk0, DWORD unk1) +{ + FIXME("(%p, %08x, %08x): stub!\n", h, unk0, unk1); + return FALSE; +} + DWORD WINAPI I_CryptFlushLruCache(HLRUCACHE h, DWORD unk0, DWORD unk1) { FIXME("(%p, %08x, %08x): stub!\n", h, unk0, unk1); @@ -163,7 +187,7 @@ HCRYPTPROV WINAPI I_CryptGetDefaultCryptProv(DWORD reserved) BOOL WINAPI I_CryptReadTrustedPublisherDWORDValueFromRegistry(LPCWSTR name, DWORD *value) { - static const WCHAR safer[] = { + static const WCHAR safer[] = { 'S','o','f','t','w','a','r','e','\\','P','o','l','i','c','i','e','s','\\', 'M','i','c','r','o','s','o','f','t','\\','S','y','s','t','e','m', 'C','e','r','t','i','f','i','c','a','t','e','s','\\', @@ -188,7 +212,7 @@ BOOL WINAPI I_CryptReadTrustedPublisherDWORDValueFromRegistry(LPCWSTR name, return ret; } -int WINAPI I_CryptInstallOssGlobal(DWORD x, DWORD y, DWORD z) +DWORD WINAPI I_CryptInstallOssGlobal(DWORD x, DWORD y, DWORD z) { static int ret = 8; ret++; @@ -196,18 +220,30 @@ int WINAPI I_CryptInstallOssGlobal(DWORD x, DWORD y, DWORD z) return ret; } -BOOL WINAPI I_CryptInstallAsn1Module(void *x, DWORD y, DWORD z) +BOOL WINAPI I_CryptInstallAsn1Module(ASN1module_t x, DWORD y, void* z) { - FIXME("%p %08x %08x\n", x, y, z); + FIXME("(%p %08x %p): stub\n", x, y, z); return TRUE; } -BOOL WINAPI I_CryptUninstallAsn1Module(void *x) +BOOL WINAPI I_CryptUninstallAsn1Module(HCRYPTASN1MODULE x) { - FIXME("%p\n", x); + FIXME("(%08x): stub\n", x); return TRUE; } +ASN1decoding_t WINAPI I_CryptGetAsn1Decoder(HCRYPTASN1MODULE x) +{ + FIXME("(%08x): stub\n", x); + return NULL; +} + +ASN1encoding_t WINAPI I_CryptGetAsn1Encoder(HCRYPTASN1MODULE x) +{ + FIXME("(%08x): stub\n", x); + return NULL; +} + BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat) @@ -217,28 +253,3 @@ BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType, debugstr_a(lpszStructType), pbEncoded, cbEncoded, pbFormat, pcbFormat); return FALSE; } - -BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void* pvObject, - DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, - DWORD dwFlags, DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType, - DWORD* pdwFormatType, HCERTSTORE* phCertStore, HCRYPTMSG* phMsg, - const void** ppvContext) -{ - FIXME( "%08x %p %08x %08x %08x %p %p %p %p %p %p\n", dwObjectType, - pvObject, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, - dwFlags, pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, - phCertStore, phMsg, ppvContext); - return FALSE; -} - -BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, - DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob, - BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert) -{ - FIXME("stub: %p, %d, %p, %d, %p, %p, %p\n", - pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob, - pbDecoded, pcbDecoded, ppSignerCert); - if (ppSignerCert) - *ppSignerCert = NULL; - return FALSE; -} diff --git a/reactos/dll/win32/crypt32/msg.c b/reactos/dll/win32/crypt32/msg.c new file mode 100644 index 00000000000..1bb8767b4c6 --- /dev/null +++ b/reactos/dll/win32/crypt32/msg.c @@ -0,0 +1,2614 @@ +/* + * Copyright 2007 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "snmp.h" + +#include "wine/debug.h" +#include "wine/exception.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +/* Called when a message's ref count reaches zero. Free any message-specific + * data here. + */ +typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg); + +typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData); + +typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData, + DWORD cbData, BOOL fFinal); + +typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags, + DWORD dwCtrlType, const void *pvCtrlPara); + +BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags, + DWORD dwCtrlType, const void *pvCtrlPara) +{ + TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara); + SetLastError(E_INVALIDARG); + return FALSE; +} + +typedef enum _CryptMsgState { + MsgStateInit, + MsgStateUpdated, + MsgStateDataFinalized, + MsgStateFinalized +} CryptMsgState; + +typedef struct _CryptMsgBase +{ + LONG ref; + DWORD open_flags; + BOOL streamed; + CMSG_STREAM_INFO stream_info; + CryptMsgState state; + CryptMsgCloseFunc close; + CryptMsgUpdateFunc update; + CryptMsgGetParamFunc get_param; + CryptMsgControlFunc control; +} CryptMsgBase; + +static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags, + PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close, + CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update, + CryptMsgControlFunc control) +{ + msg->ref = 1; + msg->open_flags = dwFlags; + if (pStreamInfo) + { + msg->streamed = TRUE; + msg->stream_info = *pStreamInfo; + } + else + { + msg->streamed = FALSE; + memset(&msg->stream_info, 0, sizeof(msg->stream_info)); + } + msg->close = close; + msg->get_param = get_param; + msg->update = update; + msg->control = control; + msg->state = MsgStateInit; +} + +typedef struct _CDataEncodeMsg +{ + CryptMsgBase base; + DWORD bare_content_len; + LPBYTE bare_content; +} CDataEncodeMsg; + +static const BYTE empty_data_content[] = { 0x04,0x00 }; + +static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg) +{ + CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg; + + if (msg->bare_content != empty_data_content) + LocalFree(msg->bare_content); +} + +static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + DWORD dataLen = *(DWORD *)pvStructInfo; + DWORD lenBytes; + BOOL ret = TRUE; + + /* Trick: report bytes needed based on total message length, even though + * the message isn't available yet. The caller will use the length + * reported here to encode its length. + */ + CRYPT_EncodeLen(dataLen, NULL, &lenBytes); + if (!pbEncoded) + *pcbEncoded = 1 + lenBytes + dataLen; + else + { + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, + pcbEncoded, 1 + lenBytes))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + *pbEncoded++ = ASN_OCTETSTRING; + CRYPT_EncodeLen(dataLen, pbEncoded, + &lenBytes); + } + } + return ret; +} + +static BOOL CRYPT_EncodeDataContentInfoHeader(CDataEncodeMsg *msg, + CRYPT_DATA_BLOB *header) +{ + BOOL ret; + + if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff) + { + static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48, + 0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 }; + + header->pbData = LocalAlloc(0, sizeof(headerValue)); + if (header->pbData) + { + header->cbData = sizeof(headerValue); + memcpy(header->pbData, headerValue, sizeof(headerValue)); + ret = TRUE; + } + else + ret = FALSE; + } + else + { + struct AsnConstructedItem constructed = { 0, + &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength }; + struct AsnEncodeSequenceItem items[2] = { + { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 }, + { &constructed, CRYPT_AsnEncodeConstructed, 0 }, + }; + + ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, + sizeof(items) / sizeof(items[0]), CRYPT_ENCODE_ALLOC_FLAG, NULL, + (LPBYTE)&header->pbData, &header->cbData); + if (ret) + { + /* Trick: subtract the content length from the reported length, + * as the actual content hasn't come yet. + */ + header->cbData -= msg->base.stream_info.cbContent; + } + } + return ret; +} + +static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, + DWORD cbData, BOOL fFinal) +{ + CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + if (msg->base.state == MsgStateFinalized) + SetLastError(CRYPT_E_MSG_ERROR); + else if (msg->base.streamed) + { + __TRY + { + if (msg->base.state != MsgStateUpdated) + { + CRYPT_DATA_BLOB header; + + ret = CRYPT_EncodeDataContentInfoHeader(msg, &header); + if (ret) + { + ret = msg->base.stream_info.pfnStreamOutput( + msg->base.stream_info.pvArg, header.pbData, header.cbData, + FALSE); + LocalFree(header.pbData); + } + } + /* Curiously, every indefinite-length streamed update appears to + * get its own tag and length, regardless of fFinal. + */ + if (msg->base.stream_info.cbContent == 0xffffffff) + { + BYTE *header; + DWORD headerLen; + + ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL, + &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header, + &headerLen); + if (ret) + { + ret = msg->base.stream_info.pfnStreamOutput( + msg->base.stream_info.pvArg, header, headerLen, + FALSE); + LocalFree(header); + } + } + if (!fFinal) + { + ret = msg->base.stream_info.pfnStreamOutput( + msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, + FALSE); + msg->base.state = MsgStateUpdated; + } + else + { + msg->base.state = MsgStateFinalized; + if (msg->base.stream_info.cbContent == 0xffffffff) + { + BYTE indefinite_trailer[6] = { 0 }; + + ret = msg->base.stream_info.pfnStreamOutput( + msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, + FALSE); + if (ret) + ret = msg->base.stream_info.pfnStreamOutput( + msg->base.stream_info.pvArg, indefinite_trailer, + sizeof(indefinite_trailer), TRUE); + } + else + ret = msg->base.stream_info.pfnStreamOutput( + msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY; + } + else + { + if (!fFinal) + { + if (msg->base.open_flags & CMSG_DETACHED_FLAG) + SetLastError(E_INVALIDARG); + else + SetLastError(CRYPT_E_MSG_ERROR); + } + else + { + msg->base.state = MsgStateFinalized; + if (!cbData) + SetLastError(E_INVALIDARG); + else + { + CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData }; + + /* non-streamed data messages don't allow non-final updates, + * don't bother checking whether data already exist, they can't. + */ + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, + &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content, + &msg->bare_content_len); + } + } + } + return ret; +} + +static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src, + DWORD len) +{ + BOOL ret = TRUE; + + if (!pvData) + *pcbData = len; + else if (*pcbData < len) + { + *pcbData = len; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbData = len; + memcpy(pvData, src, len); + } + return ret; +} + +static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData) +{ + CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + switch (dwParamType) + { + case CMSG_CONTENT_PARAM: + if (msg->base.streamed) + SetLastError(E_INVALIDARG); + else + { + CRYPT_CONTENT_INFO info; + char rsa_data[] = "1.2.840.113549.1.7.1"; + + info.pszObjId = rsa_data; + info.Content.cbData = msg->bare_content_len; + info.Content.pbData = msg->bare_content; + ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info, + pvData, pcbData); + } + break; + case CMSG_BARE_CONTENT_PARAM: + if (msg->base.streamed) + SetLastError(E_INVALIDARG); + else + ret = CRYPT_CopyParam(pvData, pcbData, msg->bare_content, + msg->bare_content_len); + break; + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + return ret; +} + +static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo, + LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo) +{ + CDataEncodeMsg *msg; + + if (pvMsgEncodeInfo) + { + SetLastError(E_INVALIDARG); + return NULL; + } + msg = CryptMemAlloc(sizeof(CDataEncodeMsg)); + if (msg) + { + CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, + CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update, + CRYPT_DefaultMsgControl); + msg->bare_content_len = sizeof(empty_data_content); + msg->bare_content = (LPBYTE)empty_data_content; + } + return (HCRYPTMSG)msg; +} + +typedef struct _CHashEncodeMsg +{ + CryptMsgBase base; + HCRYPTPROV prov; + HCRYPTHASH hash; + CRYPT_DATA_BLOB data; +} CHashEncodeMsg; + +static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg) +{ + CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg; + + CryptMemFree(msg->data.pbData); + CryptDestroyHash(msg->hash); + if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) + CryptReleaseContext(msg->prov, 0); +} + +static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData, + DWORD *pcbData) +{ + BOOL ret; + ALG_ID algID; + DWORD size = sizeof(algID); + + ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0); + if (ret) + { + CRYPT_DIGESTED_DATA digestedData = { 0 }; + char oid_rsa_data[] = szOID_RSA_data; + + digestedData.version = CMSG_HASHED_DATA_PKCS_1_5_VERSION; + digestedData.DigestAlgorithm.pszObjId = (LPSTR)CertAlgIdToOID(algID); + /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */ + /* Quirk: OID is only encoded messages if an update has happened */ + if (msg->base.state != MsgStateInit) + digestedData.ContentInfo.pszObjId = oid_rsa_data; + if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData) + { + ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data, + CRYPT_ENCODE_ALLOC_FLAG, NULL, + (LPBYTE)&digestedData.ContentInfo.Content.pbData, + &digestedData.ContentInfo.Content.cbData); + } + if (msg->base.state == MsgStateFinalized) + { + size = sizeof(DWORD); + ret = CryptGetHashParam(msg->hash, HP_HASHSIZE, + (LPBYTE)&digestedData.hash.cbData, &size, 0); + if (ret) + { + digestedData.hash.pbData = CryptMemAlloc( + digestedData.hash.cbData); + ret = CryptGetHashParam(msg->hash, HP_HASHVAL, + digestedData.hash.pbData, &digestedData.hash.cbData, 0); + } + } + if (ret) + ret = CRYPT_AsnEncodePKCSDigestedData(&digestedData, pvData, + pcbData); + CryptMemFree(digestedData.hash.pbData); + LocalFree(digestedData.ContentInfo.Content.pbData); + } + return ret; +} + +static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData) +{ + CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex, + pvData, pcbData); + + switch (dwParamType) + { + case CMSG_BARE_CONTENT_PARAM: + if (msg->base.streamed) + SetLastError(E_INVALIDARG); + else + ret = CRYPT_EncodePKCSDigestedData(msg, pvData, pcbData); + break; + case CMSG_CONTENT_PARAM: + { + CRYPT_CONTENT_INFO info; + + ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL, + &info.Content.cbData); + if (ret) + { + info.Content.pbData = CryptMemAlloc(info.Content.cbData); + if (info.Content.pbData) + { + ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, + info.Content.pbData, &info.Content.cbData); + if (ret) + { + char oid_rsa_hashed[] = szOID_RSA_hashedData; + + info.pszObjId = oid_rsa_hashed; + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, + PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData); + } + CryptMemFree(info.Content.pbData); + } + else + ret = FALSE; + } + break; + } + case CMSG_COMPUTED_HASH_PARAM: + ret = CryptGetHashParam(msg->hash, HP_HASHVAL, (BYTE *)pvData, pcbData, + 0); + break; + case CMSG_VERSION_PARAM: + if (msg->base.state != MsgStateFinalized) + SetLastError(CRYPT_E_MSG_ERROR); + else + { + DWORD version = CMSG_HASHED_DATA_PKCS_1_5_VERSION; + + /* Since the data are always encoded as octets, the version is + * always 0 (see rfc3852, section 7) + */ + ret = CRYPT_CopyParam(pvData, pcbData, &version, sizeof(version)); + } + break; + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + return ret; +} + +static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, + DWORD cbData, BOOL fFinal) +{ + CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal); + + if (msg->base.state == MsgStateFinalized) + SetLastError(CRYPT_E_MSG_ERROR); + else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG)) + { + /* Doesn't do much, as stream output is never called, and you + * can't get the content. + */ + ret = CryptHashData(msg->hash, pbData, cbData, 0); + msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated; + } + else + { + if (!fFinal) + SetLastError(CRYPT_E_MSG_ERROR); + else + { + ret = CryptHashData(msg->hash, pbData, cbData, 0); + if (ret) + { + msg->data.pbData = CryptMemAlloc(cbData); + if (msg->data.pbData) + { + memcpy(msg->data.pbData + msg->data.cbData, pbData, cbData); + msg->data.cbData += cbData; + } + else + ret = FALSE; + } + msg->base.state = MsgStateFinalized; + } + } + return ret; +} + +static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo, + LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo) +{ + CHashEncodeMsg *msg; + const CMSG_HASHED_ENCODE_INFO *info = + (const CMSG_HASHED_ENCODE_INFO *)pvMsgEncodeInfo; + HCRYPTPROV prov; + ALG_ID algID; + + if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO)) + { + SetLastError(E_INVALIDARG); + return NULL; + } + if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId))) + { + SetLastError(CRYPT_E_UNKNOWN_ALGO); + return NULL; + } + if (info->hCryptProv) + prov = info->hCryptProv; + else + { + prov = CRYPT_GetDefaultProvider(); + dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG; + } + msg = CryptMemAlloc(sizeof(CHashEncodeMsg)); + if (msg) + { + CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, + CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update, + CRYPT_DefaultMsgControl); + msg->prov = prov; + msg->data.cbData = 0; + msg->data.pbData = NULL; + if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash)) + { + CryptMsgClose(msg); + msg = NULL; + } + } + return (HCRYPTMSG)msg; +} + +typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS +{ + DWORD cbSize; + PCERT_INFO pCertInfo; + HCRYPTPROV hCryptProv; + DWORD dwKeySpec; + CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; + void *pvHashAuxInfo; + DWORD cAuthAttr; + PCRYPT_ATTRIBUTE rgAuthAttr; + DWORD cUnauthAttr; + PCRYPT_ATTRIBUTE rgUnauthAttr; + CERT_ID SignerId; + CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; + void *pvHashEncryptionAuxInfo; +} CMSG_SIGNER_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNER_ENCODE_INFO_WITH_CMS; + +typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS +{ + DWORD cbSize; + DWORD cSigners; + PCMSG_SIGNER_ENCODE_INFO_WITH_CMS rgSigners; + DWORD cCertEncoded; + PCERT_BLOB rgCertEncoded; + DWORD cCrlEncoded; + PCRL_BLOB rgCrlEncoded; + DWORD cAttrCertEncoded; + PCERT_BLOB rgAttrCertEncoded; +} CMSG_SIGNED_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNED_ENCODE_INFO_WITH_CMS; + +static BOOL CRYPT_IsValidSigner(CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer) +{ + if (signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO) && + signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS)) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS)) + { + FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n"); + return FALSE; + } + if (!signer->pCertInfo->SerialNumber.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!signer->pCertInfo->Issuer.cbData) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!signer->hCryptProv) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (!CertOIDToAlgId(signer->HashAlgorithm.pszObjId)) + { + SetLastError(CRYPT_E_UNKNOWN_ALGO); + return FALSE; + } + return TRUE; +} + +static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in) +{ + BOOL ret = TRUE; + + out->cbData = in->cbData; + if (out->cbData) + { + out->pbData = CryptMemAlloc(out->cbData); + if (out->pbData) + memcpy(out->pbData, in->pbData, out->cbData); + else + ret = FALSE; + } + else + out->pbData = NULL; + return ret; +} + +typedef struct _BlobArray +{ + DWORD cBlobs; + PCRYPT_DATA_BLOB blobs; +} BlobArray; + +static BOOL CRYPT_ConstructBlobArray(BlobArray *out, const BlobArray *in) +{ + BOOL ret = TRUE; + + out->cBlobs = in->cBlobs; + if (out->cBlobs) + { + out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB)); + if (out->blobs) + { + DWORD i; + + memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB)); + for (i = 0; ret && i < out->cBlobs; i++) + ret = CRYPT_ConstructBlob(&out->blobs[i], &in->blobs[i]); + } + else + ret = FALSE; + } + return ret; +} + +static void CRYPT_FreeBlobArray(BlobArray *array) +{ + DWORD i; + + for (i = 0; i < array->cBlobs; i++) + CryptMemFree(array->blobs[i].pbData); + CryptMemFree(array->blobs); +} + +static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out, + const CRYPT_ATTRIBUTE *in) +{ + BOOL ret; + + out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1); + if (out->pszObjId) + { + strcpy(out->pszObjId, in->pszObjId); + ret = CRYPT_ConstructBlobArray((BlobArray *)&out->cValue, + (const BlobArray *)&in->cValue); + } + else + ret = FALSE; + return ret; +} + +static BOOL CRYPT_ConstructAttributes(CRYPT_ATTRIBUTES *out, + const CRYPT_ATTRIBUTES *in) +{ + BOOL ret = TRUE; + + out->cAttr = in->cAttr; + if (out->cAttr) + { + out->rgAttr = CryptMemAlloc(out->cAttr * sizeof(CRYPT_ATTRIBUTE)); + if (out->rgAttr) + { + DWORD i; + + memset(out->rgAttr, 0, out->cAttr * sizeof(CRYPT_ATTRIBUTE)); + for (i = 0; ret && i < out->cAttr; i++) + ret = CRYPT_ConstructAttribute(&out->rgAttr[i], &in->rgAttr[i]); + } + else + ret = FALSE; + } + else + out->rgAttr = NULL; + return ret; +} + +/* Constructs a CMSG_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */ +static BOOL CSignerInfo_Construct(CMSG_SIGNER_INFO *info, + CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in) +{ + BOOL ret; + + /* Note: needs to change if CMS fields are supported */ + info->dwVersion = CMSG_SIGNER_INFO_V1; + ret = CRYPT_ConstructBlob(&info->Issuer, &in->pCertInfo->Issuer); + if (ret) + ret = CRYPT_ConstructBlob(&info->SerialNumber, + &in->pCertInfo->SerialNumber); + /* Assumption: algorithm IDs will point to static strings, not + * stack-based ones, so copying the pointer values is safe. + */ + info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId; + if (ret) + ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters, + &in->HashAlgorithm.Parameters); + memset(&info->HashEncryptionAlgorithm, 0, + sizeof(info->HashEncryptionAlgorithm)); + if (ret) + ret = CRYPT_ConstructAttributes(&info->AuthAttrs, + (CRYPT_ATTRIBUTES *)&in->cAuthAttr); + if (ret) + ret = CRYPT_ConstructAttributes(&info->UnauthAttrs, + (CRYPT_ATTRIBUTES *)&in->cUnauthAttr); + return ret; +} + +static void CSignerInfo_Free(CMSG_SIGNER_INFO *info) +{ + DWORD i, j; + + CryptMemFree(info->Issuer.pbData); + CryptMemFree(info->SerialNumber.pbData); + CryptMemFree(info->HashAlgorithm.Parameters.pbData); + CryptMemFree(info->EncryptedHash.pbData); + for (i = 0; i < info->AuthAttrs.cAttr; i++) + { + for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++) + CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData); + CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue); + CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId); + } + CryptMemFree(info->AuthAttrs.rgAttr); + for (i = 0; i < info->UnauthAttrs.cAttr; i++) + { + for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++) + CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData); + CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue); + CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId); + } + CryptMemFree(info->UnauthAttrs.rgAttr); +} + +typedef struct _CSignerHandles +{ + HCRYPTHASH contentHash; + HCRYPTHASH authAttrHash; +} CSignerHandles; + +typedef struct _CSignedMsgData +{ + CRYPT_SIGNED_INFO *info; + DWORD cSignerHandle; + CSignerHandles *signerHandles; +} CSignedMsgData; + +/* Constructs the signer handles for the signerIndex'th signer of msg_data. + * Assumes signerIndex is a valid idnex, and that msg_data's info has already + * been constructed. + */ +static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data, + DWORD signerIndex, HCRYPTPROV crypt_prov) +{ + ALG_ID algID; + BOOL ret; + + algID = CertOIDToAlgId( + msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId); + ret = CryptCreateHash(crypt_prov, algID, 0, 0, + &msg_data->signerHandles->contentHash); + if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0) + ret = CryptCreateHash(crypt_prov, algID, 0, 0, + &msg_data->signerHandles->authAttrHash); + return ret; +} + +/* Allocates a CSignedMsgData's handles. Assumes its info has already been + * constructed. + */ +static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data) +{ + BOOL ret = TRUE; + + if (msg_data->info->cSignerInfo) + { + msg_data->signerHandles = + CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles)); + if (msg_data->signerHandles) + { + msg_data->cSignerHandle = msg_data->info->cSignerInfo; + memset(msg_data->signerHandles, 0, + msg_data->info->cSignerInfo * sizeof(CSignerHandles)); + } + else + { + msg_data->cSignerHandle = 0; + ret = FALSE; + } + } + else + { + msg_data->cSignerHandle = 0; + msg_data->signerHandles = NULL; + } + return ret; +} + +static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data) +{ + DWORD i; + + for (i = 0; i < msg_data->cSignerHandle; i++) + { + if (msg_data->signerHandles[i].contentHash) + CryptDestroyHash(msg_data->signerHandles[i].contentHash); + if (msg_data->signerHandles[i].authAttrHash) + CryptDestroyHash(msg_data->signerHandles[i].authAttrHash); + } + CryptMemFree(msg_data->signerHandles); + msg_data->signerHandles = NULL; + msg_data->cSignerHandle = 0; +} + +static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data, + const BYTE *pbData, DWORD cbData) +{ + DWORD i; + BOOL ret = TRUE; + + for (i = 0; ret && i < msg_data->cSignerHandle; i++) + ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData, + cbData, 0); + return ret; +} + +static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out, + const CRYPT_ATTRIBUTE *in) +{ + BOOL ret = FALSE; + + out->rgAttr = CryptMemRealloc(out->rgAttr, + (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE)); + if (out->rgAttr) + { + ret = CRYPT_ConstructAttribute(&out->rgAttr[out->cAttr], in); + if (ret) + out->cAttr++; + } + return ret; +} + +static BOOL CSignedMsgData_AppendMessageDigestAttribute( + CSignedMsgData *msg_data, DWORD signerIndex) +{ + BOOL ret; + DWORD size; + CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL }; + char messageDigest[] = szOID_RSA_messageDigest; + CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash }; + + size = sizeof(DWORD); + ret = CryptGetHashParam( + msg_data->signerHandles[signerIndex].contentHash, HP_HASHSIZE, + (LPBYTE)&hash.cbData, &size, 0); + if (ret) + { + hash.pbData = CryptMemAlloc(hash.cbData); + ret = CryptGetHashParam( + msg_data->signerHandles[signerIndex].contentHash, HP_HASHVAL, + hash.pbData, &hash.cbData, 0); + if (ret) + { + ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG, + NULL, (LPBYTE)&encodedHash.pbData, &encodedHash.cbData); + if (ret) + { + ret = CRYPT_AppendAttribute( + &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs, + &messageDigestAttr); + LocalFree(encodedHash.pbData); + } + } + CryptMemFree(hash.pbData); + } + return ret; +} + +typedef enum { + Sign, + Verify +} SignOrVerify; + +static BOOL CSignedMsgData_UpdateAuthenticatedAttributes( + CSignedMsgData *msg_data, SignOrVerify flag) +{ + DWORD i; + BOOL ret = TRUE; + + TRACE("(%p)\n", msg_data); + + for (i = 0; ret && i < msg_data->info->cSignerInfo; i++) + { + if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr) + { + if (flag == Sign) + { + BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86, + 0xf7,0x0d,0x01,0x07,0x01 }; + CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded), + oid_rsa_data_encoded }; + char contentType[] = szOID_RSA_contentType; + CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content }; + + /* FIXME: does this depend on inner OID? */ + ret = CRYPT_AppendAttribute( + &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr); + if (ret) + ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data, + i); + } + if (ret) + { + LPBYTE encodedAttrs; + DWORD size; + + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES, + &msg_data->info->rgSignerInfo[i].AuthAttrs, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&encodedAttrs, &size); + if (ret) + { + ret = CryptHashData( + msg_data->signerHandles[i].authAttrHash, encodedAttrs, + size, 0); + LocalFree(encodedAttrs); + } + } + } + } + TRACE("returning %d\n", ret); + return ret; +} + +static void CRYPT_ReverseBytes(CRYPT_HASH_BLOB *hash) +{ + DWORD i; + BYTE tmp; + + for (i = 0; i < hash->cbData / 2; i++) + { + tmp = hash->pbData[hash->cbData - i - 1]; + hash->pbData[hash->cbData - i - 1] = hash->pbData[i]; + hash->pbData[i] = tmp; + } +} + +static BOOL CSignedMsgData_Sign(CSignedMsgData *msg_data) +{ + DWORD i; + BOOL ret = TRUE; + + TRACE("(%p)\n", msg_data); + + for (i = 0; ret && i < msg_data->info->cSignerInfo; i++) + { + HCRYPTHASH hash; + + if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr) + hash = msg_data->signerHandles[i].authAttrHash; + else + hash = msg_data->signerHandles[i].contentHash; + ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0, NULL, + &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData); + if (ret) + { + msg_data->info->rgSignerInfo[i].EncryptedHash.pbData = + CryptMemAlloc( + msg_data->info->rgSignerInfo[i].EncryptedHash.cbData); + if (msg_data->info->rgSignerInfo[i].EncryptedHash.pbData) + { + ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0, + msg_data->info->rgSignerInfo[i].EncryptedHash.pbData, + &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData); + if (ret) + CRYPT_ReverseBytes( + &msg_data->info->rgSignerInfo[i].EncryptedHash); + } + else + ret = FALSE; + } + } + return ret; +} + +static BOOL CSignedMsgData_Update(CSignedMsgData *msg_data, + const BYTE *pbData, DWORD cbData, BOOL fFinal, SignOrVerify flag) +{ + BOOL ret = CSignedMsgData_UpdateHash(msg_data, pbData, cbData); + + if (ret && fFinal) + { + ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data, flag); + if (ret && flag == Sign) + ret = CSignedMsgData_Sign(msg_data); + } + return ret; +} + +typedef struct _CSignedEncodeMsg +{ + CryptMsgBase base; + CRYPT_DATA_BLOB data; + CSignedMsgData msg_data; +} CSignedEncodeMsg; + +static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg) +{ + CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg; + DWORD i; + + CryptMemFree(msg->data.pbData); + CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded); + CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded); + for (i = 0; i < msg->msg_data.info->cSignerInfo; i++) + CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]); + CSignedMsgData_CloseHandles(&msg->msg_data); + CryptMemFree(msg->msg_data.info->rgSignerInfo); + CryptMemFree(msg->msg_data.info); +} + +static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData) +{ + CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + switch (dwParamType) + { + case CMSG_CONTENT_PARAM: + { + CRYPT_CONTENT_INFO info; + + ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL, + &info.Content.cbData); + if (ret) + { + info.Content.pbData = CryptMemAlloc(info.Content.cbData); + if (info.Content.pbData) + { + ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, + info.Content.pbData, &info.Content.cbData); + if (ret) + { + char oid_rsa_signed[] = szOID_RSA_signedData; + + info.pszObjId = oid_rsa_signed; + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, + PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData); + } + CryptMemFree(info.Content.pbData); + } + else + ret = FALSE; + } + break; + } + case CMSG_BARE_CONTENT_PARAM: + { + CRYPT_SIGNED_INFO info; + char oid_rsa_data[] = szOID_RSA_data; + + info = *msg->msg_data.info; + /* Quirk: OID is only encoded messages if an update has happened */ + if (msg->base.state != MsgStateInit) + info.content.pszObjId = oid_rsa_data; + else + info.content.pszObjId = NULL; + if (msg->data.cbData) + { + CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData }; + + ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, + &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, + &info.content.Content.pbData, &info.content.Content.cbData); + } + else + { + info.content.Content.cbData = 0; + info.content.Content.pbData = NULL; + ret = TRUE; + } + if (ret) + { + ret = CRYPT_AsnEncodePKCSSignedInfo(&info, pvData, pcbData); + LocalFree(info.content.Content.pbData); + } + break; + } + case CMSG_COMPUTED_HASH_PARAM: + if (dwIndex >= msg->msg_data.cSignerHandle) + SetLastError(CRYPT_E_INVALID_INDEX); + else + ret = CryptGetHashParam( + msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL, + pvData, pcbData, 0); + break; + case CMSG_ENCODED_SIGNER: + if (dwIndex >= msg->msg_data.info->cSignerInfo) + SetLastError(CRYPT_E_INVALID_INDEX); + else + ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + PKCS7_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0, + NULL, pvData, pcbData); + break; + case CMSG_VERSION_PARAM: + ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version, + sizeof(msg->msg_data.info->version)); + break; + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + return ret; +} + +static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, + DWORD cbData, BOOL fFinal) +{ + CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + if (msg->base.state == MsgStateFinalized) + SetLastError(CRYPT_E_MSG_ERROR); + else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG)) + { + ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal, + Sign); + if (msg->base.streamed) + FIXME("streamed partial stub\n"); + msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated; + } + else + { + if (!fFinal) + SetLastError(CRYPT_E_MSG_ERROR); + else + { + if (cbData) + { + msg->data.pbData = CryptMemAlloc(cbData); + if (msg->data.pbData) + { + memcpy(msg->data.pbData, pbData, cbData); + msg->data.cbData = cbData; + ret = TRUE; + } + } + else + ret = TRUE; + if (ret) + ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, + fFinal, Sign); + msg->base.state = MsgStateFinalized; + } + } + return ret; +} + +static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags, + const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID, + PCMSG_STREAM_INFO pStreamInfo) +{ + const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info = + (const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *)pvMsgEncodeInfo; + DWORD i; + CSignedEncodeMsg *msg; + + if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) && + info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS)) + { + SetLastError(E_INVALIDARG); + return NULL; + } + if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS)) + { + FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n"); + return NULL; + } + for (i = 0; i < info->cSigners; i++) + if (!CRYPT_IsValidSigner(&info->rgSigners[i])) + return NULL; + msg = CryptMemAlloc(sizeof(CSignedEncodeMsg)); + if (msg) + { + BOOL ret = TRUE; + + CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, + CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam, + CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl); + msg->data.cbData = 0; + msg->data.pbData = NULL; + msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO)); + if (msg->msg_data.info) + { + memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO)); + msg->msg_data.info->version = CMSG_SIGNED_DATA_V1; + } + else + ret = FALSE; + if (ret) + { + if (info->cSigners) + { + msg->msg_data.info->rgSignerInfo = + CryptMemAlloc(info->cSigners * sizeof(CMSG_SIGNER_INFO)); + if (msg->msg_data.info->rgSignerInfo) + { + msg->msg_data.info->cSignerInfo = info->cSigners; + memset(msg->msg_data.info->rgSignerInfo, 0, + msg->msg_data.info->cSignerInfo * sizeof(CMSG_SIGNER_INFO)); + ret = CSignedMsgData_AllocateHandles(&msg->msg_data); + for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++) + { + ret = CSignerInfo_Construct( + &msg->msg_data.info->rgSignerInfo[i], + &info->rgSigners[i]); + if (ret) + { + ret = CSignedMsgData_ConstructSignerHandles( + &msg->msg_data, i, info->rgSigners[i].hCryptProv); + if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) + CryptReleaseContext(info->rgSigners[i].hCryptProv, + 0); + } + } + } + else + ret = FALSE; + } + else + { + msg->msg_data.info->cSignerInfo = 0; + msg->msg_data.signerHandles = NULL; + msg->msg_data.cSignerHandle = 0; + } + } + if (ret) + ret = CRYPT_ConstructBlobArray( + (BlobArray *)&msg->msg_data.info->cCertEncoded, + (const BlobArray *)&info->cCertEncoded); + if (ret) + ret = CRYPT_ConstructBlobArray( + (BlobArray *)&msg->msg_data.info->cCrlEncoded, + (const BlobArray *)&info->cCrlEncoded); + if (!ret) + { + CSignedEncodeMsg_Close(msg); + msg = NULL; + } + } + return msg; +} + +static inline const char *MSG_TYPE_STR(DWORD type) +{ + switch (type) + { +#define _x(x) case (x): return #x + _x(CMSG_DATA); + _x(CMSG_SIGNED); + _x(CMSG_ENVELOPED); + _x(CMSG_SIGNED_AND_ENVELOPED); + _x(CMSG_HASHED); + _x(CMSG_ENCRYPTED); +#undef _x + default: + return wine_dbg_sprintf("unknown (%d)", type); + } +} + +HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags, + DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID, + PCMSG_STREAM_INFO pStreamInfo) +{ + HCRYPTMSG msg = NULL; + + TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags, + dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo); + + if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING) + { + SetLastError(E_INVALIDARG); + return NULL; + } + switch (dwMsgType) + { + case CMSG_DATA: + msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo, + pszInnerContentObjID, pStreamInfo); + break; + case CMSG_HASHED: + msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo, + pszInnerContentObjID, pStreamInfo); + break; + case CMSG_SIGNED: + msg = CSignedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo, + pszInnerContentObjID, pStreamInfo); + break; + case CMSG_ENVELOPED: + FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType)); + break; + case CMSG_SIGNED_AND_ENVELOPED: + case CMSG_ENCRYPTED: + /* defined but invalid, fall through */ + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + return msg; +} + +typedef struct _CDecodeMsg +{ + CryptMsgBase base; + DWORD type; + HCRYPTPROV crypt_prov; + union { + HCRYPTHASH hash; + CSignedMsgData signed_data; + } u; + CRYPT_DATA_BLOB msg_data; + PCONTEXT_PROPERTY_LIST properties; +} CDecodeMsg; + +static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg) +{ + CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg; + + if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) + CryptReleaseContext(msg->crypt_prov, 0); + switch (msg->type) + { + case CMSG_HASHED: + if (msg->u.hash) + CryptDestroyHash(msg->u.hash); + break; + case CMSG_SIGNED: + if (msg->u.signed_data.info) + { + LocalFree(msg->u.signed_data.info); + CSignedMsgData_CloseHandles(&msg->u.signed_data); + } + break; + } + CryptMemFree(msg->msg_data.pbData); + ContextPropertyList_Free(msg->properties); +} + +static BOOL CDecodeMsg_CopyData(CDecodeMsg *msg, const BYTE *pbData, + DWORD cbData) +{ + BOOL ret = TRUE; + + if (cbData) + { + if (msg->msg_data.cbData) + msg->msg_data.pbData = CryptMemRealloc(msg->msg_data.pbData, + msg->msg_data.cbData + cbData); + else + msg->msg_data.pbData = CryptMemAlloc(cbData); + if (msg->msg_data.pbData) + { + memcpy(msg->msg_data.pbData + msg->msg_data.cbData, pbData, cbData); + msg->msg_data.cbData += cbData; + } + else + ret = FALSE; + } + return ret; +} + +static BOOL CDecodeMsg_DecodeDataContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob) +{ + BOOL ret; + CRYPT_DATA_BLOB *data; + DWORD size; + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, + blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&data, + &size); + if (ret) + { + ret = ContextPropertyList_SetProperty(msg->properties, + CMSG_CONTENT_PARAM, data->pbData, data->cbData); + LocalFree(data); + } + return ret; +} + +static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg *msg, DWORD param, + const CRYPT_ALGORITHM_IDENTIFIER *id) +{ + static const BYTE nullParams[] = { ASN_NULL, 0 }; + CRYPT_ALGORITHM_IDENTIFIER *copy; + DWORD len = sizeof(CRYPT_ALGORITHM_IDENTIFIER); + + /* Linearize algorithm id */ + len += strlen(id->pszObjId) + 1; + len += id->Parameters.cbData; + copy = CryptMemAlloc(len); + if (copy) + { + copy->pszObjId = + (LPSTR)((BYTE *)copy + sizeof(CRYPT_ALGORITHM_IDENTIFIER)); + strcpy(copy->pszObjId, id->pszObjId); + copy->Parameters.pbData = (BYTE *)copy->pszObjId + strlen(id->pszObjId) + + 1; + /* Trick: omit NULL parameters */ + if (id->Parameters.cbData == sizeof(nullParams) && + !memcmp(id->Parameters.pbData, nullParams, sizeof(nullParams))) + { + copy->Parameters.cbData = 0; + len -= sizeof(nullParams); + } + else + copy->Parameters.cbData = id->Parameters.cbData; + if (copy->Parameters.cbData) + memcpy(copy->Parameters.pbData, id->Parameters.pbData, + id->Parameters.cbData); + ContextPropertyList_SetProperty(msg->properties, param, (BYTE *)copy, + len); + CryptMemFree(copy); + } +} + +static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER *id) +{ + id->pszObjId = (LPSTR)((BYTE *)id + sizeof(CRYPT_ALGORITHM_IDENTIFIER)); + id->Parameters.pbData = (BYTE *)id->pszObjId + strlen(id->pszObjId) + 1; +} + +static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg, + CRYPT_DER_BLOB *blob) +{ + BOOL ret; + CRYPT_DIGESTED_DATA *digestedData; + DWORD size; + + ret = CRYPT_AsnDecodePKCSDigestedData(blob->pbData, blob->cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_DIGESTED_DATA *)&digestedData, + &size); + if (ret) + { + ContextPropertyList_SetProperty(msg->properties, CMSG_VERSION_PARAM, + (const BYTE *)&digestedData->version, sizeof(digestedData->version)); + CDecodeMsg_SaveAlgorithmID(msg, CMSG_HASH_ALGORITHM_PARAM, + &digestedData->DigestAlgorithm); + ContextPropertyList_SetProperty(msg->properties, + CMSG_INNER_CONTENT_TYPE_PARAM, + (const BYTE *)digestedData->ContentInfo.pszObjId, + digestedData->ContentInfo.pszObjId ? + strlen(digestedData->ContentInfo.pszObjId) + 1 : 0); + if (digestedData->ContentInfo.Content.cbData) + CDecodeMsg_DecodeDataContent(msg, + &digestedData->ContentInfo.Content); + else + ContextPropertyList_SetProperty(msg->properties, + CMSG_CONTENT_PARAM, NULL, 0); + ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM, + digestedData->hash.pbData, digestedData->hash.cbData); + LocalFree(digestedData); + } + return ret; +} + +static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg, + CRYPT_DER_BLOB *blob) +{ + BOOL ret; + CRYPT_SIGNED_INFO *signedInfo; + DWORD size; + + ret = CRYPT_AsnDecodePKCSSignedInfo(blob->pbData, blob->cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo, + &size); + if (ret) + { + DWORD i; + + msg->u.signed_data.info = signedInfo; + ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data); + for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++) + ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i, + msg->crypt_prov); + if (ret) + { + /* Now that we have all the content, update the hash handles with + * it. Have to decode it if the type is szOID_RSA_data. + */ + if (msg->u.signed_data.info->content.Content.cbData) + { + if (!strcmp(msg->u.signed_data.info->content.pszObjId, + szOID_RSA_data)) + { + CRYPT_DATA_BLOB *blob; + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, + X509_OCTET_STRING, + msg->u.signed_data.info->content.Content.pbData, + msg->u.signed_data.info->content.Content.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size); + if (ret) + { + ret = CSignedMsgData_Update(&msg->u.signed_data, + blob->pbData, blob->cbData, TRUE, Verify); + LocalFree(blob); + } + } + else + ret = CSignedMsgData_Update(&msg->u.signed_data, + msg->u.signed_data.info->content.Content.pbData, + msg->u.signed_data.info->content.Content.cbData, TRUE, + Verify); + } + } + } + return ret; +} +/* Decodes the content in blob as the type given, and updates the value + * (type, parameters, etc.) of msg based on what blob contains. + * It doesn't just use msg's type, to allow a recursive call from an implicitly + * typed message once the outer content info has been decoded. + */ +static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob, + DWORD type) +{ + BOOL ret; + + switch (type) + { + case CMSG_DATA: + if ((ret = CDecodeMsg_DecodeDataContent(msg, blob))) + msg->type = CMSG_DATA; + break; + case CMSG_HASHED: + if ((ret = CDecodeMsg_DecodeHashedContent(msg, blob))) + msg->type = CMSG_HASHED; + break; + case CMSG_ENVELOPED: + FIXME("unimplemented for type %s\n", MSG_TYPE_STR(type)); + ret = TRUE; + break; + case CMSG_SIGNED: + if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob))) + msg->type = CMSG_SIGNED; + break; + default: + { + CRYPT_CONTENT_INFO *info; + DWORD size; + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO, + msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG, + NULL, (LPBYTE)&info, &size); + if (ret) + { + if (!strcmp(info->pszObjId, szOID_RSA_data)) + ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_DATA); + else if (!strcmp(info->pszObjId, szOID_RSA_digestedData)) + ret = CDecodeMsg_DecodeContent(msg, &info->Content, + CMSG_HASHED); + else if (!strcmp(info->pszObjId, szOID_RSA_envelopedData)) + ret = CDecodeMsg_DecodeContent(msg, &info->Content, + CMSG_ENVELOPED); + else if (!strcmp(info->pszObjId, szOID_RSA_signedData)) + ret = CDecodeMsg_DecodeContent(msg, &info->Content, + CMSG_SIGNED); + else + { + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + ret = FALSE; + } + LocalFree(info); + } + } + } + return ret; +} + +static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, + DWORD cbData, BOOL fFinal) +{ + CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal); + + if (msg->base.state == MsgStateFinalized) + SetLastError(CRYPT_E_MSG_ERROR); + else if (msg->base.streamed) + { + FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg, pbData, + cbData, fFinal); + if (fFinal) + { + if (msg->base.open_flags & CMSG_DETACHED_FLAG && + msg->base.state != MsgStateDataFinalized) + { + ret = CDecodeMsg_CopyData(msg, pbData, cbData); + msg->base.state = MsgStateDataFinalized; + if (ret) + ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, + msg->type); + } + else + { + FIXME("(%p, %p, %d, %d): detached update stub\n", hCryptMsg, + pbData, cbData, fFinal); + ret = TRUE; + msg->base.state = MsgStateFinalized; + } + } + else + { + ret = CDecodeMsg_CopyData(msg, pbData, cbData); + if (msg->base.state == MsgStateInit) + msg->base.state = MsgStateUpdated; + } + } + else + { + if (!fFinal) + SetLastError(CRYPT_E_MSG_ERROR); + else + { + if (msg->base.state == MsgStateInit) + { + ret = CDecodeMsg_CopyData(msg, pbData, cbData); + if (ret) + ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, + msg->type); + if (msg->base.open_flags & CMSG_DETACHED_FLAG) + msg->base.state = MsgStateDataFinalized; + else + msg->base.state = MsgStateFinalized; + } + else if (msg->base.state == MsgStateDataFinalized) + { + FIXME("(%p, %p, %d, %d): detached update stub\n", hCryptMsg, + pbData, cbData, fFinal); + ret = TRUE; + msg->base.state = MsgStateFinalized; + } + } + } + return ret; +} + +static BOOL CDecodeHashMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData) +{ + BOOL ret = FALSE; + + switch (dwParamType) + { + case CMSG_TYPE_PARAM: + ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type)); + break; + case CMSG_HASH_ALGORITHM_PARAM: + { + CRYPT_DATA_BLOB blob; + + ret = ContextPropertyList_FindProperty(msg->properties, dwParamType, + &blob); + if (ret) + { + ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData); + if (ret && pvData) + CRYPT_FixUpAlgorithmID((CRYPT_ALGORITHM_IDENTIFIER *)pvData); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + } + case CMSG_COMPUTED_HASH_PARAM: + if (!msg->u.hash) + { + CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL; + DWORD size = 0; + ALG_ID algID = 0; + + CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size); + hashAlgoID = CryptMemAlloc(size); + ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, + hashAlgoID, &size); + if (ret) + algID = CertOIDToAlgId(hashAlgoID->pszObjId); + ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash); + if (ret) + { + CRYPT_DATA_BLOB content; + + ret = ContextPropertyList_FindProperty(msg->properties, + CMSG_CONTENT_PARAM, &content); + if (ret) + ret = CryptHashData(msg->u.hash, content.pbData, + content.cbData, 0); + } + CryptMemFree(hashAlgoID); + } + else + ret = TRUE; + if (ret) + ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData, + 0); + break; + default: + { + CRYPT_DATA_BLOB blob; + + ret = ContextPropertyList_FindProperty(msg->properties, dwParamType, + &blob); + if (ret) + ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData); + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + } + return ret; +} + +/* nextData is an in/out parameter - on input it's the memory location in + * which a copy of in's data should be made, and on output it's the memory + * location immediately after out's copy of in's data. + */ +static inline void CRYPT_CopyBlob(CRYPT_DATA_BLOB *out, + const CRYPT_DATA_BLOB *in, LPBYTE *nextData) +{ + out->cbData = in->cbData; + if (in->cbData) + { + out->pbData = *nextData; + memcpy(out->pbData, in->pbData, in->cbData); + *nextData += in->cbData; + } +} + +static inline void CRYPT_CopyAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out, + const CRYPT_ALGORITHM_IDENTIFIER *in, LPBYTE *nextData) +{ + if (in->pszObjId) + { + out->pszObjId = (LPSTR)*nextData; + strcpy(out->pszObjId, in->pszObjId); + *nextData += strlen(out->pszObjId) + 1; + } + CRYPT_CopyBlob(&out->Parameters, &in->Parameters, nextData); +} + +static inline void CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out, + const CRYPT_ATTRIBUTES *in, LPBYTE *nextData) +{ + out->cAttr = in->cAttr; + if (in->cAttr) + { + DWORD i; + + if ((*nextData - (LPBYTE)0) % sizeof(DWORD_PTR)) + *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD_PTR); + out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData; + *nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE); + for (i = 0; i < in->cAttr; i++) + { + if (in->rgAttr[i].pszObjId) + { + out->rgAttr[i].pszObjId = (LPSTR)*nextData; + strcpy(out->rgAttr[i].pszObjId, in->rgAttr[i].pszObjId); + *nextData += strlen(in->rgAttr[i].pszObjId) + 1; + } + if (in->rgAttr[i].cValue) + { + DWORD j; + + out->rgAttr[i].cValue = in->rgAttr[i].cValue; + if ((*nextData - (LPBYTE)0) % sizeof(DWORD_PTR)) + *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD_PTR); + out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData; + *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB); + for (j = 0; j < in->rgAttr[i].cValue; j++) + CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j], + &in->rgAttr[i].rgValue[j], nextData); + } + } + } +} + +static DWORD CRYPT_SizeOfAttributes(const CRYPT_ATTRIBUTES *attr) +{ + DWORD size = attr->cAttr * sizeof(CRYPT_ATTRIBUTE), i, j; + + for (i = 0; i < attr->cAttr; i++) + { + if (attr->rgAttr[i].pszObjId) + size += strlen(attr->rgAttr[i].pszObjId) + 1; + /* align pointer */ + if (size % sizeof(DWORD_PTR)) + size += size % sizeof(DWORD_PTR); + size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB); + for (j = 0; j < attr->rgAttr[i].cValue; j++) + size += attr->rgAttr[i].rgValue[j].cbData; + } + /* align pointer again to be conservative */ + if (size % sizeof(DWORD_PTR)) + size += size % sizeof(DWORD_PTR); + return size; +} + +static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData, + const CMSG_SIGNER_INFO *in) +{ + DWORD size = sizeof(CMSG_SIGNER_INFO); + BOOL ret; + + TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in); + + size += in->Issuer.cbData; + size += in->SerialNumber.cbData; + if (in->HashAlgorithm.pszObjId) + size += strlen(in->HashAlgorithm.pszObjId) + 1; + size += in->HashAlgorithm.Parameters.cbData; + if (in->HashEncryptionAlgorithm.pszObjId) + size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1; + size += in->HashEncryptionAlgorithm.Parameters.cbData; + size += in->EncryptedHash.cbData; + /* align pointer */ + if (size % sizeof(DWORD_PTR)) + size += size % sizeof(DWORD_PTR); + size += CRYPT_SizeOfAttributes(&in->AuthAttrs); + size += CRYPT_SizeOfAttributes(&in->UnauthAttrs); + if (!pvData) + { + *pcbData = size; + ret = TRUE; + } + else if (*pcbData < size) + { + *pcbData = size; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO); + CMSG_SIGNER_INFO *out = (CMSG_SIGNER_INFO *)pvData; + + out->dwVersion = in->dwVersion; + CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData); + CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData); + CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm, + &nextData); + CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm, + &in->HashEncryptionAlgorithm, &nextData); + CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData); + /* align pointer */ + if ((nextData - (LPBYTE)0) % sizeof(DWORD_PTR)) + nextData += (nextData - (LPBYTE)0) % sizeof(DWORD_PTR); + CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData); + CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData); + ret = TRUE; + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData, + const CMSG_SIGNER_INFO *in) +{ + DWORD size = sizeof(CERT_INFO); + BOOL ret; + + TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in); + + size += in->Issuer.cbData; + size += in->SerialNumber.cbData; + if (!pvData) + { + *pcbData = size; + ret = TRUE; + } + else if (*pcbData < size) + { + *pcbData = size; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO); + CERT_INFO *out = (CERT_INFO *)pvData; + + memset(out, 0, sizeof(CERT_INFO)); + CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData); + CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData); + ret = TRUE; + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData) +{ + BOOL ret = FALSE; + + switch (dwParamType) + { + case CMSG_TYPE_PARAM: + ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type)); + break; + case CMSG_CONTENT_PARAM: + if (msg->u.signed_data.info) + { + if (!strcmp(msg->u.signed_data.info->content.pszObjId, + szOID_RSA_data)) + { + CRYPT_DATA_BLOB *blob; + DWORD size; + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, + msg->u.signed_data.info->content.Content.pbData, + msg->u.signed_data.info->content.Content.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size); + if (ret) + { + ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData, + blob->cbData); + LocalFree(blob); + } + } + else + ret = CRYPT_CopyParam(pvData, pcbData, + msg->u.signed_data.info->content.Content.pbData, + msg->u.signed_data.info->content.Content.cbData); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_INNER_CONTENT_TYPE_PARAM: + if (msg->u.signed_data.info) + ret = CRYPT_CopyParam(pvData, pcbData, + msg->u.signed_data.info->content.pszObjId, + strlen(msg->u.signed_data.info->content.pszObjId) + 1); + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_SIGNER_COUNT_PARAM: + if (msg->u.signed_data.info) + ret = CRYPT_CopyParam(pvData, pcbData, + &msg->u.signed_data.info->cSignerInfo, sizeof(DWORD)); + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_SIGNER_INFO_PARAM: + if (msg->u.signed_data.info) + { + if (dwIndex >= msg->u.signed_data.info->cSignerInfo) + SetLastError(CRYPT_E_INVALID_INDEX); + else + ret = CRYPT_CopySignerInfo(pvData, pcbData, + &msg->u.signed_data.info->rgSignerInfo[dwIndex]); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_SIGNER_CERT_INFO_PARAM: + if (msg->u.signed_data.info) + { + if (dwIndex >= msg->u.signed_data.info->cSignerInfo) + SetLastError(CRYPT_E_INVALID_INDEX); + else + ret = CRYPT_CopySignerCertInfo(pvData, pcbData, + &msg->u.signed_data.info->rgSignerInfo[dwIndex]); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_CERT_COUNT_PARAM: + if (msg->u.signed_data.info) + ret = CRYPT_CopyParam(pvData, pcbData, + &msg->u.signed_data.info->cCertEncoded, sizeof(DWORD)); + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_CERT_PARAM: + if (msg->u.signed_data.info) + { + if (dwIndex >= msg->u.signed_data.info->cCertEncoded) + SetLastError(CRYPT_E_INVALID_INDEX); + else + ret = CRYPT_CopyParam(pvData, pcbData, + msg->u.signed_data.info->rgCertEncoded[dwIndex].pbData, + msg->u.signed_data.info->rgCertEncoded[dwIndex].cbData); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_CRL_COUNT_PARAM: + if (msg->u.signed_data.info) + ret = CRYPT_CopyParam(pvData, pcbData, + &msg->u.signed_data.info->cCrlEncoded, sizeof(DWORD)); + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_CRL_PARAM: + if (msg->u.signed_data.info) + { + if (dwIndex >= msg->u.signed_data.info->cCrlEncoded) + SetLastError(CRYPT_E_INVALID_INDEX); + else + ret = CRYPT_CopyParam(pvData, pcbData, + msg->u.signed_data.info->rgCrlEncoded[dwIndex].pbData, + msg->u.signed_data.info->rgCrlEncoded[dwIndex].cbData); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_COMPUTED_HASH_PARAM: + if (msg->u.signed_data.info) + { + if (dwIndex >= msg->u.signed_data.cSignerHandle) + SetLastError(CRYPT_E_INVALID_INDEX); + else + ret = CryptGetHashParam( + msg->u.signed_data.signerHandles[dwIndex].contentHash, + HP_HASHVAL, pvData, pcbData, 0); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_ATTR_CERT_COUNT_PARAM: + if (msg->u.signed_data.info) + { + DWORD attrCertCount = 0; + + ret = CRYPT_CopyParam(pvData, pcbData, + &attrCertCount, sizeof(DWORD)); + } + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + case CMSG_ATTR_CERT_PARAM: + if (msg->u.signed_data.info) + SetLastError(CRYPT_E_INVALID_INDEX); + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + break; + default: + FIXME("unimplemented for %d\n", dwParamType); + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + return ret; +} + +static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData) +{ + CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + switch (msg->type) + { + case CMSG_HASHED: + ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData, + pcbData); + break; + case CMSG_SIGNED: + ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData, + pcbData); + break; + default: + switch (dwParamType) + { + case CMSG_TYPE_PARAM: + ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, + sizeof(msg->type)); + break; + default: + { + CRYPT_DATA_BLOB blob; + + ret = ContextPropertyList_FindProperty(msg->properties, dwParamType, + &blob); + if (ret) + ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, + blob.cbData); + else + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + } + } + return ret; +} + +static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg) +{ + BOOL ret; + CRYPT_DATA_BLOB hashBlob; + + ret = ContextPropertyList_FindProperty(msg->properties, + CMSG_HASH_DATA_PARAM, &hashBlob); + if (ret) + { + DWORD computedHashSize = 0; + + ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, + &computedHashSize); + if (hashBlob.cbData == computedHashSize) + { + LPBYTE computedHash = CryptMemAlloc(computedHashSize); + + if (computedHash) + { + ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, + computedHash, &computedHashSize); + if (ret) + ret = !memcmp(hashBlob.pbData, computedHash, + hashBlob.cbData); + CryptMemFree(computedHash); + } + else + ret = FALSE; + } + } + return ret; +} + +static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg, + HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo) +{ + HCRYPTKEY key; + BOOL ret; + + if (!prov) + prov = msg->crypt_prov; + ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key); + if (ret) + { + HCRYPTHASH hash; + CRYPT_HASH_BLOB reversedHash; + + if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr) + hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash; + else + hash = msg->u.signed_data.signerHandles[signerIndex].contentHash; + ret = CRYPT_ConstructBlob(&reversedHash, + &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash); + if (ret) + { + CRYPT_ReverseBytes(&reversedHash); + ret = CryptVerifySignatureW(hash, reversedHash.pbData, + reversedHash.cbData, key, NULL, 0); + CryptMemFree(reversedHash.pbData); + } + CryptDestroyKey(key); + } + return ret; +} + +static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info) +{ + BOOL ret = FALSE; + DWORD i; + + for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++) + { + ret = CertCompareCertificateName(X509_ASN_ENCODING, + &msg->u.signed_data.info->rgSignerInfo[i].Issuer, &info->Issuer); + if (ret) + { + ret = CertCompareIntegerBlob( + &msg->u.signed_data.info->rgSignerInfo[i].SerialNumber, + &info->SerialNumber); + if (ret) + break; + } + } + if (ret) + ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i, + &info->SubjectPublicKeyInfo); + else + SetLastError(CRYPT_E_SIGNER_NOT_FOUND); + + return ret; +} + +static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg, + PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para) +{ + BOOL ret = FALSE; + + if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)) + SetLastError(ERROR_INVALID_PARAMETER); + else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo) + SetLastError(CRYPT_E_SIGNER_NOT_FOUND); + else + { + switch (para->dwSignerType) + { + case CMSG_VERIFY_SIGNER_PUBKEY: + ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, + para->hCryptProv, para->dwSignerIndex, + (PCERT_PUBLIC_KEY_INFO)para->pvSigner); + break; + case CMSG_VERIFY_SIGNER_CERT: + { + PCCERT_CONTEXT cert = (PCCERT_CONTEXT)para->pvSigner; + + ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv, + para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo); + break; + } + default: + FIXME("unimplemented for signer type %d\n", para->dwSignerType); + SetLastError(CRYPT_E_SIGNER_NOT_FOUND); + } + } + return ret; +} + +static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags, + DWORD dwCtrlType, const void *pvCtrlPara) +{ + CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg; + BOOL ret = FALSE; + + switch (dwCtrlType) + { + case CMSG_CTRL_VERIFY_SIGNATURE: + switch (msg->type) + { + case CMSG_SIGNED: + ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara); + break; + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + break; + case CMSG_CTRL_DECRYPT: + switch (msg->type) + { + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + break; + case CMSG_CTRL_VERIFY_HASH: + switch (msg->type) + { + case CMSG_HASHED: + ret = CDecodeHashMsg_VerifyHash(msg); + break; + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + break; + case CMSG_CTRL_VERIFY_SIGNATURE_EX: + switch (msg->type) + { + case CMSG_SIGNED: + ret = CDecodeSignedMsg_VerifySignatureEx(msg, + (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara); + break; + default: + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + } + break; + default: + SetLastError(CRYPT_E_CONTROL_TYPE); + } + return ret; +} + +HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags, + DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo, + PCMSG_STREAM_INFO pStreamInfo) +{ + CDecodeMsg *msg; + + TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType, + dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo); + + if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING) + { + SetLastError(E_INVALIDARG); + return NULL; + } + msg = CryptMemAlloc(sizeof(CDecodeMsg)); + if (msg) + { + CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, + CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update, + CDecodeMsg_Control); + msg->type = dwMsgType; + if (hCryptProv) + msg->crypt_prov = hCryptProv; + else + { + msg->crypt_prov = CRYPT_GetDefaultProvider(); + msg->base.open_flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG; + } + memset(&msg->u, 0, sizeof(msg->u)); + msg->msg_data.cbData = 0; + msg->msg_data.pbData = NULL; + msg->properties = ContextPropertyList_Create(); + } + return msg; +} + +HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg) +{ + TRACE("(%p)\n", hCryptMsg); + + if (hCryptMsg) + { + CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg; + + InterlockedIncrement(&msg->ref); + } + return hCryptMsg; +} + +BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg) +{ + TRACE("(%p)\n", hCryptMsg); + + if (hCryptMsg) + { + CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg; + + if (InterlockedDecrement(&msg->ref) == 0) + { + TRACE("freeing %p\n", msg); + if (msg->close) + msg->close(msg); + CryptMemFree(msg); + } + } + return TRUE; +} + +BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData, + DWORD cbData, BOOL fFinal) +{ + CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg; + + TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal); + + return msg->update(hCryptMsg, pbData, cbData, fFinal); +} + +BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData) +{ + CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg; + + TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex, + pvData, pcbData); + return msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData); +} + +BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags, + DWORD dwCtrlType, const void *pvCtrlPara) +{ + CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg; + + TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, + pvCtrlPara); + return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara); +} + +HCERTSTORE WINAPI CryptGetMessageCertificates(DWORD dwMsgAndCertEncodingType, + HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const BYTE* pbSignedBlob, + DWORD cbSignedBlob) +{ + CRYPT_DATA_BLOB blob = { cbSignedBlob, (LPBYTE)pbSignedBlob }; + + TRACE("(%08x, %ld, %d08x %p, %d)\n", dwMsgAndCertEncodingType, hCryptProv, + dwFlags, pbSignedBlob, cbSignedBlob); + + return CertOpenStore(CERT_STORE_PROV_PKCS7, dwMsgAndCertEncodingType, + hCryptProv, dwFlags, &blob); +} + +LONG WINAPI CryptGetMessageSignerCount(DWORD dwMsgEncodingType, + const BYTE *pbSignedBlob, DWORD cbSignedBlob) +{ + HCRYPTMSG msg; + LONG count = -1; + + TRACE("(%08x, %p, %d)\n", dwMsgEncodingType, pbSignedBlob, cbSignedBlob); + + msg = CryptMsgOpenToDecode(dwMsgEncodingType, 0, 0, 0, NULL, NULL); + if (msg) + { + if (CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE)) + { + DWORD size = sizeof(count); + + CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 0, &count, &size); + } + CryptMsgClose(msg); + } + return count; +} + +static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg, + DWORD dwSignerIndex) +{ + CERT_INFO *certInfo = NULL; + DWORD size; + + if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL, + &size)) + { + certInfo = CryptMemAlloc(size); + if (certInfo) + { + if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, + dwSignerIndex, certInfo, &size)) + { + CryptMemFree(certInfo); + certInfo = NULL; + } + } + } + return certInfo; +} + +static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg, + DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore) +{ + return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0, + CERT_FIND_SUBJECT_CERT, pSignerId, NULL); +} + +static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg, + PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store) +{ + PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert; + + if (pVerifyPara->pfnGetSignerCertificate) + getCert = pVerifyPara->pfnGetSignerCertificate; + else + getCert = CRYPT_DefaultGetSignerCertificate; + return getCert(pVerifyPara->pvGetArg, + pVerifyPara->dwMsgAndCertEncodingType, certInfo, store); +} + +BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, + DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob, + BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert) +{ + BOOL ret = FALSE; + DWORD size; + CRYPT_CONTENT_INFO *contentInfo; + + TRACE("(%p, %d, %p, %d, %p, %p, %p)\n", + pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob, + pbDecoded, pcbDecoded, ppSignerCert); + + if (ppSignerCert) + *ppSignerCert = NULL; + if (pcbDecoded) + *pcbDecoded = 0; + if (!pVerifyPara || + pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) || + GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) != + PKCS_7_ASN_ENCODING) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + + ret = CryptDecodeObjectEx(pVerifyPara->dwMsgAndCertEncodingType, + PKCS_CONTENT_INFO, pbSignedBlob, cbSignedBlob, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + (LPBYTE)&contentInfo, &size); + if (ret) + { + if (strcmp(contentInfo->pszObjId, szOID_RSA_signedData)) + { + SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE); + ret = FALSE; + } + else + { + HCRYPTMSG msg = CryptMsgOpenToDecode( + pVerifyPara->dwMsgAndCertEncodingType, 0, CMSG_SIGNED, + pVerifyPara->hCryptProv, NULL, NULL); + + if (msg) + { + ret = CryptMsgUpdate(msg, contentInfo->Content.pbData, + contentInfo->Content.cbData, TRUE); + if (ret && pcbDecoded) + ret = CRYPT_CopyParam(pbDecoded, pcbDecoded, + contentInfo->Content.pbData, contentInfo->Content.cbData); + if (ret) + { + CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg, + dwSignerIndex); + + ret = FALSE; + if (certInfo) + { + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG, + pVerifyPara->dwMsgAndCertEncodingType, + pVerifyPara->hCryptProv, 0, msg); + + if (store) + { + PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate( + msg, pVerifyPara, certInfo, store); + + if (cert) + { + ret = CryptMsgControl(msg, 0, + CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo); + if (ret && ppSignerCert) + *ppSignerCert = cert; + else + CertFreeCertificateContext(cert); + } + CertCloseStore(store, 0); + } + } + CryptMemFree(certInfo); + } + CryptMsgClose(msg); + } + } + LocalFree(contentInfo); + } + TRACE("returning %d\n", ret); + return ret; +} diff --git a/reactos/dll/win32/crypt32/object.c b/reactos/dll/win32/crypt32/object.c new file mode 100644 index 00000000000..4184e6c0fa0 --- /dev/null +++ b/reactos/dll/win32/crypt32/object.c @@ -0,0 +1,522 @@ +/* + * crypt32 Crypt*Object functions + * + * Copyright 2007 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "imagehlp.h" +#include "crypt32_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob) +{ + BOOL ret = FALSE; + HANDLE file; + + TRACE("%s\n", debugstr_w(fileName)); + + file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); + if (file != INVALID_HANDLE_VALUE) + { + ret = TRUE; + blob->cbData = GetFileSize(file, NULL); + if (blob->cbData) + { + blob->pbData = CryptMemAlloc(blob->cbData); + if (blob->pbData) + { + DWORD read; + + ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL); + } + } + CloseHandle(file); + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject, + DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType, + DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext) +{ + CERT_BLOB fileBlob; + const CERT_BLOB *blob; + HCERTSTORE store; + DWORD contentType; + BOOL ret; + + switch (dwObjectType) + { + case CERT_QUERY_OBJECT_FILE: + /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so + * just read the file directly + */ + ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob); + blob = &fileBlob; + break; + case CERT_QUERY_OBJECT_BLOB: + blob = (const CERT_BLOB *)pvObject; + ret = TRUE; + break; + default: + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + ret = FALSE; + } + if (!ret) + return FALSE; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ret = FALSE; + if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) + { + ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING, + blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext); + if (ret) + contentType = CERT_QUERY_CONTENT_CERT; + } + if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL)) + { + ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING, + blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext); + if (ret) + contentType = CERT_QUERY_CONTENT_CRL; + } + if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL)) + { + ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING, + blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext); + if (ret) + contentType = CERT_QUERY_CONTENT_CTL; + } + if (ret) + { + if (pdwMsgAndCertEncodingType) + *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; + if (pdwContentType) + *pdwContentType = contentType; + if (phCertStore) + *phCertStore = CertDuplicateStore(store); + } + CertCloseStore(store, 0); + if (blob == &fileBlob) + CryptMemFree(blob->pbData); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType, + const void *pvObject, DWORD dwExpectedContentTypeFlags, + DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, + HCERTSTORE *phCertStore, const void **ppvContext) +{ + CERT_BLOB fileBlob; + const CERT_BLOB *blob; + const WINE_CONTEXT_INTERFACE *contextInterface = NULL; + const void *context; + DWORD contextType; + BOOL ret; + + switch (dwObjectType) + { + case CERT_QUERY_OBJECT_FILE: + /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so + * just read the file directly + */ + ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob); + blob = &fileBlob; + break; + case CERT_QUERY_OBJECT_BLOB: + blob = (const CERT_BLOB *)pvObject; + ret = TRUE; + break; + default: + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + ret = FALSE; + } + if (!ret) + return FALSE; + + context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData, + CERT_STORE_ALL_CONTEXT_FLAG, &contextType); + if (context) + { + DWORD contentType, certStoreOffset; + + ret = TRUE; + switch (contextType) + { + case CERT_STORE_CERTIFICATE_CONTEXT: + contextInterface = pCertInterface; + contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT; + certStoreOffset = offsetof(CERT_CONTEXT, hCertStore); + if (!(dwExpectedContentTypeFlags & + CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT)) + { + SetLastError(ERROR_INVALID_DATA); + ret = FALSE; + goto end; + } + break; + case CERT_STORE_CRL_CONTEXT: + contextInterface = pCRLInterface; + contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL; + certStoreOffset = offsetof(CRL_CONTEXT, hCertStore); + if (!(dwExpectedContentTypeFlags & + CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL)) + { + SetLastError(ERROR_INVALID_DATA); + ret = FALSE; + goto end; + } + break; + case CERT_STORE_CTL_CONTEXT: + contextInterface = pCTLInterface; + contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL; + certStoreOffset = offsetof(CTL_CONTEXT, hCertStore); + if (!(dwExpectedContentTypeFlags & + CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)) + { + SetLastError(ERROR_INVALID_DATA); + ret = FALSE; + goto end; + } + break; + default: + SetLastError(ERROR_INVALID_DATA); + ret = FALSE; + goto end; + } + if (pdwMsgAndCertEncodingType) + *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; + if (pdwContentType) + *pdwContentType = contentType; + if (phCertStore) + *phCertStore = CertDuplicateStore( + *(HCERTSTORE *)((const BYTE *)context + certStoreOffset)); + if (ppvContext) + *ppvContext = contextInterface->duplicate(context); + } + +end: + if (contextInterface && context) + contextInterface->free(context); + if (blob == &fileBlob) + CryptMemFree(blob->pbData); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType, + const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, + HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) +{ + LPCWSTR fileName = (LPCWSTR)pvObject; + HANDLE file; + BOOL ret = FALSE; + + if (dwObjectType != CERT_QUERY_OBJECT_FILE) + { + FIXME("unimplemented for non-file type %d\n", dwObjectType); + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + return FALSE; + } + TRACE("%s\n", debugstr_w(fileName)); + file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); + if (file != INVALID_HANDLE_VALUE) + { + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + ret = CRYPT_ReadSerializedStoreFromFile(file, store); + if (ret) + { + if (pdwMsgAndCertEncodingType) + *pdwMsgAndCertEncodingType = X509_ASN_ENCODING; + if (pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE; + if (phCertStore) + *phCertStore = CertDuplicateStore(store); + } + CertCloseStore(store, 0); + CloseHandle(file); + } + TRACE("returning %d\n", ret); + return ret; +} + +/* Used to decode non-embedded messages */ +static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject, + DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType, + DWORD *pdwContentType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) +{ + CERT_BLOB fileBlob; + const CERT_BLOB *blob; + BOOL ret; + HCRYPTMSG msg = NULL; + DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; + + switch (dwObjectType) + { + case CERT_QUERY_OBJECT_FILE: + /* This isn't an embedded PKCS7 message, so just read the file + * directly + */ + ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob); + blob = &fileBlob; + break; + case CERT_QUERY_OBJECT_BLOB: + blob = (const CERT_BLOB *)pvObject; + ret = TRUE; + break; + default: + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + ret = FALSE; + } + if (!ret) + return FALSE; + + ret = FALSE; + /* Try it first as a PKCS content info */ + if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) || + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)) + { + msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL); + if (msg) + { + ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE); + if (ret) + { + DWORD type, len = sizeof(type); + + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len); + if (ret) + { + if ((dwExpectedContentTypeFlags & + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)) + { + if (type != CMSG_SIGNED) + { + SetLastError(ERROR_INVALID_DATA); + ret = FALSE; + } + else if (pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED; + } + else if ((dwExpectedContentTypeFlags & + CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)) + { + if (type != CMSG_DATA) + { + SetLastError(ERROR_INVALID_DATA); + ret = FALSE; + } + else if (pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED; + } + } + } + if (!ret) + { + CryptMsgClose(msg); + msg = NULL; + } + } + } + /* Failing that, try explicitly typed messages */ + if (!ret && + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)) + { + msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL); + if (msg) + { + ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE); + if (!ret) + { + CryptMsgClose(msg); + msg = NULL; + } + } + if (msg && pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED; + } + if (!ret && + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)) + { + msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL); + if (msg) + { + ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE); + if (!ret) + { + CryptMsgClose(msg); + msg = NULL; + } + } + if (msg && pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED; + } + if (pdwMsgAndCertEncodingType) + *pdwMsgAndCertEncodingType = encodingType; + if (msg) + { + if (phMsg) + *phMsg = msg; + if (phCertStore) + *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0, + 0, msg); + } + if (blob == &fileBlob) + CryptMemFree(blob->pbData); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType, + const void *pvObject, DWORD dwExpectedContentTypeFlags, + DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, + HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) +{ + HANDLE file; + BOOL ret = FALSE; + + if (dwObjectType != CERT_QUERY_OBJECT_FILE) + { + FIXME("don't know what to do for type %d embedded signed messages\n", + dwObjectType); + SetLastError(E_INVALIDARG); + return FALSE; + } + file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + DWORD len; + + ret = ImageGetCertificateData(file, 0, NULL, &len); + if (ret) + { + WIN_CERTIFICATE *winCert = HeapAlloc(GetProcessHeap(), 0, len); + + if (winCert) + { + ret = ImageGetCertificateData(file, 0, winCert, &len); + if (ret) + { + CERT_BLOB blob = { winCert->dwLength, + winCert->bCertificate }; + + ret = CRYPT_QueryMessageObject(CERT_QUERY_OBJECT_BLOB, + &blob, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, + pdwMsgAndCertEncodingType, NULL, phCertStore, phMsg); + if (ret && pdwContentType) + *pdwContentType = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED; + } + HeapFree(GetProcessHeap(), 0, winCert); + } + } + CloseHandle(file); + } + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject, + DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, + DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, + DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg, + const void **ppvContext) +{ + static const DWORD unimplementedTypes = + CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX | + CERT_QUERY_CONTENT_FLAG_CERT_PAIR; + BOOL ret = TRUE; + + TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n", + dwObjectType, pvObject, dwExpectedContentTypeFlags, + dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType, + pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext); + + if (dwExpectedContentTypeFlags & unimplementedTypes) + WARN("unimplemented for types %08x\n", + dwExpectedContentTypeFlags & unimplementedTypes); + if (!(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)) + { + FIXME("unimplemented for anything but binary\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + if (pdwFormatType) + *pdwFormatType = CERT_QUERY_FORMAT_BINARY; + + if (phCertStore) + *phCertStore = NULL; + if (phMsg) + *phMsg = NULL; + if (ppvContext) + *ppvContext = NULL; + + ret = FALSE; + if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) || + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) || + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL)) + { + ret = CRYPT_QueryContextObject(dwObjectType, pvObject, + dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType, + phCertStore, ppvContext); + } + if (!ret && + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE)) + { + ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject, + pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg); + } + if (!ret && + ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) || + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) || + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))) + { + ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject, + dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType, + phCertStore, ppvContext); + } + if (!ret && + ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) || + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))) + { + ret = CRYPT_QueryMessageObject(dwObjectType, pvObject, + dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType, + phCertStore, phMsg); + } + if (!ret && + (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED)) + { + ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject, + dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType, + phCertStore, phMsg); + } + TRACE("returning %d\n", ret); + return ret; +} diff --git a/reactos/dll/win32/crypt32/oid.c b/reactos/dll/win32/crypt32/oid.c index b574bc2e7fd..5a71c74b0bd 100644 --- a/reactos/dll/win32/crypt32/oid.c +++ b/reactos/dll/win32/crypt32/oid.c @@ -37,14 +37,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt); static const WCHAR DllW[] = { 'D','l','l',0 }; -static void init_function_sets(void); static void init_oid_info(HINSTANCE hinst); static void free_function_sets(void); static void free_oid_info(void); void crypt_oid_init(HINSTANCE hinst) { - init_function_sets(); init_oid_info(hinst); } @@ -55,7 +53,14 @@ void crypt_oid_free(void) } static CRITICAL_SECTION funcSetCS; -static struct list funcSets; +static CRITICAL_SECTION_DEBUG funcSetCSDebug = +{ + 0, 0, &funcSetCS, + { &funcSetCSDebug.ProcessLocksList, &funcSetCSDebug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": funcSetCS") } +}; +static CRITICAL_SECTION funcSetCS = { &funcSetCSDebug, -1, 0, 0, 0, 0 }; +static struct list funcSets = { &funcSets, &funcSets }; struct OIDFunctionSet { @@ -72,12 +77,12 @@ struct OIDFunction struct list next; }; -static void init_function_sets(void) -{ - InitializeCriticalSection(&funcSetCS); - funcSetCS.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": funcSetCS"); - list_init(&funcSets); -} +static const WCHAR ROOT[] = {'R','O','O','T',0}; +static const WCHAR MY[] = {'M','Y',0}; +static const WCHAR CA[] = {'C','A',0}; +static const WCHAR ADDRESSBOOK[] = {'A','D','D','R','E','S','S','B','O','O','K',0}; +static const LPCWSTR LocalizedKeys[] = {ROOT,MY,CA,ADDRESSBOOK}; +static WCHAR LocalizedNames[4][256]; static void free_function_sets(void) { @@ -100,8 +105,6 @@ static void free_function_sets(void) DeleteCriticalSection(&setCursor->cs); CryptMemFree(setCursor); } - funcSetCS.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&funcSetCS); } /* There is no free function associated with this; therefore, the sets are @@ -181,7 +184,8 @@ static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName, len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid); szKey = CryptMemAlloc(len); if (szKey) - sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid); + sprintf(szKey, szEncodingTypeFmt, + GET_CERT_ENCODING_TYPE(dwEncodingType), pszFuncName, oid); return szKey; } @@ -211,7 +215,7 @@ BOOL WINAPI CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet, else { /* No value, return an empty list */ - if (*pcchDllList) + if (pwszDllList && *pcchDllList) *pwszDllList = '\0'; *pcchDllList = 1; } @@ -219,8 +223,10 @@ BOOL WINAPI CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet, } else { - SetLastError(rc); - ret = FALSE; + /* No value, return an empty list */ + if (pwszDllList && *pcchDllList) + *pwszDllList = '\0'; + *pcchDllList = 1; } CryptMemFree(keyName); @@ -254,7 +260,7 @@ BOOL WINAPI CryptInstallOIDFunctionAddress(HMODULE hModule, func = CryptMemAlloc(sizeof(struct OIDFunction)); if (func) { - func->encoding = dwEncodingType; + func->encoding = GET_CERT_ENCODING_TYPE(dwEncodingType); if (HIWORD(rgFuncEntry[i].pszOID)) { LPSTR oid; @@ -278,6 +284,13 @@ BOOL WINAPI CryptInstallOIDFunctionAddress(HMODULE hModule, return ret; } +struct FuncAddr +{ + HMODULE lib; + LPWSTR dllList; + LPWSTR currentDll; +}; + static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID, LPCSTR szFuncName, LPVOID *ppvFuncAddr, HCRYPTOIDFUNCADDR *phFuncAddr) { @@ -294,7 +307,7 @@ static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID, DWORD type, size = 0; rc = RegQueryValueExA(key, "FuncName", NULL, &type, NULL, &size); - if (rc == ERROR_MORE_DATA && type == REG_SZ) + if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ) { funcName = CryptMemAlloc(size); rc = RegQueryValueExA(key, "FuncName", NULL, &type, @@ -303,7 +316,7 @@ static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID, else funcName = szFuncName; rc = RegQueryValueExW(key, DllW, NULL, &type, NULL, &size); - if (rc == ERROR_MORE_DATA && type == REG_SZ) + if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ) { LPWSTR dllName = CryptMemAlloc(size); @@ -322,11 +335,24 @@ static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID, lib = LoadLibraryW(dllName); if (lib) { - *ppvFuncAddr = GetProcAddress(lib, szFuncName); + *ppvFuncAddr = GetProcAddress(lib, funcName); if (*ppvFuncAddr) { - *phFuncAddr = (HCRYPTOIDFUNCADDR)lib; - ret = TRUE; + struct FuncAddr *addr = + CryptMemAlloc(sizeof(struct FuncAddr)); + + if (addr) + { + addr->lib = lib; + addr->dllList = addr->currentDll = NULL; + *phFuncAddr = addr; + ret = TRUE; + } + else + { + *phFuncAddr = NULL; + FreeLibrary(lib); + } } else { @@ -372,7 +398,7 @@ BOOL WINAPI CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet, EnterCriticalSection(&set->cs); LIST_FOR_EACH_ENTRY(function, &set->functions, struct OIDFunction, next) { - if (function->encoding == dwEncodingType) + if (function->encoding == GET_CERT_ENCODING_TYPE(dwEncodingType)) { if (HIWORD(pszOID)) { @@ -399,6 +425,7 @@ BOOL WINAPI CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet, if (!*ppvFuncAddr) ret = CRYPT_GetFuncFromReg(dwEncodingType, pszOID, set->name, ppvFuncAddr, phFuncAddr); + TRACE("returning %d\n", ret); return ret; } @@ -411,17 +438,151 @@ BOOL WINAPI CryptFreeOIDFunctionAddress(HCRYPTOIDFUNCADDR hFuncAddr, * and only unload it if it can be unloaded. Also need to implement ref * counting on the functions. */ - FreeLibrary((HMODULE)hFuncAddr); + if (hFuncAddr) + { + struct FuncAddr *addr = (struct FuncAddr *)hFuncAddr; + + CryptMemFree(addr->dllList); + FreeLibrary(addr->lib); + CryptMemFree(addr); + } return TRUE; } +static BOOL CRYPT_GetFuncFromDll(LPCWSTR dll, LPCSTR func, HMODULE *lib, + void **ppvFuncAddr) +{ + BOOL ret = FALSE; + + *lib = LoadLibraryW(dll); + if (*lib) + { + *ppvFuncAddr = GetProcAddress(*lib, func); + if (*ppvFuncAddr) + ret = TRUE; + else + { + FreeLibrary(*lib); + *lib = NULL; + } + } + return ret; +} + BOOL WINAPI CryptGetDefaultOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet, - DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void *ppvFuncAddr, + DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void **ppvFuncAddr, HCRYPTOIDFUNCADDR *phFuncAddr) { - FIXME("(%p, %d, %s, %08x, %p, %p): stub\n", hFuncSet, dwEncodingType, + struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet; + BOOL ret = FALSE; + + TRACE("(%p, %d, %s, %08x, %p, %p)\n", hFuncSet, dwEncodingType, debugstr_w(pwszDll), dwFlags, ppvFuncAddr, phFuncAddr); - return FALSE; + + if (pwszDll) + { + HMODULE lib; + + *phFuncAddr = NULL; + ret = CRYPT_GetFuncFromDll(pwszDll, set->name, &lib, ppvFuncAddr); + if (ret) + { + struct FuncAddr *addr = CryptMemAlloc(sizeof(struct FuncAddr)); + + if (addr) + { + addr->lib = lib; + addr->dllList = addr->currentDll = NULL; + *phFuncAddr = addr; + } + else + { + FreeLibrary(lib); + *ppvFuncAddr = NULL; + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + else + SetLastError(ERROR_FILE_NOT_FOUND); + } + else + { + struct FuncAddr *addr = (struct FuncAddr *)*phFuncAddr; + + if (!addr) + { + DWORD size; + + ret = CryptGetDefaultOIDDllList(hFuncSet, dwEncodingType, NULL, + &size); + if (ret) + { + LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)); + + if (dllList) + { + ret = CryptGetDefaultOIDDllList(hFuncSet, dwEncodingType, + dllList, &size); + if (ret) + { + addr = CryptMemAlloc(sizeof(struct FuncAddr)); + if (addr) + { + addr->dllList = dllList; + addr->currentDll = dllList; + addr->lib = NULL; + *phFuncAddr = addr; + } + else + { + CryptMemFree(dllList); + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + } + if (addr) + { + if (!*addr->currentDll) + { + CryptFreeOIDFunctionAddress(*phFuncAddr, 0); + SetLastError(ERROR_FILE_NOT_FOUND); + *phFuncAddr = NULL; + ret = FALSE; + } + else + { + /* FIXME: as elsewhere, can't free until DllCanUnloadNow says + * it's possible, and should defer unloading for some time to + * avoid repeated LoadLibrary/FreeLibrary on the same dll. + */ + FreeLibrary(addr->lib); + ret = CRYPT_GetFuncFromDll(addr->currentDll, set->name, + &addr->lib, ppvFuncAddr); + if (ret) + { + /* Move past the current DLL */ + addr->currentDll += lstrlenW(addr->currentDll) + 1; + *phFuncAddr = addr; + } + else + { + CryptFreeOIDFunctionAddress(*phFuncAddr, 0); + SetLastError(ERROR_FILE_NOT_FOUND); + *phFuncAddr = NULL; + } + } + } + } + return ret; } /*********************************************************************** @@ -454,10 +615,6 @@ BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName, TRACE("(%x, %s, %s, %s, %s)\n", dwEncodingType, pszFuncName, debugstr_a(pszOID), debugstr_w(pwszDll), pszOverrideFuncName); - /* This only registers functions for encoding certs, not messages */ - if (!GET_CERT_ENCODING_TYPE(dwEncodingType)) - return TRUE; - /* Native does nothing pwszDll is NULL */ if (!pwszDll) return TRUE; @@ -497,7 +654,7 @@ error_close_key: RegCloseKey(hKey); - if (r != ERROR_SUCCESS) + if (r != ERROR_SUCCESS) { SetLastError(r); return FALSE; @@ -515,10 +672,8 @@ BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName, LPSTR szKey; LONG rc; - TRACE("%x %s %s\n", dwEncodingType, pszFuncName, pszOID); - - if (!GET_CERT_ENCODING_TYPE(dwEncodingType)) - return TRUE; + TRACE("%x %s %s\n", dwEncodingType, debugstr_a(pszFuncName), + debugstr_a(pszOID)); if (!pszFuncName || !pszOID) { @@ -783,11 +938,10 @@ BOOL WINAPI CryptRegisterDefaultOIDFunction(DWORD dwEncodingType, { HKEY key; LPWSTR dlls; - LPCWSTR existing; BOOL ret = FALSE; - TRACE("(%x, %s, %x, %s)\n", dwEncodingType, pszFuncName, dwIndex, - debugstr_w(pwszDll)); + TRACE("(%x, %s, %d, %s)\n", dwEncodingType, debugstr_a(pszFuncName), + dwIndex, debugstr_w(pwszDll)); if (!pwszDll) { @@ -799,7 +953,7 @@ BOOL WINAPI CryptRegisterDefaultOIDFunction(DWORD dwEncodingType, return FALSE; dlls = CRYPT_GetDefaultOIDDlls(key); - if ((existing = CRYPT_FindStringInMultiString(dlls, pwszDll))) + if (CRYPT_FindStringInMultiString(dlls, pwszDll)) SetLastError(ERROR_FILE_EXISTS); else { @@ -839,8 +993,44 @@ BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType, return ret; } +static void oid_init_localizednames(HINSTANCE hInstance) +{ + int i; + + for(i = 0; i < sizeof(LocalizedKeys)/sizeof(LPCWSTR); i++) + { + LoadStringW(hInstance, IDS_LOCALIZEDNAME_ROOT+i, LocalizedNames[i], 256); + } +} + +/******************************************************************** + * CryptFindLocalizedName (CRYPT32.@) + */ +LPCWSTR WINAPI CryptFindLocalizedName(LPCWSTR pwszCryptName) +{ + int i; + + for(i = 0; i < sizeof(LocalizedKeys)/sizeof(LPCWSTR); i++) + { + if(!lstrcmpiW(LocalizedKeys[i], pwszCryptName)) + { + return LocalizedNames[i]; + } + } + + FIXME("No name for: %s - stub\n",debugstr_w(pwszCryptName)); + return NULL; +} + static CRITICAL_SECTION oidInfoCS; -static struct list oidInfo; +static CRITICAL_SECTION_DEBUG oidInfoCSDebug = +{ + 0, 0, &oidInfoCS, + { &oidInfoCSDebug.ProcessLocksList, &oidInfoCSDebug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": oidInfoCS") } +}; +static CRITICAL_SECTION oidInfoCS = { &oidInfoCSDebug, -1, 0, 0, 0, 0 }; +static struct list oidInfo = { &oidInfo, &oidInfo }; static const WCHAR tripledes[] = { '3','d','e','s',0 }; static const WCHAR cms3deswrap[] = { 'C','M','S','3','D','E','S','w','r','a', @@ -1181,9 +1371,7 @@ static void init_oid_info(HINSTANCE hinst) { DWORD i; - InitializeCriticalSection(&oidInfoCS); - oidInfoCS.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": oidInfoCS"); - list_init(&oidInfo); + oid_init_localizednames(hinst); for (i = 0; i < sizeof(oidInfoConstructors) / sizeof(oidInfoConstructors[0]); i++) { @@ -1213,8 +1401,9 @@ static void init_oid_info(HINSTANCE hinst) } else { + LPCWSTR stringresource; int len = LoadStringW(hinst, (UINT_PTR)oidInfoConstructors[i].pwszName, - NULL, 0); + (LPWSTR)&stringresource, 0); if (len) { @@ -1226,12 +1415,11 @@ static void init_oid_info(HINSTANCE hinst) memset(info, 0, sizeof(*info)); info->info.cbSize = sizeof(CRYPT_OID_INFO); info->info.pszOID = oidInfoConstructors[i].pszOID; - info->info.pwszName = - (LPWSTR)((LPBYTE)info + sizeof(struct OIDInfo)); + info->info.pwszName = (LPWSTR)(info + 1); info->info.dwGroupId = oidInfoConstructors[i].dwGroupId; info->info.u.Algid = oidInfoConstructors[i].Algid; - LoadStringW(hinst, (UINT_PTR)oidInfoConstructors[i].pwszName, - (LPWSTR)info->info.pwszName, len + 1); + memcpy(info + 1, stringresource, len*sizeof(WCHAR)); + ((LPWSTR)(info + 1))[len] = 0; if (oidInfoConstructors[i].blob) { info->info.ExtraInfo.cbData = @@ -1255,8 +1443,6 @@ static void free_oid_info(void) list_remove(&info->entry); CryptMemFree(info); } - oidInfoCS.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&oidInfoCS); } /*********************************************************************** diff --git a/reactos/dll/win32/crypt32/protectdata.c b/reactos/dll/win32/crypt32/protectdata.c index 4eba6b150fc..d3e0034909c 100644 --- a/reactos/dll/win32/crypt32/protectdata.c +++ b/reactos/dll/win32/crypt32/protectdata.c @@ -42,14 +42,15 @@ #include "windef.h" #include "winbase.h" #include "wincrypt.h" -#include "winreg.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); #define CRYPT32_PROTECTDATA_PROV PROV_RSA_FULL -#define CRYPT32_PROTECTDATA_HASH_CALG CALG_MD5 -#define CRYPT32_PROTECTDATA_KEY_CALG CALG_RC2 +#define CRYPT32_PROTECTDATA_HASH_CALG CALG_SHA1 +#define CRYPT32_PROTECTDATA_HASH_LEN 160 +#define CRYPT32_PROTECTDATA_KEY_CALG CALG_3DES +#define CRYPT32_PROTECTDATA_KEY_LEN 168 #define CRYPT32_PROTECTDATA_SALT_LEN 16 static const BYTE crypt32_protectdata_secret[] = { @@ -62,21 +63,22 @@ static const BYTE crypt32_protectdata_secret[] = { * to be something like this: DWORD count0; - how many "info0_*[16]" blocks follow (was always 1) - BYTE info0_0[16]; - unknown information - ... + BYTE info0_0[16]; - unknown information - persistent across invocations, + ... reboots, password changes, and users DWORD count1; - how many "info1_*[16]" blocks follow (was always 1) - BYTE info1_0[16]; - unknown information - ... + BYTE info1_0[16]; - unknown information - unique to each user, but + ... persistent across reboots and password changes DWORD null0; - NULL "end of records"? - DWORD str_len; - length of WCHAR string including term - WCHAR str[str_len]; - The "dataDescription" value - DWORD unknown0; - unknown value (seems large, but only WORD large) - DWORD unknown1; - unknown value (seems small, less than a BYTE) + DWORD str_len; - byte length of WCHAR string including term + BYTE str[str_len]; - The "dataDescription" value as a NULL-terminated + little-endian WCHAR string + ALG_ID cipher_alg; - cipher algo - was CALG_3DES + DWORD cipher_key_len; - cipher key bit length - was 0xa8==168 DWORD data_len; - length of data (was 16 in samples) BYTE data[data_len]; - unknown data (fingerprint?) DWORD null1; - NULL ? - DWORD unknown2; - unknown value (seems large, but only WORD large) - DWORD unknown3; - unknown value (seems small, less than a BYTE) + ALG_ID hash_alg; - hash algo - was CALG_SHA1 + DWORD hash_len; - bit length of hash - was 0xa0==160 DWORD salt_len; - length of salt(?) data BYTE salt[salt_len]; - salt(?) for symmetric encryption DWORD cipher_len; - length of cipher(?) data - was close to plain len @@ -95,12 +97,12 @@ struct protect_data_t DATA_BLOB info1; DWORD null0; WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */ - DWORD unknown0; /* perhaps the HASH alg const should go here? */ - DWORD unknown1; + ALG_ID cipher_alg; + DWORD cipher_key_len; DATA_BLOB data0; DWORD null1; - DWORD unknown2; /* perhaps the KEY alg const should go here? */ - DWORD unknown3; + ALG_ID hash_alg; + DWORD hash_len; DATA_BLOB salt; DATA_BLOB cipher; DATA_BLOB fingerprint; @@ -264,7 +266,7 @@ BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial) /* count0 */ serialize_dword(pInfo->count0,&ptr); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - + /* info0 */ serialize_string(pInfo->info0.pbData,&ptr, pInfo->info0.cbData,sizeof(BYTE),FALSE); @@ -282,19 +284,19 @@ BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial) /* null0 */ serialize_dword(pInfo->null0,&ptr); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - + /* szDataDescr */ serialize_string((BYTE*)pInfo->szDataDescr,&ptr, (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - /* unknown0 */ - serialize_dword(pInfo->unknown0,&ptr); + /* cipher_alg */ + serialize_dword(pInfo->cipher_alg,&ptr); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - /* unknown1 */ - serialize_dword(pInfo->unknown1,&ptr); + /* cipher_key_len */ + serialize_dword(pInfo->cipher_key_len,&ptr); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - + /* data0 */ serialize_string(pInfo->data0.pbData,&ptr, pInfo->data0.cbData,sizeof(BYTE),TRUE); @@ -303,14 +305,14 @@ BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial) /* null1 */ serialize_dword(pInfo->null1,&ptr); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - - /* unknown2 */ - serialize_dword(pInfo->unknown2,&ptr); + + /* hash_alg */ + serialize_dword(pInfo->hash_alg,&ptr); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - /* unknown3 */ - serialize_dword(pInfo->unknown3,&ptr); + /* hash_len */ + serialize_dword(pInfo->hash_len,&ptr); /*TRACE("used %u\n",ptr-pSerial->pbData);*/ - + /* salt */ serialize_string(pInfo->salt.pbData,&ptr, pInfo->salt.cbData,sizeof(BYTE),TRUE); @@ -329,7 +331,7 @@ BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial) if (ptr - pSerial->pbData != dwStruct) { ERR("struct size changed!? %u != expected %u\n", - ptr - pSerial->pbData, (unsigned int)dwStruct); + ptr - pSerial->pbData, dwStruct); LocalFree(pSerial->pbData); pSerial->pbData=NULL; pSerial->cbData=0; @@ -362,7 +364,7 @@ BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo) ERR("reading count0 failed!\n"); return FALSE; } - + /* info0 */ if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE, &pInfo->info0.pbData, &pInfo->info0.cbData)) @@ -392,7 +394,7 @@ BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo) ERR("reading null0 failed!\n"); return FALSE; } - + /* szDataDescr */ if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE, (BYTE**)&pInfo->szDataDescr, NULL)) @@ -401,20 +403,20 @@ BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo) return FALSE; } - /* unknown0 */ - if (!unserialize_dword(ptr,&index,size,&pInfo->unknown0)) + /* cipher_alg */ + if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_alg)) { - ERR("reading unknown0 failed!\n"); + ERR("reading cipher_alg failed!\n"); return FALSE; } - - /* unknown1 */ - if (!unserialize_dword(ptr,&index,size,&pInfo->unknown1)) + + /* cipher_key_len */ + if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_key_len)) { - ERR("reading unknown1 failed!\n"); + ERR("reading cipher_key_len failed!\n"); return FALSE; } - + /* data0 */ if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE, &pInfo->data0.pbData, &pInfo->data0.cbData)) @@ -429,21 +431,21 @@ BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo) ERR("reading null1 failed!\n"); return FALSE; } - - /* unknown2 */ - if (!unserialize_dword(ptr,&index,size,&pInfo->unknown2)) + + /* hash_alg */ + if (!unserialize_dword(ptr,&index,size,&pInfo->hash_alg)) { - ERR("reading unknown2 failed!\n"); + ERR("reading hash_alg failed!\n"); return FALSE; } - - /* unknown3 */ - if (!unserialize_dword(ptr,&index,size,&pInfo->unknown3)) + + /* hash_len */ + if (!unserialize_dword(ptr,&index,size,&pInfo->hash_len)) { - ERR("reading unknown3 failed!\n"); + ERR("reading hash_len failed!\n"); return FALSE; } - + /* salt */ if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE, &pInfo->salt.pbData, &pInfo->salt.cbData)) @@ -474,8 +476,7 @@ BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo) { /* this is an impossible-to-reach test, but if the padding * issue is ever understood, this may become more useful */ - ERR("loaded corrupt structure! (used %u expected %u)\n", - (unsigned int)index, (unsigned int)size); + ERR("loaded corrupt structure! (used %u expected %u)\n", index, size); status=FALSE; } @@ -596,14 +597,14 @@ BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr, memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR)); } - pInfo->unknown0=0x0000; - pInfo->unknown1=0x0000; + pInfo->cipher_alg=CRYPT32_PROTECTDATA_KEY_CALG; + pInfo->cipher_key_len=CRYPT32_PROTECTDATA_KEY_LEN; convert_str_to_blob(crypt_magic_str, &pInfo->data0); pInfo->null1=0x0000; - pInfo->unknown2=0x0000; - pInfo->unknown3=0x0000; + pInfo->hash_alg=CRYPT32_PROTECTDATA_HASH_CALG; + pInfo->hash_len=CRYPT32_PROTECTDATA_HASH_LEN; /* allocate memory to hold a salt */ pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN; @@ -704,7 +705,7 @@ BOOL hash_matches_blob(HCRYPTHASH hHash, const DATA_BLOB *two) /* create an encryption key from a given salt and optional entropy */ static -BOOL load_encryption_key(HCRYPTPROV hProv, const DATA_BLOB *salt, +BOOL load_encryption_key(HCRYPTPROV hProv, DWORD key_len, const DATA_BLOB *salt, const DATA_BLOB *pOptionalEntropy, HCRYPTKEY *phKey) { BOOL rc = TRUE; @@ -753,7 +754,7 @@ BOOL load_encryption_key(HCRYPTPROV hProv, const DATA_BLOB *salt, /* produce a symmetric key */ if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG, - hSaltHash,CRYPT_EXPORTABLE,phKey)) + hSaltHash,key_len << 16 | CRYPT_EXPORTABLE,phKey)) { ERR("CryptDeriveKey\n"); rc = FALSE; @@ -774,15 +775,15 @@ report(const DATA_BLOB* pDataIn, const DATA_BLOB* pOptionalEntropy, TRACE("pPromptStruct: %p\n", pPromptStruct); if (pPromptStruct) { - TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct->cbSize); - TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct->dwPromptFlags); + TRACE(" cbSize: 0x%x\n", pPromptStruct->cbSize); + TRACE(" dwPromptFlags: 0x%x\n", pPromptStruct->dwPromptFlags); TRACE(" hwndApp: %p\n", pPromptStruct->hwndApp); TRACE(" szPrompt: %p %s\n", pPromptStruct->szPrompt, pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt) : ""); } - TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags); + TRACE("dwFlags: 0x%04x\n", dwFlags); TRACE_DATA_BLOB(pDataIn); if (pOptionalEntropy) { @@ -857,7 +858,7 @@ BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, szDataDescr = empty_str; /* get crypt context */ - if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT)) + if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT)) { ERR("CryptAcquireContextW failed\n"); goto finished; @@ -871,7 +872,7 @@ BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, } /* load key */ - if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey)) + if (!load_encryption_key(hProv,protect_data.cipher_key_len,&protect_data.salt,pOptionalEntropy,&hKey)) { goto free_protect_data; } @@ -891,7 +892,7 @@ BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, ERR("CryptEncrypt\n"); goto free_hash; } - TRACE("required encrypted storage: %u\n",(unsigned int)dwLength); + TRACE("required encrypted storage: %u\n", dwLength); /* copy plain text into cipher area for CryptEncrypt call */ protect_data.cipher.cbData=dwLength; @@ -908,7 +909,7 @@ BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData, &dwLength, protect_data.cipher.cbData)) { - ERR("CryptEncrypt %u\n",(unsigned int)GetLastError()); + ERR("CryptEncrypt %u\n", GetLastError()); goto free_hash; } protect_data.cipher.cbData=dwLength; @@ -1016,6 +1017,11 @@ BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn, SetLastError(ERROR_INVALID_PARAMETER); goto finished; } + if (!pDataIn->cbData) + { + SetLastError(ERROR_INVALID_DATA); + goto finished; + } /* debug: show our arguments */ report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags); @@ -1038,14 +1044,14 @@ BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn, } /* get a crypt context */ - if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT)) + if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT)) { ERR("CryptAcquireContextW failed\n"); goto free_protect_data; } /* load key */ - if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey)) + if (!load_encryption_key(hProv,protect_data.cipher_key_len,&protect_data.salt,pOptionalEntropy,&hKey)) { goto free_context; } diff --git a/reactos/dll/win32/crypt32/provstore.c b/reactos/dll/win32/crypt32/provstore.c new file mode 100644 index 00000000000..b1053ae146e --- /dev/null +++ b/reactos/dll/win32/crypt32/provstore.c @@ -0,0 +1,300 @@ +/* + * Copyright 2004-2007 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +typedef struct _WINE_PROVIDERSTORE +{ + WINECRYPT_CERTSTORE hdr; + DWORD dwStoreProvFlags; + PWINECRYPT_CERTSTORE memStore; + HCERTSTOREPROV hStoreProv; + PFN_CERT_STORE_PROV_CLOSE provCloseStore; + PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert; + PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert; + PFN_CERT_STORE_PROV_WRITE_CRL provWriteCrl; + PFN_CERT_STORE_PROV_DELETE_CRL provDeleteCrl; + PFN_CERT_STORE_PROV_CONTROL provControl; +} WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE; + +static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; + + TRACE("(%p, %08x)\n", store, dwFlags); + + if (store->provCloseStore) + store->provCloseStore(store->hStoreProv, dwFlags); + if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)) + CertCloseStore(store->memStore, dwFlags); + CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store); +} + +static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert, + void *toReplace, const void **ppStoreContext) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + BOOL ret; + + TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); + + if (toReplace) + ret = ps->memStore->certs.addContext(ps->memStore, cert, toReplace, + ppStoreContext); + else + { + ret = TRUE; + if (ps->provWriteCert) + ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert, + CERT_STORE_PROV_WRITE_ADD_FLAG); + if (ret) + ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL, + ppStoreContext); + } + /* dirty trick: replace the returned context's hCertStore with + * store. + */ + if (ppStoreContext) + (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store; + return ret; +} + +static void *CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + void *ret; + + ret = ps->memStore->certs.enumContext(ps->memStore, pPrev); + if (ret) + { + /* same dirty trick: replace the returned context's hCertStore with + * store. + */ + ((PCERT_CONTEXT)ret)->hCertStore = store; + } + return ret; +} + +static BOOL CRYPT_ProvDeleteCert(PWINECRYPT_CERTSTORE store, void *cert) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + BOOL ret = TRUE; + + TRACE("(%p, %p)\n", store, cert); + + if (ps->provDeleteCert) + ret = ps->provDeleteCert(ps->hStoreProv, cert, 0); + if (ret) + ret = ps->memStore->certs.deleteContext(ps->memStore, cert); + return ret; +} + +static BOOL CRYPT_ProvAddCRL(PWINECRYPT_CERTSTORE store, void *crl, + void *toReplace, const void **ppStoreContext) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + BOOL ret; + + TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); + + if (toReplace) + ret = ps->memStore->crls.addContext(ps->memStore, crl, toReplace, + ppStoreContext); + else + { + if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) + { + SetLastError(ERROR_ACCESS_DENIED); + ret = FALSE; + } + else + { + ret = TRUE; + if (ps->provWriteCrl) + ret = ps->provWriteCrl(ps->hStoreProv, (PCCRL_CONTEXT)crl, + CERT_STORE_PROV_WRITE_ADD_FLAG); + if (ret) + ret = ps->memStore->crls.addContext(ps->memStore, crl, NULL, + ppStoreContext); + } + } + /* dirty trick: replace the returned context's hCertStore with + * store. + */ + if (ppStoreContext) + (*(PCRL_CONTEXT *)ppStoreContext)->hCertStore = store; + return ret; +} + +static void *CRYPT_ProvEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + void *ret; + + ret = ps->memStore->crls.enumContext(ps->memStore, pPrev); + if (ret) + { + /* same dirty trick: replace the returned context's hCertStore with + * store. + */ + ((PCRL_CONTEXT)ret)->hCertStore = store; + } + return ret; +} + +static BOOL CRYPT_ProvDeleteCRL(PWINECRYPT_CERTSTORE store, void *crl) +{ + PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; + BOOL ret = TRUE; + + TRACE("(%p, %p)\n", store, crl); + + if (ps->provDeleteCrl) + ret = ps->provDeleteCrl(ps->hStoreProv, crl, 0); + if (ret) + ret = ps->memStore->crls.deleteContext(ps->memStore, crl); + return ret; +} + +static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; + BOOL ret = TRUE; + + TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + if (store->provControl) + ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType, + pvCtrlPara); + return ret; +} + +PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(DWORD dwFlags, + PWINECRYPT_CERTSTORE memStore, const CERT_STORE_PROV_INFO *pProvInfo) +{ + PWINE_PROVIDERSTORE ret = CryptMemAlloc(sizeof(WINE_PROVIDERSTORE)); + + if (ret) + { + CRYPT_InitStore(&ret->hdr, dwFlags, StoreTypeProvider); + ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags; + if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG) + { + CertCloseStore(memStore, 0); + ret->memStore = NULL; + } + else + ret->memStore = memStore; + ret->hStoreProv = pProvInfo->hStoreProv; + ret->hdr.closeStore = CRYPT_ProvCloseStore; + ret->hdr.certs.addContext = CRYPT_ProvAddCert; + ret->hdr.certs.enumContext = CRYPT_ProvEnumCert; + ret->hdr.certs.deleteContext = CRYPT_ProvDeleteCert; + ret->hdr.crls.addContext = CRYPT_ProvAddCRL; + ret->hdr.crls.enumContext = CRYPT_ProvEnumCRL; + ret->hdr.crls.deleteContext = CRYPT_ProvDeleteCRL; + ret->hdr.control = CRYPT_ProvControl; + if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC) + ret->provCloseStore = + pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC]; + else + ret->provCloseStore = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_WRITE_CERT_FUNC) + ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_WRITE_CERT_FUNC]; + else + ret->provWriteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_DELETE_CERT_FUNC) + ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_DELETE_CERT_FUNC]; + else + ret->provDeleteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_WRITE_CRL_FUNC) + ret->provWriteCrl = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_WRITE_CRL_FUNC]; + else + ret->provWriteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_DELETE_CRL_FUNC) + ret->provDeleteCrl = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_DELETE_CRL_FUNC]; + else + ret->provDeleteCert = NULL; + if (pProvInfo->cStoreProvFunc > + CERT_STORE_PROV_CONTROL_FUNC) + ret->provControl = pProvInfo->rgpvStoreProvFunc[ + CERT_STORE_PROV_CONTROL_FUNC]; + else + ret->provControl = NULL; + } + return (PWINECRYPT_CERTSTORE)ret; +} + +PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider, + DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara) +{ + static HCRYPTOIDFUNCSET set = NULL; + PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc; + HCRYPTOIDFUNCADDR hFunc; + PWINECRYPT_CERTSTORE ret = NULL; + + if (!set) + set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0); + CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0, + (void **)&provOpenFunc, &hFunc); + if (provOpenFunc) + { + CERT_STORE_PROV_INFO provInfo = { 0 }; + + provInfo.cbSize = sizeof(provInfo); + if (dwFlags & CERT_STORE_DELETE_FLAG) + provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, + dwFlags, pvPara, NULL, &provInfo); + else + { + HCERTSTORE memStore; + + memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (memStore) + { + if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, + dwFlags, pvPara, memStore, &provInfo)) + ret = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); + else + CertCloseStore(memStore, 0); + } + } + CryptFreeOIDFunctionAddress(hFunc, 0); + } + else + SetLastError(ERROR_FILE_NOT_FOUND); + return ret; +} diff --git a/reactos/dll/win32/crypt32/regstore.c b/reactos/dll/win32/crypt32/regstore.c new file mode 100644 index 00000000000..35928b8960a --- /dev/null +++ b/reactos/dll/win32/crypt32/regstore.c @@ -0,0 +1,550 @@ +/* + * Copyright 2004-2007 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wincrypt.h" +#include "winreg.h" +#include "winuser.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +typedef struct _WINE_HASH_TO_DELETE +{ + BYTE hash[20]; + struct list entry; +} WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE; + +typedef struct _WINE_REGSTOREINFO +{ + DWORD dwOpenFlags; + HCERTSTORE memStore; + HKEY key; + BOOL dirty; + CRITICAL_SECTION cs; + struct list certsToDelete; + struct list crlsToDelete; +} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO; + +static void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash) +{ + static const WCHAR fmt[] = { '%','0','2','X',0 }; + DWORD i; + + assert(hash); + assert(asciiHash); + + for (i = 0; i < 20; i++) + wsprintfW(asciiHash + i * 2, fmt, hash[i]); +} + +static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s', + 0 }; +static const WCHAR CRLsW[] = { 'C','R','L','s',0 }; +static const WCHAR CTLsW[] = { 'C','T','L','s',0 }; +static const WCHAR BlobW[] = { 'B','l','o','b',0 }; + +static void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, + HCERTSTORE store) +{ + LONG rc; + DWORD index = 0; + WCHAR subKeyName[MAX_PATH]; + + do { + DWORD size = sizeof(subKeyName) / sizeof(WCHAR); + + rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL, + NULL); + if (!rc) + { + HKEY subKey; + + rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); + if (!rc) + { + LPBYTE buf = NULL; + + size = 0; + rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size); + if (!rc) + buf = CryptMemAlloc(size); + if (buf) + { + rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf, + &size); + if (!rc) + { + const void *context; + DWORD addedType; + + TRACE("Adding cert with hash %s\n", + debugstr_w(subKeyName)); + context = CRYPT_ReadSerializedElement(buf, size, + contextType, &addedType); + if (context) + { + const WINE_CONTEXT_INTERFACE *contextInterface; + BYTE hash[20]; + + switch (addedType) + { + case CERT_STORE_CERTIFICATE_CONTEXT: + contextInterface = pCertInterface; + break; + case CERT_STORE_CRL_CONTEXT: + contextInterface = pCRLInterface; + break; + case CERT_STORE_CTL_CONTEXT: + contextInterface = pCTLInterface; + break; + default: + contextInterface = NULL; + } + if (contextInterface) + { + size = sizeof(hash); + if (contextInterface->getProp(context, + CERT_HASH_PROP_ID, hash, &size)) + { + WCHAR asciiHash[20 * 2 + 1]; + + CRYPT_HashToStr(hash, asciiHash); + TRACE("comparing %s\n", + debugstr_w(asciiHash)); + TRACE("with %s\n", debugstr_w(subKeyName)); + if (!lstrcmpW(asciiHash, subKeyName)) + { + TRACE("hash matches, adding\n"); + contextInterface->addContextToStore( + store, context, + CERT_STORE_ADD_REPLACE_EXISTING, NULL); + } + else + TRACE("hash doesn't match, ignoring\n"); + } + contextInterface->free(context); + } + } + } + CryptMemFree(buf); + } + RegCloseKey(subKey); + } + /* Ignore intermediate errors, continue enumerating */ + rc = ERROR_SUCCESS; + } + } while (!rc); +} + +static void CRYPT_RegReadFromReg(HKEY key, HCERTSTORE store) +{ + static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW }; + static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG, + CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG }; + DWORD i; + + for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++) + { + HKEY hKey; + LONG rc; + + rc = RegCreateKeyExW(key, subKeys[i], 0, NULL, 0, KEY_READ, NULL, + &hKey, NULL); + if (!rc) + { + CRYPT_RegReadSerializedFromReg(hKey, contextFlags[i], store); + RegCloseKey(hKey); + } + } +} + +/* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */ +static BOOL CRYPT_WriteSerializedToReg(HKEY key, const BYTE *hash, const BYTE *buf, + DWORD len) +{ + WCHAR asciiHash[20 * 2 + 1]; + LONG rc; + HKEY subKey; + BOOL ret; + + CRYPT_HashToStr(hash, asciiHash); + rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL, + &subKey, NULL); + if (!rc) + { + rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len); + RegCloseKey(subKey); + } + if (!rc) + ret = TRUE; + else + { + SetLastError(rc); + ret = FALSE; + } + return ret; +} + +static BOOL CRYPT_SerializeContextsToReg(HKEY key, + const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore) +{ + const void *context = NULL; + BOOL ret; + + do { + context = contextInterface->enumContextsInStore(memStore, context); + if (context) + { + BYTE hash[20]; + DWORD hashSize = sizeof(hash); + + ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash, + &hashSize); + if (ret) + { + DWORD size = 0; + LPBYTE buf = NULL; + + ret = contextInterface->serialize(context, 0, NULL, &size); + if (size) + buf = CryptMemAlloc(size); + if (buf) + { + ret = contextInterface->serialize(context, 0, buf, &size); + if (ret) + ret = CRYPT_WriteSerializedToReg(key, hash, buf, size); + } + CryptMemFree(buf); + } + } + else + ret = TRUE; + } while (ret && context != NULL); + if (context) + contextInterface->free(context); + return ret; +} + +static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store) +{ + static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW }; + const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface, + pCRLInterface, pCTLInterface }; + struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete, + NULL }; + BOOL ret = TRUE; + DWORD i; + + for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++) + { + HKEY key; + LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &key, NULL); + + if (!rc) + { + if (listToDelete[i]) + { + PWINE_HASH_TO_DELETE toDelete, next; + WCHAR asciiHash[20 * 2 + 1]; + + EnterCriticalSection(&store->cs); + LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i], + WINE_HASH_TO_DELETE, entry) + { + LONG rc; + + CRYPT_HashToStr(toDelete->hash, asciiHash); + TRACE("Removing %s\n", debugstr_w(asciiHash)); + rc = RegDeleteKeyW(key, asciiHash); + if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND) + { + SetLastError(rc); + ret = FALSE; + } + list_remove(&toDelete->entry); + CryptMemFree(toDelete); + } + LeaveCriticalSection(&store->cs); + } + ret = CRYPT_SerializeContextsToReg(key, interfaces[i], + store->memStore); + RegCloseKey(key); + } + else + { + SetLastError(rc); + ret = FALSE; + } + } + return ret; +} + +/* If force is true or the registry store is dirty, writes the contents of the + * store to the registry. + */ +static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force) +{ + BOOL ret; + + TRACE("(%p, %d)\n", store, force); + + if (store->dirty || force) + ret = CRYPT_RegWriteToReg(store); + else + ret = TRUE; + return ret; +} + +static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %08x)\n", store, dwFlags); + if (dwFlags) + FIXME("Unimplemented flags: %08x\n", dwFlags); + + CRYPT_RegFlushStore(store, FALSE); + RegCloseKey(store->key); + store->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&store->cs); + CryptMemFree(store); +} + +static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store, + const void *context, DWORD dwFlags) +{ + BOOL ret; + + if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG) + { + store->dirty = TRUE; + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store, + struct list *deleteList, const void *context, + PCWINE_CONTEXT_INTERFACE contextInterface) +{ + BOOL ret; + + if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG) + { + SetLastError(ERROR_ACCESS_DENIED); + ret = FALSE; + } + else + { + PWINE_HASH_TO_DELETE toDelete = + CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE)); + + if (toDelete) + { + DWORD size = sizeof(toDelete->hash); + + ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, + toDelete->hash, &size); + if (ret) + { + EnterCriticalSection(&store->cs); + list_add_tail(deleteList, &toDelete->entry); + LeaveCriticalSection(&store->cs); + } + else + { + CryptMemFree(toDelete); + ret = FALSE; + } + } + else + ret = FALSE; + if (ret) + store->dirty = TRUE; + } + return ret; +} + +static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); + + return CRYPT_RegWriteContext(store, cert, dwFlags); +} + +static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %08x)\n", store, pCertContext, dwFlags); + + return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext, + pCertInterface); +} + +static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT crl, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); + + return CRYPT_RegWriteContext(store, crl, dwFlags); +} + +static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT pCrlContext, DWORD dwFlags) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + + TRACE("(%p, %p, %08x)\n", store, pCrlContext, dwFlags); + + return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext, + pCRLInterface); +} + +static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; + BOOL ret; + + TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + switch (dwCtrlType) + { + case CERT_STORE_CTRL_RESYNC: + { + HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + CRYPT_RegFlushStore(store, FALSE); + CRYPT_RegReadFromReg(store->key, memStore); + I_CertUpdateStore(store->memStore, memStore, 0, 0); + CertCloseStore(memStore, 0); + ret = TRUE; + break; + } + case CERT_STORE_CTRL_COMMIT: + ret = CRYPT_RegFlushStore(store, + dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG); + break; + default: + FIXME("%d: stub\n", dwCtrlType); + ret = FALSE; + } + return ret; +} + +static void *regProvFuncs[] = { + CRYPT_RegCloseStore, + NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ + CRYPT_RegWriteCert, + CRYPT_RegDeleteCert, + NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ + CRYPT_RegWriteCRL, + CRYPT_RegDeleteCRL, + NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ + CRYPT_RegControl, +}; + +PWINECRYPT_CERTSTORE CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, + const void *pvPara) +{ + PWINECRYPT_CERTSTORE store = NULL; + + TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); + + if (dwFlags & CERT_STORE_DELETE_FLAG) + { + DWORD rc = RegDeleteTreeW((HKEY)pvPara, CertsW); + + if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) + rc = RegDeleteTreeW((HKEY)pvPara, CRLsW); + if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) + rc = RegDeleteTreeW((HKEY)pvPara, CTLsW); + if (rc == ERROR_NO_MORE_ITEMS) + rc = ERROR_SUCCESS; + SetLastError(rc); + } + else + { + HKEY key; + + if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, + GetCurrentProcess(), (LPHANDLE)&key, + dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS, + TRUE, 0)) + { + PWINECRYPT_CERTSTORE memStore; + + memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, hCryptProv, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (memStore) + { + PWINE_REGSTOREINFO regInfo = CryptMemAlloc( + sizeof(WINE_REGSTOREINFO)); + + if (regInfo) + { + CERT_STORE_PROV_INFO provInfo = { 0 }; + + regInfo->dwOpenFlags = dwFlags; + regInfo->memStore = memStore; + regInfo->key = key; + InitializeCriticalSection(®Info->cs); + regInfo->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_REGSTOREINFO->cs"); + list_init(®Info->certsToDelete); + list_init(®Info->crlsToDelete); + CRYPT_RegReadFromReg(regInfo->key, regInfo->memStore); + regInfo->dirty = FALSE; + provInfo.cbSize = sizeof(provInfo); + provInfo.cStoreProvFunc = sizeof(regProvFuncs) / + sizeof(regProvFuncs[0]); + provInfo.rgpvStoreProvFunc = regProvFuncs; + provInfo.hStoreProv = regInfo; + store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); + /* Reg store doesn't need crypto provider, so close it */ + if (hCryptProv && + !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) + CryptReleaseContext(hCryptProv, 0); + } + } + } + } + TRACE("returning %p\n", store); + return store; +} diff --git a/reactos/dll/win32/crypt32/rootstore.c b/reactos/dll/win32/crypt32/rootstore.c new file mode 100644 index 00000000000..df257dd4a91 --- /dev/null +++ b/reactos/dll/win32/crypt32/rootstore.c @@ -0,0 +1,514 @@ +/* + * Copyright 2007 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include "config.h" +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wincrypt.h" +#include "winternl.h" +#include "wine/debug.h" +#include "crypt32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +#define INITIAL_CERT_BUFFER 1024 + +struct DynamicBuffer +{ + DWORD allocated; + DWORD used; + BYTE *data; +}; + +static inline void reset_buffer(struct DynamicBuffer *buffer) +{ + buffer->used = 0; + if (buffer->data) buffer->data[0] = 0; +} + +static BOOL add_line_to_buffer(struct DynamicBuffer *buffer, LPCSTR line) +{ + BOOL ret; + + if (buffer->used + strlen(line) + 1 > buffer->allocated) + { + if (!buffer->allocated) + { + buffer->data = CryptMemAlloc(INITIAL_CERT_BUFFER); + if (buffer->data) + { + buffer->data[0] = 0; + buffer->allocated = INITIAL_CERT_BUFFER; + } + } + else + { + DWORD new_size = max(buffer->allocated * 2, + buffer->used + strlen(line) + 1); + + buffer->data = CryptMemRealloc(buffer->data, new_size); + if (buffer->data) + buffer->allocated = new_size; + } + } + if (buffer->data) + { + strcpy((char *)buffer->data + strlen((char *)buffer->data), line); + /* Not strlen + 1, otherwise we'd count the NULL for every line's + * addition (but we overwrite the previous NULL character.) Not an + * overrun, we allocate strlen + 1 bytes above. + */ + buffer->used += strlen(line); + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +/* Reads any base64-encoded certificates present in fp and adds them to store. + * Returns TRUE if any certificates were successfully imported. + */ +static BOOL import_base64_certs_from_fp(FILE *fp, HCERTSTORE store) +{ + char line[1024]; + BOOL in_cert = FALSE; + struct DynamicBuffer saved_cert = { 0, 0, NULL }; + int num_certs = 0; + + TRACE("\n"); + while (fgets(line, sizeof(line), fp)) + { + static const char header[] = "-----BEGIN CERTIFICATE-----"; + static const char trailer[] = "-----END CERTIFICATE-----"; + + if (!strncmp(line, header, strlen(header))) + { + TRACE("begin new certificate\n"); + in_cert = TRUE; + reset_buffer(&saved_cert); + } + else if (!strncmp(line, trailer, strlen(trailer))) + { + DWORD size; + + TRACE("end of certificate, adding cert\n"); + in_cert = FALSE; + if (CryptStringToBinaryA((char *)saved_cert.data, saved_cert.used, + CRYPT_STRING_BASE64, NULL, &size, NULL, NULL)) + { + LPBYTE buf = CryptMemAlloc(size); + + if (buf) + { + CryptStringToBinaryA((char *)saved_cert.data, + saved_cert.used, CRYPT_STRING_BASE64, buf, &size, NULL, + NULL); + if (CertAddEncodedCertificateToStore(store, + X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_NEW, NULL)) + num_certs++; + CryptMemFree(buf); + } + } + } + else if (in_cert) + add_line_to_buffer(&saved_cert, line); + } + CryptMemFree(saved_cert.data); + TRACE("Read %d certs\n", num_certs); + return num_certs > 0; +} + +static const char *trust_status_to_str(DWORD status) +{ + static char buf[1024]; + int pos = 0; + + if (status & CERT_TRUST_IS_NOT_TIME_VALID) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\texpired"); + if (status & CERT_TRUST_IS_NOT_TIME_NESTED) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\tbad time nesting"); + if (status & CERT_TRUST_IS_REVOKED) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\trevoked"); + if (status & CERT_TRUST_IS_NOT_SIGNATURE_VALID) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\tbad signature"); + if (status & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\tbad usage"); + if (status & CERT_TRUST_IS_UNTRUSTED_ROOT) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\tuntrusted root"); + if (status & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tunknown revocation status"); + if (status & CERT_TRUST_IS_CYCLIC) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\tcyclic chain"); + if (status & CERT_TRUST_INVALID_EXTENSION) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tunsupported critical extension"); + if (status & CERT_TRUST_INVALID_POLICY_CONSTRAINTS) + pos += snprintf(buf + pos, sizeof(buf) - pos, "\n\tbad policy"); + if (status & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tbad basic constraints"); + if (status & CERT_TRUST_INVALID_NAME_CONSTRAINTS) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tbad name constraints"); + if (status & CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tunsuported name constraint"); + if (status & CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tundefined name constraint"); + if (status & CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tdisallowed name constraint"); + if (status & CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\texcluded name constraint"); + if (status & CERT_TRUST_IS_OFFLINE_REVOCATION) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\trevocation server offline"); + if (status & CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY) + pos += snprintf(buf + pos, sizeof(buf) - pos, + "\n\tno issuance policy"); + return buf; +} + +static const char *get_cert_common_name(PCCERT_CONTEXT cert) +{ + static char buf[1024]; + const char *name = NULL; + CERT_NAME_INFO *nameInfo; + DWORD size; + BOOL ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, + cert->pCertInfo->Subject.pbData, cert->pCertInfo->Subject.cbData, + CRYPT_DECODE_NOCOPY_FLAG | CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, + &size); + + if (ret) + { + PCERT_RDN_ATTR commonName = CertFindRDNAttr(szOID_COMMON_NAME, + nameInfo); + + if (commonName) + { + CertRDNValueToStrA(commonName->dwValueType, + &commonName->Value, buf, sizeof(buf)); + name = buf; + } + LocalFree(nameInfo); + } + return name; +} + +static void check_and_store_certs(HCERTSTORE from, HCERTSTORE to) +{ + DWORD root_count = 0; + CERT_CHAIN_ENGINE_CONFIG chainEngineConfig = + { sizeof(chainEngineConfig), 0 }; + HCERTCHAINENGINE engine; + + TRACE("\n"); + + CertDuplicateStore(to); + engine = CRYPT_CreateChainEngine(to, &chainEngineConfig); + if (engine) + { + PCCERT_CONTEXT cert = NULL; + + do { + cert = CertEnumCertificatesInStore(from, cert); + if (cert) + { + CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; + PCCERT_CHAIN_CONTEXT chain; + BOOL ret = CertGetCertificateChain(engine, cert, NULL, from, + &chainPara, 0, NULL, &chain); + + if (!ret) + TRACE("rejecting %s: %s\n", get_cert_common_name(cert), + "chain creation failed"); + else + { + /* The only allowed error is CERT_TRUST_IS_UNTRUSTED_ROOT */ + if (chain->TrustStatus.dwErrorStatus & + ~CERT_TRUST_IS_UNTRUSTED_ROOT) + TRACE("rejecting %s: %s\n", get_cert_common_name(cert), + trust_status_to_str(chain->TrustStatus.dwErrorStatus & + ~CERT_TRUST_IS_UNTRUSTED_ROOT)); + else + { + DWORD i, j; + + for (i = 0; i < chain->cChain; i++) + for (j = 0; j < chain->rgpChain[i]->cElement; j++) + if (CertAddCertificateContextToStore(to, + chain->rgpChain[i]->rgpElement[j]->pCertContext, + CERT_STORE_ADD_NEW, NULL)) + root_count++; + } + CertFreeCertificateChain(chain); + } + } + } while (cert); + CertFreeCertificateChainEngine(engine); + } + TRACE("Added %d root certificates\n", root_count); +} + +/* Reads the file fd, and imports any certificates in it into store. + * Returns TRUE if any certificates were successfully imported. + */ +static BOOL import_certs_from_file(int fd, HCERTSTORE store) +{ + BOOL ret = FALSE; + FILE *fp; + + TRACE("\n"); + + fp = fdopen(fd, "r"); + if (fp) + { + ret = import_base64_certs_from_fp(fp, store); + fclose(fp); + } + return ret; +} + +static BOOL import_certs_from_path(LPCSTR path, HCERTSTORE store, + BOOL allow_dir); + +/* Opens path, which must be a directory, and imports certificates from every + * file in the directory into store. + * Returns TRUE if any certificates were successfully imported. + */ +static BOOL import_certs_from_dir(LPCSTR path, HCERTSTORE store) +{ + BOOL ret = FALSE; + DIR *dir; + + TRACE("(%s, %p)\n", debugstr_a(path), store); + /* UNIX functions = bad for reactos + dir = opendir(path); + if (dir) + { + size_t bufsize = strlen(path) + 1 + PATH_MAX + 1; + char *filebuf = CryptMemAlloc(bufsize); + + if (filebuf) + { + struct dirent *entry; + while ((entry = readdir(dir))) + { + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) + { + snprintf(filebuf, bufsize, "%s/%s", path, entry->d_name); + if (import_certs_from_path(filebuf, store, FALSE) && !ret) + ret = TRUE; + } + } + closedir(dir); + CryptMemFree(filebuf); + } + } + */ + return ret; +} + +/* Opens path, which may be a file or a directory, and imports any certificates + * it finds into store. + * Returns TRUE if any certificates were successfully imported. + */ +static BOOL import_certs_from_path(LPCSTR path, HCERTSTORE store, + BOOL allow_dir) +{ + BOOL ret = FALSE; + int fd; + + TRACE("(%s, %p, %d)\n", debugstr_a(path), store, allow_dir); + + fd = open(path, O_RDONLY); + if (fd != -1) + { + struct stat st; + + if (fstat(fd, &st) == 0) + { + if (S_ISREG(st.st_mode)) + ret = import_certs_from_file(fd, store); + else if (S_ISDIR(st.st_mode)) + { + if (allow_dir) + ret = import_certs_from_dir(path, store); + else + WARN("%s is a directory and directories are disallowed\n", + debugstr_a(path)); + } + else + ERR("%s: invalid file type\n", path); + } + close(fd); + } + return ret; +} + +static BOOL WINAPI CRYPT_RootWriteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + /* The root store can't have certs added */ + return FALSE; +} + +static BOOL WINAPI CRYPT_RootDeleteCert(HCERTSTORE hCertStore, + PCCERT_CONTEXT cert, DWORD dwFlags) +{ + /* The root store can't have certs deleted */ + return FALSE; +} + +static BOOL WINAPI CRYPT_RootWriteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT crl, DWORD dwFlags) +{ + /* The root store can have CRLs added. At worst, a malicious application + * can DoS itself, as the changes aren't persisted in any way. + */ + return TRUE; +} + +static BOOL WINAPI CRYPT_RootDeleteCRL(HCERTSTORE hCertStore, + PCCRL_CONTEXT crl, DWORD dwFlags) +{ + /* The root store can't have CRLs deleted */ + return FALSE; +} + +static void *rootProvFuncs[] = { + NULL, /* CERT_STORE_PROV_CLOSE_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ + CRYPT_RootWriteCert, + CRYPT_RootDeleteCert, + NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ + CRYPT_RootWriteCRL, + CRYPT_RootDeleteCRL, + NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */ + NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ + NULL, /* CERT_STORE_PROV_CONTROL_FUNC */ +}; + +static const char * const CRYPT_knownLocations[] = { + "/etc/ssl/certs/ca-certificates.crt", + "/etc/ssl/certs", + "/etc/pki/tls/certs/ca-bundle.crt", +}; + +/* Reads certificates from the list of known locations. Stops when any + * location contains any certificates, to prevent spending unnecessary time + * adding redundant certificates, e.g. when both a certificate bundle and + * individual certificates exist in the same directory. + */ +static PWINECRYPT_CERTSTORE CRYPT_RootOpenStoreFromKnownLocations(void) +{ + HCERTSTORE root = NULL; + HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY, + X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); + HCERTSTORE to = CertOpenStore(CERT_STORE_PROV_MEMORY, + X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); + + if (from && to) + { + CERT_STORE_PROV_INFO provInfo = { + sizeof(CERT_STORE_PROV_INFO), + sizeof(rootProvFuncs) / sizeof(rootProvFuncs[0]), + rootProvFuncs, + NULL, + 0, + NULL + }; + DWORD i; + BOOL ret = FALSE; + + for (i = 0; !ret && + i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]); + i++) + ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE); + check_and_store_certs(from, to); + root = CRYPT_ProvCreateStore(0, to, &provInfo); + } + CertCloseStore(from, 0); + TRACE("returning %p\n", root); + return root; +} + +static PWINECRYPT_CERTSTORE CRYPT_rootStore; + +PWINECRYPT_CERTSTORE CRYPT_RootOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags) +{ + TRACE("(%ld, %08x)\n", hCryptProv, dwFlags); + + if (dwFlags & CERT_STORE_DELETE_FLAG) + { + WARN("root store can't be deleted\n"); + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) + { + case CERT_SYSTEM_STORE_LOCAL_MACHINE: + case CERT_SYSTEM_STORE_CURRENT_USER: + break; + default: + TRACE("location %08x unsupported\n", + dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK); + SetLastError(E_INVALIDARG); + return NULL; + } + if (!CRYPT_rootStore) + { + HCERTSTORE root = CRYPT_RootOpenStoreFromKnownLocations(); + + InterlockedCompareExchangePointer((PVOID *)&CRYPT_rootStore, root, + NULL); + if (CRYPT_rootStore != root) + CertCloseStore(root, 0); + } + CertDuplicateStore(CRYPT_rootStore); + return CRYPT_rootStore; +} + +void root_store_free(void) +{ + CertCloseStore(CRYPT_rootStore, 0); +} diff --git a/reactos/dll/win32/crypt32/serialize.c b/reactos/dll/win32/crypt32/serialize.c index 49749e38a16..5f9911f774c 100644 --- a/reactos/dll/win32/crypt32/serialize.c +++ b/reactos/dll/win32/crypt32/serialize.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2006 Juan Lang + * Copyright 2004-2007 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -15,12 +15,15 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ + +#include "config.h" +#include "wine/port.h" + #include #include "windef.h" #include "winbase.h" #include "wincrypt.h" #include "wine/debug.h" -#include "excpt.h" #include "wine/exception.h" #include "crypt32_private.h" @@ -422,7 +425,7 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' }; -BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store) +BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) { BYTE fileHeaderBuf[sizeof(fileHeader)]; DWORD read; @@ -432,7 +435,11 @@ BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store) ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL); if (ret) { - if (!memcmp(fileHeaderBuf, fileHeader, read)) + if (!read) + ; /* an empty file is okay */ + else if (read != sizeof(fileHeaderBuf)) + ret = FALSE; + else if (!memcmp(fileHeaderBuf, fileHeader, read)) { WINE_CERT_PROP_HEADER propHdr; const void *context = NULL; @@ -504,6 +511,8 @@ BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store) CryptMemFree(buf); ret = TRUE; } + else + ret = FALSE; } else ret = TRUE; @@ -534,8 +543,11 @@ static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext, CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement); } -static BOOL CRYPT_SerializeContextsToFile(HANDLE file, - const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store) +typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer, + DWORD size); + +static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output, + void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store) { const void *context = NULL; BOOL ret; @@ -554,7 +566,7 @@ static BOOL CRYPT_SerializeContextsToFile(HANDLE file, { ret = contextInterface->serialize(context, 0, buf, &size); if (ret) - ret = WriteFile(file, buf, size, &size, NULL); + ret = output(handle, buf, size); } CryptMemFree(buf); } @@ -566,35 +578,307 @@ static BOOL CRYPT_SerializeContextsToFile(HANDLE file, return ret; } -BOOL CRYPT_WriteSerializedFile(HANDLE file, HCERTSTORE store) +static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store, + SerializedOutputFunc output, void *handle) { static const BYTE fileTrailer[12] = { 0 }; WINE_CONTEXT_INTERFACE interface; BOOL ret; - DWORD size; - SetFilePointer(file, 0, NULL, FILE_BEGIN); - ret = WriteFile(file, fileHeader, sizeof(fileHeader), &size, NULL); + ret = output(handle, fileHeader, sizeof(fileHeader)); if (ret) { memcpy(&interface, pCertInterface, sizeof(interface)); interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash; - ret = CRYPT_SerializeContextsToFile(file, &interface, store); + ret = CRYPT_SerializeContextsToStream(output, handle, &interface, + store); } if (ret) { memcpy(&interface, pCRLInterface, sizeof(interface)); interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash; - ret = CRYPT_SerializeContextsToFile(file, &interface, store); + ret = CRYPT_SerializeContextsToStream(output, handle, &interface, + store); } if (ret) { memcpy(&interface, pCTLInterface, sizeof(interface)); interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash; - ret = CRYPT_SerializeContextsToFile(file, &interface, store); + ret = CRYPT_SerializeContextsToStream(output, handle, &interface, + store); } if (ret) - ret = WriteFile(file, fileTrailer, sizeof(fileTrailer), &size, NULL); + ret = output(handle, fileTrailer, sizeof(fileTrailer)); + return ret; +} + +static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size) +{ + return WriteFile(handle, buffer, size, &size, NULL); +} + +static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store) +{ + SetFilePointer(file, 0, NULL, FILE_BEGIN); + return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc, + file); +} + +static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store, + DWORD dwMsgAndCertEncodingType, void *handle) +{ + CERT_BLOB *blob = (CERT_BLOB *)handle; + CRYPT_SIGNED_INFO signedInfo = { 0 }; + PCCERT_CONTEXT cert = NULL; + PCCRL_CONTEXT crl = NULL; + DWORD size; + BOOL ret = TRUE; + + TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData); + + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + signedInfo.cCertEncoded++; + } while (cert); + if (signedInfo.cCertEncoded) + { + signedInfo.rgCertEncoded = CryptMemAlloc( + signedInfo.cCertEncoded * sizeof(CERT_BLOB)); + if (!signedInfo.rgCertEncoded) + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + else + { + DWORD i = 0; + + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + { + signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded; + signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded; + i++; + } + } while (cert); + } + } + + do { + crl = CertEnumCRLsInStore(store, crl); + if (crl) + signedInfo.cCrlEncoded++; + } while (crl); + if (signedInfo.cCrlEncoded) + { + signedInfo.rgCrlEncoded = CryptMemAlloc( + signedInfo.cCrlEncoded * sizeof(CERT_BLOB)); + if (!signedInfo.rgCrlEncoded) + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + else + { + DWORD i = 0; + + do { + crl = CertEnumCRLsInStore(store, crl); + if (crl) + { + signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded; + signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded; + i++; + } + } while (crl); + } + } + if (ret) + { + ret = CRYPT_AsnEncodePKCSSignedInfo(&signedInfo, NULL, &size); + if (ret) + { + if (!blob->pbData) + blob->cbData = size; + else if (blob->cbData < size) + { + blob->cbData = size; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + blob->cbData = size; + ret = CRYPT_AsnEncodePKCSSignedInfo(&signedInfo, blob->pbData, + &blob->cbData); + } + } + } + CryptMemFree(signedInfo.rgCertEncoded); + CryptMemFree(signedInfo.rgCrlEncoded); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store, + DWORD dwMsgAndCertEncodingType, void *handle) +{ + CERT_BLOB blob = { 0, NULL }; + BOOL ret; + + TRACE("(%p)\n", handle); + + ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob); + if (ret) + { + blob.pbData = CryptMemAlloc(blob.cbData); + if (blob.pbData) + { + ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob); + if (ret) + ret = WriteFile(handle, blob.pbData, blob.cbData, + &blob.cbData, NULL); + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store, + DWORD dwMsgAndCertEncodingType, void *handle) +{ + return CRYPT_WriteSerializedStoreToFile(handle, store); +} + +struct MemWrittenTracker +{ + DWORD cbData; + BYTE *pbData; + DWORD written; +}; + +/* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */ +static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size) +{ + struct MemWrittenTracker *tracker = (struct MemWrittenTracker *)handle; + BOOL ret; + + if (tracker->written + size > tracker->cbData) + { + SetLastError(ERROR_MORE_DATA); + /* Update written so caller can notify its caller of the required size + */ + tracker->written += size; + ret = FALSE; + } + else + { + memcpy(tracker->pbData + tracker->written, buffer, size); + tracker->written += size; + ret = TRUE; + } + return ret; +} + +static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer, + DWORD size) +{ + *(DWORD *)handle += size; + return TRUE; +} + +static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store, + DWORD dwMsgAndCertEncodingType, void *handle) +{ + CERT_BLOB *blob = (CERT_BLOB *)handle; + DWORD size; + BOOL ret; + + ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes, + &size); + if (ret) + { + if (!blob->pbData) + blob->cbData = size; + else if (blob->cbData < size) + { + SetLastError(ERROR_MORE_DATA); + blob->cbData = size; + ret = FALSE; + } + else + { + struct MemWrittenTracker tracker = { blob->cbData, blob->pbData, + 0 }; + + ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc, + &tracker); + if (!ret && GetLastError() == ERROR_MORE_DATA) + blob->cbData = tracker.written; + } + } + TRACE("returning %d\n", ret); + return ret; +} + +BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType, + DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags) +{ + BOOL (*saveFunc)(HCERTSTORE, DWORD, void *); + void *handle; + BOOL ret; + + TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore, + dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags); + + switch (dwSaveAs) + { + case CERT_STORE_SAVE_AS_STORE: + case CERT_STORE_SAVE_AS_PKCS7: + break; + default: + WARN("unimplemented for %d\n", dwSaveAs); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + switch (dwSaveTo) + { + case CERT_STORE_SAVE_TO_FILE: + handle = pvSaveToPara; + saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ? + CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile; + break; + case CERT_STORE_SAVE_TO_FILENAME_A: + handle = CreateFileA((LPCSTR)pvSaveToPara, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, 0, NULL); + saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ? + CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile; + break; + case CERT_STORE_SAVE_TO_FILENAME_W: + handle = CreateFileW((LPCWSTR)pvSaveToPara, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, 0, NULL); + saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ? + CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile; + break; + case CERT_STORE_SAVE_TO_MEMORY: + handle = pvSaveToPara; + saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ? + CRYPT_SaveSerializedToMem : CRYPT_SavePKCSToMem; + break; + default: + WARN("unimplemented for %d\n", dwSaveTo); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle); + TRACE("returning %d\n", ret); return ret; } diff --git a/reactos/dll/win32/crypt32/sip.c b/reactos/dll/win32/crypt32/sip.c index f0250347dfb..869e2a95ca8 100644 --- a/reactos/dll/win32/crypt32/sip.c +++ b/reactos/dll/win32/crypt32/sip.c @@ -30,6 +30,7 @@ #include "winuser.h" #include "wine/debug.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); @@ -324,7 +325,7 @@ BOOL WINAPI CryptSIPRetrieveSubjectGuid dos = (IMAGE_DOS_HEADER *)pMapped; if (dos->e_magic == IMAGE_DOS_SIGNATURE) { - memcpy(pgSubject, &unknown, sizeof(GUID)); + *pgSubject = unknown; SetLastError(S_OK); bRet = TRUE; goto cleanup1; @@ -334,8 +335,8 @@ BOOL WINAPI CryptSIPRetrieveSubjectGuid * There is a lot more to be checked: * - Check for MSFC in the header * - Check for the keys CryptSIPDllIsMyFileType and CryptSIPDllIsMyFileType2 - * under HKLM\Software\Microsoft\Cryptography\OID\EncodingType 0. Here are - * functions listed that need check if a SIP Provider can deal with the + * under HKLM\Software\Microsoft\Cryptography\OID\EncodingType 0. Here are + * functions listed that need check if a SIP Provider can deal with the * given file. */ @@ -354,6 +355,165 @@ cleanup3: return bRet; } +static LONG CRYPT_OpenSIPFunctionKey(const GUID *guid, LPCWSTR function, + HKEY *key) +{ + WCHAR szFullKey[ 0x100 ]; + + lstrcpyW(szFullKey, szOID); + lstrcatW(szFullKey, function); + CRYPT_guid2wstr(guid, &szFullKey[lstrlenW(szFullKey)]); + return RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, key); +} + +/* Loads the function named function for the SIP specified by pgSubject, and + * returns it if found. Returns NULL on error. If the function is loaded, + * *pLib is set to the library in which it is found. + */ +static void *CRYPT_LoadSIPFunc(const GUID *pgSubject, LPCWSTR function, + HMODULE *pLib) +{ + LONG r; + HKEY key = NULL; + DWORD size; + WCHAR dllName[MAX_PATH]; + char functionName[MAX_PATH]; + HMODULE lib; + void *func = NULL; + + TRACE("(%s, %s)\n", debugstr_guid(pgSubject), debugstr_w(function)); + + r = CRYPT_OpenSIPFunctionKey(pgSubject, function, &key); + if (r) goto error; + + /* Read the DLL entry */ + size = sizeof(dllName); + r = RegQueryValueExW(key, szDllName, NULL, NULL, (LPBYTE)dllName, &size); + if (r) goto error; + + /* Read the Function entry */ + size = sizeof(functionName); + r = RegQueryValueExA(key, "FuncName", NULL, NULL, (LPBYTE)functionName, + &size); + if (r) goto error; + + lib = LoadLibraryW(dllName); + if (!lib) + goto error; + func = GetProcAddress(lib, functionName); + if (func) + *pLib = lib; + else + FreeLibrary(lib); + +error: + RegCloseKey(key); + TRACE("returning %p\n", func); + return func; +} + +typedef struct _WINE_SIP_PROVIDER { + GUID subject; + SIP_DISPATCH_INFO info; + struct list entry; +} WINE_SIP_PROVIDER; + +static struct list providers = { &providers, &providers }; +static CRITICAL_SECTION providers_cs; +static CRITICAL_SECTION_DEBUG providers_cs_debug = +{ + 0, 0, &providers_cs, + { &providers_cs_debug.ProcessLocksList, + &providers_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": providers_cs") } +}; +static CRITICAL_SECTION providers_cs = { &providers_cs_debug, -1, 0, 0, 0, 0 }; + +static void CRYPT_CacheSIP(const GUID *pgSubject, SIP_DISPATCH_INFO *info) +{ + WINE_SIP_PROVIDER *prov = CryptMemAlloc(sizeof(WINE_SIP_PROVIDER)); + + if (prov) + { + prov->subject = *pgSubject; + prov->info = *info; + EnterCriticalSection(&providers_cs); + list_add_tail(&providers, &prov->entry); + LeaveCriticalSection(&providers_cs); + } +} + +static WINE_SIP_PROVIDER *CRYPT_GetCachedSIP(const GUID *pgSubject) +{ + WINE_SIP_PROVIDER *provider = NULL, *ret = NULL; + + EnterCriticalSection(&providers_cs); + LIST_FOR_EACH_ENTRY(provider, &providers, WINE_SIP_PROVIDER, entry) + { + if (IsEqualGUID(pgSubject, &provider->subject)) + break; + } + if (provider && IsEqualGUID(pgSubject, &provider->subject)) + ret = provider; + LeaveCriticalSection(&providers_cs); + return ret; +} + +static inline BOOL CRYPT_IsSIPCached(const GUID *pgSubject) +{ + return CRYPT_GetCachedSIP(pgSubject) != NULL; +} + +void crypt_sip_free(void) +{ + WINE_SIP_PROVIDER *prov, *next; + + LIST_FOR_EACH_ENTRY_SAFE(prov, next, &providers, WINE_SIP_PROVIDER, entry) + { + list_remove(&prov->entry); + FreeLibrary(prov->info.hSIP); + CryptMemFree(prov); + } +} + +/* Loads the SIP for pgSubject into the global cache. Returns FALSE if the + * SIP isn't registered or is invalid. + */ +static BOOL CRYPT_LoadSIP(const GUID *pgSubject) +{ + SIP_DISPATCH_INFO sip = { 0 }; + HMODULE lib = NULL, temp = NULL; + + sip.pfGet = CRYPT_LoadSIPFunc(pgSubject, szGetSigned, &lib); + if (!sip.pfGet) + goto error; + sip.pfPut = CRYPT_LoadSIPFunc(pgSubject, szPutSigned, &temp); + if (!sip.pfPut || temp != lib) + goto error; + FreeLibrary(temp); + sip.pfCreate = CRYPT_LoadSIPFunc(pgSubject, szCreate, &temp); + if (!sip.pfCreate || temp != lib) + goto error; + FreeLibrary(temp); + sip.pfVerify = CRYPT_LoadSIPFunc(pgSubject, szVerify, &temp); + if (!sip.pfVerify || temp != lib) + goto error; + FreeLibrary(temp); + sip.pfRemove = CRYPT_LoadSIPFunc(pgSubject, szRemoveSigned, &temp); + if (!sip.pfRemove || temp != lib) + goto error; + FreeLibrary(temp); + sip.hSIP = lib; + CRYPT_CacheSIP(pgSubject, &sip); + return TRUE; + +error: + FreeLibrary(lib); + FreeLibrary(temp); + SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN); + return FALSE; +} + /*********************************************************************** * CryptSIPLoad (CRYPT32.@) * @@ -382,15 +542,24 @@ cleanup3: BOOL WINAPI CryptSIPLoad (const GUID *pgSubject, DWORD dwFlags, SIP_DISPATCH_INFO *pSipDispatch) { - FIXME("(%s %d %p) stub!\n", debugstr_guid(pgSubject), dwFlags, pSipDispatch); + TRACE("(%s %d %p)\n", debugstr_guid(pgSubject), dwFlags, pSipDispatch); if (!pgSubject || dwFlags != 0 || !pSipDispatch) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } + if (!CRYPT_IsSIPCached(pgSubject) && !CRYPT_LoadSIP(pgSubject)) + return FALSE; - return FALSE; + pSipDispatch->hSIP = NULL; + pSipDispatch->pfGet = CryptSIPGetSignedDataMsg; + pSipDispatch->pfPut = CryptSIPPutSignedDataMsg; + pSipDispatch->pfCreate = CryptSIPCreateIndirectData; + pSipDispatch->pfVerify = CryptSIPVerifyIndirectData; + pSipDispatch->pfRemove = CryptSIPRemoveSignedDataMsg; + + return TRUE; } /*********************************************************************** @@ -399,9 +568,15 @@ BOOL WINAPI CryptSIPLoad BOOL WINAPI CryptSIPCreateIndirectData(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pcbIndirectData, SIP_INDIRECT_DATA* pIndirectData) { - FIXME("(%p %p %p) stub\n", pSubjectInfo, pcbIndirectData, pIndirectData); + WINE_SIP_PROVIDER *sip; + BOOL ret = FALSE; - return FALSE; + TRACE("(%p %p %p)\n", pSubjectInfo, pcbIndirectData, pIndirectData); + + if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) + ret = sip->info.pfCreate(pSubjectInfo, pcbIndirectData, pIndirectData); + TRACE("returning %d\n", ret); + return ret; } /*********************************************************************** @@ -410,10 +585,17 @@ BOOL WINAPI CryptSIPCreateIndirectData(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pcb BOOL WINAPI CryptSIPGetSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pdwEncodingType, DWORD dwIndex, DWORD* pcbSignedDataMsg, BYTE* pbSignedDataMsg) { - FIXME("(%p %p %d %p %p) stub\n", pSubjectInfo, pdwEncodingType, dwIndex, + WINE_SIP_PROVIDER *sip; + BOOL ret = FALSE; + + TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, pcbSignedDataMsg, pbSignedDataMsg); - return FALSE; + if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) + ret = sip->info.pfGet(pSubjectInfo, pdwEncodingType, dwIndex, + pcbSignedDataMsg, pbSignedDataMsg); + TRACE("returning %d\n", ret); + return ret; } /*********************************************************************** @@ -422,10 +604,17 @@ BOOL WINAPI CryptSIPGetSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pdwEn BOOL WINAPI CryptSIPPutSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD pdwEncodingType, DWORD* pdwIndex, DWORD cbSignedDataMsg, BYTE* pbSignedDataMsg) { - FIXME("(%p %d %p %d %p) stub\n", pSubjectInfo, pdwEncodingType, pdwIndex, + WINE_SIP_PROVIDER *sip; + BOOL ret = FALSE; + + TRACE("(%p %d %p %d %p)\n", pSubjectInfo, pdwEncodingType, pdwIndex, cbSignedDataMsg, pbSignedDataMsg); - return FALSE; + if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) + ret = sip->info.pfPut(pSubjectInfo, pdwEncodingType, pdwIndex, + cbSignedDataMsg, pbSignedDataMsg); + TRACE("returning %d\n", ret); + return ret; } /*********************************************************************** @@ -434,9 +623,15 @@ BOOL WINAPI CryptSIPPutSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD pdwEnc BOOL WINAPI CryptSIPRemoveSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD dwIndex) { - FIXME("(%p %d) stub\n", pSubjectInfo, dwIndex); + WINE_SIP_PROVIDER *sip; + BOOL ret = FALSE; - return FALSE; + TRACE("(%p %d)\n", pSubjectInfo, dwIndex); + + if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) + ret = sip->info.pfRemove(pSubjectInfo, dwIndex); + TRACE("returning %d\n", ret); + return ret; } /*********************************************************************** @@ -445,7 +640,13 @@ BOOL WINAPI CryptSIPRemoveSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, BOOL WINAPI CryptSIPVerifyIndirectData(SIP_SUBJECTINFO* pSubjectInfo, SIP_INDIRECT_DATA* pIndirectData) { - FIXME("(%p %p) stub\n", pSubjectInfo, pIndirectData); + WINE_SIP_PROVIDER *sip; + BOOL ret = FALSE; - return FALSE; + TRACE("(%p %p)\n", pSubjectInfo, pIndirectData); + + if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) + ret = sip->info.pfVerify(pSubjectInfo, pIndirectData); + TRACE("returning %d\n", ret); + return ret; } diff --git a/reactos/dll/win32/crypt32/store.c b/reactos/dll/win32/crypt32/store.c index f0d7ec2a6b8..9534e5c2d3a 100644 --- a/reactos/dll/win32/crypt32/store.c +++ b/reactos/dll/win32/crypt32/store.c @@ -36,14 +36,11 @@ #include "wincrypt.h" #include "wine/debug.h" #include "wine/list.h" -#include "excpt.h" #include "wine/exception.h" #include "crypt32_private.h" WINE_DEFAULT_DEBUG_CHANNEL(crypt); -#define WINE_CRYPTCERTSTORE_MAGIC 0x74726563 - static const WINE_CONTEXT_INTERFACE gCertInterface = { (CreateContextFunc)CertCreateCertificateContext, (AddContextToStoreFunc)CertAddCertificateContextToStore, @@ -89,58 +86,6 @@ static const WINE_CONTEXT_INTERFACE gCTLInterface = { }; PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface; -struct WINE_CRYPTCERTSTORE; - -typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara); - -/* Called to enumerate the next context in a store. */ -typedef void * (*EnumFunc)(struct WINE_CRYPTCERTSTORE *store, void *pPrev); - -/* Called to add a context to a store. If toReplace is not NULL, - * context replaces toReplace in the store, and access checks should not be - * performed. Otherwise context is a new context, and it should only be - * added if the store allows it. If ppStoreContext is not NULL, the added - * context should be returned in *ppStoreContext. - */ -typedef BOOL (*AddFunc)(struct WINE_CRYPTCERTSTORE *store, void *context, - void *toReplace, const void **ppStoreContext); - -typedef BOOL (*DeleteFunc)(struct WINE_CRYPTCERTSTORE *store, void *context); - -typedef struct _CONTEXT_STORE -{ - AddFunc addContext; - EnumFunc enumContext; - DeleteFunc deleteContext; -} CONTEXT_STORE, *PCONTEXT_STORE; - -typedef enum _CertStoreType { - StoreTypeMem, - StoreTypeCollection, - StoreTypeProvider, -} CertStoreType; - -/* A cert store is polymorphic through the use of function pointers. A type - * is still needed to distinguish collection stores from other types. - * On the function pointers: - * - closeStore is called when the store's ref count becomes 0 - * - control is optional, but should be implemented by any store that supports - * persistence - */ -typedef struct WINE_CRYPTCERTSTORE -{ - DWORD dwMagic; - LONG ref; - DWORD dwOpenFlags; - HCRYPTPROV cryptProv; - CertStoreType type; - PFN_CERT_STORE_PROV_CLOSE closeStore; - CONTEXT_STORE certs; - CONTEXT_STORE crls; - PFN_CERT_STORE_PROV_CONTROL control; /* optional */ -} WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE; - typedef struct _WINE_MEMSTORE { WINECRYPT_CERTSTORE hdr; @@ -148,75 +93,58 @@ typedef struct _WINE_MEMSTORE struct ContextList *crls; } WINE_MEMSTORE, *PWINE_MEMSTORE; -typedef struct _WINE_HASH_TO_DELETE -{ - BYTE hash[20]; - struct list entry; -} WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE; - -typedef struct _WINE_REGSTOREINFO -{ - DWORD dwOpenFlags; - HCRYPTPROV cryptProv; - PWINECRYPT_CERTSTORE memStore; - HKEY key; - BOOL dirty; - CRITICAL_SECTION cs; - struct list certsToDelete; - struct list crlsToDelete; -} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO; - -typedef struct _WINE_FILESTOREINFO -{ - DWORD dwOpenFlags; - HCRYPTPROV cryptProv; - PWINECRYPT_CERTSTORE memStore; - HANDLE file; - BOOL dirty; -} WINE_FILESTOREINFO, *PWINE_FILESTOREINFO; - -typedef struct _WINE_STORE_LIST_ENTRY -{ - PWINECRYPT_CERTSTORE store; - DWORD dwUpdateFlags; - DWORD dwPriority; - struct list entry; -} WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY; - -typedef struct _WINE_COLLECTIONSTORE -{ - WINECRYPT_CERTSTORE hdr; - CRITICAL_SECTION cs; - struct list stores; -} WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE; - -typedef struct _WINE_PROVIDERSTORE -{ - WINECRYPT_CERTSTORE hdr; - DWORD dwStoreProvFlags; - PWINECRYPT_CERTSTORE memStore; - HCERTSTOREPROV hStoreProv; - PFN_CERT_STORE_PROV_CLOSE provCloseStore; - PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert; - PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert; - PFN_CERT_STORE_PROV_WRITE_CRL provWriteCrl; - PFN_CERT_STORE_PROV_DELETE_CRL provDeleteCrl; - PFN_CERT_STORE_PROV_CONTROL provControl; -} WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE; - -static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv, - DWORD dwFlags, CertStoreType type) +void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags, + CertStoreType type) { store->ref = 1; store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC; store->type = type; - if (!hCryptProv) - { - hCryptProv = CRYPT_GetDefaultProvider(); - dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG; - } - store->cryptProv = hCryptProv; store->dwOpenFlags = dwFlags; + store->properties = NULL; +} + +void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store) +{ + if (store->properties) + ContextPropertyList_Free(store->properties); + CryptMemFree(store); +} + +BOOL WINAPI I_CertUpdateStore(HCERTSTORE store1, HCERTSTORE store2, DWORD unk0, + DWORD unk1) +{ + static BOOL warned = FALSE; + const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface, + pCRLInterface, pCTLInterface }; + DWORD i; + + TRACE("(%p, %p, %08x, %08x)\n", store1, store2, unk0, unk1); + if (!warned) + { + FIXME("semi-stub\n"); + warned = TRUE; + } + + /* Poor-man's resync: empty first store, then add everything from second + * store to it. + */ + for (i = 0; i < sizeof(interfaces) / sizeof(interfaces[0]); i++) + { + const void *context; + + do { + context = interfaces[i]->enumContextsInStore(store1, NULL); + if (context) + interfaces[i]->deleteFromStore(context); + } while (context); + do { + context = interfaces[i]->enumContextsInStore(store2, context); + if (context) + interfaces[i]->addContextToStore(store1, context, + CERT_STORE_ADD_ALWAYS, NULL); + } while (context); + } + return TRUE; } static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert, @@ -301,12 +229,6 @@ static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext) return TRUE; } -static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store) -{ - ContextList_Empty(store->certs); - ContextList_Empty(store->crls); -} - static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) { WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore; @@ -317,7 +239,7 @@ static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) ContextList_Free(store->certs); ContextList_Free(store->crls); - CryptMemFree(store); + CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store); } static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, @@ -338,7 +260,7 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, if (store) { memset(store, 0, sizeof(WINE_MEMSTORE)); - CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem); + CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeMem); store->hdr.closeStore = CRYPT_MemCloseStore; store->hdr.certs.addContext = CRYPT_MemAddCert; store->hdr.certs.enumContext = CRYPT_MemEnumCert; @@ -351,1164 +273,24 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, sizeof(CERT_CONTEXT)); store->crls = ContextList_Create(pCRLInterface, sizeof(CRL_CONTEXT)); + /* Mem store doesn't need crypto provider, so close it */ + if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) + CryptReleaseContext(hCryptProv, 0); } } return (PWINECRYPT_CERTSTORE)store; } -static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags) -{ - PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; - PWINE_STORE_LIST_ENTRY entry, next; - - TRACE("(%p, %08x)\n", store, dwFlags); - - LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY, - entry) - { - TRACE("closing %p\n", entry); - CertCloseStore((HCERTSTORE)entry->store, dwFlags); - CryptMemFree(entry); - } - cs->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&cs->cs); - CryptMemFree(cs); -} - -static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store, - PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize, - BOOL addRef) -{ - void *ret = Context_CreateLinkContext(contextSize, child, - sizeof(PWINE_STORE_LIST_ENTRY), addRef); - - if (ret) - *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize) - = storeEntry; - - return ret; -} - -static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store, - unsigned int contextStoreOffset, void *context, void *toReplace, unsigned int contextSize, - void **pChildContext) -{ - BOOL ret; - void *childContext = NULL; - PWINE_STORE_LIST_ENTRY storeEntry = NULL; - - TRACE("(%p, %d, %p, %p, %d)\n", store, contextStoreOffset, context, - toReplace, contextSize); - - ret = FALSE; - if (toReplace) - { - void *existingLinked = Context_GetLinkedContext(toReplace, contextSize); - PCONTEXT_STORE contextStore; - - storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace, - contextSize); - contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store + - contextStoreOffset); - ret = contextStore->addContext(storeEntry->store, context, - existingLinked, (const void **)&childContext); - } - else - { - PWINE_STORE_LIST_ENTRY entry, next; - - EnterCriticalSection(&store->cs); - LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores, - WINE_STORE_LIST_ENTRY, entry) - { - if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG) - { - PCONTEXT_STORE contextStore = (PCONTEXT_STORE)( - (LPBYTE)entry->store + contextStoreOffset); - - storeEntry = entry; - ret = contextStore->addContext(entry->store, context, NULL, - (const void **)&childContext); - break; - } - } - LeaveCriticalSection(&store->cs); - if (!storeEntry) - SetLastError(E_ACCESSDENIED); - } - *pChildContext = childContext; - return ret; -} - -/* Advances a collection enumeration by one context, if possible, where - * advancing means: - * - calling the current store's enumeration function once, and returning - * the enumerated context if one is returned - * - moving to the next store if the current store has no more items, and - * recursively calling itself to get the next item. - * Returns NULL if the collection contains no more items or on error. - * Assumes the collection store's lock is held. - */ -static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store, - PWINE_STORE_LIST_ENTRY storeEntry, size_t contextStoreOffset, - PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize) -{ - void *ret, *child; - struct list *storeNext = list_next(&store->stores, &storeEntry->entry); - PCONTEXT_STORE contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store + - contextStoreOffset); - - TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev); - - if (pPrev) - { - /* Ref-counting funny business: "duplicate" (addref) the child, because - * the free(pPrev) below can cause the ref count to become negative. - */ - child = Context_GetLinkedContext(pPrev, contextSize); - contextInterface->duplicate(child); - child = contextStore->enumContext(storeEntry->store, child); - contextInterface->free(pPrev); - pPrev = NULL; - } - else - child = storeEntry->store->certs.enumContext(storeEntry->store, NULL); - if (child) - ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child, - contextSize, FALSE); - else - { - if (storeNext) - ret = CRYPT_CollectionAdvanceEnum(store, LIST_ENTRY(storeNext, - WINE_STORE_LIST_ENTRY, entry), contextStoreOffset, - contextInterface, NULL, contextSize); - else - { - SetLastError(CRYPT_E_NOT_FOUND); - ret = NULL; - } - } - TRACE("returning %p\n", ret); - return ret; -} - -static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert, - void *toReplace, const void **ppStoreContext) -{ - BOOL ret; - void *childContext = NULL; - PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; - - ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs), - cert, toReplace, sizeof(CERT_CONTEXT), &childContext); - if (ppStoreContext && childContext) - { - PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *) - Context_GetExtra(childContext, sizeof(CERT_CONTEXT)); - PCERT_CONTEXT context = - CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext, - sizeof(CERT_CONTEXT), TRUE); - - if (context) - context->hCertStore = store; - *ppStoreContext = context; - } - CertFreeCertificateContext((PCCERT_CONTEXT)childContext); - return ret; -} - -static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) -{ - PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; - void *ret; - - TRACE("(%p, %p)\n", store, pPrev); - - EnterCriticalSection(&cs->cs); - if (pPrev) - { - PWINE_STORE_LIST_ENTRY storeEntry = - *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev, - sizeof(CERT_CONTEXT)); - - ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, - offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, pPrev, - sizeof(CERT_CONTEXT)); - } - else - { - if (!list_empty(&cs->stores)) - { - PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next, - WINE_STORE_LIST_ENTRY, entry); - - ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, - offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, NULL, - sizeof(CERT_CONTEXT)); - } - else - { - SetLastError(CRYPT_E_NOT_FOUND); - ret = NULL; - } - } - LeaveCriticalSection(&cs->cs); - if (ret) - ((PCERT_CONTEXT)ret)->hCertStore = store; - TRACE("returning %p\n", ret); - return ret; -} - -static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store, - void *pCertContext) -{ - BOOL ret; - - TRACE("(%p, %p)\n", store, pCertContext); - - ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT) - Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT))); - return ret; -} - -static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl, - void *toReplace, const void **ppStoreContext) -{ - BOOL ret; - void *childContext = NULL; - PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; - - ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls), - crl, toReplace, sizeof(CRL_CONTEXT), &childContext); - if (ppStoreContext && childContext) - { - PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *) - Context_GetExtra(childContext, sizeof(CRL_CONTEXT)); - PCRL_CONTEXT context = - CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext, - sizeof(CRL_CONTEXT), TRUE); - - if (context) - context->hCertStore = store; - *ppStoreContext = context; - } - CertFreeCRLContext((PCCRL_CONTEXT)childContext); - return ret; -} - -static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev) -{ - PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store; - void *ret; - - TRACE("(%p, %p)\n", store, pPrev); - - EnterCriticalSection(&cs->cs); - if (pPrev) - { - PWINE_STORE_LIST_ENTRY storeEntry = - *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev, - sizeof(CRL_CONTEXT)); - - ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, - offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, pPrev, - sizeof(CRL_CONTEXT)); - } - else - { - if (!list_empty(&cs->stores)) - { - PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next, - WINE_STORE_LIST_ENTRY, entry); - - ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, - offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, NULL, - sizeof(CRL_CONTEXT)); - } - else - { - SetLastError(CRYPT_E_NOT_FOUND); - ret = NULL; - } - } - LeaveCriticalSection(&cs->cs); - if (ret) - ((PCRL_CONTEXT)ret)->hCertStore = store; - TRACE("returning %p\n", ret); - return ret; -} - -static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store, - void *pCrlContext) -{ - BOOL ret; - - TRACE("(%p, %p)\n", store, pCrlContext); - - ret = CertDeleteCRLFromStore((PCCRL_CONTEXT) - Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT))); - return ret; -} - -static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - PWINE_COLLECTIONSTORE store; - - if (dwFlags & CERT_STORE_DELETE_FLAG) - { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - store = NULL; - } - else - { - store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE)); - if (store) - { - memset(store, 0, sizeof(WINE_COLLECTIONSTORE)); - CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, - StoreTypeCollection); - store->hdr.closeStore = CRYPT_CollectionCloseStore; - store->hdr.certs.addContext = CRYPT_CollectionAddCert; - store->hdr.certs.enumContext = CRYPT_CollectionEnumCert; - store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert; - store->hdr.crls.addContext = CRYPT_CollectionAddCRL; - store->hdr.crls.enumContext = CRYPT_CollectionEnumCRL; - store->hdr.crls.deleteContext = CRYPT_CollectionDeleteCRL; - InitializeCriticalSection(&store->cs); - store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs"); - list_init(&store->stores); - } - } - return (PWINECRYPT_CERTSTORE)store; -} - -static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) -{ - PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; - - TRACE("(%p, %08x)\n", store, dwFlags); - - if (store->provCloseStore) - store->provCloseStore(store->hStoreProv, dwFlags); - if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)) - CertCloseStore(store->memStore, dwFlags); - CryptMemFree(store); -} - -static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert, - void *toReplace, const void **ppStoreContext) -{ - PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; - BOOL ret; - - TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext); - - if (toReplace) - ret = ps->memStore->certs.addContext(ps->memStore, cert, toReplace, - (const void **)ppStoreContext); - else - { - ret = TRUE; - if (ps->provWriteCert) - ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert, - CERT_STORE_PROV_WRITE_ADD_FLAG); - if (ret) - ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL, - (const void **)ppStoreContext); - } - /* dirty trick: replace the returned context's hCertStore with - * store. - */ - if (ppStoreContext) - (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store; - return ret; -} - -static void *CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) -{ - PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; - void *ret; - - ret = ps->memStore->certs.enumContext(ps->memStore, pPrev); - if (ret) - { - /* same dirty trick: replace the returned context's hCertStore with - * store. - */ - ((PCERT_CONTEXT)ret)->hCertStore = store; - } - return ret; -} - -static BOOL CRYPT_ProvDeleteCert(PWINECRYPT_CERTSTORE store, void *cert) -{ - PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; - BOOL ret = TRUE; - - TRACE("(%p, %p)\n", store, cert); - - if (ps->provDeleteCert) - ret = ps->provDeleteCert(ps->hStoreProv, cert, 0); - if (ret) - ret = ps->memStore->certs.deleteContext(ps->memStore, cert); - return ret; -} - -static BOOL CRYPT_ProvAddCRL(PWINECRYPT_CERTSTORE store, void *crl, - void *toReplace, const void **ppStoreContext) -{ - PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; - BOOL ret; - - TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext); - - if (toReplace) - ret = ps->memStore->crls.addContext(ps->memStore, crl, toReplace, - (const void **)ppStoreContext); - else - { - if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG) - { - SetLastError(ERROR_ACCESS_DENIED); - ret = FALSE; - } - else - { - ret = TRUE; - if (ps->provWriteCrl) - ret = ps->provWriteCrl(ps->hStoreProv, (PCCRL_CONTEXT)crl, - CERT_STORE_PROV_WRITE_ADD_FLAG); - if (ret) - ret = ps->memStore->crls.addContext(ps->memStore, crl, NULL, - (const void **)ppStoreContext); - } - } - /* dirty trick: replace the returned context's hCertStore with - * store. - */ - if (ppStoreContext) - (*(PCRL_CONTEXT *)ppStoreContext)->hCertStore = store; - return ret; -} - -static void *CRYPT_ProvEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev) -{ - PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; - void *ret; - - ret = ps->memStore->crls.enumContext(ps->memStore, pPrev); - if (ret) - { - /* same dirty trick: replace the returned context's hCertStore with - * store. - */ - ((PCERT_CONTEXT)ret)->hCertStore = store; - } - return ret; -} - -static BOOL CRYPT_ProvDeleteCRL(PWINECRYPT_CERTSTORE store, void *crl) -{ - PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store; - BOOL ret = TRUE; - - TRACE("(%p, %p)\n", store, crl); - - if (ps->provDeleteCrl) - ret = ps->provDeleteCrl(ps->hStoreProv, crl, 0); - if (ret) - ret = ps->memStore->crls.deleteContext(ps->memStore, crl); - return ret; -} - -static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags, - DWORD dwCtrlType, void const *pvCtrlPara) -{ - PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore; - BOOL ret = TRUE; - - TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, - pvCtrlPara); - - if (store->provControl) - ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType, - pvCtrlPara); - return ret; -} - -static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv, - DWORD dwFlags, PWINECRYPT_CERTSTORE memStore, const CERT_STORE_PROV_INFO *pProvInfo) -{ - PWINE_PROVIDERSTORE ret = (PWINE_PROVIDERSTORE)CryptMemAlloc( - sizeof(WINE_PROVIDERSTORE)); - - if (ret) - { - CRYPT_InitStore(&ret->hdr, hCryptProv, dwFlags, - StoreTypeProvider); - ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags; - if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG) - { - CertCloseStore(memStore, 0); - ret->memStore = NULL; - } - else - ret->memStore = memStore; - ret->hStoreProv = pProvInfo->hStoreProv; - ret->hdr.closeStore = CRYPT_ProvCloseStore; - ret->hdr.certs.addContext = CRYPT_ProvAddCert; - ret->hdr.certs.enumContext = CRYPT_ProvEnumCert; - ret->hdr.certs.deleteContext = CRYPT_ProvDeleteCert; - ret->hdr.crls.addContext = CRYPT_ProvAddCRL; - ret->hdr.crls.enumContext = CRYPT_ProvEnumCRL; - ret->hdr.crls.deleteContext = CRYPT_ProvDeleteCRL; - ret->hdr.control = CRYPT_ProvControl; - if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC) - ret->provCloseStore = - pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC]; - else - ret->provCloseStore = NULL; - if (pProvInfo->cStoreProvFunc > - CERT_STORE_PROV_WRITE_CERT_FUNC) - ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[ - CERT_STORE_PROV_WRITE_CERT_FUNC]; - else - ret->provWriteCert = NULL; - if (pProvInfo->cStoreProvFunc > - CERT_STORE_PROV_DELETE_CERT_FUNC) - ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[ - CERT_STORE_PROV_DELETE_CERT_FUNC]; - else - ret->provDeleteCert = NULL; - if (pProvInfo->cStoreProvFunc > - CERT_STORE_PROV_WRITE_CRL_FUNC) - ret->provWriteCrl = pProvInfo->rgpvStoreProvFunc[ - CERT_STORE_PROV_WRITE_CRL_FUNC]; - else - ret->provWriteCert = NULL; - if (pProvInfo->cStoreProvFunc > - CERT_STORE_PROV_DELETE_CRL_FUNC) - ret->provDeleteCrl = pProvInfo->rgpvStoreProvFunc[ - CERT_STORE_PROV_DELETE_CRL_FUNC]; - else - ret->provDeleteCert = NULL; - if (pProvInfo->cStoreProvFunc > - CERT_STORE_PROV_CONTROL_FUNC) - ret->provControl = pProvInfo->rgpvStoreProvFunc[ - CERT_STORE_PROV_CONTROL_FUNC]; - else - ret->provControl = NULL; - } - return (PWINECRYPT_CERTSTORE)ret; -} - -static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider, - DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara) -{ - static HCRYPTOIDFUNCSET set = NULL; - PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc; - HCRYPTOIDFUNCADDR hFunc; - PWINECRYPT_CERTSTORE ret = NULL; - - if (!set) - set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0); - CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0, - (void **)&provOpenFunc, &hFunc); - if (provOpenFunc) - { - CERT_STORE_PROV_INFO provInfo = { 0 }; - - provInfo.cbSize = sizeof(provInfo); - if (dwFlags & CERT_STORE_DELETE_FLAG) - provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, - dwFlags, pvPara, NULL, &provInfo); - else - { - HCERTSTORE memStore; - - memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, - CERT_STORE_CREATE_NEW_FLAG, NULL); - if (memStore) - { - if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv, - dwFlags, pvPara, memStore, &provInfo)) - ret = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore, - &provInfo); - else - CertCloseStore(memStore, 0); - } - } - CryptFreeOIDFunctionAddress(hFunc, 0); - } - else - SetLastError(ERROR_FILE_NOT_FOUND); - return ret; -} - -static void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash) -{ - static const WCHAR fmt[] = { '%','0','2','X',0 }; - DWORD i; - - assert(hash); - assert(asciiHash); - - for (i = 0; i < 20; i++) - wsprintfW(asciiHash + i * 2, fmt, hash[i]); -} - -static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s', - 0 }; -static const WCHAR CRLsW[] = { 'C','R','L','s',0 }; -static const WCHAR CTLsW[] = { 'C','T','L','s',0 }; -static const WCHAR BlobW[] = { 'B','l','o','b',0 }; - -static void CRYPT_RegReadSerializedFromReg(const WINE_REGSTOREINFO *store, HKEY key, - DWORD contextType) -{ - LONG rc; - DWORD index = 0; - WCHAR subKeyName[MAX_PATH]; - - do { - DWORD size = sizeof(subKeyName) / sizeof(WCHAR); - - rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL, - NULL); - if (!rc) - { - HKEY subKey; - - rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); - if (!rc) - { - LPBYTE buf = NULL; - - size = 0; - rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size); - if (!rc) - buf = CryptMemAlloc(size); - if (buf) - { - rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf, - &size); - if (!rc) - { - const void *context; - DWORD addedType; - - TRACE("Adding cert with hash %s\n", - debugstr_w(subKeyName)); - context = CRYPT_ReadSerializedElement(buf, size, - contextType, &addedType); - if (context) - { - const WINE_CONTEXT_INTERFACE *contextInterface; - BYTE hash[20]; - - switch (addedType) - { - case CERT_STORE_CERTIFICATE_CONTEXT: - contextInterface = &gCertInterface; - break; - case CERT_STORE_CRL_CONTEXT: - contextInterface = &gCRLInterface; - break; - case CERT_STORE_CTL_CONTEXT: - contextInterface = &gCTLInterface; - break; - default: - contextInterface = NULL; - } - if (contextInterface) - { - size = sizeof(hash); - if (contextInterface->getProp(context, - CERT_HASH_PROP_ID, hash, &size)) - { - WCHAR asciiHash[20 * 2 + 1]; - - CRYPT_HashToStr(hash, asciiHash); - TRACE("comparing %s\n", - debugstr_w(asciiHash)); - TRACE("with %s\n", debugstr_w(subKeyName)); - if (!lstrcmpW(asciiHash, subKeyName)) - { - TRACE("hash matches, adding\n"); - contextInterface->addContextToStore( - store->memStore, context, - CERT_STORE_ADD_REPLACE_EXISTING, NULL); - } - else - TRACE("hash doesn't match, ignoring\n"); - } - contextInterface->free(context); - } - } - } - CryptMemFree(buf); - } - RegCloseKey(subKey); - } - /* Ignore intermediate errors, continue enumerating */ - rc = ERROR_SUCCESS; - } - } while (!rc); -} - -static void CRYPT_RegReadFromReg(const WINE_REGSTOREINFO *store) -{ - static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW }; - static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG, - CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG }; - DWORD i; - - for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++) - { - HKEY key; - LONG rc; - - rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL, - &key, NULL); - if (!rc) - { - CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]); - RegCloseKey(key); - } - } -} - -/* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */ -static BOOL CRYPT_WriteSerializedToReg(HKEY key, const BYTE *hash, const BYTE *buf, - DWORD len) -{ - WCHAR asciiHash[20 * 2 + 1]; - LONG rc; - HKEY subKey; - BOOL ret; - - CRYPT_HashToStr(hash, asciiHash); - rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL, - &subKey, NULL); - if (!rc) - { - rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len); - RegCloseKey(subKey); - } - if (!rc) - ret = TRUE; - else - { - SetLastError(rc); - ret = FALSE; - } - return ret; -} - -static BOOL CRYPT_SerializeContextsToReg(HKEY key, - const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore) -{ - const void *context = NULL; - BOOL ret; - - do { - context = contextInterface->enumContextsInStore(memStore, context); - if (context) - { - BYTE hash[20]; - DWORD hashSize = sizeof(hash); - - ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash, - &hashSize); - if (ret) - { - DWORD size = 0; - LPBYTE buf = NULL; - - ret = contextInterface->serialize(context, 0, NULL, &size); - if (size) - buf = CryptMemAlloc(size); - if (buf) - { - ret = contextInterface->serialize(context, 0, buf, &size); - if (ret) - ret = CRYPT_WriteSerializedToReg(key, hash, buf, size); - } - CryptMemFree(buf); - } - } - else - ret = TRUE; - } while (ret && context != NULL); - if (context) - contextInterface->free(context); - return ret; -} - -static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store) -{ - static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW }; - static const WINE_CONTEXT_INTERFACE * const interfaces[] = { &gCertInterface, - &gCRLInterface, &gCTLInterface }; - struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete, - NULL }; - BOOL ret = TRUE; - DWORD i; - - for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++) - { - HKEY key; - LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, - KEY_ALL_ACCESS, NULL, &key, NULL); - - if (!rc) - { - if (listToDelete[i]) - { - PWINE_HASH_TO_DELETE toDelete, next; - WCHAR asciiHash[20 * 2 + 1]; - - EnterCriticalSection(&store->cs); - LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i], - WINE_HASH_TO_DELETE, entry) - { - LONG rc; - - CRYPT_HashToStr(toDelete->hash, asciiHash); - TRACE("Removing %s\n", debugstr_w(asciiHash)); - rc = RegDeleteKeyW(key, asciiHash); - if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND) - { - SetLastError(rc); - ret = FALSE; - } - list_remove(&toDelete->entry); - CryptMemFree(toDelete); - } - LeaveCriticalSection(&store->cs); - } - ret = CRYPT_SerializeContextsToReg(key, interfaces[i], - store->memStore); - RegCloseKey(key); - } - else - { - SetLastError(rc); - ret = FALSE; - } - } - return ret; -} - -/* If force is true or the registry store is dirty, writes the contents of the - * store to the registry. - */ -static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force) -{ - BOOL ret; - - TRACE("(%p, %d)\n", store, force); - - if (store->dirty || force) - ret = CRYPT_RegWriteToReg(store); - else - ret = TRUE; - return ret; -} - -static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %08x)\n", store, dwFlags); - if (dwFlags) - FIXME("Unimplemented flags: %08x\n", dwFlags); - - CRYPT_RegFlushStore(store, FALSE); - RegCloseKey(store->key); - store->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&store->cs); - CryptMemFree(store); -} - -static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store, - const void *context, DWORD dwFlags) -{ - BOOL ret; - - if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG) - { - store->dirty = TRUE; - ret = TRUE; - } - else - ret = FALSE; - return ret; -} - -static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store, - struct list *deleteList, const void *context, - PCWINE_CONTEXT_INTERFACE contextInterface) -{ - BOOL ret; - - if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG) - { - SetLastError(ERROR_ACCESS_DENIED); - ret = FALSE; - } - else - { - PWINE_HASH_TO_DELETE toDelete = - CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE)); - - if (toDelete) - { - DWORD size = sizeof(toDelete->hash); - - ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, - toDelete->hash, &size); - if (ret) - { - EnterCriticalSection(&store->cs); - list_add_tail(deleteList, &toDelete->entry); - LeaveCriticalSection(&store->cs); - } - else - { - CryptMemFree(toDelete); - ret = FALSE; - } - } - else - ret = FALSE; - if (ret) - store->dirty = TRUE; - } - return ret; -} - -static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT cert, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); - - return CRYPT_RegWriteContext(store, cert, dwFlags); -} - -static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %08x)\n", store, pCertContext, dwFlags); - - return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext, - pCertInterface); -} - -static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore, - PCCRL_CONTEXT crl, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); - - return CRYPT_RegWriteContext(store, crl, dwFlags); -} - -static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore, - PCCRL_CONTEXT pCrlContext, DWORD dwFlags) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - - TRACE("(%p, %p, %08x)\n", store, pCrlContext, dwFlags); - - return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext, - pCRLInterface); -} - -static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, - DWORD dwCtrlType, void const *pvCtrlPara) -{ - PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore; - BOOL ret; - - TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, - pvCtrlPara); - - switch (dwCtrlType) - { - case CERT_STORE_CTRL_RESYNC: - CRYPT_RegFlushStore(store, FALSE); - CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore); - CRYPT_RegReadFromReg(store); - ret = TRUE; - break; - case CERT_STORE_CTRL_COMMIT: - ret = CRYPT_RegFlushStore(store, - dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG); - break; - default: - FIXME("%d: stub\n", dwCtrlType); - ret = FALSE; - } - return ret; -} - -/* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */ -static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey) -{ - DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i; - WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; - HKEY hSubKey = 0; - - TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey)); - - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - if (!dwRet) - { - /* Find how many subkeys there are */ - dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, - &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); - if (!dwRet) - { - dwMaxSubkeyLen++; - if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR)) - { - /* Name too big: alloc a buffer for it */ - lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR)); - } - - if (!lpszName) - dwRet = ERROR_NOT_ENOUGH_MEMORY; - else - { - /* Recursively delete all the subkeys */ - for (i = 0; i < dwKeyCount && !dwRet; i++) - { - dwSize = dwMaxSubkeyLen; - dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, - NULL, NULL, NULL); - if (!dwRet) - dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName); - } - - if (lpszName != szNameBuf) - { - /* Free buffer if allocated */ - CryptMemFree(lpszName); - } - } - } - - RegCloseKey(hSubKey); - if (!dwRet) - dwRet = RegDeleteKeyW(hKey, lpszSubKey); - } - return dwRet; -} - -static void *regProvFuncs[] = { - CRYPT_RegCloseStore, - NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ - CRYPT_RegWriteCert, - CRYPT_RegDeleteCert, - NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ - NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ - CRYPT_RegWriteCRL, - CRYPT_RegDeleteCRL, - NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ - NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ - NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ - NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */ - NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ - CRYPT_RegControl, -}; - -static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - PWINECRYPT_CERTSTORE store = NULL; - - TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); - - if (dwFlags & CERT_STORE_DELETE_FLAG) - { - DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW); - - if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) - rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW); - if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS) - rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW); - if (rc == ERROR_NO_MORE_ITEMS) - rc = ERROR_SUCCESS; - SetLastError(rc); - } - else - { - HKEY key; - - if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, - GetCurrentProcess(), (LPHANDLE)&key, - dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS, - TRUE, 0)) - { - PWINECRYPT_CERTSTORE memStore; - - memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL); - if (memStore) - { - PWINE_REGSTOREINFO regInfo = CryptMemAlloc( - sizeof(WINE_REGSTOREINFO)); - - if (regInfo) - { - CERT_STORE_PROV_INFO provInfo = { 0 }; - - regInfo->dwOpenFlags = dwFlags; - regInfo->cryptProv = hCryptProv; - regInfo->memStore = memStore; - regInfo->key = key; - InitializeCriticalSection(®Info->cs); - regInfo->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_REGSTOREINFO->cs"); - list_init(®Info->certsToDelete); - list_init(®Info->crlsToDelete); - CRYPT_RegReadFromReg(regInfo); - regInfo->dirty = FALSE; - provInfo.cbSize = sizeof(provInfo); - provInfo.cStoreProvFunc = sizeof(regProvFuncs) / - sizeof(regProvFuncs[0]); - provInfo.rgpvStoreProvFunc = regProvFuncs; - provInfo.hStoreProv = regInfo; - store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore, - &provInfo); - } - } - } - } - TRACE("returning %p\n", store); - return store; -} - -/* FIXME: this isn't complete for the Root store, in which the top-level - * self-signed CA certs reside. Adding a cert to the Root store should present - * the user with a dialog indicating the consequences of doing so, and asking - * the user to confirm whether the cert should be added. - */ static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara) { + static const WCHAR rootW[] = { 'R','o','o','t',0 }; static const WCHAR fmt[] = { '%','s','\\','%','s',0 }; LPCWSTR storeName = (LPCWSTR)pvPara; LPWSTR storePath; PWINECRYPT_CERTSTORE store = NULL; HKEY root; LPCWSTR base; - BOOL ret; TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w((LPCWSTR)pvPara)); @@ -1518,8 +300,9 @@ static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv, SetLastError(E_INVALIDARG); return NULL; } + if (!lstrcmpiW(storeName, rootW)) + return CRYPT_RootOpenStore(hCryptProv, dwFlags); - ret = TRUE; switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) { case CERT_SYSTEM_STORE_LOCAL_MACHINE: @@ -1669,7 +452,7 @@ static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv, if (ret) { HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, - 0, hCryptProv, dwFlags, pvPara); + 0, 0, dwFlags, pvPara); if (regStore) { @@ -1688,7 +471,7 @@ static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv, dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER; dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE; regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, - hCryptProv, dwFlags, pvPara); + 0, dwFlags, pvPara); if (regStore) { CertAddStoreToCollection(store, regStore, @@ -1697,6 +480,9 @@ static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv, CertCloseStore(regStore, 0); } } + /* System store doesn't need crypto provider, so close it */ + if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) + CryptReleaseContext(hCryptProv, 0); } } return (PWINECRYPT_CERTSTORE)store; @@ -1731,244 +517,136 @@ static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv, return ret; } -static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) +static void WINAPI CRYPT_MsgCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) { - PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; + HCRYPTMSG msg = hCertStore; - TRACE("(%p, %08x)\n", store, dwFlags); - if (store->dirty) - CRYPT_WriteSerializedFile(store->file, store->memStore); - CertCloseStore(store->memStore, dwFlags); - CloseHandle(store->file); - CryptMemFree(store); + TRACE("(%p, %08x)\n", msg, dwFlags); + CryptMsgClose(msg); } -static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT cert, DWORD dwFlags) -{ - PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; - - TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); - store->dirty = TRUE; - return TRUE; -} - -static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore, - PCCERT_CONTEXT pCertContext, DWORD dwFlags) -{ - PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; - - TRACE("(%p, %p, %08x)\n", hCertStore, pCertContext, dwFlags); - store->dirty = TRUE; - return TRUE; -} - -static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore, - PCCRL_CONTEXT crl, DWORD dwFlags) -{ - PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; - - TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); - store->dirty = TRUE; - return TRUE; -} - -static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore, - PCCRL_CONTEXT pCrlContext, DWORD dwFlags) -{ - PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; - - TRACE("(%p, %p, %08x)\n", hCertStore, pCrlContext, dwFlags); - store->dirty = TRUE; - return TRUE; -} - -static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags, - DWORD dwCtrlType, void const *pvCtrlPara) -{ - PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; - BOOL ret; - - TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, - pvCtrlPara); - - switch (dwCtrlType) - { - case CERT_STORE_CTRL_RESYNC: - CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore); - CRYPT_ReadSerializedFile(store->file, store); - ret = TRUE; - break; - case CERT_STORE_CTRL_COMMIT: - if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) - { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - ret = FALSE; - } - else if (store->dirty) - ret = CRYPT_WriteSerializedFile(store->file, store->memStore); - else - ret = TRUE; - break; - default: - FIXME("%d: stub\n", dwCtrlType); - ret = FALSE; - } - return ret; -} - -static void *fileProvFuncs[] = { - CRYPT_FileCloseStore, - NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ - CRYPT_FileWriteCert, - CRYPT_FileDeleteCert, - NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ - NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ - CRYPT_FileWriteCRL, - CRYPT_FileDeleteCRL, - NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ - NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ - NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ - NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */ - NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ - CRYPT_FileControl, +static void *msgProvFuncs[] = { + CRYPT_MsgCloseStore, }; -static PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, +static PWINECRYPT_CERTSTORE CRYPT_MsgOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara) { PWINECRYPT_CERTSTORE store = NULL; - HANDLE file = (HANDLE)pvPara; + HCRYPTMSG msg = (HCRYPTMSG)pvPara; + PWINECRYPT_CERTSTORE memStore; TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); - if (!pvPara) + memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (memStore) { - SetLastError(ERROR_INVALID_HANDLE); - return NULL; - } - if (dwFlags & CERT_STORE_DELETE_FLAG) - { - SetLastError(E_INVALIDARG); - return NULL; - } - if ((dwFlags & CERT_STORE_READONLY_FLAG) && - (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) - { - SetLastError(E_INVALIDARG); - return NULL; - } + BOOL ret; + DWORD size, count, i; - if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, - GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ? - GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0)) - { - PWINECRYPT_CERTSTORE memStore; - - memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL); - if (memStore) + size = sizeof(count); + ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &count, &size); + for (i = 0; ret && i < count; i++) { - if (CRYPT_ReadSerializedFile(file, memStore)) + size = 0; + ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, NULL, &size); + if (ret) { - PWINE_FILESTOREINFO info = CryptMemAlloc( - sizeof(WINE_FILESTOREINFO)); + LPBYTE buf = CryptMemAlloc(size); - if (info) + if (buf) { - CERT_STORE_PROV_INFO provInfo = { 0 }; - - info->dwOpenFlags = dwFlags; - info->cryptProv = hCryptProv; - info->memStore = memStore; - info->file = file; - info->dirty = FALSE; - provInfo.cbSize = sizeof(provInfo); - provInfo.cStoreProvFunc = sizeof(fileProvFuncs) / - sizeof(fileProvFuncs[0]); - provInfo.rgpvStoreProvFunc = fileProvFuncs; - provInfo.hStoreProv = info; - store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore, - &provInfo); + ret = CryptMsgGetParam(msg, CMSG_CERT_PARAM, i, buf, &size); + if (ret) + ret = CertAddEncodedCertificateToStore(memStore, + X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS, + NULL); + CryptMemFree(buf); } } } + size = sizeof(count); + ret = CryptMsgGetParam(msg, CMSG_CRL_COUNT_PARAM, 0, &count, &size); + for (i = 0; ret && i < count; i++) + { + size = 0; + ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, NULL, &size); + if (ret) + { + LPBYTE buf = CryptMemAlloc(size); + + if (buf) + { + ret = CryptMsgGetParam(msg, CMSG_CRL_PARAM, i, buf, &size); + if (ret) + ret = CertAddEncodedCRLToStore(memStore, + X509_ASN_ENCODING, buf, size, CERT_STORE_ADD_ALWAYS, + NULL); + CryptMemFree(buf); + } + } + } + if (ret) + { + CERT_STORE_PROV_INFO provInfo = { 0 }; + + provInfo.cbSize = sizeof(provInfo); + provInfo.cStoreProvFunc = sizeof(msgProvFuncs) / + sizeof(msgProvFuncs[0]); + provInfo.rgpvStoreProvFunc = msgProvFuncs; + provInfo.hStoreProv = CryptMsgDuplicate(msg); + store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); + /* Msg store doesn't need crypto provider, so close it */ + if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) + CryptReleaseContext(hCryptProv, 0); + } + else + CertCloseStore(memStore, 0); } TRACE("returning %p\n", store); return store; } -static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, +static PWINECRYPT_CERTSTORE CRYPT_PKCSOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara) { - HCERTSTORE store = 0; - LPCWSTR fileName = (LPCWSTR)pvPara; - DWORD access, create; - HANDLE file; + HCRYPTMSG msg; + PWINECRYPT_CERTSTORE store = NULL; + const CRYPT_DATA_BLOB *data = (const CRYPT_DATA_BLOB *)pvPara; + BOOL ret; + DWORD msgOpenFlags = dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG ? 0 : + CMSG_CRYPT_RELEASE_CONTEXT_FLAG; - TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName)); + TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); - if (!fileName) + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, CMSG_SIGNED, + hCryptProv, NULL, NULL); + ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE); + if (!ret) { - SetLastError(ERROR_PATH_NOT_FOUND); - return NULL; - } - if (!(dwFlags & (CERT_FILE_STORE_COMMIT_ENABLE_FLAG | - CERT_STORE_READONLY_FLAG))) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return NULL; - } - - access = GENERIC_READ; - if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG) - access |= GENERIC_WRITE; - if (dwFlags & CERT_STORE_CREATE_NEW_FLAG) - create = CREATE_NEW; - else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG) - create = OPEN_EXISTING; - else - create = OPEN_ALWAYS; - file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create, - FILE_ATTRIBUTE_NORMAL, NULL); - if (file != INVALID_HANDLE_VALUE) - { - /* FIXME: need to check whether it's a serialized store; if not, fall - * back to a PKCS#7 signed message, then to a single serialized cert. - */ - store = CertOpenStore(CERT_STORE_PROV_FILE, 0, hCryptProv, dwFlags, - file); - CloseHandle(file); - } - return (PWINECRYPT_CERTSTORE)store; -} - -static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv, - DWORD dwFlags, const void *pvPara) -{ - int len; - PWINECRYPT_CERTSTORE ret = NULL; - - TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, - debugstr_a((LPCSTR)pvPara)); - - if (!pvPara) - { - SetLastError(ERROR_FILE_NOT_FOUND); - return NULL; - } - len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0); - if (len) - { - LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); - - if (storeName) + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, msgOpenFlags, 0, + hCryptProv, NULL, NULL); + ret = CryptMsgUpdate(msg, data->pbData, data->cbData, TRUE); + if (ret) { - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len); - ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName); - CryptMemFree(storeName); + DWORD type, size = sizeof(type); + + /* Only signed messages are allowed, check type */ + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &size); + if (ret && type != CMSG_SIGNED) + { + SetLastError(CRYPT_E_INVALID_MSG_TYPE); + ret = FALSE; + } } } - return ret; + if (ret) + store = CRYPT_MsgOpenStore(0, dwFlags, msg); + CryptMsgClose(msg); + TRACE("returning %p\n", store); + return store; } static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv, @@ -1983,7 +661,7 @@ static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv, } HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, - DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, + DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara) { WINECRYPT_CERTSTORE *hcs; @@ -1996,37 +674,43 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, { switch (LOWORD(lpszStoreProvider)) { - case (int)CERT_STORE_PROV_MEMORY: + case LOWORD(CERT_STORE_PROV_MSG): + openFunc = CRYPT_MsgOpenStore; + break; + case LOWORD(CERT_STORE_PROV_MEMORY): openFunc = CRYPT_MemOpenStore; break; - case (int)CERT_STORE_PROV_FILE: + case LOWORD(CERT_STORE_PROV_FILE): openFunc = CRYPT_FileOpenStore; break; - case (int)CERT_STORE_PROV_REG: + case LOWORD(CERT_STORE_PROV_PKCS7): + openFunc = CRYPT_PKCSOpenStore; + break; + case LOWORD(CERT_STORE_PROV_REG): openFunc = CRYPT_RegOpenStore; break; - case (int)CERT_STORE_PROV_FILENAME_A: + case LOWORD(CERT_STORE_PROV_FILENAME_A): openFunc = CRYPT_FileNameOpenStoreA; break; - case (int)CERT_STORE_PROV_FILENAME_W: + case LOWORD(CERT_STORE_PROV_FILENAME_W): openFunc = CRYPT_FileNameOpenStoreW; break; - case (int)CERT_STORE_PROV_COLLECTION: + case LOWORD(CERT_STORE_PROV_COLLECTION): openFunc = CRYPT_CollectionOpenStore; break; - case (int)CERT_STORE_PROV_SYSTEM_A: + case LOWORD(CERT_STORE_PROV_SYSTEM_A): openFunc = CRYPT_SysOpenStoreA; break; - case (int)CERT_STORE_PROV_SYSTEM_W: + case LOWORD(CERT_STORE_PROV_SYSTEM_W): openFunc = CRYPT_SysOpenStoreW; break; - case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A: + case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_A): openFunc = CRYPT_SysRegOpenStoreA; break; - case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W: + case LOWORD(CERT_STORE_PROV_SYSTEM_REGISTRY_W): openFunc = CRYPT_SysRegOpenStoreW; break; - case (int)CERT_STORE_PROV_PHYSICAL_W: + case LOWORD(CERT_STORE_PROV_PHYSICAL_W): openFunc = CRYPT_PhysOpenStoreW; break; default: @@ -2058,7 +742,7 @@ HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, return (HCERTSTORE)hcs; } -HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv, +HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv, LPCSTR szSubSystemProtocol) { if (!szSubSystemProtocol) @@ -2070,7 +754,7 @@ HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol); } -HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv, +HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv, LPCWSTR szSubSystemProtocol) { if (!szSubSystemProtocol) @@ -2082,29 +766,6 @@ HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol); } -BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType, - DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags) -{ - FIXME("(%p,%d,%d,%d,%p,%08x) stub!\n", hCertStore, - dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags); - return TRUE; -} - -DWORD CertStore_GetAccessState(HCERTSTORE hCertStore) -{ - DWORD state = 0; - - if (hCertStore) - { - PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; - - if (store->type != StoreTypeMem && - !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG)) - state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; - } - return state; -} - #define CertContext_CopyProperties(to, from) \ Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT)) @@ -2119,12 +780,6 @@ BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, dwAddDisposition, ppStoreContext); - /* Weird case to pass a test */ - if (dwAddDisposition == 0) - { - SetLastError(STATUS_ACCESS_VIOLATION); - return FALSE; - } if (dwAddDisposition != CERT_STORE_ADD_ALWAYS) { BYTE hashToAdd[20]; @@ -2167,10 +822,32 @@ BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, break; case CERT_STORE_ADD_USE_EXISTING: if (existing) + { CertContext_CopyProperties(existing, pCertContext); + *ppStoreContext = CertDuplicateCertificateContext(existing); + } + else + toAdd = CertDuplicateCertificateContext(pCertContext); + break; + case CERT_STORE_ADD_NEWER: + if (existing) + { + if (CompareFileTime(&existing->pCertInfo->NotBefore, + &pCertContext->pCertInfo->NotBefore) >= 0) + { + TRACE("existing certificate is newer, not adding\n"); + SetLastError(CRYPT_E_EXISTS); + ret = FALSE; + } + else + toAdd = CertDuplicateCertificateContext(pCertContext); + } + else + toAdd = CertDuplicateCertificateContext(pCertContext); break; default: FIXME("Unimplemented add disposition %d\n", dwAddDisposition); + SetLastError(E_INVALIDARG); ret = FALSE; } @@ -2445,8 +1122,6 @@ BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) { TRACE("%p's ref count is 0, freeing\n", hcs); hcs->dwMagic = 0; - if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) - CryptReleaseContext(hcs->cryptProv, 0); hcs->closeStore(hcs, dwFlags); } else @@ -2477,6 +1152,102 @@ BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags, return ret; } +BOOL WINAPI CertGetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId, + void *pvData, DWORD *pcbData) +{ + PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; + BOOL ret = FALSE; + + TRACE("(%p, %d, %p, %p)\n", hCertStore, dwPropId, pvData, pcbData); + + switch (dwPropId) + { + case CERT_ACCESS_STATE_PROP_ID: + if (!pvData) + { + *pcbData = sizeof(DWORD); + ret = TRUE; + } + else if (*pcbData < sizeof(DWORD)) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = sizeof(DWORD); + } + else + { + DWORD state = 0; + + if (store->type != StoreTypeMem && + !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG)) + state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; + *(DWORD *)pvData = state; + ret = TRUE; + } + break; + default: + if (store->properties) + { + CRYPT_DATA_BLOB blob; + + ret = ContextPropertyList_FindProperty(store->properties, dwPropId, + &blob); + if (ret) + { + if (!pvData) + *pcbData = blob.cbData; + else if (*pcbData < blob.cbData) + { + SetLastError(ERROR_MORE_DATA); + *pcbData = blob.cbData; + ret = FALSE; + } + else + { + memcpy(pvData, blob.pbData, blob.cbData); + *pcbData = blob.cbData; + } + } + else + SetLastError(CRYPT_E_NOT_FOUND); + } + else + SetLastError(CRYPT_E_NOT_FOUND); + } + return ret; +} + +BOOL WINAPI CertSetStoreProperty(HCERTSTORE hCertStore, DWORD dwPropId, + DWORD dwFlags, const void *pvData) +{ + PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore; + BOOL ret = FALSE; + + TRACE("(%p, %d, %08x, %p)\n", hCertStore, dwPropId, dwFlags, pvData); + + if (!store->properties) + store->properties = ContextPropertyList_Create(); + switch (dwPropId) + { + case CERT_ACCESS_STATE_PROP_ID: + SetLastError(E_INVALIDARG); + break; + default: + if (pvData) + { + const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData; + + ret = ContextPropertyList_SetProperty(store->properties, dwPropId, + blob->pbData, blob->cbData); + } + else + { + ContextPropertyList_RemoveProperty(store->properties, dwPropId); + ret = TRUE; + } + } + return ret; +} + DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext, DWORD dwPropId) { @@ -2499,108 +1270,89 @@ BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext, return FALSE; } -BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore, - HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority) +static LONG CRYPT_OpenParentStore(DWORD dwFlags, + void *pvSystemStoreLocationPara, HKEY *key) { - PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; - WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; - PWINE_STORE_LIST_ENTRY entry; - BOOL ret; + HKEY root; + LPCWSTR base; - TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore, - dwUpdateFlags, dwPriority); + TRACE("(%08x, %p)\n", dwFlags, pvSystemStoreLocationPara); - if (!collection || !sibling) - return TRUE; - if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) { - SetLastError(E_INVALIDARG); - return FALSE; - } - if (collection->hdr.type != StoreTypeCollection) - { - SetLastError(E_INVALIDARG); - return FALSE; - } - if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(E_INVALIDARG); - return FALSE; + case CERT_SYSTEM_STORE_LOCAL_MACHINE: + root = HKEY_LOCAL_MACHINE; + base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_CURRENT_USER: + root = HKEY_CURRENT_USER; + base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_CURRENT_SERVICE: + /* hklm\Software\Microsoft\Cryptography\Services\servicename\ + * SystemCertificates + */ + FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE\n"); + return ERROR_FILE_NOT_FOUND; + case CERT_SYSTEM_STORE_SERVICES: + /* hklm\Software\Microsoft\Cryptography\Services\servicename\ + * SystemCertificates + */ + FIXME("CERT_SYSTEM_STORE_SERVICES\n"); + return ERROR_FILE_NOT_FOUND; + case CERT_SYSTEM_STORE_USERS: + /* hku\user sid\Software\Microsoft\SystemCertificates */ + FIXME("CERT_SYSTEM_STORE_USERS\n"); + return ERROR_FILE_NOT_FOUND; + case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: + root = HKEY_CURRENT_USER; + base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: + root = HKEY_LOCAL_MACHINE; + base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH; + break; + case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: + /* hklm\Software\Microsoft\EnterpriseCertificates */ + FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE\n"); + return ERROR_FILE_NOT_FOUND; + default: + return ERROR_FILE_NOT_FOUND; } - entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY)); - if (entry) - { - InterlockedIncrement(&sibling->ref); - TRACE("sibling %p's ref count is %d\n", sibling, sibling->ref); - entry->store = sibling; - entry->dwUpdateFlags = dwUpdateFlags; - entry->dwPriority = dwPriority; - list_init(&entry->entry); - TRACE("%p: adding %p, priority %d\n", collection, entry, dwPriority); - EnterCriticalSection(&collection->cs); - if (dwPriority) - { - PWINE_STORE_LIST_ENTRY cursor; - BOOL added = FALSE; + return RegOpenKeyExW(root, base, 0, KEY_READ, key); +} + +BOOL WINAPI CertEnumSystemStore(DWORD dwFlags, void *pvSystemStoreLocationPara, + void *pvArg, PFN_CERT_ENUM_SYSTEM_STORE pfnEnum) +{ + BOOL ret = FALSE; + LONG rc; + HKEY key; + + TRACE("(%08x, %p, %p, %p)\n", dwFlags, pvSystemStoreLocationPara, pvArg, + pfnEnum); + + rc = CRYPT_OpenParentStore(dwFlags, pvArg, &key); + if (!rc) + { + DWORD index = 0; + CERT_SYSTEM_STORE_INFO info = { sizeof(info) }; - LIST_FOR_EACH_ENTRY(cursor, &collection->stores, - WINE_STORE_LIST_ENTRY, entry) - { - if (cursor->dwPriority < dwPriority) - { - list_add_before(&cursor->entry, &entry->entry); - added = TRUE; - break; - } - } - if (!added) - list_add_tail(&collection->stores, &entry->entry); - } - else - list_add_tail(&collection->stores, &entry->entry); - LeaveCriticalSection(&collection->cs); ret = TRUE; + do { + WCHAR name[MAX_PATH]; + DWORD size = sizeof(name) / sizeof(name[0]); + + rc = RegEnumKeyExW(key, index++, name, &size, NULL, NULL, NULL, + NULL); + if (!rc) + ret = pfnEnum(name, 0, &info, NULL, pvArg); + } while (ret && !rc); + if (ret && rc != ERROR_NO_MORE_ITEMS) + SetLastError(rc); } else - ret = FALSE; + SetLastError(rc); return ret; } - -void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore, - HCERTSTORE hSiblingStore) -{ - PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore; - WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore; - PWINE_STORE_LIST_ENTRY store, next; - - TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore); - - if (!collection || !sibling) - return; - if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(E_INVALIDARG); - return; - } - if (collection->hdr.type != StoreTypeCollection) - return; - if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) - { - SetLastError(E_INVALIDARG); - return; - } - EnterCriticalSection(&collection->cs); - LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores, - WINE_STORE_LIST_ENTRY, entry) - { - if (store->store == sibling) - { - list_remove(&store->entry); - CertCloseStore(store->store, 0); - CryptMemFree(store); - break; - } - } - LeaveCriticalSection(&collection->cs); -} diff --git a/reactos/dll/win32/crypt32/str.c b/reactos/dll/win32/crypt32/str.c index 1639b8f94bb..699779fb6e0 100644 --- a/reactos/dll/win32/crypt32/str.c +++ b/reactos/dll/win32/crypt32/str.c @@ -59,6 +59,17 @@ DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, } } break; + case CERT_RDN_UTF8_STRING: + if (!psz || !csz) + ret = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pValue->pbData, + pValue->cbData / sizeof(WCHAR) + 1, NULL, 0, NULL, NULL); + else + { + ret = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pValue->pbData, + pValue->cbData / sizeof(WCHAR) + 1, psz, csz - 1, NULL, NULL); + csz -= ret; + } + break; default: FIXME("string type %d unimplemented\n", dwValueType); } @@ -110,6 +121,24 @@ DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue, } } break; + case CERT_RDN_UTF8_STRING: + if (!psz || !csz) + ret = pValue->cbData / sizeof(WCHAR); + else + { + DWORD chars = min(pValue->cbData / sizeof(WCHAR), csz - 1); + + if (chars) + { + DWORD i; + + for (i = 0; i < chars; i++) + psz[i] = *((LPWSTR)pValue->pbData + i); + ret += chars; + csz -= chars; + } + } + break; default: FIXME("string type %d unimplemented\n", dwValueType); } @@ -224,7 +253,7 @@ DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, } /* FIXME: handle quoting */ chars = CertRDNValueToStrA( - info->rgRDN[i].rgRDNAttr[j].dwValueType, + info->rgRDN[i].rgRDNAttr[j].dwValueType, &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL, psz ? csz - ret : 0); if (chars) @@ -389,7 +418,7 @@ DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, } /* FIXME: handle quoting */ chars = CertRDNValueToStrW( - info->rgRDN[i].rgRDNAttr[j].dwValueType, + info->rgRDN[i].rgRDNAttr[j].dwValueType, &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL, psz ? csz - ret : 0); if (chars) @@ -426,7 +455,6 @@ BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500, DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded, LPCSTR *ppszError) { - LPWSTR x500, errorStr; BOOL ret; int len; @@ -435,24 +463,44 @@ BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500, ppszError); len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0); - x500 = CryptMemAlloc(len * sizeof(WCHAR)); - if (x500) + if (len) { - MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len); - ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType, pvReserved, - pbEncoded, pcbEncoded, ppszError ? (LPCWSTR *)&errorStr : NULL); - if (ppszError) - { - DWORD i; + LPWSTR x500, errorStr; - *ppszError = pszX500; - for (i = 0; i < errorStr - x500; i++) - CharNextA(*ppszError); + if ((x500 = CryptMemAlloc(len * sizeof(WCHAR)))) + { + MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len); + ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType, + pvReserved, pbEncoded, pcbEncoded, + ppszError ? (LPCWSTR *)&errorStr : NULL); + if (ppszError) + { + if (!ret) + { + DWORD i; + + *ppszError = pszX500; + for (i = 0; i < errorStr - x500; i++) + *ppszError = CharNextA(*ppszError); + } + else + *ppszError = NULL; + } + CryptMemFree(x500); + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; } - CryptMemFree(x500); } else + { + SetLastError(CRYPT_E_INVALID_X500_STRING); + if (ppszError) + *ppszError = pszX500; ret = FALSE; + } return ret; } @@ -501,10 +549,10 @@ static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper, TRACE("Keyname is %s\n", debugstr_w(keeper->keyName)); } -static DWORD CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token, +static BOOL CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token, LPCWSTR *ppszError) { - DWORD ret = ERROR_SUCCESS; + BOOL ret = TRUE; while (*str && isspaceW(*str)) str++; @@ -520,7 +568,8 @@ static DWORD CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token, TRACE("missing equals char at %s\n", debugstr_w(token->start)); if (ppszError) *ppszError = token->start; - ret = CRYPT_E_INVALID_X500_STRING; + SetLastError(CRYPT_E_INVALID_X500_STRING); + ret = FALSE; } } else @@ -529,10 +578,10 @@ static DWORD CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token, } /* Assumes separators are characters in the 0-255 range */ -static DWORD CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators, +static BOOL CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators, struct X500TokenW *token, LPCWSTR *ppszError) { - DWORD ret = ERROR_SUCCESS; + BOOL ret = TRUE; TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token, ppszError); @@ -546,7 +595,7 @@ static DWORD CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators, { token->end = NULL; str++; - while (!token->end && !ret) + while (!token->end && ret) { while (*str && *str != '"') str++; @@ -562,7 +611,8 @@ static DWORD CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators, TRACE("unterminated quote at %s\n", debugstr_w(str)); if (ppszError) *ppszError = str; - ret = CRYPT_E_INVALID_X500_STRING; + SetLastError(CRYPT_E_INVALID_X500_STRING); + ret = FALSE; } } } @@ -572,7 +622,7 @@ static DWORD CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators, while (*separators) map[*separators++] = 1; - while (*str && (*str >= 0xff || !map[*(const unsigned short *)str])) + while (*str && (*str >= 0xff || !map[*str])) str++; token->end = str; } @@ -582,7 +632,8 @@ static DWORD CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators, TRACE("missing value at %s\n", debugstr_w(str)); if (ppszError) *ppszError = str; - ret = CRYPT_E_INVALID_X500_STRING; + SetLastError(CRYPT_E_INVALID_X500_STRING); + ret = FALSE; } return ret; } @@ -597,22 +648,33 @@ static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType, LPCWSTR *ppszError) { CERT_NAME_VALUE nameValue = { type, { 0, NULL } }; - BOOL ret = FALSE; + BOOL ret = TRUE; - nameValue.Value.pbData = CryptMemAlloc((value->end - value->start) * - sizeof(WCHAR)); - if (nameValue.Value.pbData) + if (value->end > value->start) { - DWORD i; - LPWSTR ptr = (LPWSTR)nameValue.Value.pbData; - - for (i = 0; i < value->end - value->start; i++) + nameValue.Value.pbData = CryptMemAlloc((value->end - value->start) * + sizeof(WCHAR)); + if (!nameValue.Value.pbData) { - *ptr++ = value->start[i]; - if (value->start[i] == '"') - i++; + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + if (ret) + { + if (value->end > value->start) + { + DWORD i; + LPWSTR ptr = (LPWSTR)nameValue.Value.pbData; + + for (i = 0; i < value->end - value->start; i++) + { + *ptr++ = value->start[i]; + if (value->start[i] == '"') + i++; + } + nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData; } - nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData; ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE, &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData, &output->cbData); @@ -690,9 +752,12 @@ static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info, ret = CRYPT_EncodeValue(dwCertEncodingType, value, &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError); } - } - if (ret) + else + SetLastError(ERROR_OUTOFMEMORY); info->cRDN++; + } + else + SetLastError(ERROR_OUTOFMEMORY); return ret; } @@ -703,7 +768,7 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, CERT_NAME_INFO info = { 0, NULL }; LPCWSTR str; struct KeynameKeeper keeper; - DWORD i, error = ERROR_SUCCESS; + DWORD i; BOOL ret = TRUE; TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType, @@ -712,12 +777,12 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, CRYPT_InitializeKeynameKeeper(&keeper); str = pszX500; - while (str && *str && !error && ret) + while (str && *str && ret) { struct X500TokenW token; - error = CRYPT_GetNextKeyW(str, &token, ppszError); - if (!error && token.start) + ret = CRYPT_GetNextKeyW(str, &token, ppszError); + if (ret && token.start) { PCCRYPT_OID_INFO keyOID; @@ -728,7 +793,8 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, { if (ppszError) *ppszError = token.start; - error = CRYPT_E_INVALID_X500_STRING; + SetLastError(CRYPT_E_INVALID_X500_STRING); + ret = FALSE; } else { @@ -739,7 +805,8 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, { if (ppszError) *ppszError = str; - error = CRYPT_E_INVALID_X500_STRING; + SetLastError(CRYPT_E_INVALID_X500_STRING); + ret = FALSE; } else { @@ -758,9 +825,9 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, sep = crlfSep; else sep = allSeps; - error = CRYPT_GetNextValueW(str, dwStrType, sep, &token, + ret = CRYPT_GetNextValueW(str, dwStrType, sep, &token, ppszError); - if (!error) + if (ret) { str = token.end; ret = CRYPT_ValueToRDN(dwCertEncodingType, &info, @@ -771,25 +838,22 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, } } CRYPT_FreeKeynameKeeper(&keeper); - if (!error) + if (ret) { + if (ppszError) + *ppszError = NULL; ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info, 0, NULL, pbEncoded, pcbEncoded); - for (i = 0; i < info.cRDN; i++) - { - DWORD j; - - for (j = 0; j < info.rgRDN[i].cRDNAttr; j++) - LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData); - CryptMemFree(info.rgRDN[i].rgRDNAttr); - } - CryptMemFree(info.rgRDN); } - else + for (i = 0; i < info.cRDN; i++) { - SetLastError(error); - ret = FALSE; + DWORD j; + + for (j = 0; j < info.rgRDN[i].cRDNAttr; j++) + LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData); + CryptMemFree(info.rgRDN[i].rgRDNAttr); } + CryptMemFree(info.rgRDN); return ret; } @@ -876,8 +940,6 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, sizeof(simpleAttributeOIDs[0]); i++) nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info); } - else - ret = 0; if (!nameAttr) { PCERT_EXTENSION ext = CertFindExtension(altNameOID, @@ -895,12 +957,14 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, * Failing that, look for the first attribute. */ FIXME("CERT_NAME_SIMPLE_DISPLAY_TYPE: stub\n"); - ret = 0; } } } - ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value, - pszNameString, cchNameString); + if (nameAttr) + ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value, + pszNameString, cchNameString); + else + ret = 0; if (info) LocalFree(info); break; diff --git a/reactos/include/psdk/i_cryptasn1tls.h b/reactos/include/psdk/i_cryptasn1tls.h new file mode 100644 index 00000000000..3e2546b5352 --- /dev/null +++ b/reactos/include/psdk/i_cryptasn1tls.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2007 Francois Gouget + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_I_CRYPTASN1TLS_H +#define __WINE_I_CRYPTASN1TLS_H + +typedef void *ASN1decoding_t; +typedef void *ASN1encoding_t; +typedef void *ASN1module_t; +typedef DWORD HCRYPTASN1MODULE; + +#ifdef __cplusplus +extern "C" { +#endif + +ASN1decoding_t WINAPI I_CryptGetAsn1Decoder(HCRYPTASN1MODULE); +ASN1encoding_t WINAPI I_CryptGetAsn1Encoder(HCRYPTASN1MODULE); +BOOL WINAPI I_CryptInstallAsn1Module(ASN1module_t, DWORD, void*); +BOOL WINAPI I_CryptUninstallAsn1Module(HCRYPTASN1MODULE); + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_I_CRYPTASN1TLS_H */ diff --git a/reactos/include/psdk/wincrypt.h b/reactos/include/psdk/wincrypt.h index 2374cd63931..d21a632e99d 100644 --- a/reactos/include/psdk/wincrypt.h +++ b/reactos/include/psdk/wincrypt.h @@ -26,15 +26,17 @@ extern "C" { /* some typedefs for function parameters */ typedef unsigned int ALG_ID; -typedef unsigned long HCRYPTPROV; -typedef unsigned long HCRYPTPROV_LEGACY; -typedef unsigned long HCRYPTKEY; -typedef unsigned long HCRYPTHASH; +typedef ULONG_PTR HCRYPTPROV; +typedef ULONG_PTR HCRYPTPROV_OR_NCRYPT_KEY_HANDLE; +typedef ULONG_PTR HCRYPTPROV_LEGACY; +typedef ULONG_PTR HCRYPTKEY; +typedef ULONG_PTR HCRYPTHASH; typedef void *HCERTSTORE; typedef void *HCRYPTMSG; typedef void *HCERTSTOREPROV; typedef void *HCRYPTOIDFUNCSET; typedef void *HCRYPTOIDFUNCADDR; +typedef void *HCRYPTDEFAULTCONTEXT; /* CSP Structs */ @@ -628,11 +630,87 @@ typedef struct _CMSG_SIGNER_INFO { CRYPT_ATTRIBUTES UnauthAttrs; } CMSG_SIGNER_INFO, *PCMSG_SIGNER_INFO; +typedef struct _CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA { + DWORD cbSize; + HCRYPTPROV hCryptProv; + DWORD dwSignerIndex; + DWORD dwSignerType; + void *pvSigner; +} CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA, *PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA; + #define CMSG_VERIFY_SIGNER_PUBKEY 1 #define CMSG_VERIFY_SIGNER_CERT 2 #define CMSG_VERIFY_SIGNER_CHAIN 3 #define CMSG_VERIFY_SIGNER_NULL 4 +#define CMSG_TYPE_PARAM 1 +#define CMSG_CONTENT_PARAM 2 +#define CMSG_BARE_CONTENT_PARAM 3 +#define CMSG_INNER_CONTENT_TYPE_PARAM 4 +#define CMSG_SIGNER_COUNT_PARAM 5 +#define CMSG_SIGNER_INFO_PARAM 6 +#define CMSG_SIGNER_CERT_INFO_PARAM 7 +#define CMSG_SIGNER_HASH_ALGORITHM_PARAM 8 +#define CMSG_SIGNER_AUTH_ATTR_PARAM 9 +#define CMSG_SIGNER_UNAUTH_ATTR_PARAM 10 +#define CMSG_CERT_COUNT_PARAM 11 +#define CMSG_CERT_PARAM 12 +#define CMSG_CRL_COUNT_PARAM 13 +#define CMSG_CRL_PARAM 14 +#define CMSG_ENVELOPE_ALGORITHM_PARAM 15 +#define CMSG_RECIPIENT_COUNT_PARAM 17 +#define CMSG_RECIPIENT_INDEX_PARAM 18 +#define CMSG_RECIPIENT_INFO_PARAM 19 +#define CMSG_HASH_ALGORITHM_PARAM 20 +#define CMSG_HASH_DATA_PARAM 21 +#define CMSG_COMPUTED_HASH_PARAM 22 +#define CMSG_ENCRYPT_PARAM 26 +#define CMSG_ENCRYPTED_DIGEST 27 +#define CMSG_ENCODED_SIGNER 28 +#define CMSG_ENCODED_MESSAGE 29 +#define CMSG_VERSION_PARAM 30 +#define CMSG_ATTR_CERT_COUNT_PARAM 31 +#define CMSG_ATTR_CERT_PARAM 32 +#define CMSG_CMS_RECIPIENT_COUNT_PARAM 33 +#define CMSG_CMS_RECIPIENT_INDEX_PARAM 34 +#define CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM 35 +#define CMSG_CMS_RECIPIENT_INFO_PARAM 36 +#define CMSG_UNPROTECTED_ATTR_PARAM 37 +#define CMSG_SIGNER_CERT_ID_PARAM 38 +#define CMSG_CMS_SIGNER_INFO_PARAM 39 + +#define CMSG_SIGNED_DATA_V1 1 +#define CMSG_SIGNED_DATA_V3 3 +#define CMSG_SIGNED_DATA_PKCS_1_5_VERSION CMSG_SIGNED_DATA_V1 +#define CMSG_SIGNED_DATA_CMS_VERSION CMSG_SIGNED_DATA_V3 + +#define CMSG_SIGNER_INFO_V1 1 +#define CMSG_SIGNER_INFO_V3 3 +#define CMSG_SIGNER_INFO_PKCS_1_5_VERSION CMSG_SIGNER_INFO_V1 +#define CMSG_SIGNER_INFO_CMS_VERSION CMSG_SIGNER_INFO_V3 + +#define CMSG_HASHED_DATA_V0 0 +#define CMSG_HASHED_DATA_V2 2 +#define CMSG_HASHED_DATA_PKCS_1_5_VERSION CMSG_HASHED_DATA_V0 +#define CMSG_HASHED_DATA_CMS_VERSION CMSG_HASHED_DATA_V2 + +#define CMSG_ENVELOPED_DATA_V0 0 +#define CMSG_ENVELOPED_DATA_V2 2 +#define CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION CMSG_ENVELOPED_DATA_V0 +#define CMSG_ENVELOPED_DATA_CMS_VERSION CMSG_ENVELOPED_DATA_V2 + +/* CryptMsgGetAndVerifySigner flags */ +#define CMSG_TRUSTED_SIGNER_FLAG 0x1 +#define CMSG_SIGNER_ONLY_FLAG 0x2 +#define CMSG_USE_SIGNER_INDEX_FLAG 0x4 + +/* CryptMsgSignCTL flags */ +#define CMSG_CMS_ENCAPSULATED_CTL_FLAG 0x00008000 + +/* CryptMsgEncodeAndSignCTL flags */ +#define CMSG_ENCODED_SORTED_CTL_FLAG 0x1 +#define CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG 0x2 + typedef struct _CERT_REVOCATION_CRL_INFO { DWORD cbSize; PCCRL_CONTEXT pBaseCrlContext; @@ -2198,6 +2276,16 @@ static const WCHAR CERT_PHYSICAL_STORE_AUTH_ROOT_NAME[] = /* CertFindChainInStore dwFindType types */ #define CERT_CHAIN_FIND_BY_ISSUER 1 +/* CertSaveStore dwSaveAs values */ +#define CERT_STORE_SAVE_AS_STORE 1 +#define CERT_STORE_SAVE_AS_PKCS7 2 +/* CertSaveStore dwSaveTo values */ +#define CERT_STORE_SAVE_TO_FILE 1 +#define CERT_STORE_SAVE_TO_MEMORY 2 +#define CERT_STORE_SAVE_TO_FILENAME_A 3 +#define CERT_STORE_SAVE_TO_FILENAME_W 4 +#define CERT_STORE_SAVE_TO_FILENAME CERT_STORE_SAVE_TO_FILENAME_W + /* CERT_INFO versions/flags */ #define CERT_V1 0 #define CERT_V2 1 @@ -3132,6 +3220,10 @@ typedef struct _CERT_ID } DUMMYUNIONNAME; } CERT_ID, *PCERT_ID; +#define CERT_ID_ISSUER_SERIAL_NUMBER 1 +#define CERT_ID_KEY_IDENTIFIER 2 +#define CERT_ID_SHA1_HASH 3 + #undef CMSG_DATA /* may be defined by sys/socket.h */ #define CMSG_DATA 1 #define CMSG_SIGNED 2 @@ -3498,7 +3590,7 @@ HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR,DWORD); BOOL WINAPI CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet, DWORD dwEncodingType, LPWSTR pwszDllList, DWORD *pcchDllList); BOOL WINAPI CryptGetDefaultOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet, - DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void *ppvFuncAddr, + DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void **ppvFuncAddr, HCRYPTOIDFUNCADDR *phFuncAddr); BOOL WINAPI CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet, DWORD dwEncodingType, LPCSTR pszOID, DWORD dwFlags, void **ppvFuncAddr, @@ -3850,7 +3942,7 @@ BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey); BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert, - DWORD dwFlags, void *pvReserved, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec, + DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv, DWORD *pdwKeySpec, BOOL *pfCallerFreeProv); BOOL WINAPI CryptProtectData( DATA_BLOB* pDataIn, LPCWSTR szDataDescr, @@ -3887,9 +3979,65 @@ BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, LPCWSTR *ppszError); #define CertStrToName WINELIB_NAME_AW(CertStrToName) +DWORD WINAPI CryptMsgCalculateEncodedLength(DWORD dwMsgEncodingType, + DWORD dwFlags, DWORD dwMsgType, const void *pvMsgEncodeInfo, + LPSTR pszInnerContentObjID, DWORD cbData); + +BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg); + +BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags, + DWORD dwCtrlType, const void *pvCtrlPara); + +BOOL WINAPI CryptMsgCountersign(HCRYPTMSG hCryptMsg, DWORD dwIndex, + DWORD dwCountersigners, PCMSG_SIGNER_ENCODE_INFO rgCountersigners); + +BOOL WINAPI CryptMsgCountersignEncoded(DWORD dwEncodingType, PBYTE pbSignerInfo, + DWORD cbSignerInfo, DWORD cCountersigners, + PCMSG_SIGNER_ENCODE_INFO rgCountersigners, PBYTE pbCountersignature, + PDWORD pcbCountersignature); + +HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg); + +BOOL WINAPI CryptMsgEncodeAndSignCTL(DWORD dwMsgEncodingType, + PCTL_INFO pCtlInfo, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags, + BYTE *pbEncoded, DWORD *pcbEncoded); + +BOOL WINAPI CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, DWORD cSignerStore, + HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT *ppSigner, + DWORD *pdwSignerIndex); + +BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, + DWORD dwIndex, void *pvData, DWORD *pcbData); + +HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags, + DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo, + PCMSG_STREAM_INFO pStreamInfo); + +HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags, + DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID, + PCMSG_STREAM_INFO pStreamInfo); + +BOOL WINAPI CryptMsgSignCTL(DWORD dwMsgEncodingType, BYTE *pbCtlContent, + DWORD cbCtlContent, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags, + BYTE *pbEncoded, DWORD *pcbEncoded); + +BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData, + DWORD cbData, BOOL fFinal); + +BOOL WINAPI CryptMsgVerifyCountersignatureEncoded(HCRYPTPROV_LEGACY hCryptProv, + DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo, + PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature, + PCERT_INFO pciCountersigner); + +BOOL WINAPI CryptMsgVerifyCountersignatureEncodedEx(HCRYPTPROV_LEGACY hCryptProv, + DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo, + PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature, + DWORD dwSignerType, void *pvSigner, DWORD dwFlags, void *pvReserved); + BOOL WINAPI CryptSignMessage(PCRYPT_SIGN_MESSAGE_PARA pSignPara, BOOL fDetachedSignature, DWORD cToBeSigned, const BYTE *rgpbToBeSigned[], DWORD rgcbToBeSigned[], BYTE *pbSignedBlob, DWORD *pcbSignedBlob); + BOOL WINAPI CryptSignMessageWithKey(PCRYPT_KEY_SIGN_MESSAGE_PARA pSignPara, const BYTE *pbToBeSigned, DWORD cbToBeSigned, BYTE *pbSignedBlob, DWORD *pcbSignedBlob); @@ -3897,6 +4045,7 @@ BOOL WINAPI CryptSignMessageWithKey(PCRYPT_KEY_SIGN_MESSAGE_PARA pSignPara, BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob, BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert); + BOOL WINAPI CryptVerifyMessageSignatureWithKey( PCRYPT_KEY_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_PUBLIC_KEY_INFO pPublicKeyInfo, const BYTE *pbSignedBlob, @@ -3907,6 +4056,7 @@ BOOL WINAPI CryptVerifyDetachedMessageSignature( const BYTE *pbDetachedSignBlob, DWORD cbDetachedSignBlob, DWORD cToBeSigned, const BYTE *rgpbToBeSigned[], DWORD rgcbToBeSigned[], PCCERT_CONTEXT *ppSignerCert); + LONG WINAPI CryptGetMessageSignerCount(DWORD dwMsgEncodingType, const BYTE *pbSignedBlob, DWORD cbSignedBlob); @@ -3914,6 +4064,7 @@ BOOL WINAPI CryptEncryptMessage(PCRYPT_ENCRYPT_MESSAGE_PARA pEncryptPara, DWORD cRecipientCert, PCCERT_CONTEXT rgpRecipientCert[], const BYTE *pbToBeEncrypted, DWORD cbToBeEncrypted, BYTE *pbEncryptedBlob, DWORD *pcbEncryptedBlob); + BOOL WINAPI CryptDecryptMessage(PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara, const BYTE *pbEncryptedBlob, DWORD cbEncryptedBlob, BYTE *pbDecrypted, DWORD *pcbDecrypted, PCCERT_CONTEXT *ppXchgCert); @@ -3923,6 +4074,7 @@ BOOL WINAPI CryptSignAndEncryptMessage(PCRYPT_SIGN_MESSAGE_PARA pSignPara, PCCERT_CONTEXT rgpRecipientCert[], const BYTE *pbToBeSignedAndEncrypted, DWORD cbToBeSignedAndEncrypted, BYTE *pbSignedAndEncryptedBlob, DWORD *pcbSignedAndEncryptedBlob); + BOOL WINAPI CryptDecryptAndVerifyMessageSignature( PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara, PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, DWORD dwSignerIndex,