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.
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(a)gmail.com>
---
dlls/crypt32/decode.c | 103 +++++++++++++++++++++++++++++++-----
dlls/crypt32/encode.c | 50 +++++++++++++++++
dlls/crypt32/tests/encode.c | 100 ++++++++++++++++++++++++++++++++++
include/wincrypt.h | 1 +
4 files changed, 242 insertions(+), 12 deletions(-)
diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c
index a0e78d62b4d..9f1949edf15 100644
--- a/dlls/crypt32/decode.c
+++ b/dlls/crypt32/decode.c
@@ -3870,7 +3870,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 +3902,69 @@ 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;
+ memcpy((BYTE *)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB),
+ &decodedKey->pubexp, sizeof(DWORD));
+ memcpy((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) +
@@ -6207,7 +6280,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 +6341,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..6d9d5737a80 100644
--- a/dlls/crypt32/encode.c
+++ b/dlls/crypt32/encode.c
@@ -3130,6 +3130,49 @@ 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;
+
+ if (hdr->Magic != BCRYPT_RSAPUBLIC_MAGIC)
+ {
+ SetLastError(E_INVALIDARG);
+ ret = FALSE;
+ } else if (hdr->cbPublicExp != sizeof(DWORD)) {
+ ERR("Unexpected public exponent size %d\n", hdr->cbPublicExp);
+ SetLastError(E_INVALIDARG);
+ ret = FALSE;
+ }
+ else
+ {
+ DWORD *pubexp = (DWORD*) ((BYTE*)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB));
+ CRYPT_INTEGER_BLOB modulus = { hdr->cbModulus, (BYTE*)pvStructInfo + sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD) };
+ struct AsnEncodeSequenceItem items[] = {
+ { &modulus, CRYPT_AsnEncodeUnsignedInteger, 0 },
+ { pubexp, CRYPT_AsnEncodeInt, 0 },
+ };
+
+ ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
+ ARRAY_SIZE(items), dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+ }
+ }
+ __EXCEPT_PAGE_FAULT
+ {
+ 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)
@@ -4563,6 +4606,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 +4665,8 @@ static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType,
encodeFunc = CRYPT_AsnEncodePolicyQualifierUserNotice;
else if (!strcmp(lpszStructType, szOID_CTL))
encodeFunc = CRYPT_AsnEncodeCTL;
+ else
+ FIXME("Unsupported encodoer for lpszStructType %s\n", lpszStructType);
return encodeFunc;
}
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
index 9597f1dfec1..80e13f48867 100644
--- a/dlls/crypt32/tests/encode.c
+++ b/dlls/crypt32/tests/encode.c
@@ -2572,6 +2572,104 @@ 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;
+
+ /* Try with a bogus magic value */
+ hdr->Magic = 1;
+ hdr->BitLength = sizeof(modulus1) * 8;
+ hdr->cbPublicExp = sizeof(DWORD);
+ hdr->cbModulus = sizeof(modulus1);
+ hdr->cbPrime1 = 0;
+ hdr->cbPrime2 = 0;
+ memcpy(toEncode + sizeof(BCRYPT_RSAKEY_BLOB), &pubexp, sizeof(DWORD));
+ memcpy(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 && GetLastError() == E_INVALIDARG,
+ "Expected E_INVALIDARG, got %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;
+ memcpy(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;
+ 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 = (DWORD*)(buf + sizeof(BCRYPT_RSAKEY_BLOB));
+
+ ok(bufSize >= sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD) +
+ 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);
+ ok(hdr->cbPublicExp == sizeof(DWORD), "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);
+ ok(!memcmp(buf + sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(DWORD),
+ rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
+ "Unexpected modulus\n");
+ LocalFree(buf);
+ }
+ }
+}
+
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 +8645,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)
--
2.32.0