bcrypt: Add support for importing and exporting DSS private keys.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
992a0ae7b9
commit
7cf9a75dfa
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
Loading…
Reference in New Issue