From 1cd9510be0b58411826516ba696c7770fdf6894f Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Tue, 12 Jun 2007 14:40:04 -0700 Subject: [PATCH] crypt32: Implement PKCS_CONTENT_INFO encoding/decoding. --- dlls/crypt32/decode.c | 67 ++++++++++++++++++++++ dlls/crypt32/encode.c | 47 ++++++++++++++++ dlls/crypt32/tests/encode.c | 109 ++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c index c3b010ac1eb..ac0a1755822 100644 --- a/dlls/crypt32/decode.c +++ b/dlls/crypt32/decode.c @@ -2126,6 +2126,70 @@ static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId2(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnDecodePKCSContent(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + DWORD dataLen; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + /* The caller has already checked the tag, no need to check it again. + * Check the outer length is valid by calling CRYPT_GetLen: + */ + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + DWORD innerLen; + + pbEncoded += 1 + lenBytes; + /* Check the inner length is valid by calling CRYPT_GetLen again: */ + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &innerLen))) + { + ret = CRYPT_AsnDecodeCopyBytes(dwCertEncodingType, NULL, + pbEncoded, dataLen, dwFlags, pDecodePara, pvStructInfo, + pcbStructInfo); + } + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePKCSContentInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = FALSE; + + TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, *pcbStructInfo); + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_CONTENT_INFO, pszObjId), + CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE, + offsetof(CRYPT_CONTENT_INFO, pszObjId), 0 }, + { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, + offsetof(CRYPT_CONTENT_INFO, Content), CRYPT_AsnDecodePKCSContent, + sizeof(CRYPT_DER_BLOB), TRUE, TRUE, + offsetof(CRYPT_CONTENT_INFO, Content.pbData), 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, + sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, NULL); + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; + 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) @@ -3592,6 +3656,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_AUTHORITY_KEY_ID2: decodeFunc = CRYPT_AsnDecodeAuthorityKeyId2; break; + case (WORD)PKCS_CONTENT_INFO: + decodeFunc = CRYPT_AsnDecodePKCSContentInfo; + break; case (WORD)X509_SEQUENCE_OF_ANY: decodeFunc = CRYPT_AsnDecodeSequenceOfAny; break; diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 1888e4c5cc2..2f6fca7f983 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -1349,6 +1349,50 @@ static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType, return ret; } +static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret = FALSE; + + __TRY + { + const CRYPT_CONTENT_INFO *info = + (const CRYPT_CONTENT_INFO *)pvStructInfo; + + if (!info->pszObjId) + SetLastError(E_INVALIDARG); + else + { + struct AsnEncodeSequenceItem items[2] = { + { info->pszObjId, CRYPT_AsnEncodeOid, 0 }, + { NULL, NULL, 0 }, + }; + struct AsnConstructedItem constructed = { 0 }; + DWORD cItem = 1; + + if (info->Content.cbData) + { + constructed.tag = 0; + constructed.pvStructInfo = &info->Content; + constructed.encodeFunc = CRYPT_CopyEncodedBlob; + items[cItem].pvStructInfo = &constructed; + items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; + cItem++; + } + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded); + } + + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + } + __ENDTRY + return ret; +} + static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value, BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -3011,6 +3055,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_UNICODE_NAME: encodeFunc = CRYPT_AsnEncodeUnicodeName; break; + case (WORD)PKCS_CONTENT_INFO: + encodeFunc = CRYPT_AsnEncodePKCSContentInfo; + break; case (WORD)X509_UNICODE_NAME_VALUE: encodeFunc = CRYPT_AsnEncodeUnicodeNameValue; break; diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 162f14f31eb..a65560290b9 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -4524,6 +4524,113 @@ static void test_decodeAuthorityKeyId2(DWORD dwEncoding) } } +static const BYTE emptyPKCSContentInfo[] = { 0x30,0x04,0x06,0x02,0x2a,0x03 }; +static const BYTE bogusPKCSContentInfo[] = { 0x30,0x07,0x06,0x02,0x2a,0x03, + 0xa0,0x01,0x01 }; +static const BYTE intPKCSContentInfo[] = { 0x30,0x09,0x06,0x02,0x2a,0x03,0xa0, + 0x03,0x02,0x01,0x01 }; +static BYTE bogusDER[] = { 1 }; + +static void test_encodePKCSContentInfo(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CRYPT_CONTENT_INFO info = { 0 }; + char oid1[] = "1.2.3"; + + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + info.pszObjId = oid1; + ret = CryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyPKCSContentInfo), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyPKCSContentInfo, size), "Unexpected value\n"); + LocalFree(buf); + } + info.Content.pbData = bogusDER; + info.Content.cbData = sizeof(bogusDER); + ret = CryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptEncodeObjectEx failed; %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(bogusPKCSContentInfo), "Unexpected size %d\n", size); + ok(!memcmp(buf, bogusPKCSContentInfo, size), "Unexpected value\n"); + LocalFree(buf); + } + info.Content.pbData = (BYTE *)ints[0].encoded; + info.Content.cbData = ints[0].encoded[1] + 2; + ret = CryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + if (buf) + { + ok(size == sizeof(intPKCSContentInfo), "Unexpected size %d\n", size); + ok(!memcmp(buf, intPKCSContentInfo, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodePKCSContentInfo(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CRYPT_CONTENT_INFO *info; + + ret = CryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + emptyPKCSContentInfo, sizeof(emptyPKCSContentInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CRYPT_CONTENT_INFO *)buf; + + ok(!strcmp(info->pszObjId, "1.2.3"), "Expected 1.2.3, got %s\n", + info->pszObjId); + ok(info->Content.cbData == 0, "Expected no data, got %d\n", + info->Content.cbData); + LocalFree(buf); + } + SetLastError(0xdeadbeef); + ret = CryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + bogusPKCSContentInfo, sizeof(bogusPKCSContentInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + /* Native fails with CRYPT_E_ASN1_EOD, accept also CRYPT_E_ASN1_CORRUPT as + * I doubt an app depends on that. + */ + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == CRYPT_E_ASN1_CORRUPT), + "Expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT, got %x\n", + GetLastError()); + ret = CryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + intPKCSContentInfo, sizeof(intPKCSContentInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CRYPT_CONTENT_INFO *)buf; + + ok(!strcmp(info->pszObjId, "1.2.3"), "Expected 1.2.3, got %s\n", + info->pszObjId); + ok(info->Content.cbData == ints[0].encoded[1] + 2, + "Unexpected size %d\n", info->Content.cbData); + ok(!memcmp(info->Content.pbData, ints[0].encoded, + info->Content.cbData), "Unexpected value\n"); + } +} + /* Free *pInfo with HeapFree */ static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo) { @@ -4731,6 +4838,8 @@ START_TEST(encode) test_decodeAuthorityKeyId(encodings[i]); test_encodeAuthorityKeyId2(encodings[i]); test_decodeAuthorityKeyId2(encodings[i]); + test_encodePKCSContentInfo(encodings[i]); + test_decodePKCSContentInfo(encodings[i]); } testPortPublicKeyInfo(); }