diff --git a/reactos/dll/win32/crypt32/base64.c b/reactos/dll/win32/crypt32/base64.c index 17e05d97530..4a6504a488e 100644 --- a/reactos/dll/win32/crypt32/base64.c +++ b/reactos/dll/win32/crypt32/base64.c @@ -60,6 +60,8 @@ static const char b64[] = typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString); +typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString); static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString) @@ -97,7 +99,8 @@ static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep, TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes); needed = bytes + pad_bytes + 1; - needed += (needed / 64 + 1) * strlen(sep); + if (sep) + needed += (needed / 64 + 1) * strlen(sep); if (needed > *out_len) { @@ -114,7 +117,7 @@ static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep, i = 0; while (div > 0) { - if (i && i % 64 == 0) + if (sep && i && i % 64 == 0) { strcpy(ptr, sep); ptr += strlen(sep); @@ -160,7 +163,8 @@ static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep, *ptr++ = '='; break; } - strcpy(ptr, sep); + if (sep) + strcpy(ptr, sep); return ERROR_SUCCESS; } @@ -170,14 +174,16 @@ static BOOL BinaryToBase64A(const BYTE *pbBinary, { static const char crlf[] = "\r\n", lf[] = "\n"; BOOL ret = TRUE; - LPCSTR header = NULL, trailer = NULL, sep = NULL; + LPCSTR header = NULL, trailer = NULL, sep; DWORD charsNeeded; if (dwFlags & CRYPT_STRING_NOCR) sep = lf; + else if (dwFlags & CRYPT_STRING_NOCRLF) + sep = NULL; else sep = crlf; - switch (dwFlags & 0x7fffffff) + switch (dwFlags & 0x0fffffff) { case CRYPT_STRING_BASE64: /* no header or footer */ @@ -198,7 +204,8 @@ static BOOL BinaryToBase64A(const BYTE *pbBinary, charsNeeded = 0; encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded); - charsNeeded += strlen(sep); + if (sep) + charsNeeded += strlen(sep); if (header) charsNeeded += strlen(header) + strlen(sep); if (trailer) @@ -212,8 +219,11 @@ static BOOL BinaryToBase64A(const BYTE *pbBinary, { strcpy(ptr, header); ptr += strlen(ptr); - strcpy(ptr, sep); - ptr += strlen(sep); + if (sep) + { + strcpy(ptr, sep); + ptr += strlen(sep); + } } encodeBase64A(pbBinary, cbBinary, sep, ptr, &size); ptr += size - 1; @@ -221,8 +231,11 @@ static BOOL BinaryToBase64A(const BYTE *pbBinary, { strcpy(ptr, trailer); ptr += strlen(ptr); - strcpy(ptr, sep); - ptr += strlen(sep); + if (sep) + { + strcpy(ptr, sep); + ptr += strlen(sep); + } } *pcchString = charsNeeded - 1; } @@ -256,7 +269,7 @@ BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary, return FALSE; } - switch (dwFlags & 0x7fffffff) + switch (dwFlags & 0x0fffffff) { case CRYPT_STRING_BINARY: encoder = EncodeBinaryToBinaryA; @@ -271,7 +284,210 @@ BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary, case CRYPT_STRING_HEXASCII: case CRYPT_STRING_HEXADDR: case CRYPT_STRING_HEXASCIIADDR: - FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff); + FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff); + /* fall through */ + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString); +} + +static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep, + WCHAR* out_buf, DWORD *out_len) +{ + int div, i; + const BYTE *d = in_buf; + int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0; + DWORD needed; + LPWSTR ptr; + + TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes); + needed = bytes + pad_bytes + 1; + if (sep) + needed += (needed / 64 + 1) * strlenW(sep); + + if (needed > *out_len) + { + *out_len = needed; + return ERROR_INSUFFICIENT_BUFFER; + } + else + *out_len = needed; + + /* Three bytes of input give 4 chars of output */ + div = in_len / 3; + + ptr = out_buf; + i = 0; + while (div > 0) + { + if (sep && i && i % 64 == 0) + { + strcpyW(ptr, sep); + ptr += strlenW(sep); + } + /* first char is the first 6 bits of the first byte*/ + *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; + /* second char is the last 2 bits of the first byte and the first 4 + * bits of the second byte */ + *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; + /* third char is the last 4 bits of the second byte and the first 2 + * bits of the third byte */ + *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)]; + /* fourth char is the remaining 6 bits of the third byte */ + *ptr++ = b64[ d[2] & 0x3f]; + i += 4; + d += 3; + div--; + } + + switch(pad_bytes) + { + case 1: + /* first char is the first 6 bits of the first byte*/ + *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; + /* second char is the last 2 bits of the first byte and the first 4 + * bits of the second byte */ + *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; + /* third char is the last 4 bits of the second byte padded with + * two zeroes */ + *ptr++ = b64[ ((d[1] << 2) & 0x3c) ]; + /* fourth char is a = to indicate one byte of padding */ + *ptr++ = '='; + break; + case 2: + /* first char is the first 6 bits of the first byte*/ + *ptr++ = b64[ ( d[0] >> 2) & 0x3f ]; + /* second char is the last 2 bits of the first byte padded with + * four zeroes*/ + *ptr++ = b64[ ((d[0] << 4) & 0x30)]; + /* third char is = to indicate padding */ + *ptr++ = '='; + /* fourth char is = to indicate padding */ + *ptr++ = '='; + break; + } + if (sep) + strcpyW(ptr, sep); + + return ERROR_SUCCESS; +} + +static BOOL BinaryToBase64W(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString) +{ + static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }; + BOOL ret = TRUE; + LPCWSTR header = NULL, trailer = NULL, sep; + DWORD charsNeeded; + + if (dwFlags & CRYPT_STRING_NOCR) + sep = lf; + else if (dwFlags & CRYPT_STRING_NOCRLF) + sep = NULL; + else + sep = crlf; + switch (dwFlags & 0x0fffffff) + { + case CRYPT_STRING_BASE64: + /* no header or footer */ + break; + case CRYPT_STRING_BASE64HEADER: + header = CERT_HEADER_W; + trailer = CERT_TRAILER_W; + break; + case CRYPT_STRING_BASE64REQUESTHEADER: + header = CERT_REQUEST_HEADER_W; + trailer = CERT_REQUEST_TRAILER_W; + break; + case CRYPT_STRING_BASE64X509CRLHEADER: + header = X509_HEADER_W; + trailer = X509_TRAILER_W; + break; + } + + charsNeeded = 0; + encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded); + if (sep) + charsNeeded += strlenW(sep); + if (header) + charsNeeded += strlenW(header) + strlenW(sep); + if (trailer) + charsNeeded += strlenW(trailer) + strlenW(sep); + if (charsNeeded <= *pcchString) + { + LPWSTR ptr = pszString; + DWORD size = charsNeeded; + + if (header) + { + strcpyW(ptr, header); + ptr += strlenW(ptr); + if (sep) + { + strcpyW(ptr, sep); + ptr += strlenW(sep); + } + } + encodeBase64W(pbBinary, cbBinary, sep, ptr, &size); + ptr += size - 1; + if (trailer) + { + strcpyW(ptr, trailer); + ptr += strlenW(ptr); + if (sep) + { + strcpyW(ptr, sep); + ptr += strlenW(sep); + } + } + *pcchString = charsNeeded - 1; + } + else if (pszString) + { + *pcchString = charsNeeded; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + ret = FALSE; + } + else + *pcchString = charsNeeded; + return ret; +} + +BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString) +{ + BinaryToStringWFunc encoder = NULL; + + TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString, + pcchString); + + if (!pbBinary) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!pcchString) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + switch (dwFlags & 0x0fffffff) + { + case CRYPT_STRING_BASE64: + case CRYPT_STRING_BASE64HEADER: + case CRYPT_STRING_BASE64REQUESTHEADER: + case CRYPT_STRING_BASE64X509CRLHEADER: + encoder = BinaryToBase64W; + break; + case CRYPT_STRING_BINARY: + case CRYPT_STRING_HEX: + case CRYPT_STRING_HEXASCII: + case CRYPT_STRING_HEXADDR: + case CRYPT_STRING_HEXASCIIADDR: + FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff); /* fall through */ default: SetLastError(ERROR_INVALID_PARAMETER); diff --git a/reactos/dll/win32/crypt32/cert.c b/reactos/dll/win32/crypt32/cert.c index 1c0c74ecd14..4f3df326943 100644 --- a/reactos/dll/win32/crypt32/cert.c +++ b/reactos/dll/win32/crypt32/cert.c @@ -71,6 +71,53 @@ BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, return ret; } +BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName, + const BYTE *pbCertEncoded, DWORD cbCertEncoded) +{ + HCERTSTORE store; + BOOL ret = FALSE; + + TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded, + cbCertEncoded); + + store = CertOpenSystemStoreA(0, pszCertStoreName); + if (store) + { + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL); + CertCloseStore(store, 0); + } + return ret; +} + +BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName, + const BYTE *pbCertEncoded, DWORD cbCertEncoded) +{ + HCERTSTORE store; + BOOL ret = FALSE; + + TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded, + cbCertEncoded); + + store = CertOpenSystemStoreW(0, pszCertStoreName); + if (store) + { + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL); + CertCloseStore(store, 0); + } + return ret; +} + +BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore, + PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition, + PCCERT_CONTEXT *ppCertContext) +{ + FIXME("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, dwAddDisposition, + ppCertContext); + return FALSE; +} + PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded) { @@ -133,12 +180,14 @@ static void CertDataContext_Free(void *context) BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext) { + BOOL ret = TRUE; + TRACE("(%p)\n", pCertContext); if (pCertContext) - Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT), + ret = Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT), CertDataContext_Free); - return TRUE; + return ret; } DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext, @@ -1120,12 +1169,6 @@ DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType, typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, const void *pvPara); -static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara) -{ - return TRUE; -} - static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, const void *pvPara) { @@ -1202,7 +1245,7 @@ static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, /* Matching serial number and subject match.. */ ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, - &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject); + &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer); if (ret) ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber, &pCertInfo->SerialNumber); @@ -1213,7 +1256,7 @@ static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext, &pCertInfo->SerialNumber); if (ret) ret = CertCompareCertificateName(pCertContext->dwCertEncodingType, - &pCertInfo->Issuer, &pCertContext->pCertInfo->Issuer); + &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer); } TRACE("returning %d\n", ret); return ret; @@ -1267,11 +1310,70 @@ static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType, return ret; } -static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType, +static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, const void *pvPara) { - BOOL ret = FALSE; - PCCERT_CONTEXT subject = pvPara; + PCCERT_CONTEXT toCompare = pvPara; + return CertCompareCertificate(pCertContext->dwCertEncodingType, + pCertContext->pCertInfo, toCompare->pCertInfo); +} + +static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, + DWORD dwFlags, const void *pvPara) +{ + const CRYPT_HASH_BLOB *hash = pvPara; + DWORD size = 0; + BOOL ret; + + ret = CertGetCertificateContextProperty(pCertContext, + CERT_SIGNATURE_HASH_PROP_ID, NULL, &size); + if (ret && size == hash->cbData) + { + LPBYTE buf = CryptMemAlloc(size); + + if (buf) + { + CertGetCertificateContextProperty(pCertContext, + CERT_SIGNATURE_HASH_PROP_ID, buf, &size); + ret = !memcmp(buf, hash->pbData, size); + CryptMemFree(buf); + } + } + else + ret = FALSE; + return ret; +} + +static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store, + PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags, + const void *pvPara) +{ + BOOL matches = FALSE; + PCCERT_CONTEXT ret; + + ret = prev; + do { + ret = CertEnumCertificatesInStore(store, ret); + if (ret) + matches = compare(ret, dwType, dwFlags, pvPara); + } while (ret != NULL && !matches); + return ret; +} + +typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType, + DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev); + +static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType, + DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev) +{ + return CertEnumCertificatesInStore(store, prev); +} + +static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType, + DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev) +{ + BOOL ret; + PCCERT_CONTEXT found = NULL, subject = pvPara; PCERT_EXTENSION ext; DWORD size; @@ -1295,18 +1397,17 @@ static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType, 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; + if (ret) + found = cert_compare_certs_in_store(store, prev, + compare_cert_by_cert_id, dwType, dwFlags, &id); LocalFree(info); } } @@ -1343,8 +1444,6 @@ static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType, memcpy(&id.u.IssuerSerialNumber.SerialNumber, &info->AuthorityCertSerialNumber, sizeof(CRYPT_INTEGER_BLOB)); - ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags, - &id); } else { @@ -1356,53 +1455,83 @@ static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType, { 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; + if (ret) + found = cert_compare_certs_in_store(store, prev, + compare_cert_by_cert_id, dwType, dwFlags, &id); LocalFree(info); } } else - ret = compare_cert_by_name(pCertContext, - CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, dwFlags, - &subject->pCertInfo->Issuer); + found = cert_compare_certs_in_store(store, prev, + compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, + dwFlags, &subject->pCertInfo->Issuer); + return found; +} + +static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext, + DWORD dwType, DWORD dwFlags, const void *pvPara) +{ + PCERT_NAME_BLOB name; + DWORD len; + BOOL ret = FALSE; + + if (dwType & CERT_INFO_SUBJECT_FLAG) + name = &pCertContext->pCertInfo->Subject; + else + name = &pCertContext->pCertInfo->Issuer; + len = CertNameToStrW(pCertContext->dwCertEncodingType, name, + CERT_SIMPLE_NAME_STR, NULL, 0); + if (len) + { + LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR)); + + if (str) + { + LPWSTR ptr; + + CertNameToStrW(pCertContext->dwCertEncodingType, name, + CERT_SIMPLE_NAME_STR, str, len); + for (ptr = str; *ptr; ptr++) + *ptr = tolowerW(*ptr); + if (strstrW(str, pvPara)) + ret = TRUE; + CryptMemFree(str); + } + } return ret; } -static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara) +static PCCERT_CONTEXT find_cert_by_name_str(HCERTSTORE store, DWORD dwType, + DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev) { - PCCERT_CONTEXT toCompare = pvPara; - return CertCompareCertificate(pCertContext->dwCertEncodingType, - pCertContext->pCertInfo, toCompare->pCertInfo); -} + PCCERT_CONTEXT found = NULL; -static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType, - DWORD dwFlags, const void *pvPara) -{ - const CRYPT_HASH_BLOB *hash = pvPara; - DWORD size = 0; - BOOL ret; + TRACE("%s\n", debugstr_w(pvPara)); - ret = CertGetCertificateContextProperty(pCertContext, - CERT_SIGNATURE_HASH_PROP_ID, NULL, &size); - if (ret && size == hash->cbData) + if (pvPara) { - LPBYTE buf = CryptMemAlloc(size); + DWORD len = strlenW(pvPara); + LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR)); - if (buf) + if (str) { - CertGetCertificateContextProperty(pCertContext, - CERT_SIGNATURE_HASH_PROP_ID, buf, &size); - ret = !memcmp(buf, hash->pbData, size); - CryptMemFree(buf); + LPCWSTR src; + LPWSTR dst; + + for (src = pvPara, dst = str; *src; src++, dst++) + *dst = tolowerW(*src); + *dst = 0; + found = cert_compare_certs_in_store(store, prev, + compare_cert_by_name_str, dwType, dwFlags, str); + CryptMemFree(str); } } else - ret = FALSE; - return ret; + found = find_cert_any(store, dwType, dwFlags, NULL, prev); + return found; } PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, @@ -1410,7 +1539,8 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext) { PCCERT_CONTEXT ret; - CertCompareFunc compare; + CertFindFunc find = NULL; + CertCompareFunc compare = NULL; TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType, dwFlags, dwType, pvPara, pPrevCertContext); @@ -1418,7 +1548,7 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, switch (dwType >> CERT_COMPARE_SHIFT) { case CERT_COMPARE_ANY: - compare = compare_cert_any; + find = find_cert_any; break; case CERT_COMPARE_MD5_HASH: compare = compare_cert_by_md5_hash; @@ -1432,6 +1562,9 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, case CERT_COMPARE_PUBLIC_KEY: compare = compare_cert_by_public_key; break; + case CERT_COMPARE_NAME_STR_W: + find = find_cert_by_name_str; + break; case CERT_COMPARE_SUBJECT_CERT: compare = compare_cert_by_subject_cert; break; @@ -1439,7 +1572,7 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, compare = compare_cert_by_cert_id; break; case CERT_COMPARE_ISSUER_OF: - compare = compare_cert_by_issuer; + find = find_cert_by_issuer; break; case CERT_COMPARE_EXISTING: compare = compare_existing_cert; @@ -1449,27 +1582,17 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, break; default: FIXME("find type %08x unimplemented\n", dwType); - compare = NULL; } - if (compare) - { - BOOL matches = FALSE; - - ret = pPrevCertContext; - do { - ret = CertEnumCertificatesInStore(hCertStore, ret); - if (ret) - matches = compare(ret, dwType, dwFlags, pvPara); - } while (ret != NULL && !matches); - if (!ret) - SetLastError(CRYPT_E_NOT_FOUND); - } + if (find) + ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext); + else if (compare) + ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext, + compare, dwType, dwFlags, pvPara); else - { - SetLastError(CRYPT_E_NOT_FOUND); ret = NULL; - } + if (!ret) + SetLastError(CRYPT_E_NOT_FOUND); TRACE("returning %p\n", ret); return ret; } @@ -1781,13 +1904,19 @@ BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid, hCryptProv = CRYPT_GetDefaultProvider(); if (!Algid) Algid = CALG_MD5; + if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } if (ret) { BYTE *buf; DWORD size = 0; - ret = CryptEncodeObjectEx(dwCertEncodingType, X509_PUBLIC_KEY_INFO, - pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType, + X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, + (LPBYTE)&buf, &size); if (ret) { ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash); @@ -2117,6 +2246,43 @@ BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv, return ret; } +BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType, + PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage) +{ + PCERT_EXTENSION ext; + BOOL ret = FALSE; + + TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage, + cbKeyUsage); + + ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension, + pCertInfo->rgExtension); + if (ext) + { + CRYPT_BIT_BLOB usage; + DWORD size = sizeof(usage); + + ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS, + ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, + &usage, &size); + if (ret) + { + if (cbKeyUsage < usage.cbData) + ret = FALSE; + else + { + memcpy(pbKeyUsage, usage.pbData, usage.cbData); + if (cbKeyUsage > usage.cbData) + memset(pbKeyUsage + usage.cbData, 0, + cbKeyUsage - usage.cbData); + } + } + } + else + SetLastError(0); + return ret; +} + BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags, PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage) { @@ -2727,7 +2893,10 @@ static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNu assert(pSubjectIssuerBlob); assert(pubKey); - info->dwVersion = CERT_V3; + if (pExtensions && pExtensions->cExtension) + info->dwVersion = CERT_V3; + else + info->dwVersion = CERT_V1; info->SerialNumber.cbData = pSerialNumber->cbData; info->SerialNumber.pbData = pSerialNumber->pbData; if (pSignatureAlgorithm) diff --git a/reactos/dll/win32/crypt32/chain.c b/reactos/dll/win32/crypt32/chain.c index fa9fdf0f34a..eb6d757ce7f 100644 --- a/reactos/dll/win32/crypt32/chain.c +++ b/reactos/dll/win32/crypt32/chain.c @@ -69,6 +69,24 @@ static inline void CRYPT_CloseStores(DWORD cStores, HCERTSTORE *stores) static const WCHAR rootW[] = { 'R','o','o','t',0 }; +/* Finds cert in store by comparing the cert's hashes. */ +static PCCERT_CONTEXT CRYPT_FindCertInStore(HCERTSTORE store, + PCCERT_CONTEXT cert) +{ + PCCERT_CONTEXT matching = NULL; + BYTE hash[20]; + DWORD size = sizeof(hash); + + if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, hash, &size)) + { + CRYPT_HASH_BLOB blob = { sizeof(hash), hash }; + + matching = CertFindCertificateInStore(store, cert->dwCertEncodingType, + 0, CERT_FIND_SHA1_HASH, &blob, NULL); + } + return matching; +} + static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store) { BOOL ret = TRUE; @@ -77,29 +95,15 @@ static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store) { HCERTSTORE rootStore = CertOpenSystemStoreW(0, rootW); PCCERT_CONTEXT cert = NULL, check; - BYTE hash[20]; - DWORD size; do { cert = CertEnumCertificatesInStore(store, cert); if (cert) { - size = sizeof(hash); - - ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, - hash, &size); - if (ret) - { - CRYPT_HASH_BLOB blob = { sizeof(hash), hash }; - - check = CertFindCertificateInStore(rootStore, - cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob, - NULL); - if (!check) - ret = FALSE; - else - CertFreeCertificateContext(check); - } + if (!(check = CRYPT_FindCertInStore(rootStore, cert))) + ret = FALSE; + else + CertFreeCertificateContext(check); } } while (ret && cert); if (cert) @@ -336,16 +340,9 @@ static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN 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; + PCCERT_CONTEXT trustedRoot = CRYPT_FindCertInStore(hRoot, + rootElement->pCertContext); - 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; @@ -418,11 +415,22 @@ static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert, } /* Checks element's basic constraints to see if it can act as a CA, with - * remainingCAs CAs left in this chain. A root certificate is assumed to be - * allowed to be a CA whether or not the basic constraints extension is present, - * whereas an intermediate CA cert is not. This matches the expected usage in - * RFC 3280: a conforming intermediate CA MUST contain the basic constraints - * extension. It also appears to match Microsoft's implementation. + * remainingCAs CAs left in this chain. In general, a cert must include the + * basic constraints extension, with the CA flag asserted, in order to be + * allowed to be a CA. A V1 or V2 cert, which has no extensions, is also + * allowed to be a CA if it's installed locally (in the engine's world store.) + * This matches the expected usage in RFC 5280, section 4.2.1.9: a conforming + * CA MUST include the basic constraints extension in all certificates that are + * used to validate digital signatures on certificates. It also matches + * section 6.1.4(k): "If a certificate is a v1 or v2 certificate, then the + * application MUST either verify that the certificate is a CA certificate + * through out-of-band means or reject the certificate." Rejecting the + * certificate prohibits a large number of commonly used certificates, so + * accepting locally installed ones is a compromise. + * Root certificates are also allowed to be CAs even without a basic + * constraints extension. This is implied by RFC 5280, section 6.1: the + * root of a certificate chain's only requirement is that it was used to issue + * the next certificate in the 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 @@ -431,16 +439,40 @@ static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert, * 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 isRoot, BOOL *pathLengthConstraintViolated) +static BOOL CRYPT_CheckBasicConstraintsForCA(PCertificateChainEngine engine, + PCCERT_CONTEXT cert, CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, + DWORD remainingCAs, BOOL isRoot, BOOL *pathLengthConstraintViolated) { - BOOL validBasicConstraints; + BOOL validBasicConstraints, implicitCA = FALSE; CERT_BASIC_CONSTRAINTS2_INFO constraints; - if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert, - &constraints, isRoot))) + if (isRoot) + implicitCA = TRUE; + else if (cert->pCertInfo->dwVersion == CERT_V1 || + cert->pCertInfo->dwVersion == CERT_V2) { + BYTE hash[20]; + DWORD size = sizeof(hash); + + if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, + hash, &size)) + { + CRYPT_HASH_BLOB blob = { sizeof(hash), hash }; + PCCERT_CONTEXT localCert = CertFindCertificateInStore( + engine->hWorld, cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, + &blob, NULL); + + if (localCert) + { + CertFreeCertificateContext(localCert); + implicitCA = TRUE; + } + } + } + if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert, + &constraints, implicitCA))) + { + chainConstraints->fCA = constraints.fCA; if (!constraints.fCA) { TRACE_(chain)("chain element %d can't be a CA\n", remainingCAs + 1); @@ -547,9 +579,13 @@ static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint, TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData, name->cbData, name->pbData); - if (constraint->cbData != sizeof(DWORD) * 2) + /* RFC5280, section 4.2.1.10, iPAddress syntax: either 8 or 32 bytes, for + * IPv4 or IPv6 addresses, respectively. + */ + if (constraint->cbData != sizeof(DWORD) * 2 && constraint->cbData != 32) *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; - else if (name->cbData == sizeof(DWORD)) + else if (name->cbData == sizeof(DWORD) && + constraint->cbData == sizeof(DWORD) * 2) { DWORD subnet, mask, addr; @@ -561,6 +597,19 @@ static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint, */ match = (subnet & mask) == (addr & mask); } + else if (name->cbData == 16 && constraint->cbData == 32) + { + const BYTE *subnet, *mask, *addr; + DWORD i; + + subnet = constraint->pbData; + mask = constraint->pbData + 16; + addr = name->pbData; + match = TRUE; + for (i = 0; match && i < 16; i++) + if ((subnet[i] & mask[i]) != (addr[i] & mask[i])) + match = FALSE; + } /* else: name is wrong size, no match */ return match; @@ -608,6 +657,18 @@ static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY *constraint, *trustErrorStatus |= match ? errorIfFound : errorIfNotFound; } +static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert) +{ + PCERT_EXTENSION ext; + + ext = CertFindExtension(szOID_SUBJECT_ALT_NAME2, + cert->cExtension, cert->rgExtension); + if (!ext) + ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, + cert->cExtension, cert->rgExtension); + return ext; +} + static void CRYPT_CheckNameConstraints( const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert, DWORD *trustErrorStatus) @@ -615,10 +676,9 @@ static void CRYPT_CheckNameConstraints( /* If there aren't any existing constraints, don't bother checking */ if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree) { - CERT_EXTENSION *ext; + CERT_EXTENSION *ext = get_subject_alt_name_ext(cert); - if ((ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, cert->cExtension, - cert->rgExtension))) + if (ext) { CERT_ALT_NAME_INFO *subjectName; DWORD size; @@ -638,15 +698,20 @@ static void CRYPT_CheckNameConstraints( for (i = 0; i < nameConstraints->cPermittedSubtree; i++) CRYPT_FindMatchingNameEntry( &nameConstraints->rgPermittedSubtree[i].Base, subjectName, - trustErrorStatus, - 0, CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT); + trustErrorStatus, 0, + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT); LocalFree(subjectName); } + else + *trustErrorStatus |= + CERT_TRUST_INVALID_EXTENSION | + CERT_TRUST_INVALID_NAME_CONSTRAINTS; } else { if (nameConstraints->cPermittedSubtree) *trustErrorStatus |= + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; if (nameConstraints->cExcludedSubtree) *trustErrorStatus |= @@ -675,6 +740,40 @@ static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert) return info; } +static BOOL CRYPT_IsValidNameConstraint(const CERT_NAME_CONSTRAINTS_INFO *info) +{ + DWORD i; + BOOL ret = TRUE; + + /* Check that none of the constraints specifies a minimum or a maximum. + * See RFC 5280, section 4.2.1.10: + * "Within this profile, the minimum and maximum fields are not used with + * any name forms, thus, the minimum MUST be zero, and maximum MUST be + * absent. However, if an application encounters a critical name + * constraints extension that specifies other values for minimum or + * maximum for a name form that appears in a subsequent certificate, the + * application MUST either process these fields or reject the + * certificate." + * Since it gives no guidance as to how to process these fields, we + * reject any name constraint that contains them. + */ + for (i = 0; ret && i < info->cPermittedSubtree; i++) + if (info->rgPermittedSubtree[i].dwMinimum || + info->rgPermittedSubtree[i].fMaximum) + { + TRACE_(chain)("found a minimum or maximum in permitted subtrees\n"); + ret = FALSE; + } + for (i = 0; ret && i < info->cExcludedSubtree; i++) + if (info->rgExcludedSubtree[i].dwMinimum || + info->rgExcludedSubtree[i].fMaximum) + { + TRACE_(chain)("found a minimum or maximum in excluded subtrees\n"); + ret = FALSE; + } + return ret; +} + static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain) { int i, j; @@ -698,21 +797,27 @@ static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain) if ((nameConstraints = CRYPT_GetNameConstraints( chain->rgpElement[i]->pCertContext->pCertInfo))) { - for (j = i - 1; j >= 0; j--) + if (!CRYPT_IsValidNameConstraint(nameConstraints)) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT; + else { - 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)) + for (j = i - 1; j >= 0; j--) { - CRYPT_CheckNameConstraints(nameConstraints, - chain->rgpElement[i]->pCertContext->pCertInfo, - &errorStatus); - chain->rgpElement[i]->TrustStatus.dwErrorStatus |= - errorStatus; + 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[j]->pCertContext->pCertInfo, + &errorStatus); + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + errorStatus; + } } } LocalFree(nameConstraints); @@ -720,6 +825,80 @@ static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain) } } +static LPWSTR name_value_to_str(const CERT_NAME_BLOB *name) +{ + DWORD len = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name, + CERT_SIMPLE_NAME_STR, NULL, 0); + LPWSTR str = NULL; + + if (len) + { + str = CryptMemAlloc(len * sizeof(WCHAR)); + if (str) + cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name, + CERT_SIMPLE_NAME_STR, str, len); + } + return str; +} + +static void dump_alt_name_entry(const CERT_ALT_NAME_ENTRY *entry) +{ + LPWSTR str; + + switch (entry->dwAltNameChoice) + { + case CERT_ALT_NAME_OTHER_NAME: + TRACE_(chain)("CERT_ALT_NAME_OTHER_NAME, oid = %s\n", + debugstr_a(entry->u.pOtherName->pszObjId)); + break; + case CERT_ALT_NAME_RFC822_NAME: + TRACE_(chain)("CERT_ALT_NAME_RFC822_NAME: %s\n", + debugstr_w(entry->u.pwszRfc822Name)); + break; + case CERT_ALT_NAME_DNS_NAME: + TRACE_(chain)("CERT_ALT_NAME_DNS_NAME: %s\n", + debugstr_w(entry->u.pwszDNSName)); + break; + case CERT_ALT_NAME_DIRECTORY_NAME: + str = name_value_to_str(&entry->u.DirectoryName); + TRACE_(chain)("CERT_ALT_NAME_DIRECTORY_NAME: %s\n", debugstr_w(str)); + CryptMemFree(str); + break; + case CERT_ALT_NAME_URL: + TRACE_(chain)("CERT_ALT_NAME_URL: %s\n", debugstr_w(entry->u.pwszURL)); + break; + case CERT_ALT_NAME_IP_ADDRESS: + TRACE_(chain)("CERT_ALT_NAME_IP_ADDRESS: %d bytes\n", + entry->u.IPAddress.cbData); + break; + case CERT_ALT_NAME_REGISTERED_ID: + TRACE_(chain)("CERT_ALT_NAME_REGISTERED_ID: %s\n", + debugstr_a(entry->u.pszRegisteredID)); + break; + default: + TRACE_(chain)("dwAltNameChoice = %d\n", entry->dwAltNameChoice); + } +} + +static void dump_alt_name(LPCSTR type, const CERT_EXTENSION *ext) +{ + CERT_ALT_NAME_INFO *name; + DWORD size; + + TRACE_(chain)("%s:\n", type); + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, + ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size)) + { + DWORD i; + + TRACE_(chain)("%d alt name entries:\n", name->cAltEntry); + for (i = 0; i < name->cAltEntry; i++) + dump_alt_name_entry(&name->rgAltEntry[i]); + LocalFree(name); + } +} + static void dump_basic_constraints(const CERT_EXTENSION *ext) { CERT_BASIC_CONSTRAINTS_INFO *info; @@ -754,14 +933,161 @@ static void dump_basic_constraints2(const CERT_EXTENSION *ext) } } +static void dump_key_usage(const CERT_EXTENSION *ext) +{ + CRYPT_BIT_BLOB usage; + DWORD size = sizeof(usage); + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData, + ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size)) + { +#define trace_usage_bit(bits, bit) \ + if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit) + if (usage.cbData) + { + trace_usage_bit(usage.pbData[0], CERT_DIGITAL_SIGNATURE_KEY_USAGE); + trace_usage_bit(usage.pbData[0], CERT_NON_REPUDIATION_KEY_USAGE); + trace_usage_bit(usage.pbData[0], CERT_KEY_ENCIPHERMENT_KEY_USAGE); + trace_usage_bit(usage.pbData[0], CERT_DATA_ENCIPHERMENT_KEY_USAGE); + trace_usage_bit(usage.pbData[0], CERT_KEY_AGREEMENT_KEY_USAGE); + trace_usage_bit(usage.pbData[0], CERT_KEY_CERT_SIGN_KEY_USAGE); + trace_usage_bit(usage.pbData[0], CERT_CRL_SIGN_KEY_USAGE); + trace_usage_bit(usage.pbData[0], CERT_ENCIPHER_ONLY_KEY_USAGE); + } +#undef trace_usage_bit + if (usage.cbData > 1 && usage.pbData[1] & CERT_DECIPHER_ONLY_KEY_USAGE) + TRACE_(chain)("CERT_DECIPHER_ONLY_KEY_USAGE\n"); + } +} + +static void dump_general_subtree(const CERT_GENERAL_SUBTREE *subtree) +{ + dump_alt_name_entry(&subtree->Base); + TRACE_(chain)("dwMinimum = %d, fMaximum = %d, dwMaximum = %d\n", + subtree->dwMinimum, subtree->fMaximum, subtree->dwMaximum); +} + +static void dump_name_constraints(const CERT_EXTENSION *ext) +{ + CERT_NAME_CONSTRAINTS_INFO *nameConstraints; + DWORD size; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS, + ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &nameConstraints, + &size)) + { + DWORD i; + + TRACE_(chain)("%d permitted subtrees:\n", + nameConstraints->cPermittedSubtree); + for (i = 0; i < nameConstraints->cPermittedSubtree; i++) + dump_general_subtree(&nameConstraints->rgPermittedSubtree[i]); + TRACE_(chain)("%d excluded subtrees:\n", + nameConstraints->cExcludedSubtree); + for (i = 0; i < nameConstraints->cExcludedSubtree; i++) + dump_general_subtree(&nameConstraints->rgExcludedSubtree[i]); + LocalFree(nameConstraints); + } +} + +static void dump_cert_policies(const CERT_EXTENSION *ext) +{ + CERT_POLICIES_INFO *policies; + DWORD size; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES, + ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, + &policies, &size)) + { + DWORD i, j; + + TRACE_(chain)("%d policies:\n", policies->cPolicyInfo); + for (i = 0; i < policies->cPolicyInfo; i++) + { + TRACE_(chain)("policy identifier: %s\n", + debugstr_a(policies->rgPolicyInfo[i].pszPolicyIdentifier)); + TRACE_(chain)("%d policy qualifiers:\n", + policies->rgPolicyInfo[i].cPolicyQualifier); + for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++) + TRACE_(chain)("%s\n", debugstr_a( + policies->rgPolicyInfo[i].rgPolicyQualifier[j]. + pszPolicyQualifierId)); + } + LocalFree(policies); + } +} + +static void dump_enhanced_key_usage(const CERT_EXTENSION *ext) +{ + CERT_ENHKEY_USAGE *usage; + DWORD size; + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, + ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, + &usage, &size)) + { + DWORD i; + + TRACE_(chain)("%d usages:\n", usage->cUsageIdentifier); + for (i = 0; i < usage->cUsageIdentifier; i++) + TRACE_(chain)("%s\n", usage->rgpszUsageIdentifier[i]); + LocalFree(usage); + } +} + +static void dump_netscape_cert_type(const CERT_EXTENSION *ext) +{ + CRYPT_BIT_BLOB usage; + DWORD size = sizeof(usage); + + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData, + ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size)) + { +#define trace_cert_type_bit(bits, bit) \ + if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit) + if (usage.cbData) + { + trace_cert_type_bit(usage.pbData[0], + NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE); + trace_cert_type_bit(usage.pbData[0], + NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE); + trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CERT_TYPE); + trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CERT_TYPE); + trace_cert_type_bit(usage.pbData[0], NETSCAPE_SSL_CA_CERT_TYPE); + trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CA_CERT_TYPE); + trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CA_CERT_TYPE); + } +#undef trace_cert_type_bit + } +} + static void dump_extension(const CERT_EXTENSION *ext) { TRACE_(chain)("%s (%scritical)\n", debugstr_a(ext->pszObjId), ext->fCritical ? "" : "not "); - if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS)) + if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME)) + dump_alt_name("subject alt name", ext); + else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME)) + dump_alt_name("issuer alt name", ext); + else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS)) dump_basic_constraints(ext); + else if (!strcmp(ext->pszObjId, szOID_KEY_USAGE)) + dump_key_usage(ext); + else if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME2)) + dump_alt_name("subject alt name 2", ext); + else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME2)) + dump_alt_name("issuer alt name 2", ext); else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS2)) dump_basic_constraints2(ext); + else if (!strcmp(ext->pszObjId, szOID_NAME_CONSTRAINTS)) + dump_name_constraints(ext); + else if (!strcmp(ext->pszObjId, szOID_CERT_POLICIES)) + dump_cert_policies(ext); + else if (!strcmp(ext->pszObjId, szOID_ENHANCED_KEY_USAGE)) + dump_enhanced_key_usage(ext); + else if (!strcmp(ext->pszObjId, szOID_NETSCAPE_CERT_TYPE)) + dump_netscape_cert_type(ext); } static LPCWSTR filetime_to_str(const FILETIME *time) @@ -785,7 +1111,7 @@ static void dump_element(PCCERT_CONTEXT cert) LPWSTR name = NULL; DWORD len, i; - TRACE_(chain)("%p\n", cert); + TRACE_(chain)("%p: version %d\n", cert, cert->pCertInfo->dwVersion); len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0); name = CryptMemAlloc(len * sizeof(WCHAR)); @@ -814,33 +1140,263 @@ static void dump_element(PCCERT_CONTEXT cert) dump_extension(&cert->pCertInfo->rgExtension[i]); } +static BOOL CRYPT_KeyUsageValid(PCertificateChainEngine engine, + PCCERT_CONTEXT cert, BOOL isRoot, BOOL isCA, DWORD index) +{ + PCERT_EXTENSION ext; + BOOL ret; + BYTE usageBits = 0; + + ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension, + cert->pCertInfo->rgExtension); + if (ext) + { + CRYPT_BIT_BLOB usage; + DWORD size = sizeof(usage); + + ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_BITS, + ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, + &usage, &size); + if (!ret) + return FALSE; + else if (usage.cbData > 2) + { + /* The key usage extension only defines 9 bits => no more than 2 + * bytes are needed to encode all known usages. + */ + return FALSE; + } + else + { + /* The only bit relevant to chain validation is the keyCertSign + * bit, which is always in the least significant byte of the + * key usage bits. + */ + usageBits = usage.pbData[usage.cbData - 1]; + } + } + if (isCA) + { + if (!ext) + { + /* MS appears to violate RFC 5280, section 4.2.1.3 (Key Usage) + * here. Quoting the RFC: + * "This [key usage] extension MUST appear in certificates that + * contain public keys that are used to validate digital signatures + * on other public key certificates or CRLs." + * MS appears to accept certs that do not contain key usage + * extensions as CA certs. V1 and V2 certificates did not have + * extensions, and many root certificates are V1 certificates, so + * perhaps this is prudent. On the other hand, MS also accepts V3 + * certs without key usage extensions. We are more restrictive: + * we accept locally installed V1 or V2 certs as CA certs. + * We also accept a lack of key usage extension on root certs, + * which is implied in RFC 5280, section 6.1: the trust anchor's + * only requirement is that it was used to issue the next + * certificate in the chain. + */ + if (isRoot) + ret = TRUE; + else if (cert->pCertInfo->dwVersion == CERT_V1 || + cert->pCertInfo->dwVersion == CERT_V2) + { + PCCERT_CONTEXT localCert = CRYPT_FindCertInStore( + engine->hWorld, cert); + + ret = localCert != NULL; + CertFreeCertificateContext(localCert); + } + else + ret = FALSE; + if (!ret) + WARN_(chain)("no key usage extension on a CA cert\n"); + } + else + { + if (!(usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE)) + { + WARN_(chain)("keyCertSign not asserted on a CA cert\n"); + ret = FALSE; + } + else + ret = TRUE; + } + } + else + { + if (ext && (usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE)) + { + WARN_(chain)("keyCertSign asserted on a non-CA cert\n"); + ret = FALSE; + } + else + ret = TRUE; + } + return ret; +} + +static BOOL CRYPT_ExtendedKeyUsageValidForCA(PCCERT_CONTEXT cert) +{ + PCERT_EXTENSION ext; + BOOL ret; + + /* RFC 5280, section 4.2.1.12: "In general, this extension will only + * appear in end entity certificates." And, "If a certificate contains + * both a key usage extension and an extended key usage extension, then + * both extensions MUST be processed independently and the certificate MUST + * only be used for a purpose consistent with both extensions." This seems + * to imply that it should be checked if present, and ignored if not. + * Unfortunately some CAs, e.g. the Thawte SGC CA, don't include the code + * signing extended key usage, whereas they do include the keyCertSign + * key usage. Thus, when checking for a CA, we only require the + * code signing extended key usage if the extended key usage is critical. + */ + ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE, + cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); + if (ext && ext->fCritical) + { + CERT_ENHKEY_USAGE *usage; + DWORD size; + + ret = CryptDecodeObjectEx(cert->dwCertEncodingType, + X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size); + if (ret) + { + DWORD i; + + /* Explicitly require the code signing extended key usage for a CA + * with an extended key usage extension. That is, don't assume + * a cert is allowed to be a CA if it specifies the + * anyExtendedKeyUsage usage oid. See again RFC 5280, section + * 4.2.1.12: "Applications that require the presence of a + * particular purpose MAY reject certificates that include the + * anyExtendedKeyUsage OID but not the particular OID expected for + * the application." + */ + ret = FALSE; + for (i = 0; !ret && i < usage->cUsageIdentifier; i++) + if (!strcmp(usage->rgpszUsageIdentifier[i], + szOID_PKIX_KP_CODE_SIGNING)) + ret = TRUE; + LocalFree(usage); + } + } + else + ret = TRUE; + return ret; +} + +static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert) +{ + BOOL ret = TRUE; + DWORD i; + + for (i = 0; ret && i < cert->pCertInfo->cExtension; i++) + { + if (cert->pCertInfo->rgExtension[i].fCritical) + { + LPCSTR oid = cert->pCertInfo->rgExtension[i].pszObjId; + + if (!strcmp(oid, szOID_BASIC_CONSTRAINTS)) + ret = TRUE; + else if (!strcmp(oid, szOID_BASIC_CONSTRAINTS2)) + ret = TRUE; + else if (!strcmp(oid, szOID_NAME_CONSTRAINTS)) + ret = TRUE; + else if (!strcmp(oid, szOID_KEY_USAGE)) + ret = TRUE; + else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME)) + ret = TRUE; + else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME2)) + ret = TRUE; + else if (!strcmp(oid, szOID_ENHANCED_KEY_USAGE)) + ret = TRUE; + else + { + FIXME("unsupported critical extension %s\n", + debugstr_a(oid)); + ret = FALSE; + } + } + } + return ret; +} + +static BOOL CRYPT_IsCertVersionValid(PCCERT_CONTEXT cert) +{ + BOOL ret = TRUE; + + /* Checks whether the contents of the cert match the cert's version. */ + switch (cert->pCertInfo->dwVersion) + { + case CERT_V1: + /* A V1 cert may not contain unique identifiers. See RFC 5280, + * section 4.1.2.8: + * "These fields MUST only appear if the version is 2 or 3 (Section + * 4.1.2.1). These fields MUST NOT appear if the version is 1." + */ + if (cert->pCertInfo->IssuerUniqueId.cbData || + cert->pCertInfo->SubjectUniqueId.cbData) + ret = FALSE; + /* A V1 cert may not contain extensions. See RFC 5280, section 4.1.2.9: + * "This field MUST only appear if the version is 3 (Section 4.1.2.1)." + */ + if (cert->pCertInfo->cExtension) + ret = FALSE; + break; + case CERT_V2: + /* A V2 cert may not contain extensions. See RFC 5280, section 4.1.2.9: + * "This field MUST only appear if the version is 3 (Section 4.1.2.1)." + */ + if (cert->pCertInfo->cExtension) + ret = FALSE; + break; + case CERT_V3: + /* Do nothing, all fields are allowed for V3 certs */ + break; + default: + WARN_(chain)("invalid cert version %d\n", cert->pCertInfo->dwVersion); + ret = FALSE; + } + return ret; +} + 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 }; + CERT_BASIC_CONSTRAINTS2_INFO constraints = { FALSE, FALSE, 0 }; TRACE_(chain)("checking chain with %d elements for time %s\n", chain->cElement, debugstr_w(filetime_to_str(time))); for (i = chain->cElement - 1; i >= 0; i--) { + BOOL isRoot; + if (TRACE_ON(chain)) dump_element(chain->rgpElement[i]->pCertContext); + if (i == chain->cElement - 1) + isRoot = CRYPT_IsCertificateSelfSigned( + chain->rgpElement[i]->pCertContext); + else + isRoot = FALSE; + if (!CRYPT_IsCertVersionValid(chain->rgpElement[i]->pCertContext)) + { + /* MS appears to accept certs whose versions don't match their + * contents, so there isn't an appropriate error code. + */ + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_INVALID_EXTENSION; + } if (CertVerifyTimeValidity(time, chain->rgpElement[i]->pCertContext->pCertInfo) != 0) chain->rgpElement[i]->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_TIME_VALID; if (i != 0) { - BOOL isRoot; - - if (i == chain->cElement - 1) - isRoot = CRYPT_IsCertificateSelfSigned( - chain->rgpElement[i]->pCertContext); - else - isRoot = FALSE; /* Check the signature of the cert this issued */ if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING, CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, @@ -855,9 +1411,9 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine, if (pathLengthConstraintViolated) chain->rgpElement[i]->TrustStatus.dwErrorStatus |= CERT_TRUST_INVALID_BASIC_CONSTRAINTS; - else if (!CRYPT_CheckBasicConstraintsForCA( - chain->rgpElement[i]->pCertContext, &constraints, i - 1, - isRoot, &pathLengthConstraintViolated)) + else if (!CRYPT_CheckBasicConstraintsForCA(engine, + chain->rgpElement[i]->pCertContext, &constraints, i - 1, isRoot, + &pathLengthConstraintViolated)) chain->rgpElement[i]->TrustStatus.dwErrorStatus |= CERT_TRUST_INVALID_BASIC_CONSTRAINTS; else if (constraints.fPathLenConstraint && @@ -867,6 +1423,23 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine, constraints.dwPathLenConstraint--; } } + else + { + /* Check whether end cert has a basic constraints extension */ + if (!CRYPT_DecodeBasicConstraints( + chain->rgpElement[i]->pCertContext, &constraints, FALSE)) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_INVALID_BASIC_CONSTRAINTS; + } + if (!CRYPT_KeyUsageValid(engine, chain->rgpElement[i]->pCertContext, + isRoot, constraints.fCA, i)) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_NOT_VALID_FOR_USAGE; + if (i != 0) + if (!CRYPT_ExtendedKeyUsageValidForCA( + chain->rgpElement[i]->pCertContext)) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_IS_NOT_VALID_FOR_USAGE; if (CRYPT_IsSimpleChainCyclic(chain)) { /* If the chain is cyclic, then the path length constraints @@ -877,7 +1450,11 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine, CERT_TRUST_IS_PARTIAL_CHAIN | CERT_TRUST_INVALID_BASIC_CONSTRAINTS; } - /* FIXME: check valid usages */ + /* Check whether every critical extension is supported */ + if (!CRYPT_CriticalExtensionsSupported( + chain->rgpElement[i]->pCertContext)) + chain->rgpElement[i]->TrustStatus.dwErrorStatus |= + CERT_TRUST_INVALID_EXTENSION; CRYPT_CombineTrustStatus(&chain->TrustStatus, &chain->rgpElement[i]->TrustStatus); } @@ -1333,14 +1910,16 @@ static PCertificateChain CRYPT_BuildAlternateContextFromChain( 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_SIGNATURE_VALID 0x16 +#define CHAIN_QUALITY_TIME_VALID 8 +#define CHAIN_QUALITY_COMPLETE_CHAIN 4 +#define CHAIN_QUALITY_BASIC_CONSTRAINTS 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 + CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_BASIC_CONSTRAINTS | \ + CHAIN_QUALITY_TRUSTED_ROOT #define IS_TRUST_ERROR_SET(TrustStatus, bits) \ (TrustStatus)->dwErrorStatus & (bits) @@ -1352,9 +1931,11 @@ static DWORD CRYPT_ChainQuality(const CertificateChain *chain) 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_INVALID_BASIC_CONSTRAINTS)) + quality &= ~CHAIN_QUALITY_BASIC_CONSTRAINTS; 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)) @@ -1544,6 +2125,31 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, } } +static void dump_usage_match(LPCSTR name, const CERT_USAGE_MATCH *usageMatch) +{ + DWORD i; + + TRACE_(chain)("%s: %s\n", name, + usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR"); + for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++) + TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]); +} + +static void dump_chain_para(const CERT_CHAIN_PARA *pChainPara) +{ + TRACE_(chain)("%d\n", pChainPara->cbSize); + if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS)) + dump_usage_match("RequestedUsage", &pChainPara->RequestedUsage); + if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA)) + { + dump_usage_match("RequestedIssuancePolicy", + &pChainPara->RequestedIssuancePolicy); + TRACE_(chain)("%d\n", pChainPara->dwUrlRetrievalTimeout); + TRACE_(chain)("%d\n", pChainPara->fCheckRevocationFreshnessTime); + TRACE_(chain)("%d\n", pChainPara->dwRevocationFreshnessTime); + } +} + BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore, PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved, @@ -1570,6 +2176,8 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, if (!hChainEngine) hChainEngine = CRYPT_GetDefaultChainEngine(); + if (TRACE_ON(chain)) + dump_chain_para(pChainPara); /* FIXME: what about HCCE_LOCAL_MACHINE? */ ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime, hAdditionalStore, &chain); @@ -1746,6 +2354,348 @@ static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID, return TRUE; } +static BOOL match_dns_to_subject_alt_name(PCERT_EXTENSION ext, + LPCWSTR server_name) +{ + BOOL matches = FALSE; + CERT_ALT_NAME_INFO *subjectName; + DWORD size; + + TRACE_(chain)("%s\n", debugstr_w(server_name)); + /* This could be spoofed by the embedded NULL vulnerability, since the + * returned CERT_ALT_NAME_INFO doesn't have a way to indicate the + * encoded length of a name. Fortunately CryptDecodeObjectEx fails if + * the encoded form of the name contains a NULL. + */ + 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; + + /* RFC 5280 states that multiple instances of each name type may exist, + * in section 4.2.1.6: + * "Multiple name forms, and multiple instances of each name form, + * MAY be included." + * It doesn't specify the behavior in such cases, but common usage is + * to accept a certificate if any name matches. + */ + for (i = 0; !matches && i < subjectName->cAltEntry; i++) + { + if (subjectName->rgAltEntry[i].dwAltNameChoice == + CERT_ALT_NAME_DNS_NAME) + { + TRACE_(chain)("dNSName: %s\n", debugstr_w( + subjectName->rgAltEntry[i].u.pwszDNSName)); + if (!strcmpiW(server_name, + subjectName->rgAltEntry[i].u.pwszDNSName)) + matches = TRUE; + } + } + LocalFree(subjectName); + } + return matches; +} + +static BOOL find_matching_domain_component(CERT_NAME_INFO *name, + LPCWSTR component) +{ + BOOL matches = FALSE; + DWORD i, j; + + for (i = 0; !matches && i < name->cRDN; i++) + for (j = 0; j < name->rgRDN[i].cRDNAttr; j++) + if (!strcmp(szOID_DOMAIN_COMPONENT, + name->rgRDN[i].rgRDNAttr[j].pszObjId)) + { + PCERT_RDN_ATTR attr; + + attr = &name->rgRDN[i].rgRDNAttr[j]; + /* Compare with memicmpW rather than strcmpiW in order to avoid + * a match with a string with an embedded NULL. The component + * must match one domain component attribute's entire string + * value with a case-insensitive match. + */ + matches = !memicmpW(component, (LPWSTR)attr->Value.pbData, + attr->Value.cbData / sizeof(WCHAR)); + } + return matches; +} + +static BOOL match_domain_component(LPCWSTR allowed_component, DWORD allowed_len, + LPCWSTR server_component, DWORD server_len, BOOL allow_wildcards, + BOOL *see_wildcard) +{ + LPCWSTR allowed_ptr, server_ptr; + BOOL matches = TRUE; + + *see_wildcard = FALSE; + if (server_len < allowed_len) + { + WARN_(chain)("domain component %s too short for %s\n", + debugstr_wn(server_component, server_len), + debugstr_wn(allowed_component, allowed_len)); + /* A domain component can't contain a wildcard character, so a domain + * component shorter than the allowed string can't produce a match. + */ + return FALSE; + } + for (allowed_ptr = allowed_component, server_ptr = server_component; + matches && allowed_ptr - allowed_component < allowed_len; + allowed_ptr++, server_ptr++) + { + if (*allowed_ptr == '*') + { + if (allowed_ptr - allowed_component < allowed_len - 1) + { + WARN_(chain)("non-wildcard characters after wildcard not supported\n"); + matches = FALSE; + } + else if (!allow_wildcards) + { + WARN_(chain)("wildcard after non-wildcard component\n"); + matches = FALSE; + } + else + { + /* the preceding characters must have matched, so the rest of + * the component also matches. + */ + *see_wildcard = TRUE; + break; + } + } + matches = tolowerW(*allowed_ptr) == tolowerW(*server_ptr); + } + if (matches && server_ptr - server_component < server_len) + { + /* If there are unmatched characters in the server domain component, + * the server domain only matches if the allowed string ended in a '*'. + */ + matches = *allowed_ptr == '*'; + } + return matches; +} + +static BOOL match_common_name(LPCWSTR server_name, PCERT_RDN_ATTR nameAttr) +{ + LPCWSTR allowed = (LPCWSTR)nameAttr->Value.pbData; + LPCWSTR allowed_component = allowed; + DWORD allowed_len = nameAttr->Value.cbData / sizeof(WCHAR); + LPCWSTR server_component = server_name; + DWORD server_len = strlenW(server_name); + BOOL matches = TRUE, allow_wildcards = TRUE; + + TRACE_(chain)("CN = %s\n", debugstr_wn(allowed_component, allowed_len)); + + /* From RFC 2818 (HTTP over TLS), section 3.1: + * "Names may contain the wildcard character * which is considered to match + * any single domain name component or component fragment. E.g., + * *.a.com matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com + * but not bar.com." + * + * And from RFC 2595 (Using TLS with IMAP, POP3 and ACAP), section 2.4: + * "A "*" wildcard character MAY be used as the left-most name component in + * the certificate. For example, *.example.com would match a.example.com, + * foo.example.com, etc. but would not match example.com." + * + * There are other protocols which use TLS, and none of them is + * authoritative. This accepts certificates in common usage, e.g. + * *.domain.com matches www.domain.com but not domain.com, and + * www*.domain.com matches www1.domain.com but not mail.domain.com. + */ + do { + LPCWSTR allowed_dot, server_dot; + + allowed_dot = memchrW(allowed_component, '.', + allowed_len - (allowed_component - allowed)); + server_dot = memchrW(server_component, '.', + server_len - (server_component - server_name)); + /* The number of components must match */ + if ((!allowed_dot && server_dot) || (allowed_dot && !server_dot)) + { + if (!allowed_dot) + WARN_(chain)("%s: too many components for CN=%s\n", + debugstr_w(server_name), debugstr_wn(allowed, allowed_len)); + else + WARN_(chain)("%s: not enough components for CN=%s\n", + debugstr_w(server_name), debugstr_wn(allowed, allowed_len)); + matches = FALSE; + } + else + { + LPCWSTR allowed_end, server_end; + BOOL has_wildcard; + + allowed_end = allowed_dot ? allowed_dot : allowed + allowed_len; + server_end = server_dot ? server_dot : server_name + server_len; + matches = match_domain_component(allowed_component, + allowed_end - allowed_component, server_component, + server_end - server_component, allow_wildcards, &has_wildcard); + /* Once a non-wildcard component is seen, no wildcard components + * may follow + */ + if (!has_wildcard) + allow_wildcards = FALSE; + if (matches) + { + allowed_component = allowed_dot ? allowed_dot + 1 : allowed_end; + server_component = server_dot ? server_dot + 1 : server_end; + } + } + } while (matches && allowed_component && + allowed_component - allowed < allowed_len && + server_component && server_component - server_name < server_len); + TRACE_(chain)("returning %d\n", matches); + return matches; +} + +static BOOL match_dns_to_subject_dn(PCCERT_CONTEXT cert, LPCWSTR server_name) +{ + BOOL matches = FALSE; + CERT_NAME_INFO *name; + DWORD size; + + TRACE_(chain)("%s\n", debugstr_w(server_name)); + if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME, + cert->pCertInfo->Subject.pbData, cert->pCertInfo->Subject.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, + &name, &size)) + { + /* If the subject distinguished name contains any name components, + * make sure all of them are present. + */ + if (CertFindRDNAttr(szOID_DOMAIN_COMPONENT, name)) + { + LPCWSTR ptr = server_name; + + matches = TRUE; + do { + LPCWSTR dot = strchrW(ptr, '.'), end; + /* 254 is the maximum DNS label length, see RFC 1035 */ + WCHAR component[255]; + DWORD len; + + end = dot ? dot : ptr + strlenW(ptr); + len = end - ptr; + if (len >= sizeof(component) / sizeof(component[0])) + { + WARN_(chain)("domain component %s too long\n", + debugstr_wn(ptr, len)); + matches = FALSE; + } + else + { + memcpy(component, ptr, len * sizeof(WCHAR)); + component[len] = 0; + matches = find_matching_domain_component(name, component); + } + ptr = dot ? dot + 1 : end; + } while (matches && ptr && *ptr); + } + else + { + PCERT_RDN_ATTR attr; + + /* If the certificate isn't using a DN attribute in the name, make + * make sure the common name matches. + */ + if ((attr = CertFindRDNAttr(szOID_COMMON_NAME, name))) + matches = match_common_name(server_name, attr); + } + LocalFree(name); + } + return matches; +} + +static BOOL WINAPI verify_ssl_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_UNTRUSTEDROOT; + 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 if (pChainContext->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_TIME_VALID) + { + pPolicyStatus->dwError = CERT_E_EXPIRED; + find_element_with_error(pChainContext, + CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex, + &pPolicyStatus->lElementIndex); + } + else + pPolicyStatus->dwError = NO_ERROR; + /* We only need bother checking whether the name in the end certificate + * matches if the chain is otherwise okay. + */ + if (!pPolicyStatus->dwError && pPolicyPara && + pPolicyPara->cbSize >= sizeof(CERT_CHAIN_POLICY_PARA)) + { + HTTPSPolicyCallbackData *sslPara = pPolicyPara->pvExtraPolicyPara; + + if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData)) + { + if (sslPara->dwAuthType == AUTHTYPE_SERVER && + sslPara->pwszServerName) + { + PCCERT_CONTEXT cert; + PCERT_EXTENSION altNameExt; + BOOL matches; + + cert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext; + altNameExt = get_subject_alt_name_ext(cert->pCertInfo); + /* If the alternate name extension exists, the name it contains + * is bound to the certificate, so make sure the name matches + * it. Otherwise, look for the server name in the subject + * distinguished name. RFC5280, section 4.2.1.6: + * "Whenever such identities are to be bound into a + * certificate, the subject alternative name (or issuer + * alternative name) extension MUST be used; however, a DNS + * name MAY also be represented in the subject field using the + * domainComponent attribute." + */ + if (altNameExt) + matches = match_dns_to_subject_alt_name(altNameExt, + sslPara->pwszServerName); + else + matches = match_dns_to_subject_dn(cert, + sslPara->pwszServerName); + if (!matches) + { + pPolicyStatus->dwError = CERT_E_CN_NO_MATCH; + pPolicyStatus->lChainIndex = 0; + pPolicyStatus->lElementIndex = 0; + } + } + } + } + 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, @@ -1886,6 +2836,9 @@ BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID, case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE): verifyPolicy = verify_authenticode_policy; break; + case LOWORD(CERT_CHAIN_POLICY_SSL): + verifyPolicy = verify_ssl_policy; + break; case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS): verifyPolicy = verify_basic_constraints_policy; break; @@ -1909,5 +2862,6 @@ BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID, pPolicyStatus); if (hFunc) CryptFreeOIDFunctionAddress(hFunc, 0); + TRACE("returning %d (%08x)\n", ret, pPolicyStatus->dwError); return ret; } diff --git a/reactos/dll/win32/crypt32/collectionstore.c b/reactos/dll/win32/crypt32/collectionstore.c index 12eb7c3f7aa..35941dd7317 100644 --- a/reactos/dll/win32/crypt32/collectionstore.c +++ b/reactos/dll/win32/crypt32/collectionstore.c @@ -255,11 +255,19 @@ static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext) { BOOL ret; + PCCERT_CONTEXT linked; TRACE("(%p, %p)\n", store, pCertContext); - ret = CertDeleteCertificateFromStore( - Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT))); + /* Deleting the linked context results in its ref count getting + * decreased, but the caller of this (CertDeleteCertificateFromStore) also + * decreases pCertContext's ref count, by calling + * CertFreeCertificateContext. Increase ref count of linked context to + * compensate. + */ + linked = Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)); + CertDuplicateCertificateContext(linked); + ret = CertDeleteCertificateFromStore(linked); return ret; } @@ -333,11 +341,18 @@ static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store, void *pCrlContext) { BOOL ret; + PCCRL_CONTEXT linked; TRACE("(%p, %p)\n", store, pCrlContext); - ret = CertDeleteCRLFromStore( - Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT))); + /* Deleting the linked context results in its ref count getting + * decreased, but the caller of this (CertDeleteCRLFromStore) also + * decreases pCrlContext's ref count, by calling CertFreeCRLContext. + * Increase ref count of linked context to compensate. + */ + linked = Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)); + CertDuplicateCRLContext(linked); + ret = CertDeleteCRLFromStore(linked); return ret; } @@ -411,11 +426,57 @@ static BOOL CRYPT_CollectionDeleteCTL(PWINECRYPT_CERTSTORE store, void *pCtlContext) { BOOL ret; + PCCTL_CONTEXT linked; TRACE("(%p, %p)\n", store, pCtlContext); - ret = CertDeleteCTLFromStore( - Context_GetLinkedContext(pCtlContext, sizeof(CTL_CONTEXT))); + /* Deleting the linked context results in its ref count getting + * decreased, but the caller of this (CertDeleteCTLFromStore) also + * decreases pCtlContext's ref count, by calling CertFreeCTLContext. + * Increase ref count of linked context to compensate. + */ + linked = Context_GetLinkedContext(pCtlContext, sizeof(CTL_CONTEXT)); + CertDuplicateCTLContext(linked); + ret = CertDeleteCTLFromStore(linked); + return ret; +} + +static BOOL WINAPI CRYPT_CollectionControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + BOOL ret; + PWINE_COLLECTIONSTORE store = hCertStore; + PWINE_STORE_LIST_ENTRY entry; + + TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, + pvCtrlPara); + + if (!store) + return TRUE; + if (store->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if (store->hdr.type != StoreTypeCollection) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + + ret = TRUE; + EnterCriticalSection(&store->cs); + LIST_FOR_EACH_ENTRY(entry, &store->stores, WINE_STORE_LIST_ENTRY, entry) + { + if (entry->store->control) + { + ret = entry->store->control(entry->store, dwFlags, dwCtrlType, + pvCtrlPara); + if (!ret) + break; + } + } + LeaveCriticalSection(&store->cs); return ret; } @@ -446,6 +507,7 @@ PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv, store->hdr.ctls.addContext = CRYPT_CollectionAddCTL; store->hdr.ctls.enumContext = CRYPT_CollectionEnumCTL; store->hdr.ctls.deleteContext = CRYPT_CollectionDeleteCTL; + store->hdr.control = CRYPT_CollectionControl; InitializeCriticalSection(&store->cs); store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs"); list_init(&store->stores); diff --git a/reactos/dll/win32/crypt32/context.c b/reactos/dll/win32/crypt32/context.c index bb877995a1d..bf4ccf3cac1 100644 --- a/reactos/dll/win32/crypt32/context.c +++ b/reactos/dll/win32/crypt32/context.c @@ -24,7 +24,7 @@ #include "wine/list.h" #include "crypt32_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(crypt); +WINE_DEFAULT_DEBUG_CHANNEL(context); typedef enum _ContextType { ContextTypeData, @@ -94,7 +94,7 @@ void *Context_CreateLinkContext(unsigned int contextSize, void *linked, unsigned linkContext->type = ContextTypeLink; linkContext->linked = linkedBase; if (addRef) - InterlockedIncrement(&linkedBase->ref); + Context_AddRef(linked, contextSize); TRACE("%p's ref count is %d\n", context, linkContext->ref); } TRACE("returning %p\n", context); @@ -106,6 +106,37 @@ void Context_AddRef(void *context, size_t contextSize) PBASE_CONTEXT baseContext = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); InterlockedIncrement(&baseContext->ref); + TRACE("%p's ref count is %d\n", context, baseContext->ref); + if (baseContext->type == ContextTypeLink) + { + void *linkedContext = Context_GetLinkedContext(context, contextSize); + PBASE_CONTEXT linkedBase = BASE_CONTEXT_FROM_CONTEXT(linkedContext, + contextSize); + + /* Add-ref the linked contexts too */ + while (linkedContext && linkedBase->type == ContextTypeLink) + { + InterlockedIncrement(&linkedBase->ref); + TRACE("%p's ref count is %d\n", linkedContext, linkedBase->ref); + linkedContext = Context_GetLinkedContext(linkedContext, + contextSize); + if (linkedContext) + linkedBase = BASE_CONTEXT_FROM_CONTEXT(linkedContext, + contextSize); + else + linkedBase = NULL; + } + if (linkedContext) + { + /* It's not a link context, so it wasn't add-ref'ed in the while + * loop, so add-ref it here. + */ + linkedBase = BASE_CONTEXT_FROM_CONTEXT(linkedContext, + contextSize); + InterlockedIncrement(&linkedBase->ref); + TRACE("%p's ref count is %d\n", linkedContext, linkedBase->ref); + } + } } void *Context_GetExtra(const void *context, size_t contextSize) @@ -135,35 +166,39 @@ PCONTEXT_PROPERTY_LIST Context_GetProperties(const void *context, size_t context ((PDATA_CONTEXT)ptr)->properties : NULL; } -void Context_Release(void *context, size_t contextSize, +BOOL Context_Release(void *context, size_t contextSize, ContextFreeFunc dataContextFree) { PBASE_CONTEXT base = BASE_CONTEXT_FROM_CONTEXT(context, contextSize); + BOOL ret = TRUE; + if (base->ref <= 0) + { + ERR("%p's ref count is %d\n", context, base->ref); + return FALSE; + } + if (base->type == ContextTypeLink) + { + /* The linked context is of the same type as this, so release + * it as well, using the same offset and data free function. + */ + ret = Context_Release(CONTEXT_FROM_BASE_CONTEXT( + ((PLINK_CONTEXT)base)->linked, contextSize), contextSize, + dataContextFree); + } if (InterlockedDecrement(&base->ref) == 0) { TRACE("freeing %p\n", context); - switch (base->type) + if (base->type == ContextTypeData) { - case ContextTypeData: ContextPropertyList_Free(((PDATA_CONTEXT)base)->properties); dataContextFree(context); - break; - case ContextTypeLink: - /* The linked context is of the same type as this, so release - * it as well, using the same offset and data free function. - */ - Context_Release(CONTEXT_FROM_BASE_CONTEXT( - ((PLINK_CONTEXT)base)->linked, contextSize), contextSize, - dataContextFree); - break; - default: - assert(0); } CryptMemFree(context); } else TRACE("%p's ref count is %d\n", context, base->ref); + return ret; } void Context_CopyProperties(const void *to, const void *from, @@ -278,14 +313,21 @@ void *ContextList_Enum(struct ContextList *list, void *pPrev) return ret; } -void ContextList_Delete(struct ContextList *list, void *context) +BOOL ContextList_Remove(struct ContextList *list, void *context) { struct list *entry = ContextList_ContextToEntry(list, context); + BOOL inList = FALSE; EnterCriticalSection(&list->cs); - list_remove(entry); + if (!list_empty(entry)) + { + list_remove(entry); + inList = TRUE; + } LeaveCriticalSection(&list->cs); - list->contextInterface->free(context); + if (inList) + list_init(entry); + return inList; } static void ContextList_Empty(struct ContextList *list) diff --git a/reactos/dll/win32/crypt32/crl.c b/reactos/dll/win32/crypt32/crl.c index 271e4e0c1b4..522aadf616e 100644 --- a/reactos/dll/win32/crypt32/crl.c +++ b/reactos/dll/win32/crypt32/crl.c @@ -228,7 +228,8 @@ PCCRL_CONTEXT WINAPI CertGetCRLFromStore(HCERTSTORE hCertStore, PCCRL_CONTEXT WINAPI CertDuplicateCRLContext(PCCRL_CONTEXT pCrlContext) { TRACE("(%p)\n", pCrlContext); - Context_AddRef((void *)pCrlContext, sizeof(CRL_CONTEXT)); + if (pCrlContext) + Context_AddRef((void *)pCrlContext, sizeof(CRL_CONTEXT)); return pCrlContext; } @@ -242,12 +243,14 @@ static void CrlDataContext_Free(void *context) BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext) { + BOOL ret = TRUE; + TRACE("(%p)\n", pCrlContext); if (pCrlContext) - Context_Release((void *)pCrlContext, sizeof(CRL_CONTEXT), + ret = Context_Release((void *)pCrlContext, sizeof(CRL_CONTEXT), CrlDataContext_Free); - return TRUE; + return ret; } DWORD WINAPI CertEnumCRLContextProperties(PCCRL_CONTEXT pCRLContext, diff --git a/reactos/dll/win32/crypt32/crypt32.spec b/reactos/dll/win32/crypt32/crypt32.spec index 534bee7319f..b096c090c11 100644 --- a/reactos/dll/win32/crypt32/crypt32.spec +++ b/reactos/dll/win32/crypt32/crypt32.spec @@ -1,11 +1,12 @@ -@ stdcall CertAddCRLContextToStore(long ptr long ptr) -@ stdcall CertAddCTLContextToStore(long ptr long ptr) -@ stdcall CertAddCertificateContextToStore(long ptr long ptr) -@ stdcall CertAddEncodedCRLToStore(long long ptr long long ptr) -@ stdcall CertAddEncodedCTLToStore(long long ptr long long ptr) -@ stdcall CertAddEncodedCertificateToStore(long long ptr long long ptr) -@ stub CertAddEncodedCertificateToSystemStoreA -@ stub CertAddEncodedCertificateToSystemStoreW +@ stdcall CertAddCRLContextToStore(ptr ptr long ptr) +@ stdcall CertAddCTLContextToStore(ptr ptr long ptr) +@ stdcall CertAddCertificateContextToStore(ptr ptr long ptr) +@ stdcall CertAddCertificateLinkToStore(ptr ptr long ptr) +@ stdcall CertAddEncodedCRLToStore(ptr long ptr long long ptr) +@ stdcall CertAddEncodedCTLToStore(ptr long ptr long long ptr) +@ stdcall CertAddEncodedCertificateToStore(ptr long ptr long long ptr) +@ stdcall CertAddEncodedCertificateToSystemStoreA(str ptr long) +@ stdcall CertAddEncodedCertificateToSystemStoreW(wstr ptr long) @ stdcall CertAddEnhancedKeyUsageIdentifier(ptr str) @ stdcall CertAddSerializedElementToStore(ptr ptr long long long long ptr ptr) @ stdcall CertAddStoreToCollection(ptr ptr long long) @@ -15,7 +16,7 @@ @ stdcall CertCompareCertificateName(long ptr ptr) @ stdcall CertCompareIntegerBlob(ptr ptr) @ stdcall CertComparePublicKeyInfo(long ptr ptr) -@ stdcall CertControlStore(long long long ptr) +@ stdcall CertControlStore(ptr long long ptr) @ stdcall CertCreateCRLContext(long ptr long) @ stdcall CertCreateCTLContext(long ptr long) @ stdcall CertCreateCertificateChainEngine(ptr ptr) @@ -35,13 +36,13 @@ @ stdcall CertEnumCTLContextProperties(ptr long) @ stdcall CertEnumCTLsInStore(ptr ptr) @ stdcall CertEnumCertificateContextProperties(ptr long) -@ stdcall CertEnumCertificatesInStore(long ptr) +@ stdcall CertEnumCertificatesInStore(ptr ptr) @ stdcall CertEnumPhysicalStore(ptr long ptr ptr) @ stdcall CertEnumSystemStore(long ptr ptr ptr) @ stdcall CertFindAttribute(str long ptr) -@ stdcall CertFindCRLInStore(long long long long ptr ptr) -@ stdcall CertFindCTLInStore(long long long long ptr ptr) -@ stdcall CertFindCertificateInStore(long long long long ptr ptr) +@ stdcall CertFindCRLInStore(ptr long long long ptr ptr) +@ stdcall CertFindCTLInStore(ptr long long long ptr ptr) +@ stdcall CertFindCertificateInStore(ptr long long long ptr ptr) @ stdcall CertFindCertificateInCRL(ptr ptr long ptr ptr) @ stdcall CertFindExtension(str long ptr) @ stdcall CertFindRDNAttr(str ptr) @@ -57,12 +58,12 @@ @ stdcall CertGetCertificateChain(ptr ptr ptr ptr ptr long ptr ptr) @ stdcall CertGetCertificateContextProperty(ptr long ptr ptr) @ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr) -@ stub CertGetIntendedKeyUsage -@ stdcall CertGetIssuerCertificateFromStore(long ptr ptr ptr) +@ stdcall CertGetIntendedKeyUsage(long ptr ptr long) +@ stdcall CertGetIssuerCertificateFromStore(ptr ptr ptr ptr) @ 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 CertGetStoreProperty(ptr long ptr ptr) @ stdcall CertGetSubjectCertificateFromStore(ptr long ptr) @ stdcall CertGetValidUsages(long ptr ptr ptr ptr) @ stub CertIsRDNAttrsInCertificateName @@ -76,8 +77,8 @@ @ stdcall CertRDNValueToStrA(long ptr ptr long) @ stdcall CertRDNValueToStrW(long ptr ptr long) @ stdcall CertRemoveEnhancedKeyUsageIdentifier(ptr str) -@ stdcall CertRemoveStoreFromCollection(long long) -@ stdcall CertSaveStore(long long long long ptr long) +@ stdcall CertRemoveStoreFromCollection(ptr ptr) +@ stdcall CertSaveStore(ptr long long long ptr long) @ stdcall CertSerializeCRLStoreElement(ptr long ptr ptr) @ stdcall CertSerializeCTLStoreElement(ptr long ptr ptr) @ stdcall CertSerializeCertificateStoreElement(ptr long ptr ptr) @@ -98,7 +99,7 @@ @ stdcall CertVerifyValidityNesting(ptr ptr) @ stdcall CreateFileU(wstr long long ptr long long ptr) kernel32.CreateFileW @ stdcall CryptBinaryToStringA(ptr long long ptr ptr) -@ stub CryptBinaryToStringW # (ptr long long ptr ptr) +@ stdcall CryptBinaryToStringW(ptr long long ptr ptr) @ stdcall CryptStringToBinaryA(str long long ptr ptr ptr ptr) @ stdcall CryptStringToBinaryW (wstr long long ptr ptr ptr ptr) @ stdcall CryptAcquireContextU(ptr wstr wstr long long) advapi32.CryptAcquireContextW diff --git a/reactos/dll/win32/crypt32/crypt32_De.rc b/reactos/dll/win32/crypt32/crypt32_De.rc index aa3a4562c70..9c2c91e3714 100644 --- a/reactos/dll/win32/crypt32/crypt32_De.rc +++ b/reactos/dll/win32/crypt32/crypt32_De.rc @@ -41,7 +41,7 @@ STRINGTABLE DISCARDABLE IDS_ENHANCED_KEY_USAGE "Erweiterte Schlüsselbenutzung" IDS_AUTHORITY_INFO_ACCESS "Autoritätsinformationszugriff" IDS_CERT_EXTENSIONS "Zertifikatserweiterung" - IDS_NEXT_UPDATE_LOCATION "Next Update Location" + IDS_NEXT_UPDATE_LOCATION "nächster Aktualisierungsort" IDS_YES_OR_NO_TRUST "Vertrauen oder nicht vertrauen" IDS_EMAIL_ADDRESS "E-Mail-Adresse" IDS_UNSTRUCTURED_NAME "Unstrukturierter Name" diff --git a/reactos/dll/win32/crypt32/crypt32_private.h b/reactos/dll/win32/crypt32/crypt32_private.h index 07c63825b58..cbdf5116f9c 100644 --- a/reactos/dll/win32/crypt32/crypt32_private.h +++ b/reactos/dll/win32/crypt32/crypt32_private.h @@ -113,6 +113,10 @@ BOOL CRYPT_AsnDecodePKCSDigestedData(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, CRYPT_DIGESTED_DATA *digestedData, DWORD *pcbDigestedData); +BOOL WINAPI CRYPT_AsnEncodePubKeyInfoNoNull(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); + /* The following aren't defined in wincrypt.h, as they're "reserved" */ #define CERT_CERT_PROP_ID 32 #define CERT_CRL_PROP_ID 33 @@ -278,6 +282,12 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, */ BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store); +/* Reads contexts serialized in the blob into the memory store. Returns FALSE + * if the file is not of the expected format. + */ +BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob, + HCERTSTORE store); + /* 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 @@ -291,7 +301,7 @@ void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info); */ DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indent, - PCERT_NAME_BLOB pName, DWORD dwStrType, LPWSTR psz, DWORD csz); + const CERT_NAME_BLOB *pName, DWORD dwStrType, LPWSTR psz, DWORD csz); /** * Context functions @@ -336,8 +346,9 @@ typedef void (*ContextFreeFunc)(void *context); /* Decrements context's ref count. If context is a link context, releases its * linked context as well. * If a data context has its ref count reach 0, calls dataContextFree on it. + * Returns FALSE if the reference count is <= 0 when called. */ -void Context_Release(void *context, size_t contextSize, +BOOL Context_Release(void *context, size_t contextSize, ContextFreeFunc dataContextFree); /** @@ -377,7 +388,11 @@ void *ContextList_Add(struct ContextList *list, void *toLink, void *toReplace); void *ContextList_Enum(struct ContextList *list, void *pPrev); -void ContextList_Delete(struct ContextList *list, void *context); +/* Removes a context from the list. Returns TRUE if the context was removed, + * or FALSE if not. (The context may have been duplicated, so subsequent + * removes have no effect.) + */ +BOOL ContextList_Remove(struct ContextList *list, void *context); void ContextList_Free(struct ContextList *list); diff --git a/reactos/dll/win32/crypt32/ctl.c b/reactos/dll/win32/crypt32/ctl.c index 5a6d19b64fe..44b517aeff3 100644 --- a/reactos/dll/win32/crypt32/ctl.c +++ b/reactos/dll/win32/crypt32/ctl.c @@ -309,10 +309,7 @@ BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext) if (!pCtlContext) ret = TRUE; else if (!pCtlContext->hCertStore) - { - ret = TRUE; - CertFreeCTLContext(pCtlContext); - } + ret = CertFreeCTLContext(pCtlContext); else { PWINECRYPT_CERTSTORE hcs = pCtlContext->hCertStore; @@ -321,7 +318,8 @@ BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext) ret = FALSE; else ret = hcs->ctls.deleteContext(hcs, (void *)pCtlContext); - CertFreeCTLContext(pCtlContext); + if (ret) + ret = CertFreeCTLContext(pCtlContext); } return ret; } @@ -455,7 +453,8 @@ end: PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext) { TRACE("(%p)\n", pCtlContext); - Context_AddRef((void *)pCtlContext, sizeof(CTL_CONTEXT)); + if (pCtlContext) + Context_AddRef((void *)pCtlContext, sizeof(CTL_CONTEXT)); return pCtlContext; } @@ -471,12 +470,14 @@ static void CTLDataContext_Free(void *context) BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext) { + BOOL ret = TRUE; + TRACE("(%p)\n", pCTLContext); if (pCTLContext) - Context_Release((void *)pCTLContext, sizeof(CTL_CONTEXT), + ret = Context_Release((void *)pCTLContext, sizeof(CTL_CONTEXT), CTLDataContext_Free); - return TRUE; + return ret; } DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext, diff --git a/reactos/dll/win32/crypt32/decode.c b/reactos/dll/win32/crypt32/decode.c index 7a33e6afa5e..a16d89f8802 100644 --- a/reactos/dll/win32/crypt32/decode.c +++ b/reactos/dll/win32/crypt32/decode.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Juan Lang + * Copyright 2005-2009 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -58,12 +58,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(cryptasn); WINE_DECLARE_DEBUG_CHANNEL(crypt); -struct GenericArray -{ - DWORD cItems; - BYTE *rgItems; -}; - typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *, DWORD, DWORD, void *, DWORD *); typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *, @@ -81,12 +75,10 @@ static BOOL CRYPT_AsnDecodeChoiceOfTimeInternal(const BYTE *pbEncoded, 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. +/* Assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set ahead of time. */ -static BOOL CRYPT_AsnDecodeExtensionsInternal(const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, - DWORD *pcbDecoded); +static BOOL CRYPT_AsnDecodeExtension(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); @@ -113,7 +105,7 @@ static BOOL CRYPT_AsnDecodeIntegerInternal(const BYTE *pbEncoded, static BOOL CRYPT_AsnDecodeUnsignedIntegerInternal(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded); -static BOOL CRYPT_AsnDecodePKCSAttributesInternal(const BYTE *pbEncoded, +static BOOL CRYPT_AsnDecodePKCSAttributeInternal(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded); @@ -303,6 +295,10 @@ struct AsnDecodeSequenceItem DWORD size; }; +#define FINALMEMBERSIZE(s, member) (sizeof(s) - offsetof(s, member)) +#define MEMBERSIZE(s, member, nextmember) \ + (offsetof(s, nextmember) - offsetof(s, member)) + /* 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 @@ -361,8 +357,13 @@ static BOOL CRYPT_AsnDecodeSequenceItems(struct AsnDecodeSequenceItem items[], : NULL, &items[i].size, &itemDecoded); if (ret) { - /* Account for alignment padding */ - items[i].size = ALIGN_DWORD_PTR(items[i].size); + if (items[i].size < items[i].minSize) + items[i].size = items[i].minSize; + else if (items[i].size > items[i].minSize) + { + /* Account for alignment padding */ + items[i].size = ALIGN_DWORD_PTR(items[i].size); + } TRACE("item %d size: %d\n", i, items[i].size); if (nextData && items[i].hasPointer && items[i].size > items[i].minSize) @@ -563,6 +564,19 @@ static BOOL CRYPT_AsnDecodeSequence(struct AsnDecodeSequenceItem items[], * The expected tag of the entire encoded array (usually a variant * of ASN_SETOF or ASN_SEQUENCEOF.) If tag is 0, decodeFunc is called * regardless of the tag seen. + * countOffset: + * The offset within the outer structure at which the count exists. + * For example, a structure such as CRYPT_ATTRIBUTES has countOffset == 0, + * while CRYPT_ATTRIBUTE has countOffset == + * offsetof(CRYPT_ATTRIBUTE, cValue). + * arrayOffset: + * The offset within the outer structure at which the array pointer exists. + * For example, CRYPT_ATTRIBUTES has arrayOffset == + * offsetof(CRYPT_ATTRIBUTES, rgAttr). + * minArraySize: + * The minimum size of the decoded array. On WIN32, this is always 8: + * sizeof(DWORD) + sizeof(void *). On WIN64, it can be larger due to + * alignment. * decodeFunc: * used to decode each item in the array * itemSize: @@ -575,6 +589,9 @@ static BOOL CRYPT_AsnDecodeSequence(struct AsnDecodeSequenceItem items[], struct AsnArrayDescriptor { BYTE tag; + DWORD countOffset; + DWORD arrayOffset; + DWORD minArraySize; InternalDecodeFunc decodeFunc; DWORD itemSize; BOOL hasPointer; @@ -587,35 +604,37 @@ struct AsnArrayItemSize DWORD size; }; -/* Decodes an array of like types into a struct GenericArray. - * The layout and decoding of the array are described by a struct +/* Decodes an array of like types into a structure described by a struct * AsnArrayDescriptor. */ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo, - DWORD *pcbDecoded, void *startingPointer) + DWORD *pcbDecoded) { BOOL ret = TRUE; - TRACE("%p, %p, %d, %08x, %p, %p, %d, %p\n", arrayDesc, pbEncoded, - cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo, - startingPointer); + TRACE("%p, %p, %d, %p, %d\n", arrayDesc, pbEncoded, + cbEncoded, pvStructInfo, pvStructInfo ? *pcbStructInfo : 0); - if (!arrayDesc->tag || pbEncoded[0] == arrayDesc->tag) + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + ret = FALSE; + } + else if (!arrayDesc->tag || pbEncoded[0] == arrayDesc->tag) { DWORD dataLen; if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen))) { - DWORD bytesNeeded, cItems = 0, decoded; + DWORD bytesNeeded = arrayDesc->minArraySize, 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; @@ -694,25 +713,30 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, *pcbDecoded = decoded; if (!pvStructInfo) *pcbStructInfo = bytesNeeded; - else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded))) + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) { - DWORD i; + DWORD i, *pcItems; BYTE *nextData; const BYTE *ptr; - struct GenericArray *array; + void *rgItems; if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - array = pvStructInfo; - array->cItems = cItems; - if (startingPointer) - array->rgItems = startingPointer; + pvStructInfo = *(void **)pvStructInfo; + pcItems = pvStructInfo; + *pcItems = cItems; + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + { + rgItems = (BYTE *)pvStructInfo + + arrayDesc->minArraySize; + *(void **)((BYTE *)pcItems - + arrayDesc->countOffset + arrayDesc->arrayOffset) = + rgItems; + } else - array->rgItems = (BYTE *)array + - sizeof(struct GenericArray); - nextData = array->rgItems + - array->cItems * arrayDesc->itemSize; + rgItems = *(void **)((BYTE *)pcItems - + arrayDesc->countOffset + arrayDesc->arrayOffset); + nextData = (BYTE *)rgItems + cItems * arrayDesc->itemSize; for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cItems && ptr - pbEncoded - 1 - lenBytes < dataLen; i++) @@ -720,12 +744,12 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, DWORD itemDecoded; if (arrayDesc->hasPointer) - *(BYTE **)(array->rgItems + i * arrayDesc->itemSize + *(BYTE **)((BYTE *)rgItems + i * arrayDesc->itemSize + arrayDesc->pointerOffset) = nextData; ret = arrayDesc->decodeFunc(ptr, itemSizes[i].encodedLen, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, - array->rgItems + i * arrayDesc->itemSize, + (BYTE *)rgItems + i * arrayDesc->itemSize, &itemSizes[i].size, &itemDecoded); if (ret) { @@ -733,8 +757,6 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, ptr += itemDecoded; } } - if (!ret && (dwFlags & CRYPT_DECODE_ALLOC_FLAG)) - CRYPT_FreeSpace(pDecodePara, pvStructInfo); } } if (itemSizes != &itemSize) @@ -915,6 +937,25 @@ static BOOL CRYPT_AsnDecodeValidity(const BYTE *pbEncoded, DWORD cbEncoded, return ret; } +static BOOL CRYPT_AsnDecodeCertExtensionsInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_INFO, cExtension), offsetof(CERT_INFO, rgExtension), + FINALMEMBERSIZE(CERT_INFO, cExtension), + CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, + offsetof(CERT_EXTENSION, pszObjId) }; + + 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); + return ret; +} + static BOOL CRYPT_AsnDecodeCertExtensions(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) @@ -926,7 +967,7 @@ static BOOL CRYPT_AsnDecodeCertExtensions(const BYTE *pbEncoded, { BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); - ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded + 1 + lenBytes, + ret = CRYPT_AsnDecodeCertExtensionsInternal(pbEncoded + 1 + lenBytes, dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL); if (ret && pcbDecoded) *pcbDecoded = 1 + lenBytes + dataLen; @@ -961,15 +1002,15 @@ static BOOL CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType, CRYPT_AsnDecodePubKeyInfoInternal, sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO, SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 }, - { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId), + { ASN_CONTEXT | 1, offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 }, - { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId), + { ASN_CONTEXT | 2, offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 }, { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension), - CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE, - offsetof(CERT_INFO, rgExtension), 0 }, + CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(CERT_INFO, cExtension), + TRUE, TRUE, offsetof(CERT_INFO, rgExtension), 0 }, }; TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, @@ -1051,6 +1092,25 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType, return ret; } +static BOOL CRYPT_AsnDecodeCRLEntryExtensions(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CRL_ENTRY, cExtension), offsetof(CRL_ENTRY, rgExtension), + FINALMEMBERSIZE(CRL_ENTRY, cExtension), + CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, + offsetof(CERT_EXTENSION, pszObjId) }; + + 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); + return ret; +} + static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { @@ -1062,7 +1122,8 @@ static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded, { 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, + CRYPT_AsnDecodeCRLEntryExtensions, + FINALMEMBERSIZE(CRL_ENTRY, cExtension), TRUE, TRUE, offsetof(CRL_ENTRY, rgExtension), 0 }, }; PCRL_ENTRY entry = pvStructInfo; @@ -1082,28 +1143,66 @@ static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded, return ret; } -/* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has - * been set prior to calling. +/* Warning: assumes pvStructInfo points to the cCRLEntry member of a CRL_INFO + * whose rgCRLEntry member has been set prior to calling. */ static BOOL CRYPT_AsnDecodeCRLEntries(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CRL_INFO, cCRLEntry), offsetof(CRL_INFO, rgCRLEntry), + MEMBERSIZE(CRL_INFO, cCRLEntry, cExtension), CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE, offsetof(CRL_ENTRY, SerialNumber.pbData) }; - struct GenericArray *entries = 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, - entries ? entries->rgItems : NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); TRACE("Returning %d (%08x)\n", ret, GetLastError()); return ret; } +static BOOL CRYPT_AsnDecodeCRLExtensionsInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CRL_INFO, cExtension), offsetof(CRL_INFO, rgExtension), + FINALMEMBERSIZE(CRL_INFO, cExtension), + CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, + offsetof(CERT_EXTENSION, pszObjId) }; + + 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); + return ret; +} + +static BOOL CRYPT_AsnDecodeCRLExtensions(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + ret = CRYPT_AsnDecodeCRLExtensionsInternal(pbEncoded + 1 + lenBytes, + dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL); + if (ret && pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; + } + return ret; +} + static BOOL CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -1122,11 +1221,11 @@ static BOOL CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType, { 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, - offsetof(CRL_INFO, rgCRLEntry), 0 }, + CRYPT_AsnDecodeCRLEntries, MEMBERSIZE(CRL_INFO, cCRLEntry, cExtension), + TRUE, TRUE, offsetof(CRL_INFO, rgCRLEntry), 0 }, { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_INFO, cExtension), - CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE, - offsetof(CRL_INFO, rgExtension), 0 }, + CRYPT_AsnDecodeCRLExtensions, FINALMEMBERSIZE(CRL_INFO, cExtension), + TRUE, TRUE, offsetof(CRL_INFO, rgExtension), 0 }, }; BOOL ret = TRUE; @@ -1314,9 +1413,6 @@ static BOOL CRYPT_AsnDecodeOidInternal(const BYTE *pbEncoded, DWORD cbEncoded, return ret; } -/* Warning: assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set - * ahead of time! - */ static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { @@ -1348,53 +1444,26 @@ static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded, return ret; } -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, - CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, - offsetof(CERT_EXTENSION, pszObjId) }; - PCERT_EXTENSIONS exts = 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, - exts ? exts->rgExtension : NULL); - return ret; -} - static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { BOOL ret = TRUE; + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pvStructInfo ? *pcbStructInfo : 0); + __TRY { - ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL); - if (ret && pvStructInfo) - { - ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, - pcbStructInfo, *pcbStructInfo); - if (ret) - { - CERT_EXTENSIONS *exts; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_EXTENSIONS, cExtension), + offsetof(CERT_EXTENSIONS, rgExtension), + sizeof(CERT_EXTENSIONS), + CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, + offsetof(CERT_EXTENSION, pszObjId) }; - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - exts = pvStructInfo; - exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts + - sizeof(CERT_EXTENSIONS)); - ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded, - dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, - pcbStructInfo, NULL); - } - } + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); } __EXCEPT_PAGE_FAULT { @@ -1814,13 +1883,13 @@ static BOOL CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded, { BOOL ret = TRUE; struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, + offsetof(CERT_RDN, cRDNAttr), offsetof(CERT_RDN, rgRDNAttr), + sizeof(CERT_RDN), CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE, offsetof(CERT_RDN_ATTR, pszObjId) }; - PCERT_RDN rdn = pvStructInfo; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, - rdn ? rdn->rgRDNAttr : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded); return ret; } @@ -1833,11 +1902,34 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType, __TRY { struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_NAME_INFO, cRDN), offsetof(CERT_NAME_INFO, rgRDN), + sizeof(CERT_NAME_INFO), CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE, offsetof(CERT_RDN, rgRDNAttr) }; + DWORD bytesNeeded; - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded, + NULL); + if (ret) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CERT_NAME_INFO *info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = pvStructInfo; + info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo + + sizeof(CERT_NAME_INFO)); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded, NULL); + } + } } __EXCEPT_PAGE_FAULT { @@ -1886,13 +1978,13 @@ static BOOL CRYPT_AsnDecodeUnicodeRdn(const BYTE *pbEncoded, DWORD cbEncoded, { BOOL ret = TRUE; struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, + offsetof(CERT_RDN, cRDNAttr), offsetof(CERT_RDN, rgRDNAttr), + sizeof(CERT_RDN), CRYPT_AsnDecodeUnicodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE, offsetof(CERT_RDN_ATTR, pszObjId) }; - PCERT_RDN rdn = pvStructInfo; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, - rdn ? rdn->rgRDNAttr : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded); return ret; } @@ -1905,11 +1997,34 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeName(DWORD dwCertEncodingType, __TRY { struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_NAME_INFO, cRDN), offsetof(CERT_NAME_INFO, rgRDN), + sizeof(CERT_NAME_INFO), CRYPT_AsnDecodeUnicodeRdn, sizeof(CERT_RDN), TRUE, offsetof(CERT_RDN, rgRDNAttr) }; + DWORD bytesNeeded; - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded, + NULL); + if (ret) + { + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + CERT_NAME_INFO *info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = pvStructInfo; + info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo + + sizeof(CERT_NAME_INFO)); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo, + &bytesNeeded, NULL); + } + } } __EXCEPT_PAGE_FAULT { @@ -2023,34 +2138,34 @@ static BOOL CRYPT_AsnDecodeCopyBytes(const BYTE *pbEncoded, return ret; } -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 = 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_AsnDecodeCTLUsage(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CTL_USAGE, cUsageIdentifier), + offsetof(CTL_USAGE, rgpszUsageIdentifier), + sizeof(CTL_USAGE), CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 }; - CTL_USAGE *usage = pvStructInfo; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, - usage ? usage->rgpszUsageIdentifier : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded); + return ret; +} + +static BOOL CRYPT_AsnDecodeCTLEntryAttributes(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CTL_ENTRY, cAttribute), offsetof(CTL_ENTRY, rgAttribute), + FINALMEMBERSIZE(CTL_ENTRY, cAttribute), + CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE), TRUE, + offsetof(CRYPT_ATTRIBUTE, pszObjId) }; + BOOL ret; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); return ret; } @@ -2062,8 +2177,9 @@ static BOOL CRYPT_AsnDecodeCTLEntry(const BYTE *pbEncoded, DWORD cbEncoded, CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_DATA_BLOB), FALSE, TRUE, offsetof(CTL_ENTRY, SubjectIdentifier.pbData), 0 }, { ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CTL_ENTRY, cAttribute), - CRYPT_AsnDecodePKCSAttributesInternal, sizeof(CRYPT_ATTRIBUTES), FALSE, - TRUE, offsetof(CTL_ENTRY, rgAttribute), 0 }, + CRYPT_AsnDecodeCTLEntryAttributes, + FINALMEMBERSIZE(CTL_ENTRY, cAttribute), FALSE, TRUE, + offsetof(CTL_ENTRY, rgAttribute), 0 }, }; BOOL ret = TRUE; CTL_ENTRY *entry = pvStructInfo; @@ -2082,16 +2198,54 @@ static BOOL CRYPT_AsnDecodeCTLEntries(const BYTE *pbEncoded, DWORD cbEncoded, { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CTL_INFO, cCTLEntry), offsetof(CTL_INFO, rgCTLEntry), + FINALMEMBERSIZE(CTL_INFO, cExtension), CRYPT_AsnDecodeCTLEntry, sizeof(CTL_ENTRY), TRUE, offsetof(CTL_ENTRY, SubjectIdentifier.pbData) }; - struct GenericArray *entries = 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, - entries ? entries->rgItems : NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); + return ret; +} + +static BOOL CRYPT_AsnDecodeCTLExtensionsInternal(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CTL_INFO, cExtension), offsetof(CTL_INFO, rgExtension), + FINALMEMBERSIZE(CTL_INFO, cExtension), + CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE, + offsetof(CERT_EXTENSION, pszObjId) }; + + 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); + return ret; +} + +static BOOL CRYPT_AsnDecodeCTLExtensions(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + ret = CRYPT_AsnDecodeCTLExtensionsInternal(pbEncoded + 1 + lenBytes, + dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL); + if (ret && pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; + } return ret; } @@ -2128,16 +2282,14 @@ static BOOL WINAPI CRYPT_AsnDecodeCTL(DWORD dwCertEncodingType, CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CTL_INFO, SubjectAlgorithm.pszObjId), 0 }, { ASN_SEQUENCEOF, offsetof(CTL_INFO, cCTLEntry), - CRYPT_AsnDecodeCTLEntries, sizeof(struct GenericArray), + CRYPT_AsnDecodeCTLEntries, + MEMBERSIZE(CTL_INFO, cCTLEntry, cExtension), TRUE, TRUE, offsetof(CTL_INFO, rgCTLEntry), 0 }, { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CTL_INFO, cExtension), - CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE, - offsetof(CTL_INFO, rgExtension), 0 }, + CRYPT_AsnDecodeCTLExtensions, FINALMEMBERSIZE(CTL_INFO, cExtension), + TRUE, TRUE, offsetof(CTL_INFO, rgExtension), 0 }, }; - TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, *pcbStructInfo); - ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); @@ -2175,22 +2327,6 @@ static BOOL CRYPT_AsnDecodeSMIMECapability(const BYTE *pbEncoded, return ret; } -static BOOL CRYPT_AsnDecodeSMIMECapabilitiesInternal(const BYTE *pbEncoded, - DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, - DWORD *pcbDecoded) -{ - struct AsnArrayDescriptor arrayDesc = { 0, - CRYPT_AsnDecodeSMIMECapability, sizeof(CRYPT_SMIME_CAPABILITY), TRUE, - offsetof(CRYPT_SMIME_CAPABILITY, pszObjId) }; - PCRYPT_SMIME_CAPABILITIES capabilities = pvStructInfo; - BOOL ret; - - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, - capabilities ? capabilities->rgCapability : NULL); - return ret; -} - static BOOL WINAPI CRYPT_AsnDecodeSMIMECapabilities(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -2202,34 +2338,15 @@ static BOOL WINAPI CRYPT_AsnDecodeSMIMECapabilities(DWORD dwCertEncodingType, __TRY { - DWORD bytesNeeded; + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CRYPT_SMIME_CAPABILITIES, cCapability), + offsetof(CRYPT_SMIME_CAPABILITIES, rgCapability), + sizeof(CRYPT_SMIME_CAPABILITIES), + CRYPT_AsnDecodeSMIMECapability, sizeof(CRYPT_SMIME_CAPABILITY), TRUE, + offsetof(CRYPT_SMIME_CAPABILITY, pszObjId) }; - if (!cbEncoded) - SetLastError(CRYPT_E_ASN1_EOD); - else if (pbEncoded[0] != ASN_SEQUENCEOF) - SetLastError(CRYPT_E_ASN1_CORRUPT); - else if ((ret = CRYPT_AsnDecodeSMIMECapabilitiesInternal(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_SMIME_CAPABILITIES capabilities; - - if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) - pvStructInfo = *(BYTE **)pvStructInfo; - capabilities = pvStructInfo; - capabilities->rgCapability = - (PCRYPT_SMIME_CAPABILITY)((BYTE *)pvStructInfo + - sizeof(CRYPT_SMIME_CAPABILITIES)); - ret = CRYPT_AsnDecodeSMIMECapabilitiesInternal(pbEncoded, - cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, - &bytesNeeded, NULL); - } - } + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); } __EXCEPT_PAGE_FAULT { @@ -2290,21 +2407,22 @@ static BOOL CRYPT_AsnDecodeIA5String(const BYTE *pbEncoded, return ret; } -static BOOL CRYPT_AsnDecodeIntArray(const BYTE *pbEncoded, +static BOOL CRYPT_AsnDecodeNoticeNumbers(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, cNoticeNumbers), + offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, rgNoticeNumbers), + FINALMEMBERSIZE(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, cNoticeNumbers), CRYPT_AsnDecodeIntInternal, sizeof(int), FALSE, 0 }; - struct GenericArray *array = pvStructInfo; BOOL ret; TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags, pvStructInfo, pvStructInfo ? *pcbDecoded : 0); - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, - array ? array->rgItems : NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); TRACE("returning %d\n", ret); return ret; } @@ -2319,7 +2437,8 @@ static BOOL CRYPT_AsnDecodeNoticeReference(const BYTE *pbEncoded, pszOrganization), CRYPT_AsnDecodeIA5String, sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, pszOrganization), 0 }, { ASN_SEQUENCEOF, offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, - cNoticeNumbers), CRYPT_AsnDecodeIntArray, sizeof(struct GenericArray), + cNoticeNumbers), CRYPT_AsnDecodeNoticeNumbers, + FINALMEMBERSIZE(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, cNoticeNumbers), FALSE, TRUE, offsetof(CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, rgNoticeNumbers), 0 }, }; @@ -2576,6 +2695,25 @@ static BOOL WINAPI CRYPT_AsnDecodePolicyQualifierUserNotice( return ret; } +static BOOL CRYPT_AsnDecodePKCSAttributeValue(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CRYPT_ATTRIBUTE, cValue), offsetof(CRYPT_ATTRIBUTE, rgValue), + FINALMEMBERSIZE(CRYPT_ATTRIBUTE, cValue), + CRYPT_AsnDecodeCopyBytes, + sizeof(CRYPT_DER_BLOB), TRUE, offsetof(CRYPT_DER_BLOB, pbData) }; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pvStructInfo ? *pcbStructInfo : 0, pcbDecoded); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); + return ret; +} + static BOOL CRYPT_AsnDecodePKCSAttributeInternal(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) @@ -2586,8 +2724,9 @@ static BOOL CRYPT_AsnDecodePKCSAttributeInternal(const BYTE *pbEncoded, 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 }, + CRYPT_AsnDecodePKCSAttributeValue, + FINALMEMBERSIZE(CRYPT_ATTRIBUTE, cValue), FALSE, + TRUE, offsetof(CRYPT_ATTRIBUTE, rgValue), 0 }, }; PCRYPT_ATTRIBUTE attr = pvStructInfo; @@ -2650,14 +2789,14 @@ static BOOL CRYPT_AsnDecodePKCSAttributesInternal(const BYTE *pbEncoded, DWORD *pcbDecoded) { struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CRYPT_ATTRIBUTES, cAttr), offsetof(CRYPT_ATTRIBUTES, rgAttr), + sizeof(CRYPT_ATTRIBUTES), CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE), TRUE, offsetof(CRYPT_ATTRIBUTE, pszObjId) }; - PCRYPT_ATTRIBUTES attrs = pvStructInfo; BOOL ret; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, attrs ? attrs->rgAttr : - NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded); return ret; } @@ -2672,33 +2811,14 @@ static BOOL WINAPI CRYPT_AsnDecodePKCSAttributes(DWORD dwCertEncodingType, __TRY { - DWORD bytesNeeded; + struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, + offsetof(CRYPT_ATTRIBUTES, cAttr), offsetof(CRYPT_ATTRIBUTES, rgAttr), + sizeof(CRYPT_ATTRIBUTES), + CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE), + TRUE, offsetof(CRYPT_ATTRIBUTE, pszObjId) }; - 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 = pvStructInfo; - attrs->rgAttr = (PCRYPT_ATTRIBUTE)((BYTE *)pvStructInfo + - sizeof(CRYPT_ATTRIBUTES)); - ret = CRYPT_AsnDecodePKCSAttributesInternal(pbEncoded, - cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, - &bytesNeeded, NULL); - } - } + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); } __EXCEPT_PAGE_FAULT { @@ -2870,7 +2990,13 @@ static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded, case 1: /* rfc822Name */ case 2: /* dNSName */ case 6: /* uniformResourceIdentifier */ - bytesNeeded += (dataLen + 1) * sizeof(WCHAR); + if (memchr(pbEncoded + 1 + lenBytes, 0, dataLen)) + { + SetLastError(CRYPT_E_ASN1_RULE); + ret = FALSE; + } + else + bytesNeeded += (dataLen + 1) * sizeof(WCHAR); break; case 4: /* directoryName */ case 7: /* iPAddress */ @@ -2964,20 +3090,19 @@ static BOOL CRYPT_AsnDecodeAltNameInternal(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { - BOOL ret = TRUE; + BOOL ret; struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CERT_ALT_NAME_INFO, cAltEntry), + offsetof(CERT_ALT_NAME_INFO, rgAltEntry), + sizeof(CERT_ALT_NAME_INFO), CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; - PCERT_ALT_NAME_INFO info = pvStructInfo; 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, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, - info ? info->rgAltEntry : NULL); + NULL, pvStructInfo, pcbStructInfo, pcbDecoded); return ret; } @@ -3121,11 +3246,14 @@ static BOOL WINAPI CRYPT_AsnDecodeAuthorityInfoAccess(DWORD dwCertEncodingType, __TRY { struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_AUTHORITY_INFO_ACCESS, cAccDescr), + offsetof(CERT_AUTHORITY_INFO_ACCESS, rgAccDescr), + sizeof(CERT_AUTHORITY_INFO_ACCESS), CRYPT_AsnDecodeAccessDescription, sizeof(CERT_ACCESS_DESCRIPTION), TRUE, offsetof(CERT_ACCESS_DESCRIPTION, pszAccessMethod) }; - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); } __EXCEPT_PAGE_FAULT { @@ -3374,16 +3502,17 @@ static BOOL CRYPT_AsnDecodeSubtreeConstraints(const BYTE *pbEncoded, { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_BASIC_CONSTRAINTS_INFO, cSubtreesConstraint), + offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), + FINALMEMBERSIZE(CERT_BASIC_CONSTRAINTS_INFO, cSubtreesConstraint), CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE, offsetof(CERT_NAME_BLOB, pbData) }; - struct GenericArray *entries = 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, - entries ? entries->rgItems : NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); TRACE("Returning %d (%08x)\n", ret, GetLastError()); return ret; } @@ -3405,7 +3534,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType, sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 }, { ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO, cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints, - sizeof(struct GenericArray), TRUE, TRUE, + FINALMEMBERSIZE(CERT_BASIC_CONSTRAINTS_INFO, cSubtreesConstraint), + TRUE, TRUE, offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 }, }; @@ -3482,16 +3612,17 @@ static BOOL CRYPT_AsnDecodePolicyQualifiers(const BYTE *pbEncoded, { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_POLICY_INFO, cPolicyQualifier), + offsetof(CERT_POLICY_INFO, rgPolicyQualifier), + FINALMEMBERSIZE(CERT_POLICY_INFO, cPolicyQualifier), CRYPT_AsnDecodePolicyQualifier, sizeof(CERT_POLICY_QUALIFIER_INFO), TRUE, offsetof(CERT_POLICY_QUALIFIER_INFO, pszPolicyQualifierId) }; - struct GenericArray *entries = pvStructInfo; TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, pvStructInfo, pvStructInfo ? *pcbStructInfo : 0); - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - NULL, pvStructInfo, pcbStructInfo, pcbDecoded, - entries ? entries->rgItems : NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); TRACE("Returning %d (%08x)\n", ret, GetLastError()); return ret; } @@ -3504,7 +3635,8 @@ static BOOL CRYPT_AsnDecodeCertPolicy(const BYTE *pbEncoded, DWORD cbEncoded, CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_POLICY_INFO, pszPolicyIdentifier), 0 }, { ASN_SEQUENCEOF, offsetof(CERT_POLICY_INFO, cPolicyQualifier), - CRYPT_AsnDecodePolicyQualifiers, sizeof(struct GenericArray), TRUE, + CRYPT_AsnDecodePolicyQualifiers, + FINALMEMBERSIZE(CERT_POLICY_INFO, cPolicyQualifier), TRUE, TRUE, offsetof(CERT_POLICY_INFO, rgPolicyQualifier), 0 }, }; CERT_POLICY_INFO *info = pvStructInfo; @@ -3531,11 +3663,200 @@ static BOOL WINAPI CRYPT_AsnDecodeCertPolicies(DWORD dwCertEncodingType, __TRY { struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_POLICIES_INFO, cPolicyInfo), + offsetof(CERT_POLICIES_INFO, rgPolicyInfo), + sizeof(CERT_POLICIES_INFO), CRYPT_AsnDecodeCertPolicy, sizeof(CERT_POLICY_INFO), TRUE, offsetof(CERT_POLICY_INFO, pszPolicyIdentifier) }; - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +static BOOL CRYPT_AsnDecodeCertPolicyMapping(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + struct AsnDecodeSequenceItem items[] = { + { ASN_OBJECTIDENTIFIER, offsetof(CERT_POLICY_MAPPING, + pszIssuerDomainPolicy), CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), + FALSE, TRUE, offsetof(CERT_POLICY_MAPPING, pszIssuerDomainPolicy), 0 }, + { ASN_OBJECTIDENTIFIER, offsetof(CERT_POLICY_MAPPING, + pszSubjectDomainPolicy), CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), + FALSE, TRUE, offsetof(CERT_POLICY_MAPPING, pszSubjectDomainPolicy), 0 }, + }; + CERT_POLICY_MAPPING *mapping = pvStructInfo; + BOOL ret; + + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pvStructInfo ? *pcbStructInfo : 0); + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo, + pcbDecoded, mapping ? mapping->pszIssuerDomainPolicy : NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCertPolicyMappings(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, pvStructInfo ? *pcbStructInfo : 0); + + __TRY + { + struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_POLICY_MAPPINGS_INFO, cPolicyMapping), + offsetof(CERT_POLICY_MAPPINGS_INFO, rgPolicyMapping), + sizeof(CERT_POLICY_MAPPING), + CRYPT_AsnDecodeCertPolicyMapping, sizeof(CERT_POLICY_MAPPING), TRUE, + offsetof(CERT_POLICY_MAPPING, pszIssuerDomainPolicy) }; + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +static BOOL CRYPT_AsnDecodeRequireExplicit(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + DWORD skip, size = sizeof(skip); + + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + return FALSE; + } + if (pbEncoded[0] != (ASN_CONTEXT | 0)) + { + SetLastError(CRYPT_E_ASN1_BADTAG); + return FALSE; + } + if ((ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags, + &skip, &size, pcbDecoded))) + { + DWORD bytesNeeded = MEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO, + fRequireExplicitPolicy, fInhibitPolicyMapping); + + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + CERT_POLICY_CONSTRAINTS_INFO *info = + (CERT_POLICY_CONSTRAINTS_INFO *)((BYTE *)pvStructInfo - + offsetof(CERT_POLICY_CONSTRAINTS_INFO, fRequireExplicitPolicy)); + + *pcbStructInfo = bytesNeeded; + /* The BOOL is implicit: if the integer is present, then it's + * TRUE. + */ + info->fRequireExplicitPolicy = TRUE; + info->dwRequireExplicitPolicySkipCerts = skip; + } + } + return ret; +} + +static BOOL CRYPT_AsnDecodeInhibitMapping(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + DWORD skip, size = sizeof(skip); + + if (!cbEncoded) + { + SetLastError(CRYPT_E_ASN1_EOD); + return FALSE; + } + if (pbEncoded[0] != (ASN_CONTEXT | 1)) + { + SetLastError(CRYPT_E_ASN1_BADTAG); + return FALSE; + } + if ((ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags, + &skip, &size, pcbDecoded))) + { + DWORD bytesNeeded = FINALMEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO, + fInhibitPolicyMapping); + + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + CERT_POLICY_CONSTRAINTS_INFO *info = + (CERT_POLICY_CONSTRAINTS_INFO *)((BYTE *)pvStructInfo - + offsetof(CERT_POLICY_CONSTRAINTS_INFO, fInhibitPolicyMapping)); + + *pcbStructInfo = bytesNeeded; + /* The BOOL is implicit: if the integer is present, then it's + * TRUE. + */ + info->fInhibitPolicyMapping = TRUE; + info->dwInhibitPolicyMappingSkipCerts = skip; + } + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeCertPolicyConstraints( + 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, pvStructInfo ? *pcbStructInfo : 0); + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | 0, + offsetof(CERT_POLICY_CONSTRAINTS_INFO, fRequireExplicitPolicy), + CRYPT_AsnDecodeRequireExplicit, + MEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO, fRequireExplicitPolicy, + fInhibitPolicyMapping), TRUE, FALSE, 0, 0 }, + { ASN_CONTEXT | 1, + offsetof(CERT_POLICY_CONSTRAINTS_INFO, fInhibitPolicyMapping), + CRYPT_AsnDecodeInhibitMapping, + FINALMEMBERSIZE(CERT_POLICY_CONSTRAINTS_INFO, fInhibitPolicyMapping), + TRUE, FALSE, 0, 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo, NULL, NULL); } __EXCEPT_PAGE_FAULT { @@ -3833,38 +4154,40 @@ 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); + DWORD dataLen; - blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB); - ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded, 0, buf, - &size, pcbDecoded); - if (ret) + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { - if (!pvStructInfo) + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + if (pcbDecoded) + *pcbDecoded = 1 + lenBytes + dataLen; + if (dataLen > sizeof(int)) + { + SetLastError(CRYPT_E_ASN1_LARGE); + ret = FALSE; + } + else if (!pvStructInfo) *pcbStructInfo = sizeof(int); else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, sizeof(int)))) { int val, i; - if (blob->pbData[blob->cbData - 1] & 0x80) + if (dataLen && pbEncoded[1 + lenBytes] & 0x80) { /* initialize to a negative value to sign-extend */ val = -1; } else val = 0; - for (i = 0; i < blob->cbData; i++) + for (i = 0; i < dataLen; i++) { val <<= 8; - val |= blob->pbData[blob->cbData - i - 1]; + val |= pbEncoded[1 + lenBytes + i]; } memcpy(pvStructInfo, &val, sizeof(int)); } } - else if (GetLastError() == ERROR_MORE_DATA) - SetLastError(CRYPT_E_ASN1_LARGE); return ret; } @@ -4602,8 +4925,11 @@ static BOOL CRYPT_AsnDecodeDistPointName(const BYTE *pbEncoded, if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { struct AsnArrayDescriptor arrayDesc = { - ASN_CONTEXT | ASN_CONSTRUCTOR | 0, CRYPT_AsnDecodeAltNameEntry, - sizeof(CERT_ALT_NAME_ENTRY), TRUE, + ASN_CONTEXT | ASN_CONSTRUCTOR | 0, + offsetof(CRL_DIST_POINT_NAME, u.FullName.cAltEntry), + offsetof(CRL_DIST_POINT_NAME, u.FullName.rgAltEntry), + FINALMEMBERSIZE(CRL_DIST_POINT_NAME, u), + CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); DWORD nameLen; @@ -4612,13 +4938,9 @@ static BOOL CRYPT_AsnDecodeDistPointName(const BYTE *pbEncoded, { ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, - 0, NULL, NULL, &nameLen, NULL, NULL); - /* The CERT_ALT_NAME_INFO's size is included by CRYPT_AsnDecodeArray - * as the sizeof(struct GenericArray), so don't include it in the - * total bytes needed. - */ + dwFlags, NULL, NULL, &nameLen, NULL); bytesNeeded = sizeof(CRL_DIST_POINT_NAME) + nameLen - - sizeof(CERT_ALT_NAME_INFO); + FINALMEMBERSIZE(CRL_DIST_POINT_NAME, u); } else bytesNeeded = sizeof(CRL_DIST_POINT_NAME); @@ -4642,8 +4964,8 @@ static BOOL CRYPT_AsnDecodeDistPointName(const BYTE *pbEncoded, name->dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, - 0, NULL, &name->u.FullName, &nameLen, NULL, - name->u.FullName.rgAltEntry); + dwFlags, NULL, &name->u.FullName.cAltEntry, &nameLen, + NULL); } else name->dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME; @@ -4694,11 +5016,14 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType, __TRY { struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CRL_DIST_POINTS_INFO, cDistPoint), + offsetof(CRL_DIST_POINTS_INFO, rgDistPoint), + sizeof(CRL_DIST_POINTS_INFO), CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE, offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) }; - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); } __EXCEPT_PAGE_FAULT { @@ -4721,10 +5046,13 @@ static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType, __TRY { struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + offsetof(CERT_ENHKEY_USAGE, cUsageIdentifier), + offsetof(CERT_ENHKEY_USAGE, rgpszUsageIdentifier), + sizeof(CERT_ENHKEY_USAGE), CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 }; - ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags, - pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL); } __EXCEPT_PAGE_FAULT { @@ -4783,7 +5111,8 @@ static BOOL CRYPT_AsnDecodeMaximum(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { - BOOL ret = FALSE; + BOOL ret; + DWORD max, size = sizeof(max); TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, pcbDecoded); @@ -4798,12 +5127,32 @@ static BOOL CRYPT_AsnDecodeMaximum(const BYTE *pbEncoded, 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; + if ((ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags, + &max, &size, pcbDecoded))) + { + DWORD bytesNeeded = FINALMEMBERSIZE(CERT_GENERAL_SUBTREE, fMaximum); + + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if (*pcbStructInfo < bytesNeeded) + { + *pcbStructInfo = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + CERT_GENERAL_SUBTREE *subtree = (CERT_GENERAL_SUBTREE *) + ((BYTE *)pvStructInfo - offsetof(CERT_GENERAL_SUBTREE, fMaximum)); + + *pcbStructInfo = bytesNeeded; + /* The BOOL is implicit: if the integer is present, then it's + * TRUE. + */ + subtree->fMaximum = TRUE; + subtree->dwMaximum = max; + } + } TRACE("returning %d\n", ret); return ret; } @@ -4820,8 +5169,8 @@ static BOOL CRYPT_AsnDecodeSubtree(const BYTE *pbEncoded, { 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 }, + CRYPT_AsnDecodeMaximum, FINALMEMBERSIZE(CERT_GENERAL_SUBTREE, fMaximum), + TRUE, FALSE, 0, 0 }, }; CERT_GENERAL_SUBTREE *subtree = pvStructInfo; @@ -4842,25 +5191,46 @@ static BOOL CRYPT_AsnDecodeSubtree(const BYTE *pbEncoded, return ret; } -static BOOL CRYPT_AsnDecodeSubtreeArray(const BYTE *pbEncoded, +static BOOL CRYPT_AsnDecodePermittedSubtree(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) { BOOL ret = TRUE; struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree), + offsetof(CERT_NAME_CONSTRAINTS_INFO, rgPermittedSubtree), + MEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree, + cExcludedSubtree), CRYPT_AsnDecodeSubtree, sizeof(CERT_GENERAL_SUBTREE), TRUE, offsetof(CERT_GENERAL_SUBTREE, Base.u.pwszURL) }; - struct GenericArray *array = 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); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); return ret; } +static BOOL CRYPT_AsnDecodeExcludedSubtree(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret = TRUE; + struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree), + offsetof(CERT_NAME_CONSTRAINTS_INFO, rgExcludedSubtree), + FINALMEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree), + CRYPT_AsnDecodeSubtree, sizeof(CERT_GENERAL_SUBTREE), TRUE, + offsetof(CERT_GENERAL_SUBTREE, Base.u.pwszURL) }; + + 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); + return ret; +} static BOOL WINAPI CRYPT_AsnDecodeNameConstraints(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, @@ -4876,11 +5246,15 @@ static BOOL WINAPI CRYPT_AsnDecodeNameConstraints(DWORD dwCertEncodingType, struct AsnDecodeSequenceItem items[] = { { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree), - CRYPT_AsnDecodeSubtreeArray, sizeof(struct GenericArray), TRUE, TRUE, + CRYPT_AsnDecodePermittedSubtree, + MEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cPermittedSubtree, + cExcludedSubtree), 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, + CRYPT_AsnDecodeExcludedSubtree, + FINALMEMBERSIZE(CERT_NAME_CONSTRAINTS_INFO, cExcludedSubtree), + TRUE, TRUE, offsetof(CERT_NAME_CONSTRAINTS_INFO, rgExcludedSubtree), 0 }, }; @@ -5008,6 +5382,46 @@ static BOOL WINAPI CRYPT_AsnDecodePKCSSignerInfo(DWORD dwCertEncodingType, return ret; } +static BOOL CRYPT_AsnDecodeCMSCertEncoded(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CRYPT_SIGNED_INFO, cCertEncoded), + offsetof(CRYPT_SIGNED_INFO, rgCertEncoded), + MEMBERSIZE(CRYPT_SIGNED_INFO, cCertEncoded, cCrlEncoded), + CRYPT_AsnDecodeCopyBytes, + sizeof(CRYPT_DER_BLOB), TRUE, offsetof(CRYPT_DER_BLOB, pbData) }; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pvStructInfo ? *pcbStructInfo : 0, pcbDecoded); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); + return ret; +} + +static BOOL CRYPT_AsnDecodeCMSCrlEncoded(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, + DWORD *pcbDecoded) +{ + BOOL ret; + struct AsnArrayDescriptor arrayDesc = { 0, + offsetof(CRYPT_SIGNED_INFO, cCrlEncoded), + offsetof(CRYPT_SIGNED_INFO, rgCrlEncoded), + MEMBERSIZE(CRYPT_SIGNED_INFO, cCrlEncoded, content), + CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DER_BLOB), + TRUE, offsetof(CRYPT_DER_BLOB, pbData) }; + + TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, pvStructInfo ? *pcbStructInfo : 0, pcbDecoded); + + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); + return ret; +} + static BOOL CRYPT_AsnDecodeCMSSignerId(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) @@ -5137,16 +5551,17 @@ static BOOL CRYPT_DecodeSignerArray(const BYTE *pbEncoded, DWORD cbEncoded, { BOOL ret; struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF, + offsetof(CRYPT_SIGNED_INFO, cSignerInfo), + offsetof(CRYPT_SIGNED_INFO, rgSignerInfo), + FINALMEMBERSIZE(CRYPT_SIGNED_INFO, cSignerInfo), CRYPT_AsnDecodeCMSSignerInfoInternal, sizeof(CMSG_CMS_SIGNER_INFO), TRUE, offsetof(CMSG_CMS_SIGNER_INFO, SignerId.u.KeyId.pbData) }; - struct GenericArray *array = 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); + ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, + dwFlags, NULL, pvStructInfo, pcbStructInfo, pcbDecoded); return ret; } @@ -5166,15 +5581,16 @@ BOOL CRYPT_AsnDecodeCMSSignedInfo(const BYTE *pbEncoded, DWORD cbEncoded, 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, cCertEncoded), CRYPT_AsnDecodeCMSCertEncoded, + MEMBERSIZE(CRYPT_SIGNED_INFO, cCertEncoded, cCrlEncoded), 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, cCrlEncoded), CRYPT_AsnDecodeCMSCrlEncoded, + MEMBERSIZE(CRYPT_SIGNED_INFO, cCrlEncoded, content), TRUE, TRUE, offsetof(CRYPT_SIGNED_INFO, rgCrlEncoded), 0 }, { ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CRYPT_SIGNED_INFO, cSignerInfo), - CRYPT_DecodeSignerArray, sizeof(struct GenericArray), TRUE, TRUE, + CRYPT_DecodeSignerArray, + FINALMEMBERSIZE(CRYPT_SIGNED_INFO, cSignerInfo), TRUE, TRUE, offsetof(CRYPT_SIGNED_INFO, rgSignerInfo), 0 }, }; @@ -5312,6 +5728,12 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, case LOWORD(X509_NAME_CONSTRAINTS): decodeFunc = CRYPT_AsnDecodeNameConstraints; break; + case LOWORD(X509_POLICY_MAPPINGS): + decodeFunc = CRYPT_AsnDecodeCertPolicyMappings; + break; + case LOWORD(X509_POLICY_CONSTRAINTS): + decodeFunc = CRYPT_AsnDecodeCertPolicyConstraints; + break; case LOWORD(PKCS7_SIGNER_INFO): decodeFunc = CRYPT_AsnDecodePKCSSignerInfo; break; @@ -5328,6 +5750,8 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, decodeFunc = CRYPT_AsnDecodeSMIMECapabilities; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER)) decodeFunc = CRYPT_AsnDecodeAuthorityKeyId; + else if (!strcmp(lpszStructType, szOID_LEGACY_POLICY_MAPPINGS)) + decodeFunc = CRYPT_AsnDecodeCertPolicyMappings; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) decodeFunc = CRYPT_AsnDecodeAuthorityKeyId2; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) @@ -5354,6 +5778,10 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, decodeFunc = CRYPT_AsnDecodeCRLDistPoints; else if (!strcmp(lpszStructType, szOID_CERT_POLICIES)) decodeFunc = CRYPT_AsnDecodeCertPolicies; + else if (!strcmp(lpszStructType, szOID_POLICY_MAPPINGS)) + decodeFunc = CRYPT_AsnDecodeCertPolicyMappings; + else if (!strcmp(lpszStructType, szOID_POLICY_CONSTRAINTS)) + decodeFunc = CRYPT_AsnDecodeCertPolicyConstraints; else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage; else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT)) diff --git a/reactos/dll/win32/crypt32/encode.c b/reactos/dll/win32/crypt32/encode.c index 258384c7318..4d137cebc2f 100644 --- a/reactos/dll/win32/crypt32/encode.c +++ b/reactos/dll/win32/crypt32/encode.c @@ -415,7 +415,7 @@ static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType, { const CERT_PUBLIC_KEY_INFO *info = pvStructInfo; struct AsnEncodeSequenceItem items[] = { - { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 }, + { &info->Algorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 }, { &info->PublicKey, CRYPT_AsnEncodeBits, 0 }, }; @@ -464,6 +464,25 @@ static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType, return ret; } +BOOL WINAPI CRYPT_AsnEncodePubKeyInfoNoNull(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + const CERT_PUBLIC_KEY_INFO *info = pvStructInfo; + struct AsnEncodeSequenceItem items[] = { + { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 }, + { &info->PublicKey, CRYPT_AsnEncodeBits, 0 }, + }; + + TRACE("Encoding public key with OID %s\n", + debugstr_a(info->Algorithm.pszObjId)); + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded, + pcbEncoded); + return ret; +} + /* Like in Windows, this blithely ignores the validity of the passed-in * CERT_INFO, and just encodes it as-is. The resulting encoded data may not * decode properly, see CRYPT_AsnDecodeCertInfo. @@ -484,40 +503,40 @@ static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType, { &info->Issuer, CRYPT_CopyEncodedBlob, 0 }, { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 }, { &info->Subject, CRYPT_CopyEncodedBlob, 0 }, - { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 }, + { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfoNoNull, 0 }, { 0 } }; - struct AsnConstructedItem constructed[3] = { { 0 } }; - DWORD cItem = 7, cConstructed = 0; + struct AsnConstructedItem constructed = { 0 }; + struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } }; + DWORD cItem = 7, cSwapped = 0; if (info->IssuerUniqueId.cbData) { - constructed[cConstructed].tag = 1; - constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId; - constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits; - items[cItem].pvStructInfo = &constructed[cConstructed]; - items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; - cConstructed++; + swapped[cSwapped].tag = ASN_CONTEXT | 1; + swapped[cSwapped].pvStructInfo = &info->IssuerUniqueId; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; cItem++; } if (info->SubjectUniqueId.cbData) { - constructed[cConstructed].tag = 2; - constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId; - constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits; - items[cItem].pvStructInfo = &constructed[cConstructed]; - items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; - cConstructed++; + swapped[cSwapped].tag = ASN_CONTEXT | 2; + swapped[cSwapped].pvStructInfo = &info->SubjectUniqueId; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; cItem++; } if (info->cExtension) { - constructed[cConstructed].tag = 3; - constructed[cConstructed].pvStructInfo = &info->cExtension; - constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions; - items[cItem].pvStructInfo = &constructed[cConstructed]; + constructed.tag = 3; + constructed.pvStructInfo = &info->cExtension; + constructed.encodeFunc = CRYPT_AsnEncodeExtensions; + items[cItem].pvStructInfo = &constructed; items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; - cConstructed++; cItem++; } @@ -2800,13 +2819,10 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicyQualifiers(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) { - DWORD cPolicyQualifier = *(DWORD *)pvStructInfo; - const CERT_POLICY_QUALIFIER_INFO *rgPolicyQualifier = - *(const CERT_POLICY_QUALIFIER_INFO **) - ((LPBYTE)pvStructInfo + sizeof(DWORD)); + const CERT_POLICY_INFO *info = pvStructInfo; BOOL ret; - if (!cPolicyQualifier) + if (!info->cPolicyQualifier) { *pcbEncoded = 0; ret = TRUE; @@ -2820,10 +2836,11 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicyQualifiers(DWORD dwCertEncodingType, DWORD bytesNeeded = 0, lenBytes, size, i; ret = TRUE; - for (i = 0; ret && i < cPolicyQualifier; i++) + for (i = 0; ret && i < info->cPolicyQualifier; i++) { - items[0].pvStructInfo = rgPolicyQualifier[i].pszPolicyQualifierId; - items[1].pvStructInfo = &rgPolicyQualifier[i].Qualifier; + items[0].pvStructInfo = + info->rgPolicyQualifier[i].pszPolicyQualifierId; + items[1].pvStructInfo = &info->rgPolicyQualifier[i].Qualifier; ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, sizeof(items) / sizeof(items[0]), dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size); @@ -2847,12 +2864,12 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicyQualifiers(DWORD dwCertEncodingType, CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &lenBytes); pbEncoded += lenBytes; - for (i = 0; ret && i < cPolicyQualifier; i++) + for (i = 0; ret && i < info->cPolicyQualifier; i++) { items[0].pvStructInfo = - rgPolicyQualifier[i].pszPolicyQualifierId; + info->rgPolicyQualifier[i].pszPolicyQualifierId; items[1].pvStructInfo = - &rgPolicyQualifier[i].Qualifier; + &info->rgPolicyQualifier[i].Qualifier; size = bytesNeeded; ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, sizeof(items) / sizeof(items[0]), @@ -2877,7 +2894,7 @@ static BOOL CRYPT_AsnEncodeCertPolicy(DWORD dwCertEncodingType, { struct AsnEncodeSequenceItem items[2] = { { info->pszPolicyIdentifier, CRYPT_AsnEncodeOid, 0 }, - { &info->cPolicyQualifier, CRYPT_AsnEncodeCertPolicyQualifiers, 0 }, + { info, CRYPT_AsnEncodeCertPolicyQualifiers, 0 }, }; BOOL ret; @@ -2952,6 +2969,132 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicies(DWORD dwCertEncodingType, return ret; } +static BOOL CRYPT_AsnEncodeCertPolicyMapping(DWORD dwCertEncodingType, + const CERT_POLICY_MAPPING *mapping, DWORD dwFlags, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + struct AsnEncodeSequenceItem items[] = { + { mapping->pszIssuerDomainPolicy, CRYPT_AsnEncodeOid, 0 }, + { mapping->pszSubjectDomainPolicy, CRYPT_AsnEncodeOid, 0 }, + }; + + if (!mapping->pszIssuerDomainPolicy || !mapping->pszSubjectDomainPolicy) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + return CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), dwFlags, NULL, pbEncoded, pcbEncoded); +} + +static BOOL WINAPI CRYPT_AsnEncodeCertPolicyMappings(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + __TRY + { + const CERT_POLICY_MAPPINGS_INFO *info = pvStructInfo; + DWORD bytesNeeded = 0, lenBytes, size, i; + + ret = TRUE; + for (i = 0; ret && i < info->cPolicyMapping; i++) + { + ret = CRYPT_AsnEncodeCertPolicyMapping(dwCertEncodingType, + &info->rgPolicyMapping[i], dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, + NULL, &size); + if (ret) + bytesNeeded += size; + } + CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes); + bytesNeeded += 1 + lenBytes; + if (ret) + { + if (!pbEncoded) + *pcbEncoded = bytesNeeded; + else + { + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + *pbEncoded++ = ASN_SEQUENCEOF; + CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, + &lenBytes); + pbEncoded += lenBytes; + for (i = 0; ret && i < info->cPolicyMapping; i++) + { + size = bytesNeeded; + ret = CRYPT_AsnEncodeCertPolicyMapping( + dwCertEncodingType, &info->rgPolicyMapping[i], + dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pbEncoded, &size); + if (ret) + { + pbEncoded += size; + bytesNeeded -= size; + } + } + } + } + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodeCertPolicyConstraints( + DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, + DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + __TRY + { + const CERT_POLICY_CONSTRAINTS_INFO *info = pvStructInfo; + struct AsnEncodeSequenceItem items[2]; + struct AsnEncodeTagSwappedItem swapped[2]; + DWORD cItem = 0, cSwapped = 0; + + if (info->fRequireExplicitPolicy) + { + swapped[cSwapped].tag = ASN_CONTEXT | 0; + swapped[cSwapped].pvStructInfo = + &info->dwRequireExplicitPolicySkipCerts; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (info->fInhibitPolicyMapping) + { + swapped[cSwapped].tag = ASN_CONTEXT | 1; + swapped[cSwapped].pvStructInfo = + &info->dwInhibitPolicyMappingSkipCerts; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, + dwFlags, NULL, pbEncoded, pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -4314,6 +4457,12 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, case LOWORD(X509_NAME_CONSTRAINTS): encodeFunc = CRYPT_AsnEncodeNameConstraints; break; + case LOWORD(X509_POLICY_MAPPINGS): + encodeFunc = CRYPT_AsnEncodeCertPolicyMappings; + break; + case LOWORD(X509_POLICY_CONSTRAINTS): + encodeFunc = CRYPT_AsnEncodeCertPolicyConstraints; + break; case LOWORD(PKCS7_SIGNER_INFO): encodeFunc = CRYPT_AsnEncodePKCSSignerInfo; break; @@ -4330,6 +4479,8 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, encodeFunc = CRYPT_AsnEncodeUtcTime; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER)) encodeFunc = CRYPT_AsnEncodeAuthorityKeyId; + else if (!strcmp(lpszStructType, szOID_LEGACY_POLICY_MAPPINGS)) + encodeFunc = CRYPT_AsnEncodeCertPolicyMappings; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) @@ -4356,6 +4507,10 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, encodeFunc = CRYPT_AsnEncodeCRLDistPoints; else if (!strcmp(lpszStructType, szOID_CERT_POLICIES)) encodeFunc = CRYPT_AsnEncodeCertPolicies; + else if (!strcmp(lpszStructType, szOID_POLICY_MAPPINGS)) + encodeFunc = CRYPT_AsnEncodeCertPolicyMappings; + else if (!strcmp(lpszStructType, szOID_POLICY_CONSTRAINTS)) + encodeFunc = CRYPT_AsnEncodeCertPolicyConstraints; else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage; else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT)) @@ -4567,6 +4722,7 @@ static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDL } else { + *pcbInfo = sizeNeeded; pInfo->Algorithm.pszObjId = (char *)pInfo + sizeof(CERT_PUBLIC_KEY_INFO); lstrcpyA(pInfo->Algorithm.pszObjId, diff --git a/reactos/dll/win32/crypt32/filestore.c b/reactos/dll/win32/crypt32/filestore.c index f27b3b7386a..52e575271b0 100644 --- a/reactos/dll/win32/crypt32/filestore.c +++ b/reactos/dll/win32/crypt32/filestore.c @@ -43,7 +43,6 @@ static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD 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); } diff --git a/reactos/dll/win32/crypt32/main.c b/reactos/dll/win32/crypt32/main.c index d93163c1936..1a5972fe843 100644 --- a/reactos/dll/win32/crypt32/main.c +++ b/reactos/dll/win32/crypt32/main.c @@ -64,8 +64,9 @@ HCRYPTPROV CRYPT_GetDefaultProvider(void) { HCRYPTPROV prov; - CryptAcquireContextW(&prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT); + if (!CryptAcquireContextW(&prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return hDefProv; InterlockedCompareExchangePointer((PVOID *)&hDefProv, (PVOID)prov, NULL); if (hDefProv != prov) diff --git a/reactos/dll/win32/crypt32/msg.c b/reactos/dll/win32/crypt32/msg.c index 8a88b75eaed..825b6da96ff 100644 --- a/reactos/dll/win32/crypt32/msg.c +++ b/reactos/dll/win32/crypt32/msg.c @@ -719,27 +719,22 @@ static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in) return ret; } -typedef struct _BlobArray -{ - DWORD cBlobs; - PCRYPT_DATA_BLOB blobs; -} BlobArray; - -static BOOL CRYPT_ConstructBlobArray(BlobArray *out, const BlobArray *in) +static BOOL CRYPT_ConstructBlobArray(DWORD *outCBlobs, + PCRYPT_DATA_BLOB *outPBlobs, DWORD cBlobs, const PCRYPT_DATA_BLOB pBlobs) { BOOL ret = TRUE; - out->cBlobs = in->cBlobs; - if (out->cBlobs) + *outCBlobs = cBlobs; + if (cBlobs) { - out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB)); - if (out->blobs) + *outPBlobs = CryptMemAlloc(cBlobs * sizeof(CRYPT_DATA_BLOB)); + if (*outPBlobs) { 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]); + memset(*outPBlobs, 0, cBlobs * sizeof(CRYPT_DATA_BLOB)); + for (i = 0; ret && i < cBlobs; i++) + ret = CRYPT_ConstructBlob(&(*outPBlobs)[i], &pBlobs[i]); } else ret = FALSE; @@ -747,13 +742,13 @@ static BOOL CRYPT_ConstructBlobArray(BlobArray *out, const BlobArray *in) return ret; } -static void CRYPT_FreeBlobArray(BlobArray *array) +static void CRYPT_FreeBlobArray(DWORD cBlobs, PCRYPT_DATA_BLOB blobs) { DWORD i; - for (i = 0; i < array->cBlobs; i++) - CryptMemFree(array->blobs[i].pbData); - CryptMemFree(array->blobs); + for (i = 0; i < cBlobs; i++) + CryptMemFree(blobs[i].pbData); + CryptMemFree(blobs); } static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out, @@ -765,8 +760,8 @@ static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out, if (out->pszObjId) { strcpy(out->pszObjId, in->pszObjId); - ret = CRYPT_ConstructBlobArray((BlobArray *)&out->cValue, - (const BlobArray *)&in->cValue); + ret = CRYPT_ConstructBlobArray(&out->cValue, &out->rgValue, + in->cValue, in->rgValue); } else ret = FALSE; @@ -1179,8 +1174,10 @@ static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg) CryptMemFree(msg->innerOID); CryptMemFree(msg->data.pbData); - CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded); - CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded); + CRYPT_FreeBlobArray(msg->msg_data.info->cCertEncoded, + msg->msg_data.info->rgCertEncoded); + CRYPT_FreeBlobArray(msg->msg_data.info->cCrlEncoded, + msg->msg_data.info->rgCrlEncoded); for (i = 0; i < msg->msg_data.info->cSignerInfo; i++) CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]); CSignedMsgData_CloseHandles(&msg->msg_data); @@ -1435,13 +1432,13 @@ static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags, } } if (ret) - ret = CRYPT_ConstructBlobArray( - (BlobArray *)&msg->msg_data.info->cCertEncoded, - (const BlobArray *)&info->cCertEncoded); + ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCertEncoded, + &msg->msg_data.info->rgCertEncoded, info->cCertEncoded, + info->rgCertEncoded); if (ret) - ret = CRYPT_ConstructBlobArray( - (BlobArray *)&msg->msg_data.info->cCrlEncoded, - (const BlobArray *)&info->cCrlEncoded); + ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCrlEncoded, + &msg->msg_data.info->rgCrlEncoded, info->cCrlEncoded, + info->rgCrlEncoded); if (!ret) { CSignedEncodeMsg_Close(msg); diff --git a/reactos/dll/win32/crypt32/object.c b/reactos/dll/win32/crypt32/object.c index f505b7d804d..3d18c505fb4 100644 --- a/reactos/dll/win32/crypt32/object.c +++ b/reactos/dll/win32/crypt32/object.c @@ -283,20 +283,13 @@ end: return ret; } -static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType, - const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, +static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName, + DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) { - LPCWSTR fileName = 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); @@ -322,6 +315,50 @@ static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType, return ret; } +static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob, + DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, + HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) +{ + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + BOOL ret; + + TRACE("(%d, %p)\n", blob->cbData, blob->pbData); + + ret = CRYPT_ReadSerializedStoreFromBlob(blob, 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); + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType, + const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, + HCERTSTORE *phCertStore, HCRYPTMSG *phMsg) +{ + switch (dwObjectType) + { + case CERT_QUERY_OBJECT_FILE: + return CRYPT_QuerySerializedStoreFromFile(pvObject, + pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg); + case CERT_QUERY_OBJECT_BLOB: + return CRYPT_QuerySerializedStoreFromBlob(pvObject, + pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg); + default: + FIXME("unimplemented for type %d\n", dwObjectType); + SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */ + return FALSE; + } +} + static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg) { @@ -562,11 +599,13 @@ static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject, { if (pdwFormatType) *pdwFormatType = formatType; - if (phMsg) - *phMsg = msg; if (phCertStore) *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0, 0, msg); + if (phMsg) + *phMsg = msg; + else + CryptMsgClose(msg); } if (blob == &fileBlob) CryptMemFree(blob->pbData); diff --git a/reactos/dll/win32/crypt32/oid.c b/reactos/dll/win32/crypt32/oid.c index ddc6efc7655..0a3889d183c 100644 --- a/reactos/dll/win32/crypt32/oid.c +++ b/reactos/dll/win32/crypt32/oid.c @@ -873,9 +873,18 @@ static BOOL CRYPT_RemoveStringFromMultiString(LPWSTR multi, LPCWSTR toRemove) { DWORD len = CRYPT_GetMultiStringCharacterLen(multi); - /* Copy remainder of string "left" */ - memmove(spotToRemove, spotToRemove + lstrlenW(toRemove) + 1, - (len - (spotToRemove - multi)) * sizeof(WCHAR)); + if (spotToRemove + lstrlenW(toRemove) + 2 >= multi + len) + { + /* Removing last string in list, terminate multi string directly */ + *spotToRemove = 0; + *(spotToRemove + 1) = 0; + } + else + { + /* Copy remainder of string "left" */ + memmove(spotToRemove, spotToRemove + lstrlenW(toRemove) + 1, + (len - (spotToRemove - multi)) * sizeof(WCHAR)); + } ret = TRUE; } else diff --git a/reactos/dll/win32/crypt32/rootstore.c b/reactos/dll/win32/crypt32/rootstore.c index bd6dfac450a..a55b281601c 100644 --- a/reactos/dll/win32/crypt32/rootstore.c +++ b/reactos/dll/win32/crypt32/rootstore.c @@ -261,9 +261,23 @@ static void check_and_store_certs(HCERTSTORE from, HCERTSTORE to) "chain creation failed"); else { - /* The only allowed error is CERT_TRUST_IS_UNTRUSTED_ROOT */ - if (chain->TrustStatus.dwErrorStatus & - ~CERT_TRUST_IS_UNTRUSTED_ROOT) + DWORD allowedErrors = CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_INVALID_BASIC_CONSTRAINTS | + CERT_TRUST_IS_NOT_TIME_VALID; + + /* The certificate chain verification only allows certain + * invalid CA certs if they're installed locally: CA + * certs missing the key usage extension, and CA certs + * missing the basic constraints extension. Of course + * there's a chicken and egg problem: we have to accept + * them here in order for them to be accepted later. + * Expired, locally installed certs are also allowed here, + * because we don't know (yet) what date will be checked + * for an item signed by one of these certs. + * Thus, accept certs with any of the allowed errors. + */ + if (chain->TrustStatus.dwErrorStatus & ~allowedErrors) TRACE("rejecting %s: %s\n", get_cert_common_name(cert), trust_status_to_str(chain->TrustStatus.dwErrorStatus & ~CERT_TRUST_IS_UNTRUSTED_ROOT)); @@ -705,6 +719,7 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store) ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE); check_and_store_certs(from, store); } + CertCloseStore(from, 0); } static HCERTSTORE create_root_store(void) diff --git a/reactos/dll/win32/crypt32/serialize.c b/reactos/dll/win32/crypt32/serialize.c index 2cc6ffdb5a1..0c366bf4125 100644 --- a/reactos/dll/win32/crypt32/serialize.c +++ b/reactos/dll/win32/crypt32/serialize.c @@ -425,14 +425,18 @@ const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' }; -BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) +typedef BOOL (*read_serialized_func)(void *handle, void *buffer, + DWORD bytesToRead, DWORD *bytesRead); + +static BOOL CRYPT_ReadSerializedStore(void *handle, + read_serialized_func read_func, HCERTSTORE store) { BYTE fileHeaderBuf[sizeof(fileHeader)]; DWORD read; BOOL ret; /* Failure reading is non-critical, we'll leave the store empty */ - ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL); + ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read); if (ret) { if (!read) @@ -448,7 +452,7 @@ BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) DWORD bufSize = 0; do { - ret = ReadFile(file, &propHdr, sizeof(propHdr), &read, NULL); + ret = read_func(handle, &propHdr, sizeof(propHdr), &read); if (ret && read == sizeof(propHdr)) { if (contextInterface && context && @@ -470,7 +474,7 @@ BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) } if (buf) { - ret = ReadFile(file, buf, propHdr.cb, &read, NULL); + ret = read_func(handle, buf, propHdr.cb, &read); if (ret && read == propHdr.cb) { if (propHdr.propID == CERT_CERT_PROP_ID) @@ -495,8 +499,18 @@ BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) CERT_STORE_ADD_NEW, &context); } else - ret = CRYPT_ReadContextProp(contextInterface, - context, &propHdr, buf, read); + { + if (!contextInterface) + { + WARN("prop id %d before a context id\n", + propHdr.propID); + ret = FALSE; + } + else + ret = CRYPT_ReadContextProp( + contextInterface, context, &propHdr, buf, + read); + } } } else @@ -519,6 +533,48 @@ BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) return ret; } +static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead, + DWORD *bytesRead) +{ + return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL); +} + +BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) +{ + return CRYPT_ReadSerializedStore(file, read_file_wrapper, store); +} + +struct BlobReader +{ + const CRYPT_DATA_BLOB *blob; + DWORD current; +}; + +static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead, + DWORD *bytesRead) +{ + struct BlobReader *reader = handle; + BOOL ret; + + if (reader->current < reader->blob->cbData) + { + *bytesRead = min(bytesToRead, reader->blob->cbData - reader->current); + memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead); + ret = TRUE; + } + else + ret = FALSE; + return ret; +} + +BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob, + HCERTSTORE store) +{ + struct BlobReader reader = { blob, 0 }; + + return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store); +} + static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext, DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) { diff --git a/reactos/dll/win32/crypt32/store.c b/reactos/dll/win32/crypt32/store.c index 8acc6f68b12..3a786b05cf4 100644 --- a/reactos/dll/win32/crypt32/store.c +++ b/reactos/dll/win32/crypt32/store.c @@ -184,9 +184,13 @@ static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev) static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext) { WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + BOOL ret; - ContextList_Delete(ms->certs, pCertContext); - return TRUE; + if (ContextList_Remove(ms->certs, pCertContext)) + ret = CertFreeCertificateContext(pCertContext); + else + ret = TRUE; + return ret; } static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl, @@ -225,9 +229,13 @@ static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev) static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext) { WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + BOOL ret; - ContextList_Delete(ms->crls, pCrlContext); - return TRUE; + if (ContextList_Remove(ms->crls, pCrlContext)) + ret = CertFreeCRLContext(pCrlContext); + else + ret = TRUE; + return ret; } static BOOL CRYPT_MemAddCtl(PWINECRYPT_CERTSTORE store, void *ctl, @@ -266,9 +274,20 @@ static void *CRYPT_MemEnumCtl(PWINECRYPT_CERTSTORE store, void *pPrev) static BOOL CRYPT_MemDeleteCtl(PWINECRYPT_CERTSTORE store, void *pCtlContext) { WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store; + BOOL ret; - ContextList_Delete(ms->ctls, pCtlContext); - return TRUE; + if (ContextList_Remove(ms->ctls, pCtlContext)) + ret = CertFreeCTLContext(pCtlContext); + else + ret = TRUE; + return ret; +} + +static BOOL WINAPI CRYPT_MemControl(HCERTSTORE hCertStore, DWORD dwFlags, + DWORD dwCtrlType, void const *pvCtrlPara) +{ + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; } static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) @@ -314,7 +333,7 @@ static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv, store->hdr.ctls.addContext = CRYPT_MemAddCtl; store->hdr.ctls.enumContext = CRYPT_MemEnumCtl; store->hdr.ctls.deleteContext = CRYPT_MemDeleteCtl; - store->hdr.control = NULL; + store->hdr.control = CRYPT_MemControl; store->certs = ContextList_Create(pCertInterface, sizeof(CERT_CONTEXT)); store->crls = ContextList_Create(pCRLInterface, @@ -966,10 +985,7 @@ BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext) if (!pCertContext) ret = TRUE; else if (!pCertContext->hCertStore) - { - ret = TRUE; - CertFreeCertificateContext(pCertContext); - } + ret = CertFreeCertificateContext(pCertContext); else { PWINECRYPT_CERTSTORE hcs = pCertContext->hCertStore; @@ -979,7 +995,7 @@ BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext) else ret = hcs->certs.deleteContext(hcs, (void *)pCertContext); if (ret) - CertFreeCertificateContext(pCertContext); + ret = CertFreeCertificateContext(pCertContext); } return ret; } @@ -1105,10 +1121,7 @@ BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext) if (!pCrlContext) ret = TRUE; else if (!pCrlContext->hCertStore) - { - ret = TRUE; - CertFreeCRLContext(pCrlContext); - } + ret = CertFreeCRLContext(pCrlContext); else { PWINECRYPT_CERTSTORE hcs = pCrlContext->hCertStore; @@ -1117,7 +1130,8 @@ BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext) ret = FALSE; else ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext); - CertFreeCRLContext(pCrlContext); + if (ret) + ret = CertFreeCRLContext(pCrlContext); } return ret; } @@ -1161,6 +1175,8 @@ BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC ) return FALSE; + if (hcs->ref <= 0) + ERR("%p's ref count is %d\n", hcs, hcs->ref); if (InterlockedDecrement(&hcs->ref) == 0) { TRACE("%p's ref count is 0, freeing\n", hcs); diff --git a/reactos/dll/win32/crypt32/str.c b/reactos/dll/win32/crypt32/str.c index b0a3d254a6a..758abc9c072 100644 --- a/reactos/dll/win32/crypt32/str.c +++ b/reactos/dll/win32/crypt32/str.c @@ -16,6 +16,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include + +#define NONAMELESSUNION + #include "windef.h" #include "winbase.h" #include "winnls.h" @@ -1017,11 +1020,11 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, if (entry) { if (!pszNameString) - ret = strlenW(entry->pwszRfc822Name) + 1; + ret = strlenW(entry->u.pwszRfc822Name) + 1; else if (cchNameString) { - ret = min(strlenW(entry->pwszRfc822Name), cchNameString - 1); - memcpy(pszNameString, entry->pwszRfc822Name, + ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1); + memcpy(pszNameString, entry->u.pwszRfc822Name, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } @@ -1045,7 +1048,7 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, if (entry) ret = CertNameToStrW(pCertContext->dwCertEncodingType, - &entry->DirectoryName, *(DWORD *)pvTypePara, pszNameString, + &entry->u.DirectoryName, *(DWORD *)pvTypePara, pszNameString, cchNameString); if (info) LocalFree(info); @@ -1062,7 +1065,7 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, if (entry) ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, - &entry->DirectoryName, 0, pszNameString, cchNameString); + &entry->u.DirectoryName, 0, pszNameString, cchNameString); if (altInfo) LocalFree(altInfo); } @@ -1102,12 +1105,12 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, if (entry) { if (!pszNameString) - ret = strlenW(entry->pwszRfc822Name) + 1; + ret = strlenW(entry->u.pwszRfc822Name) + 1; else if (cchNameString) { - ret = min(strlenW(entry->pwszRfc822Name), + ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1); - memcpy(pszNameString, entry->pwszRfc822Name, + memcpy(pszNameString, entry->u.pwszRfc822Name, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } @@ -1139,11 +1142,11 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, if (entry) { if (!pszNameString) - ret = strlenW(entry->pwszDNSName) + 1; + ret = strlenW(entry->u.pwszDNSName) + 1; else if (cchNameString) { - ret = min(strlenW(entry->pwszDNSName), cchNameString - 1); - memcpy(pszNameString, entry->pwszDNSName, ret * sizeof(WCHAR)); + ret = min(strlenW(entry->u.pwszDNSName), cchNameString - 1); + memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } } @@ -1163,11 +1166,11 @@ DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, if (entry) { if (!pszNameString) - ret = strlenW(entry->pwszURL) + 1; + ret = strlenW(entry->u.pwszURL) + 1; else if (cchNameString) { - ret = min(strlenW(entry->pwszURL), cchNameString - 1); - memcpy(pszNameString, entry->pwszURL, ret * sizeof(WCHAR)); + ret = min(strlenW(entry->u.pwszURL), cchNameString - 1); + memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR)); pszNameString[ret++] = 0; } } diff --git a/reactos/include/psdk/wincrypt.h b/reactos/include/psdk/wincrypt.h index ae74e9082b9..b98ef794ddc 100644 --- a/reactos/include/psdk/wincrypt.h +++ b/reactos/include/psdk/wincrypt.h @@ -2750,6 +2750,7 @@ typedef struct _CTL_FIND_SUBJECT_PARA #define CRYPT_STRING_BASE64X509CRLHEADER 0x00000009 #define CRYPT_STRING_HEXADDR 0x0000000a #define CRYPT_STRING_HEXASCIIADDR 0x0000000b +#define CRYPT_STRING_NOCRLF 0x40000000 #define CRYPT_STRING_NOCR 0x80000000 /* OIDs */ @@ -2946,6 +2947,7 @@ typedef struct _CTL_FIND_SUBJECT_PARA #define szOID_POLICY_CONSTRAINTS "2.5.29.36" #define szOID_ENHANCED_KEY_USAGE "2.5.29.37" #define szOID_FRESHEST_CRL "2.5.29.46" +#define szOID_INHIBIT_ANY_POLICY "2.5.29.54" #define szOID_DOMAIN_COMPONENT "0.9.2342.19200300.100.1.25" #define szOID_PKCS_12_FRIENDLY_NAME_ATTR "1.2.840.113549.1.9.20" #define szOID_PKCS_12_LOCAL_KEY_ID "1.2.840.113549.1.9.21" @@ -4053,6 +4055,13 @@ BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded, DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext); +BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName, + const BYTE *pbCertEncoded, DWORD cbCertEncoded); +BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName, + const BYTE *pbCertEncoded, DWORD cbCertEncoded); +#define CertAddEncodedCertificateToSystemStore \ + WINELIB_NAME_AW(CertAddEncodedCertificateToSystemStore) + BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded, DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext); @@ -4139,6 +4148,9 @@ BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext, BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext, DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement); +BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType, + PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage); + BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags, PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage); BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,