Module: wine Branch: master Commit: 5308911a82e5858f419354bcc6d9e35807134bc4 URL: https://gitlab.winehq.org/wine/wine/-/commit/5308911a82e5858f419354bcc6d9e35...
Author: Hans Leidekker hans@codeweavers.com Date: Thu Nov 17 11:43:56 2022 +0100
bcrypt: Support duplicating public keys without access to the private key.
---
dlls/bcrypt/gnutls.c | 99 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 15 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index aeef64fd642..d5ffe88e2b4 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -1877,17 +1877,11 @@ static NTSTATUS key_asymmetric_destroy( void *args ) return STATUS_SUCCESS; }
-static NTSTATUS key_asymmetric_duplicate( void *args ) +static NTSTATUS dup_privkey( struct key *key_orig, struct key *key_copy ) { - const struct key_asymmetric_duplicate_params *params = args; - struct key *key_orig = params->key_orig; - struct key *key_copy = params->key_copy; gnutls_privkey_t privkey; - gnutls_pubkey_t pubkey; int ret;
- if (!key_data(key_orig)->a.privkey) return STATUS_SUCCESS; - if ((ret = pgnutls_privkey_init( &privkey ))) { pgnutls_perror( ret ); @@ -1959,25 +1953,100 @@ static NTSTATUS key_asymmetric_duplicate( void *args ) return STATUS_INTERNAL_ERROR; }
- if (key_data(key_orig)->a.pubkey) + key_data(key_copy)->a.privkey = privkey; + return STATUS_SUCCESS; +} + +static NTSTATUS dup_pubkey( struct key *key_orig, struct key *key_copy ) +{ + gnutls_pubkey_t pubkey; + int ret; + + if ((ret = pgnutls_pubkey_init( &pubkey ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + switch (key_orig->alg_id) { - if ((ret = pgnutls_pubkey_init( &pubkey ))) + case ALG_ID_RSA: + case ALG_ID_RSA_SIGN: + { + gnutls_datum_t m, e; + if ((ret = pgnutls_pubkey_export_rsa_raw( key_data(key_orig)->a.pubkey, &m, &e ))) { pgnutls_perror( ret ); - pgnutls_privkey_deinit( privkey ); return STATUS_INTERNAL_ERROR; } - if ((ret = pgnutls_pubkey_import_privkey( pubkey, key_data(key_orig)->a.privkey, 0, 0 ))) + ret = pgnutls_pubkey_import_rsa_raw( pubkey, &m, &e ); + free( m.data ); free( e.data ); + if (ret) { pgnutls_perror( ret ); - pgnutls_pubkey_deinit( pubkey ); - pgnutls_privkey_deinit( privkey ); return STATUS_INTERNAL_ERROR; } - key_data(key_copy)->a.pubkey = pubkey; + break; + } + case ALG_ID_DSA: + { + gnutls_datum_t p, q, g, y; + if ((ret = pgnutls_pubkey_export_dsa_raw( key_data(key_orig)->a.pubkey, &p, &q, &g, &y ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + ret = pgnutls_pubkey_import_dsa_raw( pubkey, &p, &q, &g, &y ); + free( p.data ); free( q.data ); free( g.data ); free( y.data ); + if (ret) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + key_copy->u.a.dss_seed = key_orig->u.a.dss_seed; + break; + } + case ALG_ID_ECDH_P256: + case ALG_ID_ECDH_P384: + case ALG_ID_ECDSA_P256: + case ALG_ID_ECDSA_P384: + { + gnutls_ecc_curve_t curve; + gnutls_datum_t x, y; + if ((ret = pgnutls_pubkey_export_ecc_raw( key_data(key_orig)->a.pubkey, &curve, &x, &y ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + ret = pgnutls_pubkey_import_ecc_raw( pubkey, curve, &x, &y ); + free( x.data ); free( y.data ); + if (ret) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + break; + } + default: + ERR( "unhandled algorithm %u\n", key_orig->alg_id ); + return STATUS_INTERNAL_ERROR; }
- key_data(key_copy)->a.privkey = privkey; + key_data(key_copy)->a.pubkey = pubkey; + return STATUS_SUCCESS; +} + +static NTSTATUS key_asymmetric_duplicate( void *args ) +{ + const struct key_asymmetric_duplicate_params *params = args; + NTSTATUS status; + + if (key_data(params->key_orig)->a.privkey && (status = dup_privkey( params->key_orig, params->key_copy ))) + return status; + + if (key_data(params->key_orig)->a.pubkey && (status = dup_pubkey( params->key_orig, params->key_copy ))) + return status; + return STATUS_SUCCESS; }