Add support for the OID CNG_RSA_PUBLIC_KEY_BLOB to CryptEncodeObjectEx and CryptDecodeObjectEx. This OID decodes to / encodes from memory consisting of a BCRYPT_RSAKEY_BLOB, followed in memory by the exponent and modulus in big-endian format.
This allows the Visual Studio 2019 web installer to progress further - it now reachs the stubbed NCryptOpenStorageProvider function.
To aid in debugging similar issues, CryptEncodeObjectEx and CryptDecodeObjectEX now print a FIXME when encountering an unknown OID/struct type, instead of silently returning an error.
Signed-off-by: Aaron Hill aa1ronham@gmail.com --- v2: Correctly handle endianness --- dlls/crypt32/crypt32_private.h | 6 ++ dlls/crypt32/decode.c | 129 ++++++++++++++++++++++++--- dlls/crypt32/encode.c | 56 ++++++++++++ dlls/crypt32/tests/encode.c | 158 +++++++++++++++++++++++++++++++++ include/wincrypt.h | 1 + 5 files changed, 338 insertions(+), 12 deletions(-)
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index 9f8f43e7632..d165672b77a 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -42,6 +42,12 @@ BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key) #define ASN_UNIVERSALSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1c) #define ASN_BMPSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e)
+/* Copies `len` bytes from `src` to `dst`. + * On a little-endian platform, additionally swaps + * the order of the bytes + */ +void CRYPT_memcpy_be(BYTE *dst, const BYTE *src, DWORD len); + BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded) DECLSPEC_HIDDEN;
typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *, diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c index a0e78d62b4d..6dbd5b57f34 100644 --- a/dlls/crypt32/decode.c +++ b/dlls/crypt32/decode.c @@ -55,6 +55,27 @@ WINE_DEFAULT_DEBUG_CHANNEL(cryptasn); WINE_DECLARE_DEBUG_CHANNEL(crypt);
+/* Copies `len` bytes from `src` to `dst`. + * On a little-endian platform, additionally swaps + * the order of the bytes + */ +#ifdef WORDS_BIGENDIAN + +void CRYPT_memcpy_be(BYTE *dst, const BYTE *src, size_t len) +{ + memcpy(dst, src, len); +} + +#else +void CRYPT_memcpy_be(BYTE *dst, const BYTE *src, size_t len) +{ + DWORD i; + for (i = 0; i < len; i++) { + dst[len - i - 1] = src[i]; + } +} +#endif + typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *, DWORD, DWORD, void *, DWORD *); typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *, @@ -3870,7 +3891,31 @@ struct DECODED_RSA_PUB_KEY CRYPT_INTEGER_BLOB modulus; };
-static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, +/* Helper function to decode an ASN.1 DER encoded RSA public key, writing the decoded + * key into 'decodedKey', and the length into 'size'. The memory + * for 'decodedKey' is allocated with 'CRYPT_DECODE_ALLOC_FLAG' + */ +static BOOL CRYPT_raw_decode_rsa_pub_key(struct DECODED_RSA_PUB_KEY **decodedKey, + DWORD *size, const BYTE *pbEncoded, DWORD cbEncoded) +{ + BOOL ret; + + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + }; + + ret = CRYPT_AsnDecodeSequence(items, ARRAY_SIZE(items), + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, decodedKey, + size, NULL, NULL); + return ret; +} + +static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey_Bcrypt(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) { @@ -3878,20 +3923,73 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
__TRY { - struct AsnDecodeSequenceItem items[] = { - { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus), - CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), - FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData), - 0 }, - { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp), - CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, - }; struct DECODED_RSA_PUB_KEY *decodedKey = NULL; DWORD size = 0;
- ret = CRYPT_AsnDecodeSequence(items, ARRAY_SIZE(items), - pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, - &size, NULL, NULL); + TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, + pvStructInfo, *pcbStructInfo); + + ret = CRYPT_raw_decode_rsa_pub_key(&decodedKey, &size, pbEncoded, cbEncoded); + if (ret) + { + /* Header, exponent, and modulus */ + DWORD bytesNeeded = sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD) + + decodedKey->modulus.cbData; + + if (!pvStructInfo) + { + *pcbStructInfo = bytesNeeded; + ret = TRUE; + } + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + BCRYPT_RSAKEY_BLOB *hdr; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + + hdr = pvStructInfo; + hdr->Magic = BCRYPT_RSAPUBLIC_MAGIC; + hdr->BitLength = decodedKey->modulus.cbData * 8; + hdr->cbPublicExp = sizeof(DWORD); + hdr->cbModulus = decodedKey->modulus.cbData; + hdr->cbPrime1 = 0; + hdr->cbPrime2 = 0; + /* CNG_RSA_PUBLIC_KEY_BLOB always stores the exponent and modulus + * in big-endian format, so we need to convert from the native + * endianness + */ + CRYPT_memcpy_be((BYTE *)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB), + (BYTE *)&decodedKey->pubexp, sizeof(DWORD)); + CRYPT_memcpy_be((BYTE *)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB) + + sizeof(DWORD), decodedKey->modulus.pbData, + decodedKey->modulus.cbData); + } + LocalFree(decodedKey); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + + +static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + + __TRY + { + struct DECODED_RSA_PUB_KEY *decodedKey = NULL; + DWORD size = 0; + ret = CRYPT_raw_decode_rsa_pub_key(&decodedKey, &size, pbEncoded, cbEncoded); if (ret) { DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + @@ -4591,6 +4689,7 @@ static BOOL CRYPT_AsnDecodeUnsignedIntegerInternal(const BYTE *pbEncoded, } else { + /* FIXME This assumes that the system is little-endian */ CRYPT_INTEGER_BLOB *blob = pvStructInfo;
*pcbStructInfo = bytesNeeded; @@ -6207,7 +6306,11 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, break; case LOWORD(X509_ECC_SIGNATURE): decodeFunc = CRYPT_AsnDecodeEccSignature; + case LOWORD(CNG_RSA_PUBLIC_KEY_BLOB): + decodeFunc = CRYPT_AsnDecodeRsaPubKey_Bcrypt; break; + default: + FIXME("Unimplemented decoder for lpszStructType OID %d\n", LOWORD(lpszStructType)); } } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) @@ -6264,6 +6367,8 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, decodeFunc = CRYPT_AsnDecodeCTL; else if (!strcmp(lpszStructType, szOID_ECC_PUBLIC_KEY)) decodeFunc = CRYPT_AsnDecodeObjectIdentifier; + else + FIXME("Unsupported decoder for lpszStructType %s\n", lpszStructType); return decodeFunc; }
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 02b235696ce..94c3033facc 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -3130,6 +3130,53 @@ static BOOL WINAPI CRYPT_AsnEncodeCertPolicyConstraints( return ret; }
+static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey_Bcrypt(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, + PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) +{ + BOOL ret; + + __TRY + { + const BCRYPT_RSAKEY_BLOB *hdr = pvStructInfo; + + BYTE *pubexp = (BYTE*)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB); + BYTE *modulus = (BYTE*)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB) + hdr->cbPublicExp; + BYTE *pubexp_be = CryptMemAlloc(hdr->cbPublicExp); + BYTE *modulus_be = CryptMemAlloc(hdr->cbModulus); + CRYPT_INTEGER_BLOB pubexp_int = { hdr->cbPublicExp, pubexp_be }; + CRYPT_INTEGER_BLOB modulus_int = { hdr->cbModulus, modulus_be}; + + struct AsnEncodeSequenceItem items[] = { + { &modulus_int, CRYPT_AsnEncodeUnsignedInteger, 0 }, + { &pubexp_int, CRYPT_AsnEncodeInteger, 0 }, + }; + + /* CNG_RSA_PUBLIC_KEY_BLOB stores the exponent and modulus + * in big-endian format, so we need to convert them + * to the native endianness before encoding + */ + CRYPT_memcpy_be(pubexp_be, pubexp, hdr->cbPublicExp); + CRYPT_memcpy_be(modulus_be, modulus, hdr->cbModulus); + + ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, + ARRAY_SIZE(items), dwFlags, pEncodePara, pbEncoded, pcbEncoded); + + CryptMemFree(pubexp_be); + CryptMemFree(modulus_be); + } + __EXCEPT_PAGE_FAULT + { + ERR("PAGE FAULT\n"); + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __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) @@ -3350,6 +3397,7 @@ static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType, significantBytes = blob->cbData; if (significantBytes) { + /* FIXME This assumes that the system is little-endian */ if (blob->pbData[significantBytes - 1] & 0x80) { /* negative, lop off leading (little-endian) 0xffs */ @@ -3484,6 +3532,7 @@ static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType, } __EXCEPT_PAGE_FAULT { + ERR("Other page fault\n"); SetLastError(STATUS_ACCESS_VIOLATION); ret = FALSE; } @@ -4563,6 +4612,11 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, case LOWORD(CMS_SIGNER_INFO): encodeFunc = CRYPT_AsnEncodeCMSSignerInfo; break; + case LOWORD(CNG_RSA_PUBLIC_KEY_BLOB): + encodeFunc = CRYPT_AsnEncodeRsaPubKey_Bcrypt; + break; + default: + FIXME("Unimplemented encoder for lpszStructType OID %d\n", LOWORD(lpszStructType)); } } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) @@ -4617,6 +4671,8 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType, encodeFunc = CRYPT_AsnEncodePolicyQualifierUserNotice; else if (!strcmp(lpszStructType, szOID_CTL)) encodeFunc = CRYPT_AsnEncodeCTL; + else + FIXME("Unsupported encoder for lpszStructType %s\n", lpszStructType); return encodeFunc; }
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 9597f1dfec1..fbdb05992d5 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -31,6 +31,35 @@ static BOOL (WINAPI *pCryptDecodeObjectEx)(DWORD,LPCSTR,const BYTE*,DWORD,DWORD,PCRYPT_DECODE_PARA,void*,DWORD*); static BOOL (WINAPI *pCryptEncodeObjectEx)(DWORD,LPCSTR,const void*,DWORD,PCRYPT_ENCODE_PARA,void*,DWORD*);
+/* Copies `len` bytes from `src` to `dst`. + * On a little-endian platform, additionally swaps + * the order of the bytes + */ +#ifdef WORDS_BIGENDIAN + +void CRYPT_memcpy_be(BYTE *dst, const BYTE *src, size_t len) +{ + memcpy(dst, src, len); +} + +#else +void CRYPT_memcpy_be(BYTE *dst, const BYTE *src, size_t len) +{ + DWORD i; + for (i = 0; i < len; i++) { + dst[len - i - 1] = src[i]; + } +} +#endif + +static void CRYPT_ReverseBytes(BYTE *dst, const BYTE *src, DWORD len) +{ + DWORD i; + for (i = 0; i < len; i++) { + dst[len - i - 1] = src[i]; + } +} + struct encodedInt { int val; @@ -2572,6 +2601,133 @@ static void test_decodeRsaPublicKey(DWORD dwEncoding) } }
+static void test_encodeRsaPublicKey_Bcrypt(DWORD dwEncoding) +{ + BYTE toEncode[sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD) + sizeof(modulus1)]; + BCRYPT_RSAKEY_BLOB *hdr = (BCRYPT_RSAKEY_BLOB *)toEncode; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0, i; + DWORD pubexp = 65537; + + /* Verify that the Magic value doesn't matter */ + hdr->Magic = 1; + hdr->BitLength = sizeof(modulus1) * 8; + hdr->cbPublicExp = sizeof(DWORD); + hdr->cbModulus = sizeof(modulus1); + hdr->cbPrime1 = 0; + hdr->cbPrime2 = 0; + + /* CNG_RSA_PUBLIC_KEY_BLOB stores the exponent + * in big-endian format, so we need to it + * from native endianness before encoding + */ + CRYPT_memcpy_be(toEncode + sizeof(BCRYPT_RSAKEY_BLOB), (BYTE *)&pubexp, sizeof(DWORD)); + /* Our modulus is always stored in little-endian format, so we need to reverse + * the bytes to get it into big-endian format for CNG_RSA_PUBLIC_KEY_BLOB + */ + CRYPT_ReverseBytes(toEncode + sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD), modulus1, sizeof(modulus1)); + + ret = pCryptEncodeObjectEx(dwEncoding, CNG_RSA_PUBLIC_KEY_BLOB, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + + /* Finally, all valid */ + hdr->Magic = BCRYPT_RSAPUBLIC_MAGIC; + for (i = 0; i < ARRAY_SIZE(rsaPubKeys); i++) + { + hdr->BitLength = rsaPubKeys[i].modulusLen * 8; + hdr->cbModulus = rsaPubKeys[i].modulusLen; + + /* Our modulus is always stored in little-endian format, so we need to reverse + * the bytes to get it into big-endian format for CNG_RSA_PUBLIC_KEY_BLOB + */ + CRYPT_ReverseBytes(toEncode + sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD), + rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen); + + ret = pCryptEncodeObjectEx(dwEncoding, CNG_RSA_PUBLIC_KEY_BLOB, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(bufSize == rsaPubKeys[i].encoded[1] + 2, + "Expected size %d, got %d\n", rsaPubKeys[i].encoded[1] + 2, + bufSize); + ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize), + "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodeRsaPublicKey_Bcrypt(DWORD dwEncoding) +{ + DWORD i; + LPBYTE buf = NULL; + LPBYTE leModulus = NULL; + DWORD bufSize = 0; + BOOL ret; + + /* Try with a bad length */ + ret = pCryptDecodeObjectEx(dwEncoding, CNG_RSA_PUBLIC_KEY_BLOB, + rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1], + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_MORE_INPUT /* Win9x/NT4 */), + "Expected CRYPT_E_ASN1_EOD or OSS_MORE_INPUT, got %08x\n", + GetLastError()); + /* Now try success cases */ + for (i = 0; i < ARRAY_SIZE(rsaPubKeys); i++) + { + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, CNG_RSA_PUBLIC_KEY_BLOB, + rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + BCRYPT_RSAKEY_BLOB *hdr = (BCRYPT_RSAKEY_BLOB *)buf; + DWORD pubexp = 0; + /* CNG_RSA_PUBLIC_KEY_BLOB always stores the exponent and modulus + * in big-endian format, so we need to convert it to the native + * endianness + */ + CRYPT_memcpy_be((BYTE *)&pubexp, buf + sizeof(BCRYPT_RSAKEY_BLOB), hdr->cbPublicExp); + ok(bufSize >= sizeof(BCRYPT_RSAKEY_BLOB) + + rsaPubKeys[i].decodedModulusLen, + "Wrong size %d\n", bufSize); + ok(hdr->Magic == BCRYPT_RSAPUBLIC_MAGIC, + "Expected magic BCRYPT_RSAPUBLIC_MAGIC (%d), got %d\n", BCRYPT_RSAPUBLIC_MAGIC, + hdr->Magic); + ok(hdr->BitLength == rsaPubKeys[i].decodedModulusLen * 8, + "Wrong bit len %d\n", hdr->BitLength); + /* Windows decodes the exponent to 3 bytes, since it will fit. + * Our implementation currently unconditionally decodes to a DWORD (4 bytes) + */ + ok(hdr->cbPublicExp == sizeof(DWORD) || hdr->cbPublicExp == 3, "Expected cbPublicExp %d, got %d\n", + sizeof(DWORD), hdr->cbPublicExp); + ok(hdr->cbModulus == rsaPubKeys[i].decodedModulusLen, + "Wrong modulus len %d\n", hdr->cbModulus); + ok(hdr->cbPrime1 == 0,"Wrong cbPrime1 %d\n", hdr->cbPrime1); + ok(hdr->cbPrime2 == 0,"Wrong cbPrime2 %d\n", hdr->cbPrime2); + ok(pubexp== 65537, "Expected pubexp 65537, got %d\n", + pubexp); + + leModulus = HeapAlloc(GetProcessHeap(), 0, hdr->cbModulus); + /* Unconditionally reverse the bytes, since rsaPubKeys always stores + * the modulus in little-endian format, and CNG_RSA_PUBLIC_KEY_BLOB always + * stores the modulus in big-endian format */ + CRYPT_ReverseBytes(leModulus, buf + sizeof(BCRYPT_RSAKEY_BLOB) + hdr->cbPublicExp, + hdr->cbModulus); + ok(!memcmp(leModulus, + rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen), + "Unexpected modulus\n"); + LocalFree(buf); + LocalFree(leModulus); + } + } +} + static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01, 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d }; @@ -8547,6 +8703,8 @@ START_TEST(encode) test_decodeBasicConstraints(encodings[i]); test_encodeRsaPublicKey(encodings[i]); test_decodeRsaPublicKey(encodings[i]); + test_encodeRsaPublicKey_Bcrypt(encodings[i]); + test_decodeRsaPublicKey_Bcrypt(encodings[i]); test_encodeSequenceOfAny(encodings[i]); test_decodeSequenceOfAny(encodings[i]); test_encodeExtensions(encodings[i]); diff --git a/include/wincrypt.h b/include/wincrypt.h index 28bebf8dc4b..456f2f14446 100644 --- a/include/wincrypt.h +++ b/include/wincrypt.h @@ -3179,6 +3179,7 @@ typedef struct _CTL_FIND_SUBJECT_PARA #define CMC_ADD_EXTENSIONS ((LPCSTR)62) #define CMC_ADD_ATTRIBUTES ((LPCSTR)63) #define X509_CERTIFICATE_TEMPLATE ((LPCSTR)64) +#define CNG_RSA_PUBLIC_KEY_BLOB ((LPCSTR)72) #define X509_OBJECT_IDENTIFIER ((LPCSTR)73) #define PKCS7_SIGNER_INFO ((LPCSTR)500) #define CMS_SIGNER_INFO ((LPCSTR)501)