v2: - Fixed calculation of cbPublicExp and cbModulus. - pass PublicExp in BE format to follow MSDN.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50925 Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/crypt32/cert.c | 81 +++++++++++++++++++++++++++++++++++++ dlls/crypt32/tests/encode.c | 13 +++++- 2 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c index 95e2746a7d5..920561b9c76 100644 --- a/dlls/crypt32/cert.c +++ b/dlls/crypt32/cert.c @@ -2689,11 +2689,92 @@ done: return !status; }
+static BOOL CNG_ImportRSAPubKey(CERT_PUBLIC_KEY_INFO *info, BCRYPT_KEY_HANDLE *key) +{ + DWORD size, rsakey_len, modulus_len; + BLOBHEADER *hdr; + RSAPUBKEY *rsapubkey; + const WCHAR *rsa_algo; + BCRYPT_ALG_HANDLE alg = NULL; + BCRYPT_RSAKEY_BLOB *rsakey; + BYTE *p; + NTSTATUS status; + + if (!info->PublicKey.cbData) + { + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + if (!CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, info->PublicKey.pbData, + info->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &hdr, &size)) + { + WARN("CryptDecodeObjectEx failed\n"); + return FALSE; + } + + if (hdr->aiKeyAlg == CALG_RSA_KEYX) + rsa_algo = BCRYPT_RSA_ALGORITHM; + else if (hdr->aiKeyAlg == CALG_RSA_SIGN) + rsa_algo = BCRYPT_RSA_SIGN_ALGORITHM; + else + { + FIXME("Unsupported RSA algorithm: %#x\n", hdr->aiKeyAlg); + CryptMemFree(hdr); + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + if ((status = BCryptOpenAlgorithmProvider(&alg, rsa_algo, NULL, 0))) + goto done; + + rsapubkey = (RSAPUBKEY *)(hdr + 1); + + modulus_len = size - sizeof(*hdr) - sizeof(*rsapubkey); + if (modulus_len != rsapubkey->bitlen / 8) + FIXME("RSA pubkey has wrong modulus_len %u\n", modulus_len); + + rsakey_len = sizeof(*rsakey) + sizeof(ULONG) + modulus_len; + + if (!(rsakey = CryptMemAlloc(rsakey_len))) + { + status = STATUS_NO_MEMORY; + goto done; + } + + rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; + rsakey->BitLength = rsapubkey->bitlen; + rsakey->cbPublicExp = sizeof(ULONG); + rsakey->cbModulus = modulus_len; + rsakey->cbPrime1 = 0; + rsakey->cbPrime2 = 0; + + p = (BYTE *)(rsakey + 1); + /* According to MSDN RSAPUBKEY.pubexp is in LE while + * BCRYPT_RSAKEY_BLOB is supposed to have it in BE format */ + *(ULONG *)p = RtlUlongByteSwap(rsapubkey->pubexp); + p += sizeof(ULONG); + memcpy(p, rsapubkey + 1, modulus_len); + + status = BCryptImportKeyPair(alg, NULL, BCRYPT_RSAPUBLIC_BLOB, key, (BYTE *)rsakey, rsakey_len, 0); + CryptMemFree(rsakey); + +done: + CryptMemFree(hdr); + if (alg) BCryptCloseAlgorithmProvider(alg, 0); + if (status) SetLastError(RtlNtStatusToDosError(status)); + return !status; +} + BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key) { if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY)) return CNG_ImportECCPubKey(pubKeyInfo, key);
+ + if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA)) + return CNG_ImportRSAPubKey(pubKeyInfo, key); + FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId)); SetLastError(NTE_BAD_ALGID); return FALSE; diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 38d2f84db14..7c72eba1b9b 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -30,6 +30,7 @@
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*); +static DWORD (WINAPI *pBCryptDestroyKey)(BCRYPT_KEY_HANDLE);
struct encodedInt { @@ -8400,6 +8401,7 @@ static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info) { BOOL ret; HCRYPTKEY key; + BCRYPT_KEY_HANDLE key2; PCCERT_CONTEXT context; DWORD dwSize; ALG_ID ai; @@ -8469,6 +8471,12 @@ static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info) &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key); ok(ret, "CryptImportPublicKeyInfoEx failed: %08x\n", GetLastError()); CryptDestroyKey(key); + + ret = CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, + &context->pCertInfo->SubjectPublicKeyInfo, 0, NULL, &key2); + ok(ret, "CryptImportPublicKeyInfoEx2 failed: %08x\n", GetLastError()); + if (pBCryptDestroyKey) pBCryptDestroyKey(key2); + CertFreeCertificateContext(context); } } @@ -8502,7 +8510,7 @@ START_TEST(encode) { static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING }; - HMODULE hCrypt32; + HMODULE hCrypt32, hBcrypt; DWORD i;
hCrypt32 = GetModuleHandleA("crypt32.dll"); @@ -8514,6 +8522,9 @@ START_TEST(encode) return; }
+ hBcrypt = GetModuleHandleA("bcrypt.dll"); + pBCryptDestroyKey = (void*)GetProcAddress(hBcrypt, "BCryptDestroyKey"); + for (i = 0; i < ARRAY_SIZE(encodings); i++) { test_encodeInt(encodings[i]);