[PATCH] bcrypt: Add support for BCRYPT_DSA_ALGORITHM.

Hans Leidekker hans at codeweavers.com
Fri May 29 04:29:06 CDT 2020


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/bcrypt/bcrypt_internal.h |   1 +
 dlls/bcrypt/bcrypt_main.c     |  46 +++++++--
 dlls/bcrypt/gnutls.c          | 178 +++++++++++++++++++++++++++++++++-
 dlls/bcrypt/tests/bcrypt.c    |  96 ++++++++++++++++++
 include/bcrypt.h              |  69 +++++++++++--
 5 files changed, 369 insertions(+), 21 deletions(-)

diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index 5cc2c249da..2c834bec48 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -137,6 +137,7 @@ enum alg_id
     ALG_ID_RSA_SIGN,
     ALG_ID_ECDSA_P256,
     ALG_ID_ECDSA_P384,
+    ALG_ID_DSA,
 
     /* rng */
     ALG_ID_RNG,
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index 6311700880..5492c1947e 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -118,6 +118,7 @@ builtin_algorithms[] =
     {  BCRYPT_RSA_SIGN_ALGORITHM,   BCRYPT_SIGNATURE_INTERFACE,             0,      0,    0 },
     {  BCRYPT_ECDSA_P256_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE,             0,      0,    0 },
     {  BCRYPT_ECDSA_P384_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE,             0,      0,    0 },
+    {  BCRYPT_DSA_ALGORITHM,        BCRYPT_SIGNATURE_INTERFACE,             0,      0,    0 },
     {  BCRYPT_RNG_ALGORITHM,        BCRYPT_RNG_INTERFACE,                   0,      0,    0 },
 };
 
@@ -541,6 +542,13 @@ static NTSTATUS get_rsa_property( enum mode_id mode, const WCHAR *prop, UCHAR *b
     return STATUS_NOT_IMPLEMENTED;
 }
 
+static NTSTATUS get_dsa_property( enum mode_id mode, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
+{
+    if (!strcmpW( prop, BCRYPT_PADDING_SCHEMES )) return STATUS_NOT_SUPPORTED;
+    FIXME( "unsupported property %s\n", debugstr_w(prop) );
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
 {
     NTSTATUS status;
@@ -557,11 +565,14 @@ NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR
     case ALG_ID_RSA:
         return get_rsa_property( alg->mode, prop, buf, size, ret_size );
 
+    case ALG_ID_DSA:
+        return get_dsa_property( alg->mode, prop, buf, size, ret_size );
+
     default:
         break;
     }
 
-    FIXME( "unsupported property %s\n", debugstr_w(prop) );
+    FIXME( "unsupported property %s algorithm %u\n", debugstr_w(prop), alg->id );
     return STATUS_NOT_IMPLEMENTED;
 }
 
@@ -924,15 +935,8 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U
         memcpy( output + sizeof(len), key->u.s.secret, key->u.s.secret_len );
         return STATUS_SUCCESS;
     }
-    else if (!strcmpW( type, BCRYPT_RSAPUBLIC_BLOB ))
-    {
-        *size = key->u.a.pubkey_len;
-        if (output_len < key->u.a.pubkey_len) return STATUS_SUCCESS;
-
-        memcpy( output, key->u.a.pubkey, key->u.a.pubkey_len );
-        return STATUS_SUCCESS;
-    }
-    else if (!strcmpW( type, BCRYPT_ECCPUBLIC_BLOB ))
+    else if (!strcmpW( type, BCRYPT_RSAPUBLIC_BLOB ) || !strcmpW( type, BCRYPT_DSA_PUBLIC_BLOB ) ||
+             !strcmpW( type, BCRYPT_ECCPUBLIC_BLOB ))
     {
         *size = key->u.a.pubkey_len;
         if (output_len < key->u.a.pubkey_len) return STATUS_SUCCESS;
@@ -1241,6 +1245,28 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
         *ret_key = key;
         return STATUS_SUCCESS;
     }
+    else if (!strcmpW( type, BCRYPT_DSA_PUBLIC_BLOB ))
+    {
+        BCRYPT_DSA_KEY_BLOB *dsa_blob = (BCRYPT_DSA_KEY_BLOB *)input;
+        ULONG size;
+
+        if (input_len < sizeof(*dsa_blob)) return STATUS_INVALID_PARAMETER;
+        if ((alg->id != ALG_ID_DSA) || dsa_blob->dwMagic != BCRYPT_DSA_PUBLIC_MAGIC)
+            return STATUS_NOT_SUPPORTED;
+
+        if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
+        key->hdr.magic = MAGIC_KEY;
+
+        size = sizeof(*dsa_blob) + dsa_blob->cbKey * 3;
+        if ((status = key_asymmetric_init( key, alg, dsa_blob->cbKey * 8, (BYTE *)dsa_blob, size )))
+        {
+            heap_free( key );
+            return status;
+        }
+
+        *ret_key = key;
+        return STATUS_SUCCESS;
+    }
 
     FIXME( "unsupported key type %s\n", debugstr_w(type) );
     return STATUS_NOT_SUPPORTED;
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c
index 2b11566566..d4ad327bc4 100644
--- a/dlls/bcrypt/gnutls.c
+++ b/dlls/bcrypt/gnutls.c
@@ -75,7 +75,11 @@ static int (*pgnutls_pubkey_verify_hash2)(gnutls_pubkey_t, gnutls_sign_algorithm
                                           const gnutls_datum_t *, const gnutls_datum_t *);
 
 /* Not present in gnutls version < 2.11.0 */
-static int (*pgnutls_pubkey_import_rsa_raw)(gnutls_pubkey_t key, const gnutls_datum_t *m, const gnutls_datum_t *e);
+static int (*pgnutls_pubkey_import_rsa_raw)(gnutls_pubkey_t, const gnutls_datum_t *, const gnutls_datum_t *);
+
+/* Not present in gnutls version < 2.12.0 */
+static int (*pgnutls_pubkey_import_dsa_raw)(gnutls_pubkey_t, const gnutls_datum_t *, const gnutls_datum_t *,
+                                            const gnutls_datum_t *, const gnutls_datum_t *);
 
 /* Not present in gnutls version < 3.3.0 */
 static int (*pgnutls_privkey_export_ecc_raw)(gnutls_privkey_t, gnutls_ecc_curve_t *,
@@ -83,6 +87,8 @@ static int (*pgnutls_privkey_export_ecc_raw)(gnutls_privkey_t, gnutls_ecc_curve_
 static int (*pgnutls_privkey_export_rsa_raw)(gnutls_privkey_t, gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *,
                                              gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *,
                                              gnutls_datum_t *);
+static int (*pgnutls_privkey_export_dsa_raw)(gnutls_privkey_t, gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *,
+                                             gnutls_datum_t *, gnutls_datum_t *);
 static int (*pgnutls_privkey_generate)(gnutls_privkey_t, gnutls_pk_algorithm_t, unsigned int, unsigned int);
 
 /* Not present in gnutls version < 3.6.0 */
@@ -142,6 +148,12 @@ static int compat_gnutls_privkey_import_ecc_raw(gnutls_privkey_t key, gnutls_ecc
     return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
 }
 
+static int compat_gnutls_privkey_export_dsa_raw(gnutls_privkey_t key, gnutls_datum_t *p, gnutls_datum_t *q,
+                                                gnutls_datum_t *g, gnutls_datum_t *y, gnutls_datum_t *x)
+{
+    return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+}
+
 static gnutls_sign_algorithm_t compat_gnutls_pk_to_sign(gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash)
 {
     return GNUTLS_SIGN_UNKNOWN;
@@ -159,6 +171,12 @@ static int compat_gnutls_pubkey_import_rsa_raw(gnutls_pubkey_t key, const gnutls
     return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
 }
 
+static int compat_gnutls_pubkey_import_dsa_raw(gnutls_pubkey_t key, const gnutls_datum_t *p, const gnutls_datum_t *q,
+                                               const gnutls_datum_t *g, const gnutls_datum_t *y)
+{
+    return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+}
+
 static int compat_gnutls_privkey_generate(gnutls_privkey_t key, gnutls_pk_algorithm_t algo, unsigned int bits,
                                           unsigned int flags)
 {
@@ -244,6 +262,11 @@ BOOL gnutls_initialize(void)
         WARN("gnutls_privkey_import_ecc_raw not found\n");
         pgnutls_privkey_import_ecc_raw = compat_gnutls_privkey_import_ecc_raw;
     }
+    if (!(pgnutls_privkey_export_dsa_raw = dlsym( libgnutls_handle, "gnutls_privkey_export_dsa_raw" )))
+    {
+        WARN("gnutls_privkey_export_dsa_raw not found\n");
+        pgnutls_privkey_export_dsa_raw = compat_gnutls_privkey_export_dsa_raw;
+    }
     if (!(pgnutls_pk_to_sign = dlsym( libgnutls_handle, "gnutls_pk_to_sign" )))
     {
         WARN("gnutls_pk_to_sign not found\n");
@@ -259,6 +282,11 @@ BOOL gnutls_initialize(void)
         WARN("gnutls_pubkey_import_rsa_raw not found\n");
         pgnutls_pubkey_import_rsa_raw = compat_gnutls_pubkey_import_rsa_raw;
     }
+    if (!(pgnutls_pubkey_import_dsa_raw = dlsym( libgnutls_handle, "gnutls_pubkey_import_dsa_raw" )))
+    {
+        WARN("gnutls_pubkey_import_dsa_raw not found\n");
+        pgnutls_pubkey_import_dsa_raw = compat_gnutls_pubkey_import_dsa_raw;
+    }
     if (!(pgnutls_privkey_generate = dlsym( libgnutls_handle, "gnutls_privkey_generate" )))
     {
         WARN("gnutls_privkey_generate not found\n");
@@ -704,6 +732,80 @@ static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, UCHAR **p
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS export_gnutls_pubkey_dsa( gnutls_privkey_t gnutls_key, ULONG bitlen, UCHAR **pubkey, ULONG *pubkey_len )
+{
+    BCRYPT_DSA_KEY_BLOB *dsa_blob;
+    gnutls_datum_t p, q, g, y;
+    UCHAR *dst, *src;
+    int ret;
+
+    if ((ret = pgnutls_privkey_export_dsa_raw( gnutls_key, &p, &q, &g, &y, NULL )))
+    {
+        pgnutls_perror( ret );
+        return STATUS_INTERNAL_ERROR;
+    }
+
+    if (bitlen > 1024)
+    {
+        FIXME( "bitlen > 1024 not supported\n" );
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    if (!(dsa_blob = heap_alloc( sizeof(*dsa_blob) + p.size + g.size + y.size )))
+    {
+        pgnutls_perror( ret );
+        free( p.data ); free( q.data ); free( g.data ); free( y.data );
+        return STATUS_NO_MEMORY;
+    }
+
+    dst = (UCHAR *)(dsa_blob + 1);
+    if (p.size == bitlen / 8 + 1 && !p.data[0])
+    {
+        src = p.data + 1;
+        p.size--;
+    }
+    else src = p.data;
+    memcpy( dst, src, p.size );
+
+    dst += p.size;
+    if (g.size == bitlen / 8 + 1 && !g.data[0])
+    {
+        src = g.data + 1;
+        g.size--;
+    }
+    else src = g.data;
+    memcpy( dst, src, g.size );
+
+    dst += g.size;
+    if (y.size == bitlen / 8 + 1 && !y.data[0])
+    {
+        src = y.data + 1;
+        y.size--;
+    }
+    else src = y.data;
+    memcpy( dst, src, y.size );
+
+    dst = dsa_blob->q;
+    if (q.size == sizeof(dsa_blob->q) + 1 && !q.data[0])
+    {
+        src = q.data + 1;
+        q.size--;
+    }
+    else src = q.data;
+    memcpy( dst, src, sizeof(dsa_blob->q) );
+
+    dsa_blob->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC;
+    dsa_blob->cbKey   = bitlen / 8;
+    memset( dsa_blob->Count, 0, sizeof(dsa_blob->Count) ); /* FIXME */
+    memset( dsa_blob->Seed, 0, sizeof(dsa_blob->Seed) ); /* FIXME */
+
+    *pubkey = (UCHAR *)dsa_blob;
+    *pubkey_len = sizeof(*dsa_blob) + p.size + g.size + y.size;
+
+    free( p.data ); free( q.data ); free( g.data ); free( y.data );
+    return STATUS_SUCCESS;
+}
+
 NTSTATUS key_asymmetric_generate( struct key *key )
 {
     gnutls_pk_algorithm_t pk_alg;
@@ -722,6 +824,11 @@ NTSTATUS key_asymmetric_generate( struct key *key )
         bitlen = key->u.a.bitlen;
         break;
 
+    case ALG_ID_DSA:
+        pk_alg = GNUTLS_PK_DSA;
+        bitlen = key->u.a.bitlen;
+        break;
+
     case ALG_ID_ECDH_P256:
     case ALG_ID_ECDSA_P256:
         pk_alg = GNUTLS_PK_ECC; /* compatible with ECDSA and ECDH */
@@ -756,6 +863,10 @@ NTSTATUS key_asymmetric_generate( struct key *key )
         status = export_gnutls_pubkey_ecc( handle, &key->u.a.pubkey, &key->u.a.pubkey_len );
         break;
 
+    case GNUTLS_PK_DSA:
+        status = export_gnutls_pubkey_dsa( handle, key->u.a.bitlen, &key->u.a.pubkey, &key->u.a.pubkey_len );
+        break;
+
     default:
         ERR( "unhandled algorithm %u\n", pk_alg );
         return STATUS_INTERNAL_ERROR;
@@ -889,6 +1000,7 @@ NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, ULONG bitl
     case ALG_ID_ECDSA_P384:
     case ALG_ID_RSA:
     case ALG_ID_RSA_SIGN:
+    case ALG_ID_DSA:
         break;
 
     default:
@@ -975,6 +1087,38 @@ static NTSTATUS import_gnutls_pubkey_rsa( struct key *key, gnutls_pubkey_t *gnut
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS import_gnutls_pubkey_dsa( struct key *key, gnutls_pubkey_t *gnutls_key )
+{
+    BCRYPT_DSA_KEY_BLOB *dsa_blob;
+    gnutls_datum_t p, q, g, y;
+    int ret;
+
+    if ((ret = pgnutls_pubkey_init( gnutls_key )))
+    {
+        pgnutls_perror( ret );
+        return STATUS_INTERNAL_ERROR;
+    }
+
+    dsa_blob = (BCRYPT_DSA_KEY_BLOB *)key->u.a.pubkey;
+    p.data = key->u.a.pubkey + sizeof(*dsa_blob);
+    p.size = dsa_blob->cbKey;
+    q.data = dsa_blob->q;
+    q.size = sizeof(dsa_blob->q);
+    g.data = key->u.a.pubkey + sizeof(*dsa_blob) + dsa_blob->cbKey;
+    g.size = dsa_blob->cbKey;
+    y.data = key->u.a.pubkey + sizeof(*dsa_blob) + dsa_blob->cbKey * 2;
+    y.size = dsa_blob->cbKey;
+
+    if ((ret = pgnutls_pubkey_import_dsa_raw( *gnutls_key, &p, &q, &g, &y )))
+    {
+        pgnutls_perror( ret );
+        pgnutls_pubkey_deinit( *gnutls_key );
+        return STATUS_INTERNAL_ERROR;
+    }
+
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS import_gnutls_pubkey( struct key *key, gnutls_pubkey_t *gnutls_key )
 {
     switch (key->alg_id)
@@ -987,13 +1131,16 @@ static NTSTATUS import_gnutls_pubkey( struct key *key, gnutls_pubkey_t *gnutls_k
     case ALG_ID_RSA_SIGN:
         return import_gnutls_pubkey_rsa( key, gnutls_key );
 
+    case ALG_ID_DSA:
+        return import_gnutls_pubkey_dsa( key, gnutls_key );
+
     default:
         FIXME("algorithm %u not yet supported\n", key->alg_id );
         return STATUS_NOT_IMPLEMENTED;
     }
 }
 
-static NTSTATUS prepare_gnutls_signature_ecc( struct key *key, UCHAR *signature, ULONG signature_len,
+static NTSTATUS prepare_gnutls_signature_dsa( struct key *key, UCHAR *signature, ULONG signature_len,
                                               gnutls_datum_t *gnutls_signature )
 {
     struct buffer buffer;
@@ -1030,7 +1177,8 @@ static NTSTATUS prepare_gnutls_signature( struct key *key, UCHAR *signature, ULO
     {
     case ALG_ID_ECDSA_P256:
     case ALG_ID_ECDSA_P384:
-        return prepare_gnutls_signature_ecc( key, signature, signature_len, gnutls_signature );
+    case ALG_ID_DSA:
+        return prepare_gnutls_signature_dsa( key, signature, signature_len, gnutls_signature );
 
     case ALG_ID_RSA:
     case ALG_ID_RSA_SIGN:
@@ -1101,6 +1249,18 @@ NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *hash, ULO
         pk_alg = GNUTLS_PK_RSA;
         break;
     }
+    case ALG_ID_DSA:
+    {
+        if (flags) FIXME( "flags %08x not supported\n", flags );
+        if (hash_len != 20)
+        {
+            FIXME( "hash size %u not supported\n", hash_len );
+            return STATUS_INVALID_PARAMETER;
+        }
+        hash_alg = GNUTLS_DIG_SHA1;
+        pk_alg = GNUTLS_PK_DSA;
+        break;
+    }
     default:
         FIXME( "algorithm %u not yet supported\n", key->alg_id );
         return STATUS_NOT_IMPLEMENTED;
@@ -1134,6 +1294,7 @@ static unsigned int get_signature_length( enum alg_id id )
     {
     case ALG_ID_ECDSA_P256: return 64;
     case ALG_ID_ECDSA_P384: return 96;
+    case ALG_ID_DSA:        return 40;
     default:
         FIXME( "unhandled algorithm %u\n", id );
         return 0;
@@ -1155,6 +1316,7 @@ static NTSTATUS format_gnutls_signature( enum alg_id type, gnutls_datum_t signat
     }
     case ALG_ID_ECDSA_P256:
     case ALG_ID_ECDSA_P384:
+    case ALG_ID_DSA:
     {
         int err;
         unsigned int pad_size, sig_len = get_signature_length( type );
@@ -1230,6 +1392,16 @@ NTSTATUS key_asymmetric_sign( struct key *key, void *padding, UCHAR *input, ULON
             return STATUS_INVALID_PARAMETER;
         }
     }
+    else if (key->alg_id == ALG_ID_DSA)
+    {
+        if (flags) FIXME( "flags %08x not supported\n", flags );
+        if (input_len != 20)
+        {
+            FIXME( "hash size %u not supported\n", input_len );
+            return STATUS_INVALID_PARAMETER;
+        }
+        hash_alg = GNUTLS_DIG_SHA1;
+    }
     else if (flags == BCRYPT_PAD_PKCS1)
     {
         if (!pad || !pad->pszAlgId)
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index e64e78546d..a67b14f4e4 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -2422,6 +2422,101 @@ static void test_BcryptDeriveKeyCapi(void)
     ok(!ret, "got %08x\n", ret);
 }
 
+static UCHAR dsaHash[] =
+{
+    0x7e,0xe3,0x74,0xe7,0xc5,0x0b,0x6b,0x70,0xdb,0xab,0x32,0x6d,0x1d,0x51,0xd6,0x74,0x79,0x8e,0x5b,0x4b
+};
+
+static UCHAR dsaSignature[] =
+{
+    0x5f,0x95,0x1f,0x08,0x19,0x44,0xa5,0xab,0x28,0x11,0x51,0x68,0x82,0x9b,0xe4,0xc3,0x04,0x1b,0xc9,0xdc,
+    0x41,0x2a,0x89,0xd4,0x4a,0x8b,0x86,0xaf,0x98,0x2c,0x59,0x0b,0xd2,0x88,0xf6,0xe8,0x29,0x13,0x84,0x49
+};
+
+static UCHAR dsaPublicBlob[] =
+{
+    0x44,0x53,0x50,0x42,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x8f,0xd2,0x92,0xbb,0x92,0xb9,0x00,0xc5,0xed,
+    0x52,0xcc,0x48,0x4a,0x44,0x1d,0xd3,0x74,0xfb,0x75,0xd1,0x7e,0xb6,0x24,0x9b,0x5d,0x57,0x0a,0x8a,0xc4,
+    0x5d,0xab,0x9c,0x26,0x86,0xc6,0x25,0x16,0x20,0xf9,0xa9,0x71,0xbc,0x1d,0x30,0xc4,0xef,0x8c,0xc4,0xdf,
+    0x1a,0xaf,0x96,0xdf,0x90,0xd8,0x85,0x9d,0xf9,0x2c,0x86,0x8c,0x91,0x39,0x6c,0x6d,0x11,0x4e,0x53,0x63,
+    0x2a,0x2b,0x26,0xa7,0xf9,0x76,0x74,0x51,0xbf,0x08,0x87,0x6f,0xe0,0x71,0x91,0x24,0x8a,0xc2,0x84,0x2d,
+    0x84,0x9c,0x5f,0x94,0xaa,0x38,0x53,0x77,0x84,0xba,0xbc,0xff,0x49,0x3a,0x08,0x0f,0x38,0xb5,0x91,0x5c,
+    0x06,0x15,0xa4,0x27,0xf4,0xa5,0x59,0xaa,0x1c,0x41,0xa3,0xa0,0xbb,0xf7,0x32,0x86,0xfb,0x94,0x41,0xff,
+    0xcd,0xed,0x69,0xeb,0xc6,0x5e,0xb6,0xa8,0x15,0x82,0x3b,0x60,0x1e,0x91,0x55,0xd5,0x2c,0xa5,0x74,0x5a,
+    0x65,0x8f,0xc6,0x56,0xc4,0x3f,0x4e,0xe3,0x3a,0x71,0xb2,0x63,0x66,0xa4,0x0d,0x0d,0xf9,0xdd,0x1e,0x48,
+    0x81,0xe9,0xbf,0x8f,0xbb,0x85,0x47,0x81,0x68,0x11,0xb5,0x91,0x6b,0xc4,0x05,0xef,0xa3,0xc7,0xbf,0x26,
+    0x53,0x4f,0xc4,0x10,0xfd,0xfa,0xed,0x61,0x64,0xd6,0x2e,0xad,0x04,0x3e,0x82,0xed,0xb2,0x22,0x76,0xd0,
+    0x44,0xad,0xc1,0x4c,0xde,0x33,0xa3,0x61,0x55,0xec,0x24,0xe5,0x79,0x45,0xcf,0x94,0x39,0x92,0x9f,0xd8,
+    0x24,0xce,0x85,0xb9
+};
+
+static void test_DSA(void)
+{
+    BCRYPT_ALG_HANDLE alg;
+    BCRYPT_KEY_HANDLE key;
+    BCRYPT_DSA_KEY_BLOB *dsablob;
+    UCHAR sig[40], schemes;
+    ULONG len, size;
+    NTSTATUS ret;
+    BYTE *buf;
+
+    ret = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_DSA_ALGORITHM, NULL, 0);
+    ok(!ret, "got %08x\n", ret);
+
+    ret = pBCryptGetProperty(alg, L"PaddingSchemes", (UCHAR *)&schemes, sizeof(schemes), &size, 0);
+    ok(ret == STATUS_NOT_SUPPORTED, "got %08x\n", ret);
+
+    ret = pBCryptImportKeyPair(alg, NULL, BCRYPT_DSA_PUBLIC_BLOB, &key, dsaPublicBlob, sizeof(dsaPublicBlob), 0);
+    ok(!ret, "got %08x\n", ret);
+
+    ret = pBCryptVerifySignature(key, NULL, dsaHash, sizeof(dsaHash), dsaSignature, sizeof(dsaSignature), 0);
+    ok(!ret, "got %08x\n", ret);
+
+    ret = pBCryptDestroyKey(key);
+    ok(!ret, "got %08x\n", ret);
+
+    /* sign/verify with export/import round-trip */
+    ret = pBCryptGenerateKeyPair(alg, &key, 512, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+
+    ret = pBCryptFinalizeKeyPair(key, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+
+    len = 0;
+    memset(sig, 0, sizeof(sig));
+    ret = pBCryptSignHash(key, NULL, dsaHash, sizeof(dsaHash), sig, sizeof(sig), &len, 0);
+    ok(!ret, "got %08x\n", ret);
+    ok(len == 40, "got %u\n", len);
+
+    size = 0;
+    ret = pBCryptExportKey(key, NULL, BCRYPT_DSA_PUBLIC_BLOB, NULL, 0, &size, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    ok(size, "size not set\n");
+
+    buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+    ret = pBCryptExportKey(key, NULL, BCRYPT_DSA_PUBLIC_BLOB, buf, size, &size, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    dsablob = (BCRYPT_DSA_KEY_BLOB *)buf;
+    ok(dsablob->dwMagic == BCRYPT_DSA_PUBLIC_MAGIC, "got %08x\n", dsablob->dwMagic);
+    ok(dsablob->cbKey == 64, "got %u\n", dsablob->cbKey);
+    ok(size == sizeof(*dsablob) + dsablob->cbKey * 3, "got %u\n", size);
+
+    ret = pBCryptDestroyKey(key);
+    ok(!ret, "got %08x\n", ret);
+
+    ret = pBCryptImportKeyPair(alg, NULL, BCRYPT_DSA_PUBLIC_BLOB, &key, buf, size, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    HeapFree(GetProcessHeap(), 0, buf);
+
+    ret = pBCryptVerifySignature(key, NULL, dsaHash, sizeof(dsaHash), sig, len, 0);
+    ok(!ret, "got %08x\n", ret);
+    ret = pBCryptDestroyKey(key);
+    ok(!ret, "got %08x\n", ret);
+
+    ret = pBCryptCloseAlgorithmProvider(alg, 0);
+    ok(!ret, "got %08x\n", ret);
+}
+
 START_TEST(bcrypt)
 {
     HMODULE module;
@@ -2486,6 +2581,7 @@ START_TEST(bcrypt)
     test_BCryptEnumAlgorithms();
     test_aes_vector();
     test_BcryptDeriveKeyCapi();
+    test_DSA();
 
     FreeLibrary(module);
 }
diff --git a/include/bcrypt.h b/include/bcrypt.h
index 62e6074f59..be170a613c 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -66,14 +66,25 @@ typedef LONG NTSTATUS;
 #define BCRYPT_ECCPRIVATE_BLOB      L"ECCPRIVATEBLOB"
 #define BCRYPT_RSAPUBLIC_BLOB       L"RSAPUBLICBLOB"
 #define BCRYPT_RSAPRIVATE_BLOB      L"RSAPRIVATEBLOB"
+#define BCRYPT_DSA_PUBLIC_BLOB      L"DSAPUBLICBLOB"
+#define BCRYPT_DSA_PRIVATE_BLOB     L"DSAPRIVATEBLOB"
 
 #define MS_PRIMITIVE_PROVIDER       L"Microsoft Primitive Provider"
 #define MS_PLATFORM_CRYPTO_PROVIDER L"Microsoft Platform Crypto Provider"
 
+#define BCRYPT_3DES_ALGORITHM       L"3DES"
 #define BCRYPT_AES_ALGORITHM        L"AES"
+#define BCRYPT_DES_ALGORITHM        L"DES"
+#define BCRYPT_DSA_ALGORITHM        L"DSA"
+#define BCRYPT_ECDH_P256_ALGORITHM  L"ECDH_P256"
+#define BCRYPT_ECDSA_P256_ALGORITHM L"ECDSA_P256"
+#define BCRYPT_ECDSA_P384_ALGORITHM L"ECDSA_P384"
+#define BCRYPT_ECDSA_P521_ALGORITHM L"ECDSA_P521"
 #define BCRYPT_MD2_ALGORITHM        L"MD2"
 #define BCRYPT_MD4_ALGORITHM        L"MD4"
 #define BCRYPT_MD5_ALGORITHM        L"MD5"
+#define BCRYPT_RC2_ALGORITHM        L"RC2"
+#define BCRYPT_RC4_ALGORITHM        L"RC4"
 #define BCRYPT_RNG_ALGORITHM        L"RNG"
 #define BCRYPT_RSA_ALGORITHM        L"RSA"
 #define BCRYPT_RSA_SIGN_ALGORITHM   L"RSA_SIGN"
@@ -81,10 +92,6 @@ typedef LONG NTSTATUS;
 #define BCRYPT_SHA256_ALGORITHM     L"SHA256"
 #define BCRYPT_SHA384_ALGORITHM     L"SHA384"
 #define BCRYPT_SHA512_ALGORITHM     L"SHA512"
-#define BCRYPT_ECDH_P256_ALGORITHM  L"ECDH_P256"
-#define BCRYPT_ECDSA_P256_ALGORITHM L"ECDSA_P256"
-#define BCRYPT_ECDSA_P384_ALGORITHM L"ECDSA_P384"
-#define BCRYPT_ECDSA_P521_ALGORITHM L"ECDSA_P521"
 
 #define BCRYPT_CHAIN_MODE_NA        L"ChainingModeN/A"
 #define BCRYPT_CHAIN_MODE_CBC       L"ChainingModeCBC"
@@ -124,16 +131,27 @@ static const WCHAR BCRYPT_ECCPUBLIC_BLOB[] = {'E','C','C','P','U','B','L','I','C
 static const WCHAR BCRYPT_ECCPRIVATE_BLOB[] = {'E','C','C','P','R','I','V','A','T','E','B','L','O','B',0};
 static const WCHAR BCRYPT_RSAPUBLIC_BLOB[] = {'R','S','A','P','U','B','L','I','C','B','L','O','B',0};
 static const WCHAR BCRYPT_RSAPRIVATE_BLOB[] = {'R','S','A','P','R','I','V','A','T','E','B','L','O','B',0};
+static const WCHAR BCRYPT_DSA_PUBLIC_BLOB[] = {'D','S','A','P','U','B','L','I','C','B','L','O','B',0};
+static const WCHAR BCRYPT_DSA_PRIVATE_BLOB[] = {'D','S','A','P','R','I','V','A','T','E','B','L','O','B',0};
 
 static const WCHAR MS_PRIMITIVE_PROVIDER[] = \
 {'M','i','c','r','o','s','o','f','t',' ','P','r','i','m','i','t','i','v','e',' ','P','r','o','v','i','d','e','r',0};
 static const WCHAR MS_PLATFORM_CRYPTO_PROVIDER[] = \
 {'M','i','c','r','o','s','o','f','t',' ','P','l','a','t','f','o','r','m',' ','C','r','y','p','t','o',' ','P','r','o','v','i','d','e','r',0};
 
+static const WCHAR BCRYPT_3DES_ALGORITHM[] = {'3','D','E','S',0};
 static const WCHAR BCRYPT_AES_ALGORITHM[] = {'A','E','S',0};
+static const WCHAR BCRYPT_DES_ALGORITHM[] = {'D','E','S',0};
+static const WCHAR BCRYPT_DSA_ALGORITHM[] = {'D','S','A',0};
+static const WCHAR BCRYPT_ECDH_P256_ALGORITHM[] = {'E','C','D','H','_','P','2','5','6',0};
+static const WCHAR BCRYPT_ECDSA_P256_ALGORITHM[] = {'E','C','D','S','A','_','P','2','5','6',0};
+static const WCHAR BCRYPT_ECDSA_P384_ALGORITHM[] = {'E','C','D','S','A','_','P','3','8','4',0};
+static const WCHAR BCRYPT_ECDSA_P521_ALGORITHM[] = {'E','C','D','S','A','_','P','5','2','1',0};
 static const WCHAR BCRYPT_MD2_ALGORITHM[] = {'M','D','2',0};
 static const WCHAR BCRYPT_MD4_ALGORITHM[] = {'M','D','4',0};
 static const WCHAR BCRYPT_MD5_ALGORITHM[] = {'M','D','5',0};
+static const WCHAR BCRYPT_RC2_ALGORITHM[] = {'R','C','2',0};
+static const WCHAR BCRYPT_RC4_ALGORITHM[] = {'R','C','4',0};
 static const WCHAR BCRYPT_RNG_ALGORITHM[] = {'R','N','G',0};
 static const WCHAR BCRYPT_RSA_ALGORITHM[] = {'R','S','A',0};
 static const WCHAR BCRYPT_RSA_SIGN_ALGORITHM[] = {'R','S','A','_','S','I','G','N',0};
@@ -141,10 +159,6 @@ static const WCHAR BCRYPT_SHA1_ALGORITHM[] = {'S','H','A','1',0};
 static const WCHAR BCRYPT_SHA256_ALGORITHM[] = {'S','H','A','2','5','6',0};
 static const WCHAR BCRYPT_SHA384_ALGORITHM[] = {'S','H','A','3','8','4',0};
 static const WCHAR BCRYPT_SHA512_ALGORITHM[] = {'S','H','A','5','1','2',0};
-static const WCHAR BCRYPT_ECDH_P256_ALGORITHM[] = {'E','C','D','H','_','P','2','5','6',0};
-static const WCHAR BCRYPT_ECDSA_P256_ALGORITHM[] = {'E','C','D','S','A','_','P','2','5','6',0};
-static const WCHAR BCRYPT_ECDSA_P384_ALGORITHM[] = {'E','C','D','S','A','_','P','3','8','4',0};
-static const WCHAR BCRYPT_ECDSA_P521_ALGORITHM[] = {'E','C','D','S','A','_','P','5','2','1',0};
 
 static const WCHAR BCRYPT_CHAIN_MODE_NA[] = {'C','h','a','i','n','i','n','g','M','o','d','e','N','/','A',0};
 static const WCHAR BCRYPT_CHAIN_MODE_CBC[] = {'C','h','a','i','n','i','n','g','M','o','d','e','C','B','C',0};
@@ -257,6 +271,45 @@ typedef struct _BCRYPT_PKCS1_PADDING_INFO
 #define BCRYPT_PAD_PSS                      0x00000008
 #define BCRYPT_PAD_PKCS1_OPTIONAL_HASH_OID  0x00000010
 
+#define BCRYPT_DSA_PUBLIC_MAGIC     0x42505344
+#define BCRYPT_DSA_PRIVATE_MAGIC    0x56505344
+
+typedef struct _BCRYPT_DSA_KEY_BLOB
+{
+    ULONG dwMagic;
+    ULONG cbKey;
+    UCHAR Count[4];
+    UCHAR Seed[20];
+    UCHAR q[20];
+} BCRYPT_DSA_KEY_BLOB, *PBCRYPT_DSA_KEY_BLOB;
+
+#define BCRYPT_DSA_PUBLIC_MAGIC_V2  0x32425044
+#define BCRYPT_DSA_PRIVATE_MAGIC_V2 0x32565044
+
+typedef enum
+{
+    DSA_HASH_ALGORITHM_SHA1,
+    DSA_HASH_ALGORITHM_SHA256,
+    DSA_HASH_ALGORITHM_SHA512
+} HASHALGORITHM_ENUM;
+
+typedef enum
+{
+    DSA_FIPS186_2,
+    DSA_FIPS186_3
+} DSAFIPSVERSION_ENUM;
+
+typedef struct _BCRYPT_DSA_KEY_BLOB_V2
+{
+    ULONG               dwMagic;
+    ULONG               cbKey;
+    HASHALGORITHM_ENUM  hashAlgorithm;
+    DSAFIPSVERSION_ENUM standardVersion;
+    ULONG               cbSeedLength;
+    ULONG               cbGroupSize;
+    UCHAR               Count[4];
+} BCRYPT_DSA_KEY_BLOB_V2, *PBCRYPT_DSA_KEY_BLOB_V2;
+
 #define BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION 1
 
 #define BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG 0x00000001
-- 
2.20.1




More information about the wine-devel mailing list