bcrypt: Add support for generating RSA keys.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7c9139dffb
commit
b2bbb6f48f
|
@ -158,6 +158,7 @@ struct key_symmetric
|
||||||
struct key_asymmetric
|
struct key_asymmetric
|
||||||
{
|
{
|
||||||
gnutls_privkey_t handle;
|
gnutls_privkey_t handle;
|
||||||
|
ULONG bitlen; /* ignored for ECC keys */
|
||||||
UCHAR *pubkey;
|
UCHAR *pubkey;
|
||||||
ULONG pubkey_len;
|
ULONG pubkey_len;
|
||||||
};
|
};
|
||||||
|
@ -185,6 +186,7 @@ struct key_symmetric
|
||||||
|
|
||||||
struct key_asymmetric
|
struct key_asymmetric
|
||||||
{
|
{
|
||||||
|
ULONG bitlen;
|
||||||
UCHAR *pubkey;
|
UCHAR *pubkey;
|
||||||
ULONG pubkey_len;
|
ULONG pubkey_len;
|
||||||
};
|
};
|
||||||
|
@ -225,7 +227,7 @@ NTSTATUS key_symmetric_set_auth_data( struct key *, UCHAR *, ULONG ) DECLSPEC_HI
|
||||||
NTSTATUS key_symmetric_encrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
NTSTATUS key_symmetric_encrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS key_symmetric_decrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
NTSTATUS key_symmetric_decrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS key_symmetric_get_tag( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
NTSTATUS key_symmetric_get_tag( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS key_asymmetric_init( struct key *, struct algorithm *, const UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
NTSTATUS key_asymmetric_init( struct key *, struct algorithm *, ULONG, const UCHAR *, ULONG ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS key_asymmetric_generate( struct key * ) DECLSPEC_HIDDEN;
|
NTSTATUS key_asymmetric_generate( struct key * ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS key_asymmetric_verify( struct key *, void *, UCHAR *, ULONG, UCHAR *, ULONG, DWORD ) DECLSPEC_HIDDEN;
|
NTSTATUS key_asymmetric_verify( struct key *, void *, UCHAR *, ULONG, UCHAR *, ULONG, DWORD ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS key_destroy( struct key * ) DECLSPEC_HIDDEN;
|
NTSTATUS key_destroy( struct key * ) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -854,6 +854,14 @@ 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 );
|
memcpy( output + sizeof(len), key->u.s.secret, key->u.s.secret_len );
|
||||||
return STATUS_SUCCESS;
|
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_ECCPUBLIC_BLOB ))
|
||||||
{
|
{
|
||||||
*size = key->u.a.pubkey_len;
|
*size = key->u.a.pubkey_len;
|
||||||
|
@ -1059,7 +1067,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
|
||||||
if (!strcmpW( type, BCRYPT_ECCPUBLIC_BLOB ))
|
if (!strcmpW( type, BCRYPT_ECCPUBLIC_BLOB ))
|
||||||
{
|
{
|
||||||
BCRYPT_ECCKEY_BLOB *ecc_blob = (BCRYPT_ECCKEY_BLOB *)input;
|
BCRYPT_ECCKEY_BLOB *ecc_blob = (BCRYPT_ECCKEY_BLOB *)input;
|
||||||
DWORD key_size, magic;
|
DWORD key_size, magic, size;
|
||||||
|
|
||||||
if (input_len < sizeof(*ecc_blob)) return STATUS_INVALID_PARAMETER;
|
if (input_len < sizeof(*ecc_blob)) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
@ -1091,7 +1099,9 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
|
||||||
|
|
||||||
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
|
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
|
||||||
key->hdr.magic = MAGIC_KEY;
|
key->hdr.magic = MAGIC_KEY;
|
||||||
if ((status = key_asymmetric_init( key, alg, (BYTE *)ecc_blob, sizeof(*ecc_blob) + ecc_blob->cbKey * 2 )))
|
|
||||||
|
size = sizeof(*ecc_blob) + ecc_blob->cbKey * 2;
|
||||||
|
if ((status = key_asymmetric_init( key, alg, key_size * 8, (BYTE *)ecc_blob, size )))
|
||||||
{
|
{
|
||||||
heap_free( key );
|
heap_free( key );
|
||||||
return status;
|
return status;
|
||||||
|
@ -1125,7 +1135,8 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
|
||||||
|
|
||||||
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
|
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
|
||||||
key->hdr.magic = MAGIC_KEY;
|
key->hdr.magic = MAGIC_KEY;
|
||||||
if ((status = key_asymmetric_init( key, alg, NULL, 0 )))
|
|
||||||
|
if ((status = key_asymmetric_init( key, alg, key_size * 8, NULL, 0 )))
|
||||||
{
|
{
|
||||||
heap_free( key );
|
heap_free( key );
|
||||||
return status;
|
return status;
|
||||||
|
@ -1151,7 +1162,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
|
||||||
key->hdr.magic = MAGIC_KEY;
|
key->hdr.magic = MAGIC_KEY;
|
||||||
|
|
||||||
size = sizeof(*rsa_blob) + rsa_blob->cbPublicExp + rsa_blob->cbModulus;
|
size = sizeof(*rsa_blob) + rsa_blob->cbPublicExp + rsa_blob->cbModulus;
|
||||||
if ((status = key_asymmetric_init( key, alg, (BYTE *)rsa_blob, size )))
|
if ((status = key_asymmetric_init( key, alg, rsa_blob->BitLength, (BYTE *)rsa_blob, size )))
|
||||||
{
|
{
|
||||||
heap_free( key );
|
heap_free( key );
|
||||||
return status;
|
return status;
|
||||||
|
@ -1189,7 +1200,8 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
|
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, ULONG bitlen, const UCHAR *pubkey,
|
||||||
|
ULONG pubkey_len )
|
||||||
{
|
{
|
||||||
ERR( "support for keys not available at build time\n" );
|
ERR( "support for keys not available at build time\n" );
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
@ -1302,7 +1314,7 @@ NTSTATUS WINAPI BCryptGenerateKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_H
|
||||||
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
|
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
|
||||||
key->hdr.magic = MAGIC_KEY;
|
key->hdr.magic = MAGIC_KEY;
|
||||||
|
|
||||||
if ((status = key_asymmetric_init( key, alg, NULL, 0 )))
|
if ((status = key_asymmetric_init( key, alg, key_len, NULL, 0 )))
|
||||||
{
|
{
|
||||||
heap_free( key );
|
heap_free( key );
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -81,6 +81,9 @@ static int (*pgnutls_pubkey_import_rsa_raw)(gnutls_pubkey_t key, const gnutls_da
|
||||||
/* Not present in gnutls version < 3.3.0 */
|
/* Not present in gnutls version < 3.3.0 */
|
||||||
static int (*pgnutls_privkey_export_ecc_raw)(gnutls_privkey_t, gnutls_ecc_curve_t *,
|
static int (*pgnutls_privkey_export_ecc_raw)(gnutls_privkey_t, gnutls_ecc_curve_t *,
|
||||||
gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *);
|
gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *);
|
||||||
|
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_generate)(gnutls_privkey_t, gnutls_pk_algorithm_t, unsigned int, unsigned int);
|
static int (*pgnutls_privkey_generate)(gnutls_privkey_t, gnutls_pk_algorithm_t, unsigned int, unsigned int);
|
||||||
|
|
||||||
static void *libgnutls_handle;
|
static void *libgnutls_handle;
|
||||||
|
@ -116,6 +119,13 @@ static int compat_gnutls_pubkey_import_ecc_raw(gnutls_pubkey_t key, gnutls_ecc_c
|
||||||
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
|
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int compat_gnutls_privkey_export_rsa_raw(gnutls_privkey_t key, gnutls_datum_t *m, gnutls_datum_t *e,
|
||||||
|
gnutls_datum_t *d, gnutls_datum_t *p, gnutls_datum_t *q,
|
||||||
|
gnutls_datum_t *u, gnutls_datum_t *e1, gnutls_datum_t *e2)
|
||||||
|
{
|
||||||
|
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
|
||||||
|
}
|
||||||
|
|
||||||
static int compat_gnutls_privkey_export_ecc_raw(gnutls_privkey_t key, gnutls_ecc_curve_t *curve,
|
static int compat_gnutls_privkey_export_ecc_raw(gnutls_privkey_t key, gnutls_ecc_curve_t *curve,
|
||||||
gnutls_datum_t *x, gnutls_datum_t *y, gnutls_datum_t *k)
|
gnutls_datum_t *x, gnutls_datum_t *y, gnutls_datum_t *k)
|
||||||
{
|
{
|
||||||
|
@ -210,6 +220,11 @@ BOOL gnutls_initialize(void)
|
||||||
WARN("gnutls_pubkey_import_ecc_raw not found\n");
|
WARN("gnutls_pubkey_import_ecc_raw not found\n");
|
||||||
pgnutls_pubkey_import_ecc_raw = compat_gnutls_pubkey_import_ecc_raw;
|
pgnutls_pubkey_import_ecc_raw = compat_gnutls_pubkey_import_ecc_raw;
|
||||||
}
|
}
|
||||||
|
if (!(pgnutls_privkey_export_rsa_raw = wine_dlsym( libgnutls_handle, "gnutls_privkey_export_rsa_raw", NULL, 0 )))
|
||||||
|
{
|
||||||
|
WARN("gnutls_privkey_export_rsa_raw not found\n");
|
||||||
|
pgnutls_privkey_export_rsa_raw = compat_gnutls_privkey_export_rsa_raw;
|
||||||
|
}
|
||||||
if (!(pgnutls_privkey_export_ecc_raw = wine_dlsym( libgnutls_handle, "gnutls_privkey_export_ecc_raw", NULL, 0 )))
|
if (!(pgnutls_privkey_export_ecc_raw = wine_dlsym( libgnutls_handle, "gnutls_privkey_export_ecc_raw", NULL, 0 )))
|
||||||
{
|
{
|
||||||
WARN("gnutls_privkey_export_ecc_raw not found\n");
|
WARN("gnutls_privkey_export_ecc_raw not found\n");
|
||||||
|
@ -535,6 +550,58 @@ NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS export_gnutls_pubkey_rsa( gnutls_privkey_t gnutls_key, ULONG bitlen, UCHAR **pubkey, ULONG *pubkey_len )
|
||||||
|
{
|
||||||
|
BCRYPT_RSAKEY_BLOB *rsa_blob;
|
||||||
|
gnutls_datum_t m, e;
|
||||||
|
UCHAR *dst, *src;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = pgnutls_privkey_export_rsa_raw( gnutls_key, &m, &e, NULL, NULL, NULL, NULL, NULL, NULL )))
|
||||||
|
{
|
||||||
|
pgnutls_perror( ret );
|
||||||
|
return STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(rsa_blob = heap_alloc( sizeof(*rsa_blob) + e.size + m.size )))
|
||||||
|
{
|
||||||
|
pgnutls_perror( ret );
|
||||||
|
free( e.data ); free( m.data );
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = (UCHAR *)(rsa_blob + 1);
|
||||||
|
if (e.size == bitlen / 8 + 1 && !e.data[0])
|
||||||
|
{
|
||||||
|
src = e.data + 1;
|
||||||
|
e.size--;
|
||||||
|
}
|
||||||
|
else src = e.data;
|
||||||
|
memcpy( dst, src, e.size );
|
||||||
|
|
||||||
|
dst += e.size;
|
||||||
|
if (m.size == bitlen / 8 + 1 && !m.data[0])
|
||||||
|
{
|
||||||
|
src = m.data + 1;
|
||||||
|
m.size--;
|
||||||
|
}
|
||||||
|
else src = m.data;
|
||||||
|
memcpy( dst, src, m.size );
|
||||||
|
|
||||||
|
rsa_blob->Magic = BCRYPT_RSAPUBLIC_MAGIC;
|
||||||
|
rsa_blob->BitLength = bitlen;
|
||||||
|
rsa_blob->cbPublicExp = e.size;
|
||||||
|
rsa_blob->cbModulus = m.size;
|
||||||
|
rsa_blob->cbPrime1 = 0;
|
||||||
|
rsa_blob->cbPrime2 = 0;
|
||||||
|
|
||||||
|
*pubkey = (UCHAR *)rsa_blob;
|
||||||
|
*pubkey_len = sizeof(*rsa_blob) + e.size + m.size;
|
||||||
|
|
||||||
|
free( e.data ); free( m.data );
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, UCHAR **pubkey, ULONG *pubkey_len )
|
static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, UCHAR **pubkey, ULONG *pubkey_len )
|
||||||
{
|
{
|
||||||
BCRYPT_ECCKEY_BLOB *ecc_blob;
|
BCRYPT_ECCKEY_BLOB *ecc_blob;
|
||||||
|
@ -593,8 +660,8 @@ static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, UCHAR **p
|
||||||
NTSTATUS key_asymmetric_generate( struct key *key )
|
NTSTATUS key_asymmetric_generate( struct key *key )
|
||||||
{
|
{
|
||||||
gnutls_pk_algorithm_t pk_alg;
|
gnutls_pk_algorithm_t pk_alg;
|
||||||
gnutls_ecc_curve_t curve;
|
|
||||||
gnutls_privkey_t handle;
|
gnutls_privkey_t handle;
|
||||||
|
unsigned int bitlen;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -602,9 +669,14 @@ NTSTATUS key_asymmetric_generate( struct key *key )
|
||||||
|
|
||||||
switch (key->alg_id)
|
switch (key->alg_id)
|
||||||
{
|
{
|
||||||
|
case ALG_ID_RSA:
|
||||||
|
pk_alg = GNUTLS_PK_RSA;
|
||||||
|
bitlen = key->u.a.bitlen;
|
||||||
|
break;
|
||||||
|
|
||||||
case ALG_ID_ECDH_P256:
|
case ALG_ID_ECDH_P256:
|
||||||
pk_alg = GNUTLS_PK_ECC; /* compatible with ECDSA and ECDH */
|
pk_alg = GNUTLS_PK_ECC; /* compatible with ECDSA and ECDH */
|
||||||
curve = GNUTLS_ECC_CURVE_SECP256R1;
|
bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP256R1 );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -618,14 +690,29 @@ NTSTATUS key_asymmetric_generate( struct key *key )
|
||||||
return STATUS_INTERNAL_ERROR;
|
return STATUS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = pgnutls_privkey_generate( handle, pk_alg, GNUTLS_CURVE_TO_BITS(curve), 0 )))
|
if ((ret = pgnutls_privkey_generate( handle, pk_alg, bitlen, 0 )))
|
||||||
{
|
{
|
||||||
pgnutls_perror( ret );
|
pgnutls_perror( ret );
|
||||||
pgnutls_privkey_deinit( handle );
|
pgnutls_privkey_deinit( handle );
|
||||||
return STATUS_INTERNAL_ERROR;
|
return STATUS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status = export_gnutls_pubkey_ecc( handle, &key->u.a.pubkey, &key->u.a.pubkey_len )))
|
switch (pk_alg)
|
||||||
|
{
|
||||||
|
case GNUTLS_PK_RSA:
|
||||||
|
status = export_gnutls_pubkey_rsa( handle, key->u.a.bitlen, &key->u.a.pubkey, &key->u.a.pubkey_len );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GNUTLS_PK_ECC:
|
||||||
|
status = export_gnutls_pubkey_ecc( handle, &key->u.a.pubkey, &key->u.a.pubkey_len );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ERR( "unhandled algorithm %u\n", pk_alg );
|
||||||
|
return STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status)
|
||||||
{
|
{
|
||||||
pgnutls_privkey_deinit( handle );
|
pgnutls_privkey_deinit( handle );
|
||||||
return status;
|
return status;
|
||||||
|
@ -741,7 +828,8 @@ NTSTATUS key_import_ecc( struct key *key, UCHAR *buf, ULONG len )
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
|
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, ULONG bitlen, const UCHAR *pubkey,
|
||||||
|
ULONG pubkey_len )
|
||||||
{
|
{
|
||||||
if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
|
if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
|
||||||
|
|
||||||
|
@ -764,7 +852,8 @@ NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHA
|
||||||
memcpy( key->u.a.pubkey, pubkey, pubkey_len );
|
memcpy( key->u.a.pubkey, pubkey, pubkey_len );
|
||||||
key->u.a.pubkey_len = pubkey_len;
|
key->u.a.pubkey_len = pubkey_len;
|
||||||
}
|
}
|
||||||
key->alg_id = alg->id;
|
key->alg_id = alg->id;
|
||||||
|
key->u.a.bitlen = bitlen;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,8 @@ NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
|
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, ULONG bitlen, const UCHAR *pubkey,
|
||||||
|
ULONG pubkey_len )
|
||||||
{
|
{
|
||||||
FIXME( "not implemented on Mac\n" );
|
FIXME( "not implemented on Mac\n" );
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
|
Loading…
Reference in New Issue