Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/bcrypt/bcrypt_internal.h | 6 ++
dlls/bcrypt/bcrypt_main.c | 47 ++++++++++++++
dlls/bcrypt/gnutls.c | 112 ++++++++++++++++++++++++++++++++++
dlls/bcrypt/tests/bcrypt.c | 36 +++++++++++
include/bcrypt.h | 12 ++++
5 files changed, 213 insertions(+)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index 2c834bec48..18343a6c74 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -32,8 +32,11 @@
#include "windef.h"
#include "winbase.h"
+#include "wincrypt.h"
#include "bcrypt.h"
+#define MAGIC_DSS2 ('D' | ('S' << 8) | ('S' << 16) | ('2' << 24))
+
typedef struct
{
ULONG64 len;
@@ -176,6 +179,7 @@ struct key_asymmetric
ULONG bitlen; /* ignored for ECC keys */
UCHAR *pubkey;
ULONG pubkey_len;
+ DSSSEED dss_seed;
};
struct key
@@ -250,7 +254,9 @@ NTSTATUS key_asymmetric_sign( struct key *, void *, UCHAR *, ULONG, UCHAR *, ULO
NTSTATUS key_asymmetric_verify( struct key *, void *, UCHAR *, ULONG, UCHAR *, ULONG, DWORD ) DECLSPEC_HIDDEN;
NTSTATUS key_destroy( struct key * ) DECLSPEC_HIDDEN;
BOOL key_is_symmetric( struct key * ) DECLSPEC_HIDDEN;
+NTSTATUS key_export_dsa_capi( struct key *, UCHAR *, ULONG, ULONG * ) DECLSPEC_HIDDEN;
NTSTATUS key_export_ecc( struct key *, UCHAR *, ULONG, ULONG * ) DECLSPEC_HIDDEN;
+NTSTATUS key_import_dsa_capi( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_import_ecc( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
BOOL is_zero_vector( const UCHAR *, ULONG ) DECLSPEC_HIDDEN;
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index 5492c1947e..fee40ebe8d 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -31,6 +31,7 @@
#include "windef.h"
#include "winbase.h"
#include "ntsecapi.h"
+#include "wincrypt.h"
#include "bcrypt.h"
#include "bcrypt_internal.h"
@@ -948,6 +949,10 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U
{
return key_export_ecc( key, output, output_len, size );
}
+ else if (!strcmpW( type, LEGACY_DSA_V2_PRIVATE_BLOB ))
+ {
+ return key_export_dsa_capi( key, output, output_len, size );
+ }
FIXME( "unsupported key type %s\n", debugstr_w(type) );
return STATUS_NOT_IMPLEMENTED;
@@ -1267,6 +1272,48 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
*ret_key = key;
return STATUS_SUCCESS;
}
+ else if (!strcmpW( type, LEGACY_DSA_V2_PRIVATE_BLOB ))
+ {
+ BLOBHEADER *hdr = (BLOBHEADER *)input;
+ DSSPUBKEY *pubkey;
+
+ if (input_len < sizeof(*hdr)) return STATUS_INVALID_PARAMETER;
+
+ if (hdr->bType != PRIVATEKEYBLOB && hdr->bVersion != 2 && hdr->aiKeyAlg != CALG_DSS_SIGN)
+ {
+ FIXME( "blob type %u version %u alg id %u not supported\n", hdr->bType, hdr->bVersion, hdr->aiKeyAlg );
+ return STATUS_NOT_SUPPORTED;
+ }
+ if (alg->id != ALG_ID_DSA)
+ {
+ FIXME( "algorithm %u does not support importing blob of type %s\n", alg->id, debugstr_w(type) );
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ if (input_len < sizeof(*hdr) + sizeof(*pubkey)) return STATUS_INVALID_PARAMETER;
+ pubkey = (DSSPUBKEY *)(hdr + 1);
+ if (pubkey->magic != MAGIC_DSS2) return STATUS_NOT_SUPPORTED;
+
+ if (input_len < sizeof(*hdr) + sizeof(*pubkey) + (pubkey->bitlen / 8) * 2 + 40 + sizeof(DSSSEED))
+ return STATUS_INVALID_PARAMETER;
+
+ if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
+ key->hdr.magic = MAGIC_KEY;
+
+ if ((status = key_asymmetric_init( key, alg, pubkey->bitlen, NULL, 0 )))
+ {
+ heap_free( key );
+ return status;
+ }
+ if ((status = key_import_dsa_capi( key, input, input_len )))
+ {
+ 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 d4ad327bc4..d447e90a11 100644
--- a/dlls/bcrypt/gnutls.c
+++ b/dlls/bcrypt/gnutls.c
@@ -33,6 +33,7 @@
#include "windef.h"
#include "winbase.h"
#include "ntsecapi.h"
+#include "wincrypt.h"
#include "bcrypt.h"
#include "bcrypt_internal.h"
@@ -106,6 +107,7 @@ MAKE_FUNCPTR(gnutls_global_set_log_function);
MAKE_FUNCPTR(gnutls_global_set_log_level);
MAKE_FUNCPTR(gnutls_perror);
MAKE_FUNCPTR(gnutls_privkey_deinit);
+MAKE_FUNCPTR(gnutls_privkey_import_dsa_raw);
MAKE_FUNCPTR(gnutls_privkey_init);
MAKE_FUNCPTR(gnutls_privkey_sign_hash);
MAKE_FUNCPTR(gnutls_pubkey_deinit);
@@ -220,6 +222,7 @@ BOOL gnutls_initialize(void)
LOAD_FUNCPTR(gnutls_global_set_log_level)
LOAD_FUNCPTR(gnutls_perror)
LOAD_FUNCPTR(gnutls_privkey_deinit);
+ LOAD_FUNCPTR(gnutls_privkey_import_dsa_raw);
LOAD_FUNCPTR(gnutls_privkey_init);
LOAD_FUNCPTR(gnutls_privkey_sign_hash);
LOAD_FUNCPTR(gnutls_pubkey_deinit);
@@ -988,6 +991,115 @@ NTSTATUS key_import_ecc( struct key *key, UCHAR *buf, ULONG len )
return STATUS_SUCCESS;
}
+NTSTATUS key_export_dsa_capi( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len )
+{
+ BLOBHEADER *hdr;
+ DSSPUBKEY *pubkey;
+ gnutls_datum_t p, q, g, y, x;
+ UCHAR *src, *dst;
+ int ret, size;
+
+ if ((ret = pgnutls_privkey_export_dsa_raw( key->u.a.handle, &p, &q, &g, &y, &x )))
+ {
+ pgnutls_perror( ret );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ if ((q.size != 20 && q.size != 21) || (x.size != 20 && x.size != 21))
+ {
+ ERR( "can't export key in this format\n" );
+ free( p.data ); free( q.data ); free( g.data ); free( y.data ); free( x.data );
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ size = key->u.a.bitlen / 8;
+ *ret_len = sizeof(*hdr) + sizeof(*pubkey) + size * 2 + 40 + sizeof(key->u.a.dss_seed);
+ if (len >= *ret_len && buf)
+ {
+ hdr = (BLOBHEADER *)buf;
+ hdr->bType = PRIVATEKEYBLOB;
+ hdr->bVersion = 2;
+ hdr->reserved = 0;
+ hdr->aiKeyAlg = CALG_DSS_SIGN;
+
+ pubkey = (DSSPUBKEY *)(hdr + 1);
+ pubkey->magic = MAGIC_DSS2;
+ pubkey->bitlen = key->u.a.bitlen;
+
+ dst = (UCHAR *)(pubkey + 1);
+ if (p.size == size + 1) src = p.data + 1;
+ else src = p.data;
+ memcpy( dst, src, size );
+
+ dst += size;
+ if (q.size == 21) src = q.data + 1;
+ else src = q.data;
+ memcpy( dst, src, 20 );
+
+ dst += 20;
+ if (g.size == size + 1) src = g.data + 1;
+ else src = g.data;
+ memcpy( dst, src, size );
+
+ dst += size;
+ if (x.size == 21) src = x.data + 1;
+ else src = x.data;
+ memcpy( dst, src, 20 );
+
+ dst += 20;
+ memcpy( dst, &key->u.a.dss_seed, sizeof(key->u.a.dss_seed) );
+ }
+
+ free( p.data ); free( q.data ); free( g.data ); free( y.data ); free( x.data );
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS key_import_dsa_capi( struct key *key, UCHAR *buf, ULONG len )
+{
+ BLOBHEADER *hdr = (BLOBHEADER *)buf;
+ DSSPUBKEY *pubkey;
+ gnutls_privkey_t handle;
+ gnutls_datum_t p, q, g, y, x;
+ unsigned char dummy[128];
+ int ret, size;
+
+ if ((ret = pgnutls_privkey_init( &handle )))
+ {
+ pgnutls_perror( ret );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ hdr = (BLOBHEADER *)buf;
+ pubkey = (DSSPUBKEY *)(hdr + 1);
+ size = pubkey->bitlen / 8;
+
+ p.data = (unsigned char *)(pubkey + 1);
+ p.size = size;
+ q.data = p.data + size;
+ q.size = 20;
+ g.data = q.data + 20;
+ g.size = size;
+ x.data = g.data + size;
+ x.size = 20;
+
+ WARN( "using dummy public key\n" );
+ memset( dummy, 1, sizeof(dummy) );
+ y.data = dummy;
+ y.size = min( p.size, sizeof(dummy) );
+
+ if ((ret = pgnutls_privkey_import_dsa_raw( handle, &p, &q, &g, &y, &x )))
+ {
+ pgnutls_perror( ret );
+ pgnutls_privkey_deinit( handle );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ memcpy( &key->u.a.dss_seed, x.data + x.size, sizeof(key->u.a.dss_seed) );
+
+ key->u.a.handle = handle;
+ return STATUS_SUCCESS;
+}
+
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, ULONG bitlen, const UCHAR *pubkey,
ULONG pubkey_len )
{
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index a67b14f4e4..e4a99d6304 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -2450,6 +2450,27 @@ static UCHAR dsaPublicBlob[] =
0x24,0xce,0x85,0xb9
};
+static UCHAR dssKey[] =
+{
+ 0x07,0x02,0x00,0x00,0x00,0x22,0x00,0x00,0x44,0x53,0x53,0x32,0x00,0x04,0x00,0x00,0x01,0xd1,0xfc,0x7a,
+ 0x70,0x53,0xb2,0x48,0x70,0x23,0x19,0x1f,0x3c,0xe1,0x26,0x14,0x7e,0x9f,0x0f,0x7f,0x33,0x5e,0x2b,0xf7,
+ 0xca,0x01,0x74,0x8c,0xb4,0xfd,0xf6,0x44,0x95,0x35,0x56,0xaa,0x4d,0x62,0x48,0xe2,0xd1,0xa2,0x7e,0x6e,
+ 0xeb,0xd6,0xcc,0x7c,0xe8,0xfd,0x21,0x9a,0xa2,0xfd,0x7a,0x9d,0x1a,0x38,0x69,0x87,0x39,0x5a,0x91,0xc0,
+ 0x52,0x2b,0x9f,0x2a,0x54,0x78,0x37,0x82,0x9a,0x70,0x57,0xab,0xec,0x93,0x8e,0xac,0x73,0x04,0xe8,0x53,
+ 0x72,0x72,0x32,0xc6,0xcb,0xef,0x47,0x98,0x3c,0x56,0x49,0x62,0xcb,0xbb,0xe7,0x34,0x84,0xa6,0x72,0x3a,
+ 0xbe,0x26,0x46,0x86,0xca,0xcb,0x35,0x62,0x4f,0x19,0x18,0x0b,0xb0,0x78,0xae,0xd5,0x42,0xdf,0x26,0xdb,
+ 0x85,0x63,0x77,0x85,0x01,0x3b,0x32,0xbe,0x5c,0xf8,0x05,0xc8,0xde,0x17,0x7f,0xb9,0x03,0x82,0xfa,0xf1,
+ 0x9e,0x32,0x73,0xfa,0x8d,0xea,0xa3,0x30,0x48,0xe2,0xdf,0x5a,0xcb,0x83,0x3d,0xff,0x56,0xe9,0xc0,0x94,
+ 0xf8,0x6d,0xb3,0xaf,0x4a,0x97,0xb9,0x43,0x0e,0xd4,0x28,0x98,0x57,0x2e,0x3a,0xca,0xde,0x6f,0x45,0x0d,
+ 0xfb,0x58,0xec,0x78,0x34,0x2e,0x46,0x4d,0xfe,0x98,0x02,0xbb,0xef,0x07,0x1a,0x13,0xb6,0xc2,0x2c,0x06,
+ 0xd9,0x0c,0xc4,0xb0,0x4c,0x3a,0xfc,0x01,0x63,0xb5,0x5a,0x5d,0x2d,0x9c,0x47,0x04,0x67,0x51,0xf2,0x52,
+ 0xf5,0x82,0x36,0xeb,0x6e,0x66,0x58,0x4c,0x10,0x2c,0x29,0x72,0x4a,0x6f,0x6b,0x6c,0xe0,0x93,0x31,0x42,
+ 0xf6,0xda,0xfa,0x5b,0x22,0x43,0x9b,0x1a,0x98,0x71,0xe7,0x41,0x74,0xe9,0x12,0xa4,0x1f,0x27,0x0a,0x63,
+ 0x94,0x49,0xd7,0xad,0xa5,0xc4,0x5c,0xc3,0xc9,0x70,0xb3,0x7b,0x16,0xb6,0x1d,0xd4,0x09,0xc4,0x9a,0x46,
+ 0x2d,0x0e,0x75,0x07,0x31,0x7b,0xed,0x45,0xcd,0x99,0x84,0x14,0xf1,0x01,0x00,0x00,0x93,0xd5,0xa3,0xe4,
+ 0x34,0x05,0xeb,0x98,0x3b,0x5f,0x2f,0x11,0xa4,0xa5,0xc4,0xff,0xfb,0x22,0x7c,0x54
+};
+
static void test_DSA(void)
{
BCRYPT_ALG_HANDLE alg;
@@ -2513,6 +2534,21 @@ static void test_DSA(void)
ret = pBCryptDestroyKey(key);
ok(!ret, "got %08x\n", ret);
+ ret = pBCryptImportKeyPair(alg, NULL, LEGACY_DSA_V2_PRIVATE_BLOB, &key, dssKey, sizeof(dssKey), 0);
+ ok(!ret, "got %08x\n", ret);
+
+ size = 0;
+ ret = pBCryptExportKey(key, NULL, LEGACY_DSA_V2_PRIVATE_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, LEGACY_DSA_V2_PRIVATE_BLOB, buf, size, &size, 0);
+ ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+ ok(size == sizeof(dssKey), "got %u expected %u\n", size, sizeof(dssKey));
+ ok(!memcmp(dssKey, buf, size), "wrong data\n");
+ HeapFree(GetProcessHeap(), 0, buf);
+
ret = pBCryptCloseAlgorithmProvider(alg, 0);
ok(!ret, "got %08x\n", ret);
}
diff --git a/include/bcrypt.h b/include/bcrypt.h
index be170a613c..a099f2f4b0 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -68,6 +68,12 @@ typedef LONG NTSTATUS;
#define BCRYPT_RSAPRIVATE_BLOB L"RSAPRIVATEBLOB"
#define BCRYPT_DSA_PUBLIC_BLOB L"DSAPUBLICBLOB"
#define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB"
+#define BCRYPT_PUBLIC_KEY_BLOB L"PUBLICBLOB"
+#define BCRYPT_PRIVATE_KEY_BLOB L"PRIVATEBLOB"
+#define LEGACY_DSA_PUBLIC_BLOB L"CAPIDSAPUBLICBLOB"
+#define LEGACY_DSA_PRIVATE_BLOB L"CAPIDSAPRIVATEBLOB"
+#define LEGACY_DSA_V2_PUBLIC_BLOB L"V2CAPIDSAPUBLICBLOB"
+#define LEGACY_DSA_V2_PRIVATE_BLOB L"V2CAPIDSAPRIVATEBLOB"
#define MS_PRIMITIVE_PROVIDER L"Microsoft Primitive Provider"
#define MS_PLATFORM_CRYPTO_PROVIDER L"Microsoft Platform Crypto Provider"
@@ -133,6 +139,12 @@ static const WCHAR BCRYPT_RSAPUBLIC_BLOB[] = {'R','S','A','P','U','B','L','I','C
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 BCRYPT_PUBLIC_KEY_BLOB[] = {'P','U','B','L','I','C','B','L','O','B',0};
+static const WCHAR BCRYPT_PRIVATE_KEY_BLOB[] = {'P','R','I','V','A','T','E','B','L','O','B',0};
+static const WCHAR LEGACY_DSA_PUBLIC_BLOB[] = {'C','A','P','I','D','S','A','P','U','B','L','I','C','B','L','O','B',0};
+static const WCHAR LEGACY_DSA_PRIVATE_BLOB[] = {'C','A','P','I','D','S','A','P','R','I','V','A','T','E','B','L','O','B',0};
+static const WCHAR LEGACY_DSA_V2_PUBLIC_BLOB[] = {'V','2','C','A','P','I','D','S','A','P','U','B','L','I','C','B','L','O','B',0};
+static const WCHAR LEGACY_DSA_V2_PRIVATE_BLOB[] = {'V','2','C','A','P','I','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};
--
2.20.1