diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index 5cc2c249da8..2c834bec48d 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 63117008800..5492c1947e3 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 2b115665663..d4ad327bc47 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 e64e78546d3..a67b14f4e4f 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 62e6074f59b..be170a613c4 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