Signed-off-by: Hans Leidekker hans@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;