[PATCH 2/5] bcrypt: Implement importing of ECDSA keys.

Hans Leidekker hans at codeweavers.com
Mon Mar 26 08:04:33 CDT 2018


From: Michael Müller <michael at fds-team.de>

Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/bcrypt/bcrypt.spec    |   4 +-
 dlls/bcrypt/bcrypt_main.c  | 173 +++++++++++++++++++++++++++++++++++++++++----
 dlls/bcrypt/tests/bcrypt.c |   4 +-
 dlls/ncrypt/ncrypt.spec    |   4 +-
 include/bcrypt.h           |   2 +
 5 files changed, 167 insertions(+), 20 deletions(-)

diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec
index 28c2394ce4..78824d73b3 100644
--- a/dlls/bcrypt/bcrypt.spec
+++ b/dlls/bcrypt/bcrypt.spec
@@ -32,7 +32,7 @@
 @ stdcall BCryptHash(ptr ptr long ptr long ptr long)
 @ stdcall BCryptHashData(ptr ptr long long)
 @ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long)
-@ stub BCryptImportKeyPair
+@ stdcall BCryptImportKeyPair(ptr ptr wstr ptr ptr long long)
 @ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long)
 @ stub BCryptQueryContextConfiguration
 @ stub BCryptQueryContextFunctionConfiguration
@@ -50,7 +50,7 @@
 @ stub BCryptSignHash
 @ stub BCryptUnregisterConfigChangeNotify
 @ stdcall BCryptUnregisterProvider(wstr)
-@ stub BCryptVerifySignature
+@ stdcall BCryptVerifySignature(ptr ptr ptr long ptr long long)
 @ stub GetAsymmetricEncryptionInterface
 @ stub GetCipherInterface
 @ stub GetHashInterface
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index 57cb3632d5..82a742cbc0 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -220,7 +220,9 @@ enum alg_id
     ALG_ID_SHA1,
     ALG_ID_SHA256,
     ALG_ID_SHA384,
-    ALG_ID_SHA512
+    ALG_ID_SHA512,
+    ALG_ID_ECDSA_P256,
+    ALG_ID_ECDSA_P384,
 };
 
 enum mode_id
@@ -251,7 +253,9 @@ alg_props[] =
     /* ALG_ID_SHA1   */ {  278,   20,  512, BCRYPT_SHA1_ALGORITHM,   FALSE },
     /* ALG_ID_SHA256 */ {  286,   32,  512, BCRYPT_SHA256_ALGORITHM, FALSE },
     /* ALG_ID_SHA384 */ {  382,   48, 1024, BCRYPT_SHA384_ALGORITHM, FALSE },
-    /* ALG_ID_SHA512 */ {  382,   64, 1024, BCRYPT_SHA512_ALGORITHM, FALSE }
+    /* ALG_ID_SHA512 */ {  382,   64, 1024, BCRYPT_SHA512_ALGORITHM, FALSE },
+    /* ALG_ID_ECDSA_P256 */ { 0,   0,     0, BCRYPT_ECDSA_P256_ALGORITHM, FALSE  },
+    /* ALG_ID_ECDSA_P384 */ { 0,   0,     0, BCRYPT_ECDSA_P384_ALGORITHM, FALSE  },
 };
 
 struct algorithm
@@ -327,6 +331,8 @@ NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR
     else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
     else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
     else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
+    else if (!strcmpW( id, BCRYPT_ECDSA_P256_ALGORITHM )) alg_id = ALG_ID_ECDSA_P256;
+    else if (!strcmpW( id, BCRYPT_ECDSA_P384_ALGORITHM )) alg_id = ALG_ID_ECDSA_P384;
     else
     {
         FIXME( "algorithm %s not supported\n", debugstr_w(id) );
@@ -869,6 +875,12 @@ struct key_symmetric
     ULONG               secret_len;
 };
 
+struct key_asymmetric
+{
+    UCHAR *pubkey;
+    ULONG  pubkey_len;
+};
+
 struct key
 {
     struct object hdr;
@@ -876,6 +888,7 @@ struct key
     union
     {
         struct key_symmetric  s;
+        struct key_asymmetric a;
     } u;
 };
 
@@ -890,6 +903,12 @@ struct key_symmetric
     ULONG          secret_len;
 };
 
+struct key_asymmetric
+{
+    UCHAR *pubkey;
+    ULONG  pubkey_len;
+};
+
 struct key
 {
     struct object hdr;
@@ -897,6 +916,7 @@ struct key
     union
     {
         struct key_symmetric  s;
+        struct key_asymmetric a;
     } u;
 };
 #else
@@ -954,18 +974,28 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
 {
     UCHAR *buffer;
 
-    if (!key_is_symmetric( key_orig )) return STATUS_NOT_IMPLEMENTED;
+    memset( key_copy, 0, sizeof(*key_copy) );
+    key_copy->hdr    = key_orig->hdr;
+    key_copy->alg_id = key_orig->alg_id;
 
-    if (!(buffer = heap_alloc( key_orig->u.s.secret_len ))) return STATUS_NO_MEMORY;
-    memcpy( buffer, key_orig->u.s.secret, key_orig->u.s.secret_len );
+    if (key_is_symmetric( key_orig ))
+    {
+        if (!(buffer = heap_alloc( key_orig->u.s.secret_len ))) return STATUS_NO_MEMORY;
+        memcpy( buffer, key_orig->u.s.secret, key_orig->u.s.secret_len );
 
-    memset( key_copy, 0, sizeof(*key_copy) );
-    key_copy->hdr            = key_orig->hdr;
-    key_copy->alg_id         = key_orig->alg_id;
-    key_copy->u.s.mode       = key_orig->u.s.mode;
-    key_copy->u.s.block_size = key_orig->u.s.block_size;
-    key_copy->u.s.secret     = buffer;
-    key_copy->u.s.secret_len = key_orig->u.s.secret_len;
+        key_copy->u.s.mode       = key_orig->u.s.mode;
+        key_copy->u.s.block_size = key_orig->u.s.block_size;
+        key_copy->u.s.secret     = buffer;
+        key_copy->u.s.secret_len = key_orig->u.s.secret_len;
+    }
+    else
+    {
+        if (!(buffer = heap_alloc( key_orig->u.a.pubkey_len ))) return STATUS_NO_MEMORY;
+        memcpy( buffer, key_orig->u.a.pubkey, key_orig->u.a.pubkey_len );
+
+        key_copy->u.a.pubkey     = buffer;
+        key_copy->u.a.pubkey_len = key_orig->u.a.pubkey_len;
+    }
 
     return STATUS_SUCCESS;
 }
@@ -1149,10 +1179,41 @@ static NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
+{
+    UCHAR *buffer;
+
+    if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
+
+    switch (alg->id)
+    {
+    case ALG_ID_ECDSA_P256:
+    case ALG_ID_ECDSA_P384:
+        break;
+
+    default:
+        FIXME( "algorithm %u not supported\n", alg->id );
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    if (!(buffer = heap_alloc( pubkey_len ))) return STATUS_NO_MEMORY;
+    memcpy( buffer, pubkey, pubkey_len );
+
+    key->alg_id         = alg->id;
+    key->u.a.pubkey     = buffer;
+    key->u.a.pubkey_len = pubkey_len;
+
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS key_destroy( struct key *key )
 {
-    if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle );
-    heap_free( key->u.s.secret );
+    if (key_is_symmetric( key ))
+    {
+        if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle );
+        heap_free( key->u.s.secret );
+    }
+    else heap_free( key->u.a.pubkey );
     heap_free( key );
     return STATUS_SUCCESS;
 }
@@ -1315,6 +1376,12 @@ static NTSTATUS key_destroy( struct key *key )
     heap_free( key );
     return STATUS_SUCCESS;
 }
+
+static NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
+{
+    FIXME( "not implemented on Mac\n" );
+    return STATUS_NOT_IMPLEMENTED;
+}
 #else
 static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
 {
@@ -1383,6 +1450,12 @@ static inline BOOL key_is_symmetric( struct key *key )
     ERR( "support for keys not available at build time\n" );
     return FALSE;
 }
+
+static NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
+{
+    ERR( "support for keys not available at build time\n" );
+    return STATUS_NOT_IMPLEMENTED;
+}
 #endif
 
 NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
@@ -1498,6 +1571,78 @@ NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE
     return STATUS_SUCCESS;
 }
 
+NTSTATUS WINAPI BCryptImportKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, const WCHAR *type,
+                                     BCRYPT_KEY_HANDLE *ret_key, UCHAR *input, ULONG input_len, ULONG flags )
+{
+    struct algorithm *alg = algorithm;
+    NTSTATUS status;
+    struct key *key;
+
+    TRACE( "%p, %p, %s, %p, %p, %u, %08x\n", algorithm, decrypt_key, debugstr_w(type), ret_key, input,
+           input_len, flags );
+
+    if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
+    if (!ret_key || !type || !input) return STATUS_INVALID_PARAMETER;
+    if (decrypt_key)
+    {
+        FIXME( "decryption of key not yet supported\n" );
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    if (!strcmpW( type, BCRYPT_ECCPUBLIC_BLOB ))
+    {
+        BCRYPT_ECCKEY_BLOB *ecc_blob = (BCRYPT_ECCKEY_BLOB *)input;
+        DWORD key_size, magic;
+
+        if (input_len < sizeof(*ecc_blob)) return STATUS_INVALID_PARAMETER;
+
+        switch (alg->id)
+        {
+        case ALG_ID_ECDSA_P256:
+            key_size = 32;
+            magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
+            break;
+
+        case ALG_ID_ECDSA_P384:
+            key_size = 48;
+            magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
+            break;
+
+        default:
+            FIXME( "algorithm %u does not yet support importing blob of type %s\n", alg->id, debugstr_w(type) );
+            return STATUS_NOT_SUPPORTED;
+        }
+
+        if (ecc_blob->dwMagic != magic) return STATUS_NOT_SUPPORTED;
+        if (ecc_blob->cbKey != key_size) return STATUS_INVALID_PARAMETER;
+
+        if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
+        key->hdr.magic = MAGIC_KEY;
+        if ((status = key_asymmetric_init( key, alg, (BYTE *)ecc_blob, sizeof(*ecc_blob) + ecc_blob->cbKey * 2 )))
+        {
+            heap_free( key );
+            return status;
+        }
+
+        *ret_key = key;
+        return STATUS_SUCCESS;
+    }
+
+    FIXME( "unsupported key type %s\n", debugstr_w(type) );
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS WINAPI BCryptVerifySignature( BCRYPT_KEY_HANDLE handle, void *padding, UCHAR *hash, ULONG hash_len,
+                                       UCHAR *signature, ULONG signature_len, ULONG flags )
+{
+    struct key *key = handle;
+
+    FIXME( "%p, %p, %p, %u, %p, %u, %08x: stub!\n", handle, padding, hash, hash_len, signature, signature_len, flags );
+
+    if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
 {
     struct key *key = handle;
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index 57d04882b5..fa244d1924 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -1486,10 +1486,10 @@ static void test_ECDSA(void)
     ok(!status, "BCryptImportKeyPair failed: %08x\n", status);
 
     status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash) - 1, certSignature, sizeof(certSignature), 0);
-    ok(status == STATUS_INVALID_SIGNATURE, "Expected STATUS_INVALID_SIGNATURE, got %08x\n", status);
+    todo_wine ok(status == STATUS_INVALID_SIGNATURE, "Expected STATUS_INVALID_SIGNATURE, got %08x\n", status);
 
     status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash), certSignature, sizeof(certSignature), 0);
-    ok(!status, "BCryptVerifySignature failed: %08x\n", status);
+    todo_wine ok(!status, "BCryptVerifySignature failed: %08x\n", status);
 
     pBCryptDestroyKey(key);
     pBCryptCloseAlgorithmProvider(alg, 0);
diff --git a/dlls/ncrypt/ncrypt.spec b/dlls/ncrypt/ncrypt.spec
index d0f0f56cc4..e7b12e0059 100644
--- a/dlls/ncrypt/ncrypt.spec
+++ b/dlls/ncrypt/ncrypt.spec
@@ -34,7 +34,7 @@
 @ stdcall BCryptHash(ptr ptr long ptr long ptr long) bcrypt.BCryptHash
 @ stdcall BCryptHashData(ptr ptr long long) bcrypt.BCryptHashData
 @ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long) bcrypt.BCryptImportKey
-@ stub BCryptImportKeyPair
+@ stdcall BCryptImportKeyPair(ptr ptr wstr ptr ptr long long) bcrypt.BCryptImportKeyPair
 @ stub BCryptKeyDerivation
 @ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long) bcrypt.BCryptOpenAlgorithmProvider
 @ stub BCryptQueryContextConfiguration
@@ -53,7 +53,7 @@
 @ stub BCryptSignHash
 @ stub BCryptUnregisterConfigChangeNotify
 @ stdcall BCryptUnregisterProvider(wstr) bcrypt.BCryptUnregisterProvider
-@ stub BCryptVerifySignature
+@ stdcall BCryptVerifySignature(ptr ptr ptr long ptr long long) bcrypt.BCryptVerifySignature
 @ stub GetIsolationServerInterface
 @ stub GetKeyStorageInterface
 @ stub GetSChannelInterface
diff --git a/include/bcrypt.h b/include/bcrypt.h
index 717d77c731..f28b0d395d 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -211,8 +211,10 @@ NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *);
 NTSTATUS WINAPI BCryptGetProperty(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG);
 NTSTATUS WINAPI BCryptHash(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, PUCHAR, ULONG, PUCHAR, ULONG);
 NTSTATUS WINAPI BCryptHashData(BCRYPT_HASH_HANDLE, PUCHAR, ULONG, ULONG);
+NTSTATUS WINAPI BCryptImportKeyPair(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG);
 NTSTATUS WINAPI BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *, LPCWSTR, LPCWSTR, ULONG);
 NTSTATUS WINAPI BCryptSetProperty(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG);
 NTSTATUS WINAPI BCryptDuplicateHash(BCRYPT_HASH_HANDLE, BCRYPT_HASH_HANDLE *, UCHAR *, ULONG, ULONG);
+NTSTATUS WINAPI BCryptVerifySignature(BCRYPT_KEY_HANDLE, void *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG);
 
 #endif  /* __WINE_BCRYPT_H */
-- 
2.11.0




More information about the wine-devel mailing list