From 2d00a4f0f54eef9dcc67ce2844f700e4e483d9f8 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Tue, 12 Jun 2007 14:39:19 -0700 Subject: [PATCH] crypt32: Implement CERT_AUTHORITY_KEY_ID2_INFO encoding/decoding. --- dlls/crypt32/decode.c | 49 ++++++++++- dlls/crypt32/encode.c | 61 ++++++++++++++ dlls/crypt32/tests/encode.c | 161 ++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+), 3 deletions(-) diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c index 2ab9de385d0..c3b010ac1eb 100644 --- a/dlls/crypt32/decode.c +++ b/dlls/crypt32/decode.c @@ -475,7 +475,8 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, /* tag: * The expected tag of the entire encoded array (usually a variant - * of ASN_SETOF or ASN_SEQUENCEOF.) + * of ASN_SETOF or ASN_SEQUENCEOF.) If tag is 0, decodeFunc is called + * regardless of the tag seen. * decodeFunc: * used to decode each item in the array * itemSize: @@ -515,7 +516,7 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc, cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo, startingPointer); - if (pbEncoded[0] == arrayDesc->tag) + if (!arrayDesc->tag || pbEncoded[0] == arrayDesc->tag) { DWORD dataLen; @@ -2038,7 +2039,7 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { BOOL ret = TRUE; - struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF, + struct AsnArrayDescriptor arrayDesc = { 0, CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE, offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) }; PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo; @@ -2088,6 +2089,43 @@ static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId2(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId), + CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_DATA_BLOB), + TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId.pbData), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR| 1, + offsetof(CERT_AUTHORITY_KEY_ID2_INFO, AuthorityCertIssuer), + CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, + TRUE, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, + AuthorityCertIssuer.rgAltEntry), 0 }, + { ASN_CONTEXT | 2, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, + AuthorityCertSerialNumber), CRYPT_AsnDecodeIntegerInternal, + sizeof(CRYPT_INTEGER_BLOB), TRUE, TRUE, + offsetof(CERT_AUTHORITY_KEY_ID2_INFO, + AuthorityCertSerialNumber.pbData), 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) @@ -3551,6 +3589,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_CHOICE_OF_TIME: decodeFunc = CRYPT_AsnDecodeChoiceOfTime; break; + case (WORD)X509_AUTHORITY_KEY_ID2: + decodeFunc = CRYPT_AsnDecodeAuthorityKeyId2; + break; case (WORD)X509_SEQUENCE_OF_ANY: decodeFunc = CRYPT_AsnDecodeSequenceOfAny; break; @@ -3576,6 +3617,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, decodeFunc = CRYPT_AsnDecodeUtcTime; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER)) decodeFunc = CRYPT_AsnDecodeAuthorityKeyId; + else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) + decodeFunc = CRYPT_AsnDecodeAuthorityKeyId2; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) decodeFunc = CRYPT_AsnDecodeEnumerated; else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 9522b967dc3..1888e4c5cc2 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -1941,6 +1941,62 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const CERT_AUTHORITY_KEY_ID2_INFO *info = + (const CERT_AUTHORITY_KEY_ID2_INFO *)pvStructInfo; + struct AsnEncodeSequenceItem items[3] = { { 0 } }; + struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } }; + DWORD cItem = 0, cSwapped = 0; + + if (info->KeyId.cbData) + { + swapped[cSwapped].tag = ASN_CONTEXT | 0; + swapped[cSwapped].pvStructInfo = &info->KeyId; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (info->AuthorityCertIssuer.cAltEntry) + { + swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1; + swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + if (info->AuthorityCertSerialNumber.cbData) + { + swapped[cSwapped].tag = ASN_CONTEXT | 2; + swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber; + swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger; + items[cItem].pvStructInfo = &swapped[cSwapped]; + items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag; + cSwapped++; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags, + pEncodePara, pbEncoded, pcbEncoded); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -2980,6 +3036,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_CHOICE_OF_TIME: encodeFunc = CRYPT_AsnEncodeChoiceOfTime; break; + case (WORD)X509_AUTHORITY_KEY_ID2: + encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2; + break; case (WORD)X509_SEQUENCE_OF_ANY: encodeFunc = CRYPT_AsnEncodeSequenceOfAny; break; @@ -3005,6 +3064,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, encodeFunc = CRYPT_AsnEncodeUtcTime; else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER)) encodeFunc = CRYPT_AsnEncodeAuthorityKeyId; + else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) + encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) encodeFunc = CRYPT_AsnEncodeEnumerated; else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 23f0553ac09..162f14f31eb 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -4365,6 +4365,165 @@ static void test_decodeAuthorityKeyId(DWORD dwEncoding) } } +static const BYTE authorityKeyIdWithIssuerUrl[] = { 0x30,0x15,0xa1,0x13,0x86, + 0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e, + 0x6f,0x72,0x67 }; + +static void test_encodeAuthorityKeyId2(DWORD dwEncoding) +{ + CERT_AUTHORITY_KEY_ID2_INFO info = { { 0 } }; + CERT_ALT_NAME_ENTRY entry = { 0 }; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + + /* Test with empty id */ + ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptySequence), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With just a key id */ + info.KeyId.cbData = sizeof(serialNum); + info.KeyId.pbData = (BYTE *)serialNum; + ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithId), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithId, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With a bogus issuer name */ + info.KeyId.cbData = 0; + info.AuthorityCertIssuer.cAltEntry = 1; + info.AuthorityCertIssuer.rgAltEntry = &entry; + ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* With an issuer name */ + entry.dwAltNameChoice = CERT_ALT_NAME_URL; + entry.pwszURL = (LPWSTR)url; + ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithIssuerUrl), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithIssuerUrl, size), + "Unexpected value\n"); + LocalFree(buf); + } + /* With just a serial number */ + info.AuthorityCertIssuer.cAltEntry = 0; + info.AuthorityCertSerialNumber.cbData = sizeof(serialNum); + info.AuthorityCertSerialNumber.pbData = (BYTE *)serialNum; + ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithSerial), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithSerial, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeAuthorityKeyId2(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + + ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 0, + "Expected no issuer name entries\n"); + ok(info->AuthorityCertSerialNumber.cbData == 0, + "Expected no serial number\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + authorityKeyIdWithId, sizeof(authorityKeyIdWithId), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == sizeof(serialNum), "Unexpected key id len\n"); + ok(!memcmp(info->KeyId.pbData, serialNum, sizeof(serialNum)), + "Unexpected key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 0, + "Expected no issuer name entries\n"); + ok(info->AuthorityCertSerialNumber.cbData == 0, + "Expected no serial number\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + authorityKeyIdWithIssuerUrl, sizeof(authorityKeyIdWithIssuerUrl), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 1, + "Expected 1 issuer entry, got %d\n", + info->AuthorityCertIssuer.cAltEntry); + ok(info->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice == + CERT_ALT_NAME_URL, "Expected CERT_ALT_NAME_URL, got %d\n", + info->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice); + ok(!lstrcmpW(info->AuthorityCertIssuer.rgAltEntry[0].pwszURL, + url), "Unexpected URL\n"); + ok(info->AuthorityCertSerialNumber.cbData == 0, + "Expected no serial number\n"); + LocalFree(buf); + } + ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + authorityKeyIdWithSerial, sizeof(authorityKeyIdWithSerial), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 0, + "Expected no issuer name entries\n"); + ok(info->AuthorityCertSerialNumber.cbData == sizeof(serialNum), + "Unexpected serial number len\n"); + ok(!memcmp(info->AuthorityCertSerialNumber.pbData, serialNum, + sizeof(serialNum)), "Unexpected serial number\n"); + LocalFree(buf); + } +} + /* Free *pInfo with HeapFree */ static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo) { @@ -4570,6 +4729,8 @@ START_TEST(encode) test_decodeEnhancedKeyUsage(encodings[i]); test_encodeAuthorityKeyId(encodings[i]); test_decodeAuthorityKeyId(encodings[i]); + test_encodeAuthorityKeyId2(encodings[i]); + test_decodeAuthorityKeyId2(encodings[i]); } testPortPublicKeyInfo(); }