Dmitry Timoshkov : crypt32: Add support for importing RSA public keys with BCrypt.

Alexandre Julliard julliard at winehq.org
Tue Oct 26 09:40:27 CDT 2021


Module: wine
Branch: stable
Commit: d54b02e28139b8c7d43f6f5537ac81242a57004c
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=d54b02e28139b8c7d43f6f5537ac81242a57004c

Author: Dmitry Timoshkov <dmitry at baikal.ru>
Date:   Mon Apr 12 15:21:04 2021 +0300

crypt32: Add support for importing RSA public keys with BCrypt.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50925
Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
(cherry picked from commit 9d1ae850dfd73c60fbe2904c443f79a050a20b96)
Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>

---

 dlls/crypt32/cert.c         | 83 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/crypt32/tests/encode.c | 13 ++++++-
 2 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c
index 95e2746a7d5..7d4041f1fb3 100644
--- a/dlls/crypt32/cert.c
+++ b/dlls/crypt32/cert.c
@@ -2689,11 +2689,94 @@ done:
     return !status;
 }
 
+static BOOL CNG_ImportRSAPubKey(CERT_PUBLIC_KEY_INFO *info, BCRYPT_KEY_HANDLE *key)
+{
+    DWORD size, modulus_len, i;
+    BLOBHEADER *hdr;
+    RSAPUBKEY *rsapubkey;
+    const WCHAR *rsa_algo;
+    BCRYPT_ALG_HANDLE alg = NULL;
+    BCRYPT_RSAKEY_BLOB *rsakey;
+    BYTE *s, *d;
+    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);
+
+    size = sizeof(*rsakey) + sizeof(ULONG) + modulus_len;
+
+    if (!(rsakey = CryptMemAlloc(size)))
+    {
+        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;
+
+    d = (BYTE *)(rsakey + 1);
+    /* According to MSDN modulus and pubexp are in LE while
+     * BCRYPT_RSAKEY_BLOB is supposed to have them in BE format */
+    *(ULONG *)d = RtlUlongByteSwap(rsapubkey->pubexp);
+    d += sizeof(ULONG);
+    s = (BYTE *)(rsapubkey + 1);
+    for (i = 0; i < modulus_len; i++)
+        d[i] = s[modulus_len - i - 1];
+
+    status = BCryptImportKeyPair(alg, NULL, BCRYPT_RSAPUBLIC_BLOB, key, (BYTE *)rsakey, size, 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]);




More information about the wine-cvs mailing list