[PATCH 1/2] bcrypt: Add support for generating RSA keys.
Hans Leidekker
hans at codeweavers.com
Mon Sep 23 08:48:51 CDT 2019
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/bcrypt/bcrypt_internal.h | 4 +-
dlls/bcrypt/bcrypt_main.c | 24 ++++++--
dlls/bcrypt/gnutls.c | 101 ++++++++++++++++++++++++++++++++--
dlls/bcrypt/macos.c | 3 +-
4 files changed, 118 insertions(+), 14 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index 943c33d2b2..ee16762593 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -158,6 +158,7 @@ struct key_symmetric
struct key_asymmetric
{
gnutls_privkey_t handle;
+ ULONG bitlen; /* ignored for ECC keys */
UCHAR *pubkey;
ULONG pubkey_len;
};
@@ -185,6 +186,7 @@ struct key_symmetric
struct key_asymmetric
{
+ ULONG bitlen;
UCHAR *pubkey;
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_decrypt( struct key *, const UCHAR *, ULONG, 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_verify( struct key *, void *, UCHAR *, ULONG, UCHAR *, ULONG, DWORD ) DECLSPEC_HIDDEN;
NTSTATUS key_destroy( struct key * ) DECLSPEC_HIDDEN;
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index 79660c1cf1..369e445db0 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -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 );
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 ))
{
*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 ))
{
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;
@@ -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;
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 );
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;
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 );
return status;
@@ -1151,7 +1162,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
key->hdr.magic = MAGIC_KEY;
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 );
return status;
@@ -1189,7 +1200,8 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
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" );
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;
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 );
return status;
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c
index 583a0e47e6..8b2cc8b316 100644
--- a/dlls/bcrypt/gnutls.c
+++ b/dlls/bcrypt/gnutls.c
@@ -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 */
static int (*pgnutls_privkey_export_ecc_raw)(gnutls_privkey_t, gnutls_ecc_curve_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 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;
}
+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,
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");
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 )))
{
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;
}
+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 )
{
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 )
{
gnutls_pk_algorithm_t pk_alg;
- gnutls_ecc_curve_t curve;
gnutls_privkey_t handle;
+ unsigned int bitlen;
NTSTATUS status;
int ret;
@@ -602,9 +669,14 @@ NTSTATUS key_asymmetric_generate( struct key *key )
switch (key->alg_id)
{
+ case ALG_ID_RSA:
+ pk_alg = GNUTLS_PK_RSA;
+ bitlen = key->u.a.bitlen;
+ break;
+
case ALG_ID_ECDH_P256:
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;
default:
@@ -618,14 +690,29 @@ NTSTATUS key_asymmetric_generate( struct key *key )
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_privkey_deinit( handle );
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 );
return status;
@@ -741,7 +828,8 @@ NTSTATUS key_import_ecc( struct key *key, UCHAR *buf, ULONG len )
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;
@@ -764,7 +852,8 @@ NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHA
memcpy( key->u.a.pubkey, pubkey, 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;
}
diff --git a/dlls/bcrypt/macos.c b/dlls/bcrypt/macos.c
index df79f3e80d..0dd1066130 100644
--- a/dlls/bcrypt/macos.c
+++ b/dlls/bcrypt/macos.c
@@ -192,7 +192,8 @@ NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
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" );
return STATUS_NOT_IMPLEMENTED;
--
2.20.1
More information about the wine-devel
mailing list