From 417edaadcfe8d09f83698c65b22619a581856665 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Thu, 7 Jul 2005 11:26:50 +0000 Subject: [PATCH] Encode/decode CERT_PUBLIC_KEY_INFO, with tests. --- dlls/crypt32/encode.c | 350 ++++++++++++++++++++++++++++++++++-- dlls/crypt32/tests/encode.c | 119 ++++++++++-- 2 files changed, 446 insertions(+), 23 deletions(-) diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 9a6695204af..b8142322fa0 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -68,6 +68,9 @@ static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded); static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); +static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); @@ -81,6 +84,9 @@ static BOOL WINAPI CRYPT_DecodeBool(const BYTE *pbEncoded, DWORD cbEncoded, static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); +static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo); @@ -516,7 +522,7 @@ static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType, __TRY { DWORD bytesNeeded, dataLen, lenBytes, i; - CERT_EXTENSIONS *exts = (CERT_EXTENSIONS *)pvStructInfo; + const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo; ret = TRUE; for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++) @@ -881,7 +887,7 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType, __TRY { - CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo; + const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo; DWORD bytesNeeded = 0, lenBytes, size, i; TRACE("encoding name with %ld RDNs\n", info->cRDN); @@ -934,6 +940,107 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType, return ret; } +static BOOL CRYPT_AsnEncodeAlgorithmIdentifier( + const CRYPT_ALGORITHM_IDENTIFIER *algo, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + DWORD bytesNeeded, dataBytes, lenBytes; + + ret = CRYPT_AsnEncodeOid(algo->pszObjId, NULL, &dataBytes); + if (ret) + { + if (algo->Parameters.cbData) + dataBytes += algo->Parameters.cbData; + else + dataBytes += 2; /* enough space for ASN_NULL */ + CRYPT_EncodeLen(dataBytes, NULL, &lenBytes); + bytesNeeded = 1 + lenBytes + dataBytes; + if (!pbEncoded) + *pcbEncoded = bytesNeeded; + else if (*pcbEncoded < bytesNeeded) + { + *pcbEncoded = bytesNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbEncoded = bytesNeeded; + *pbEncoded++ = ASN_SEQUENCE; + CRYPT_EncodeLen(dataBytes, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + ret = CRYPT_AsnEncodeOid(algo->pszObjId, pbEncoded, &dataBytes); + if (ret) + { + pbEncoded += dataBytes; + if (algo->Parameters.cbData) + memcpy(pbEncoded, algo->Parameters.pbData, + algo->Parameters.cbData); + else + { + *pbEncoded++ = ASN_NULL; + *pbEncoded++ = 0; + } + } + } + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const CERT_PUBLIC_KEY_INFO *info = + (const CERT_PUBLIC_KEY_INFO *)pvStructInfo; + DWORD bitBlobLen, lenBytes, dataBytes, bytesNeeded; + + TRACE("Encoding public key with OID %s\n", + debugstr_a(info->Algorithm.pszObjId)); + ret = CRYPT_AsnEncodeAlgorithmIdentifier(&info->Algorithm, NULL, + &dataBytes); + if (ret) + { + ret = CRYPT_AsnEncodeBits(dwCertEncodingType, X509_BITS, + &info->PublicKey, 0, NULL, NULL, &bitBlobLen); + if (ret) + { + dataBytes += bitBlobLen; + CRYPT_EncodeLen(dataBytes, NULL, &lenBytes); + bytesNeeded = 1 + lenBytes + dataBytes; + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + *pbEncoded++ = ASN_SEQUENCE; + CRYPT_EncodeLen(dataBytes, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + ret = CRYPT_AsnEncodeAlgorithmIdentifier(&info->Algorithm, + pbEncoded, &dataBytes); + if (ret) + { + pbEncoded += dataBytes; + ret = CRYPT_AsnEncodeBits(dwCertEncodingType, X509_BITS, + &info->PublicKey, 0, NULL, pbEncoded, &bitBlobLen); + } + } + } + } + } + __EXCEPT(page_fault) + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded) { if (!pbEncoded) @@ -962,8 +1069,8 @@ static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType, __TRY { - CERT_BASIC_CONSTRAINTS2_INFO *info = - (CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo; + const CERT_BASIC_CONSTRAINTS2_INFO *info = + (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo; DWORD bytesNeeded = 0, lenBytes, caLen = 0, pathConstraintLen = 0; ret = TRUE; @@ -1030,7 +1137,7 @@ static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType, __TRY { - CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo; + const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo; DWORD bytesNeeded, lenBytes; CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes); @@ -1072,12 +1179,17 @@ static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType, __TRY { - CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo; + const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo; DWORD bytesNeeded, lenBytes, dataBytes; BYTE unusedBits; /* yep, MS allows cUnusedBits to be >= 8 */ - if (blob->cbData * 8 > blob->cUnusedBits) + if (!blob->cUnusedBits) + { + dataBytes = blob->cbData; + unusedBits = 0; + } + else if (blob->cbData * 8 > blob->cUnusedBits) { dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1; unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 : @@ -1150,7 +1262,8 @@ static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType, DWORD significantBytes, lenBytes; BYTE padByte = 0, bytesNeeded; BOOL pad = FALSE; - CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; + const CRYPT_INTEGER_BLOB *blob = + (const CRYPT_INTEGER_BLOB *)pvStructInfo; significantBytes = blob->cbData; if (significantBytes) @@ -1238,7 +1351,8 @@ static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType, DWORD significantBytes, lenBytes; BYTE bytesNeeded; BOOL pad = FALSE; - CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; + const CRYPT_INTEGER_BLOB *blob = + (const CRYPT_INTEGER_BLOB *)pvStructInfo; significantBytes = blob->cbData; if (significantBytes) @@ -1464,7 +1578,8 @@ static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType, __TRY { DWORD bytesNeeded, dataLen, lenBytes, i; - CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo; + const CRYPT_SEQUENCE_OF_ANY *seq = + (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo; for (i = 0, dataLen = 0; i < seq->cValue; i++) dataLen += seq->rgValue[i].cbData; @@ -1544,6 +1659,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_NAME: encodeFunc = CRYPT_AsnEncodeName; break; + case (WORD)X509_PUBLIC_KEY_INFO: + encodeFunc = CRYPT_AsnEncodePubKeyInfo; + break; case (WORD)X509_BASIC_CONSTRAINTS2: encodeFunc = CRYPT_AsnEncodeBasicConstraints2; break; @@ -1795,6 +1913,8 @@ static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded, (ptr - pbEncoded), &ext->fCritical); ptr += 3; } + else + ext->fCritical = FALSE; ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING, X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded), @@ -2496,13 +2616,213 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType, } } } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + } + __EXCEPT(page_fault) + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + +/* Warning: assumes algo->Parameters.pbData is set ahead of time! */ +static BOOL CRYPT_AsnDecodeAlgorithmIdentifier(const BYTE *pbEncoded, + DWORD cbEncoded, DWORD dwFlags, CRYPT_ALGORITHM_IDENTIFIER *algo, + DWORD *pcbAlgo) +{ + BOOL ret = TRUE; + + if (pbEncoded[0] == ASN_SEQUENCE) + { + DWORD dataLen, bytesNeeded; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0; + + bytesNeeded = sizeof(CRYPT_ALGORITHM_IDENTIFIER); + if (dataLen) + { + const BYTE *ptr = pbEncoded + 1 + lenBytes; + DWORD encodedOidLen, oidLen; + + CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), + &encodedOidLen); + oidLenBytes = GET_LEN_BYTES(ptr[1]); + ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded), + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen); + if (ret) + { + bytesNeeded += oidLen; + ptr += 1 + encodedOidLen + oidLenBytes; + /* The remaining bytes are just copied as-is, no decoding + * is done. + * FIXME: is the CRYPT_DECODE_NOCOPY_FLAG used? + */ + bytesNeeded += cbEncoded - (ptr - pbEncoded); + if (!algo) + *pcbAlgo = bytesNeeded; + else if (*pcbAlgo < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + DWORD paramsLen; + + /* Get and sanity-check parameters first */ + if ((ret = CRYPT_GetLen(ptr, cbEncoded - + (ptr - pbEncoded), ¶msLen))) + { + BYTE paramsLenBytes = GET_LEN_BYTES(ptr[1]); + + if (paramsLen != dataLen - encodedOidLen - 1 - + oidLenBytes - 1 - paramsLenBytes) + { + SetLastError(CRYPT_E_ASN1_CORRUPT); + ret = FALSE; + } + else + { + *pcbAlgo = bytesNeeded; + algo->Parameters.cbData = dataLen - + encodedOidLen - 1 - oidLenBytes; + if (algo->Parameters.cbData) + { + memcpy(algo->Parameters.pbData, ptr, + algo->Parameters.cbData); + algo->pszObjId = algo->Parameters.pbData + + algo->Parameters.cbData; + } + else + algo->pszObjId = algo->Parameters.pbData; + ptr = pbEncoded + 1 + lenBytes; + ret = CRYPT_AsnDecodeOid(ptr, + cbEncoded - (ptr - pbEncoded), + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, + algo->pszObjId, &oidLen); + } + } + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_EOD); + ret = FALSE; + } + } + } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret = TRUE; + + __TRY + { + if (pbEncoded[0] == ASN_SEQUENCE) + { + DWORD dataLen; + + if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) + { + DWORD algoLen, bitLen, bytesNeeded = 0; + BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + + /* at least enough for the outer sequence and the inner + * sequence/OID combo + */ + if (dataLen >= 6) + { + DWORD encodedAlgoLen; + BYTE algoLenBytes; + + CRYPT_GetLen(pbEncoded + 1 + lenBytes, + cbEncoded - 1 - lenBytes, &encodedAlgoLen); + algoLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]); + ret = CRYPT_AsnDecodeAlgorithmIdentifier( + pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, + dwFlags, NULL, &algoLen); + if (ret) + { + bytesNeeded += algoLen; + ret = CRYPT_AsnDecodeBits(dwCertEncodingType, + X509_BITS, pbEncoded + 2 + lenBytes + algoLenBytes + + encodedAlgoLen, cbEncoded - (2 + lenBytes + + algoLenBytes + encodedAlgoLen), dwFlags, pDecodePara, + NULL, &bitLen); + if (ret) + { + bytesNeeded += bitLen; + if (!pvStructInfo) + *pcbStructInfo = bytesNeeded; + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, + pDecodePara, pvStructInfo, pcbStructInfo, + bytesNeeded))) + { + CERT_PUBLIC_KEY_INFO *info; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + info = (CERT_PUBLIC_KEY_INFO *)pvStructInfo; + memset(info, 0, sizeof(*info)); + ret = CRYPT_AsnDecodeBits( + dwCertEncodingType, X509_BITS, + pbEncoded + 2 + lenBytes + algoLenBytes + + encodedAlgoLen, + cbEncoded - (2 + lenBytes + algoLenBytes + + encodedAlgoLen), + dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, + pDecodePara, &info->PublicKey, &bitLen); + if (ret) + { + if (info->PublicKey.cbData) + info->Algorithm.Parameters.pbData = + info->PublicKey.pbData + + info->PublicKey.cbData; + else + info->Algorithm.Parameters.pbData = + (BYTE *)pvStructInfo + + sizeof(CERT_PUBLIC_KEY_INFO); + ret = CRYPT_AsnDecodeAlgorithmIdentifier( + pbEncoded + 1 + lenBytes, cbEncoded - 1 - + lenBytes, dwFlags, &info->Algorithm, + &algoLen); + } + } + } + } + } else { - SetLastError(CRYPT_E_ASN1_BADTAG); + SetLastError(CRYPT_E_ASN1_EOD); ret = FALSE; } } } + else + { + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + } } __EXCEPT(page_fault) { @@ -2705,6 +3025,11 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType, { BOOL ret; + TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n", + dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) : + "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo); + __TRY { if (pbEncoded[0] == ASN_BITSTRING) @@ -3467,6 +3792,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, case (WORD)X509_NAME: decodeFunc = CRYPT_AsnDecodeName; break; + case (WORD)X509_PUBLIC_KEY_INFO: + decodeFunc = CRYPT_AsnDecodePubKeyInfo; + break; case (WORD)X509_BASIC_CONSTRAINTS2: decodeFunc = CRYPT_AsnDecodeBasicConstraints2; break; diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 89fbbe601b7..fc91d4b01d8 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -916,7 +916,8 @@ struct encodedBits }; static const struct encodedBits bits[] = { - /* normal test case */ + /* normal test cases */ + { 0, "\x03\x03\x00\xff\xff", 2, "\xff\xff" }, { 1, "\x03\x03\x01\xff\xfe", 2, "\xff\xfe" }, /* strange test case, showing cUnusedBits >= 8 is allowed */ { 9, "\x03\x02\x01\xfe", 1, "\xfe" }, @@ -1233,17 +1234,6 @@ static const struct encodedExtensions exts[] = { "\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" }, }; -#if 0 -static void printBytes(const BYTE *pbData, size_t cb) -{ - size_t i; - - for (i = 0; i < cb; i++) - printf("%02x ", pbData[i]); - putchar('\n'); -} -#endif - static void test_encodeExtensions(DWORD dwEncoding) { DWORD i; @@ -1307,6 +1297,109 @@ static void test_decodeExtensions(DWORD dwEncoding) } } +struct encodedPublicKey +{ + CERT_PUBLIC_KEY_INFO info; + const BYTE *encoded; + CERT_PUBLIC_KEY_INFO decoded; +}; + +static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, + 0xe, 0xf }; +static const BYTE params[] = { 0x02, 0x01, 0x01 }; + +static const struct encodedPublicKey pubKeys[] = { + /* with a bogus OID */ + { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } }, + "\x30\x0b\x30\x06\x06\x02\x2a\x03\x05\x00\x03\x01\x00", + { { "1.2.3", { 2, "\x05\x00" } }, { 0, NULL, 0 } } }, + /* some normal keys */ + { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} }, + "\x30\x0f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x01\x00", + { { szOID_RSA, { 2, "\x05\x00" } }, { 0, NULL, 0 } } }, + { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} }, + "\x30\x1f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x11\x00\x00\x01" + "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + { { szOID_RSA, { 2, "\x05\x00" } }, { sizeof(aKey), (BYTE *)aKey, 0} } }, + /* with add'l parameters--note they must be DER-encoded */ + { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey), + (BYTE *)aKey, 0 } }, + "\x30\x20\x30\x0b\x06\x06\x2a\x86\x48\x86\xf7\x0d\x02\x01\x01" + "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e" + "\x0f", + { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey), + (BYTE *)aKey, 0 } } }, +}; + +static void test_encodePublicKeyInfo(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++) + { + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO, + &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, + &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError()); + if (buf) + { + ok(bufSize == pubKeys[i].encoded[1] + 2, + "Expected %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2, + bufSize); + ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2), + "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodePublicKeyInfo(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++) + { + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO, + pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, + NULL, (BYTE *)&buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError()); + if (buf) + { + CERT_PUBLIC_KEY_INFO *info = (CERT_PUBLIC_KEY_INFO *)buf; + + ok(!strcmp(pubKeys[i].decoded.Algorithm.pszObjId, + info->Algorithm.pszObjId), "Expected OID %s, got %s\n", + pubKeys[i].decoded.Algorithm.pszObjId, info->Algorithm.pszObjId); + ok(pubKeys[i].decoded.Algorithm.Parameters.cbData == + info->Algorithm.Parameters.cbData, + "Expected parameters of %ld bytes, got %ld\n", + pubKeys[i].decoded.Algorithm.Parameters.cbData, + info->Algorithm.Parameters.cbData); + if (pubKeys[i].decoded.Algorithm.Parameters.cbData) + ok(!memcmp(pubKeys[i].decoded.Algorithm.Parameters.pbData, + info->Algorithm.Parameters.pbData, + info->Algorithm.Parameters.cbData), + "Unexpected algorithm parameters\n"); + ok(pubKeys[i].decoded.PublicKey.cbData == info->PublicKey.cbData, + "Expected public key of %ld bytes, got %ld\n", + pubKeys[i].decoded.PublicKey.cbData, info->PublicKey.cbData); + if (pubKeys[i].decoded.PublicKey.cbData) + ok(!memcmp(pubKeys[i].decoded.PublicKey.pbData, + info->PublicKey.pbData, info->PublicKey.cbData), + "Unexpected public key value\n"); + LocalFree(buf); + } + } +} + static void test_registerOIDFunction(void) { static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 }; @@ -1387,6 +1480,8 @@ START_TEST(encode) test_decodeSequenceOfAny(encodings[i]); test_encodeExtensions(encodings[i]); test_decodeExtensions(encodings[i]); + test_encodePublicKeyInfo(encodings[i]); + test_decodePublicKeyInfo(encodings[i]); } test_registerOIDFunction(); }