This series depends on secret agreement APIs added in GnuTLS 3.8.2.
From: Hans Leidekker hans@codeweavers.com
This series depends on secret agreement APIs added in GnuTLS 3.8.2.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49543 --- dlls/bcrypt/bcrypt_internal.h | 6 ++-- dlls/bcrypt/bcrypt_main.c | 65 +++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 28 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index 10b1cc12e8c..505435c6ac2 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -197,6 +197,8 @@ struct key struct secret { struct object hdr; + struct key *privkey; + struct key *pubkey; };
struct key_symmetric_set_auth_data_params @@ -253,8 +255,8 @@ struct key_asymmetric_encrypt_params
struct key_asymmetric_duplicate_params { - struct key *key_orig; - struct key *key_copy; + struct key *key_orig; + struct key *key_copy; };
struct key_asymmetric_sign_params diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index ebfcbfb7049..b76a36482de 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1996,18 +1996,24 @@ NTSTATUS WINAPI BCryptExportKey( BCRYPT_KEY_HANDLE export_key_handle, BCRYPT_KEY return key_export( key, type, output, output_len, size ); }
-static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy ) +static NTSTATUS key_duplicate( struct key *key_orig, struct key **ret_key ) { - UCHAR *buffer; + struct key_asymmetric_duplicate_params params; + struct key *key_copy; NTSTATUS status; + UCHAR *buffer;
- memset( key_copy, 0, sizeof(*key_copy) ); + if (!(key_copy = calloc( 1, sizeof(*key_copy) ))) return STATUS_NO_MEMORY; key_copy->hdr = key_orig->hdr; key_copy->alg_id = key_orig->alg_id;
if (is_symmetric_key( key_orig )) { - if (!(buffer = malloc( key_orig->u.s.secret_len ))) return STATUS_NO_MEMORY; + if (!(buffer = malloc( key_orig->u.s.secret_len ))) + { + free( key_copy ); + return STATUS_NO_MEMORY; + } memcpy( buffer, key_orig->u.s.secret, key_orig->u.s.secret_len );
key_copy->u.s.mode = key_orig->u.s.mode; @@ -2015,25 +2021,23 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy ) key_copy->u.s.secret = buffer; key_copy->u.s.secret_len = key_orig->u.s.secret_len; InitializeCriticalSection( &key_copy->u.s.cs ); + *ret_key = key_copy; + return STATUS_SUCCESS; } - else - { - struct key_asymmetric_duplicate_params params; - - key_copy->u.a.bitlen = key_orig->u.a.bitlen; - key_copy->u.a.flags = key_orig->u.a.flags; - key_copy->u.a.dss_seed = key_orig->u.a.dss_seed;
- params.key_orig = key_orig; - params.key_copy = key_copy; - if ((status = UNIX_CALL( key_asymmetric_duplicate, ¶ms ))) return status; - } + key_copy->u.a.bitlen = key_orig->u.a.bitlen; + key_copy->u.a.flags = key_orig->u.a.flags; + key_copy->u.a.dss_seed = key_orig->u.a.dss_seed;
- return STATUS_SUCCESS; + params.key_orig = key_orig; + params.key_copy = key_copy; + if (!(status = UNIX_CALL( key_asymmetric_duplicate, ¶ms ))) *ret_key = key_copy; + else free( key_copy ); + return status; }
-NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE *handle_copy, - UCHAR *object, ULONG object_len, ULONG flags ) +NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE *handle_copy, UCHAR *object, + ULONG object_len, ULONG flags ) { struct key *key_orig = get_key_object( handle ); struct key *key_copy; @@ -2044,13 +2048,8 @@ NTSTATUS WINAPI BCryptDuplicateKey( BCRYPT_KEY_HANDLE handle, BCRYPT_KEY_HANDLE
if (!key_orig) return STATUS_INVALID_HANDLE; if (!handle_copy) return STATUS_INVALID_PARAMETER; - if (!(key_copy = malloc( sizeof(*key_copy) ))) return STATUS_NO_MEMORY;
- if ((status = key_duplicate( key_orig, key_copy ))) - { - key_destroy( key_copy ); - return status; - } + if ((status = key_duplicate( key_orig, &key_copy ))) return status;
*handle_copy = key_copy; return STATUS_SUCCESS; @@ -2433,8 +2432,9 @@ NTSTATUS WINAPI BCryptSecretAgreement( BCRYPT_KEY_HANDLE privkey_handle, BCRYPT_ struct key *privkey = get_key_object( privkey_handle ); struct key *pubkey = get_key_object( pubkey_handle ); struct secret *secret; + NTSTATUS status;
- FIXME( "%p, %p, %p, %#lx\n", privkey_handle, pubkey_handle, ret_handle, flags ); + TRACE( "%p, %p, %p, %#lx\n", privkey_handle, pubkey_handle, ret_handle, flags );
if (!privkey || !pubkey) return STATUS_INVALID_HANDLE; if (!is_agreement_key( privkey ) || !is_agreement_key( pubkey )) return STATUS_NOT_SUPPORTED; @@ -2442,6 +2442,17 @@ NTSTATUS WINAPI BCryptSecretAgreement( BCRYPT_KEY_HANDLE privkey_handle, BCRYPT_
if (!(secret = calloc( 1, sizeof(*secret) ))) return STATUS_NO_MEMORY; secret->hdr.magic = MAGIC_SECRET; + if ((status = key_duplicate( privkey, &secret->privkey ))) + { + free( secret ); + return status; + } + if ((status = key_duplicate( pubkey, &secret->pubkey ))) + { + key_destroy( secret->privkey ); + free( secret ); + return status; + }
*ret_handle = secret; return STATUS_SUCCESS; @@ -2451,9 +2462,11 @@ NTSTATUS WINAPI BCryptDestroySecret( BCRYPT_SECRET_HANDLE handle ) { struct secret *secret = get_secret_object( handle );
- FIXME( "%p\n", handle ); + TRACE( "%p\n", handle );
if (!secret) return STATUS_INVALID_HANDLE; + key_destroy( secret->privkey ); + key_destroy( secret->pubkey ); destroy_object( &secret->hdr ); return STATUS_SUCCESS; }
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_internal.h | 10 +++ dlls/bcrypt/bcrypt_main.c | 140 +++++++++++++++++++++++++++++----- dlls/bcrypt/gnutls.c | 71 ++++++++++++++++- 3 files changed, 201 insertions(+), 20 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index 505435c6ac2..2f66060ec8e 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -302,6 +302,15 @@ struct key_asymmetric_import_params ULONG len; };
+struct key_asymmetric_derive_key_params +{ + struct key *privkey; + struct key *pubkey; + UCHAR *output; + ULONG output_len; + ULONG *ret_len; +}; + enum key_funcs { unix_process_attach, @@ -321,6 +330,7 @@ enum key_funcs unix_key_asymmetric_destroy, unix_key_asymmetric_export, unix_key_asymmetric_import, + unix_key_asymmetric_derive_key, unix_funcs_count, };
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index b76a36482de..94e91fdc46a 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -17,6 +17,7 @@ * */
+#include <assert.h> #include <stdarg.h> #include <stdlib.h>
@@ -1134,24 +1135,13 @@ NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULON return hash_finalize( hash, output ); }
-NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE handle, UCHAR *secret, ULONG secret_len, - UCHAR *input, ULONG input_len, UCHAR *output, ULONG output_len ) +static NTSTATUS hash_single( struct algorithm *alg, UCHAR *secret, ULONG secret_len, UCHAR *input, ULONG input_len, + UCHAR *output, ULONG output_len ) { - struct algorithm *alg = get_alg_object( handle ); struct hash *hash; NTSTATUS status;
- TRACE( "%p, %p, %lu, %p, %lu, %p, %lu\n", handle, secret, secret_len, input, input_len, output, output_len ); - - if (!alg) return STATUS_INVALID_HANDLE; - if (!output) return STATUS_INVALID_PARAMETER; - if ((status = hash_create( alg, secret, secret_len, 0, &hash ))) return status; - if (output_len != builtin_algorithms[hash->alg_id].hash_length) - { - hash_destroy( hash ); - return STATUS_INVALID_PARAMETER; - } if ((status = hash_update( &hash->inner, hash->alg_id, input, input_len ))) { hash_destroy( hash ); @@ -1162,6 +1152,19 @@ NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE handle, UCHAR *secret, ULONG secre return status; }
+NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE handle, UCHAR *secret, ULONG secret_len, UCHAR *input, ULONG input_len, + UCHAR *output, ULONG output_len ) +{ + struct algorithm *alg = get_alg_object( handle ); + + TRACE( "%p, %p, %lu, %p, %lu, %p, %lu\n", handle, secret, secret_len, input, input_len, output, output_len ); + + if (!alg) return STATUS_INVALID_HANDLE; + if (!output || output_len != builtin_algorithms[alg->id].hash_length) return STATUS_INVALID_PARAMETER; + + return hash_single(alg, secret, secret_len, input, input_len, output, output_len ); +} + static NTSTATUS key_asymmetric_create( enum alg_id alg_id, ULONG bitlen, struct key **ret_key ) { struct key *key; @@ -2471,17 +2474,118 @@ NTSTATUS WINAPI BCryptDestroySecret( BCRYPT_SECRET_HANDLE handle ) return STATUS_SUCCESS; }
-NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, BCryptBufferDesc *parameter, - UCHAR *derived, ULONG derived_size, ULONG *result, ULONG flags ) +static void reverse_bytes( UCHAR *buf, ULONG len ) +{ + ULONG i; + for (i = 0; i < len / 2; i++) + { + UCHAR tmp = buf[i]; + buf[i] = buf[len - i - 1]; + buf[len - i - 1] = tmp; + } +} + +static NTSTATUS derive_key_raw( struct secret *secret, UCHAR *output, ULONG output_len, ULONG *ret_len ) +{ + struct key_asymmetric_derive_key_params params; + NTSTATUS status; + + params.privkey = secret->privkey; + params.pubkey = secret->pubkey; + params.output = output; + params.output_len = output_len; + params.ret_len = ret_len; + if (!(status = UNIX_CALL( key_asymmetric_derive_key, ¶ms )) && output) reverse_bytes( output, *ret_len ); + return status; +} + +static BCRYPT_ALG_HANDLE hash_handle_from_desc( BCryptBufferDesc *desc ) +{ + ULONG i; + if (!desc) return BCRYPT_SHA1_ALG_HANDLE; + for (i = 0; i < desc->cBuffers; i++) + { + if (desc->pBuffers[i].BufferType == KDF_HASH_ALGORITHM) + { + const WCHAR *str = desc->pBuffers[i].pvBuffer; + if (!wcscmp( str, BCRYPT_SHA1_ALGORITHM )) return BCRYPT_SHA1_ALG_HANDLE; + else if (!wcscmp( str, BCRYPT_SHA256_ALGORITHM )) return BCRYPT_SHA256_ALG_HANDLE; + else if (!wcscmp( str, BCRYPT_SHA384_ALGORITHM )) return BCRYPT_SHA384_ALG_HANDLE; + else if (!wcscmp( str, BCRYPT_SHA512_ALGORITHM )) return BCRYPT_SHA512_ALG_HANDLE; + else + { + FIXME( "hash algorithm %s not supported\n", debugstr_w(str) ); + return NULL; + } + } + else FIXME( "buffer type %lu not supported\n", desc->pBuffers[i].BufferType ); + } + + return BCRYPT_SHA1_ALG_HANDLE; +} + +static NTSTATUS derive_key_hash( struct secret *secret, BCryptBufferDesc *desc, UCHAR *output, ULONG output_len, + ULONG *ret_len ) +{ + struct key_asymmetric_derive_key_params params; + struct algorithm *alg = get_alg_object( hash_handle_from_desc(desc) ); + ULONG hash_len, derived_key_len = secret->privkey->u.a.bitlen / 8; + UCHAR hash_buf[MAX_HASH_OUTPUT_BYTES]; + UCHAR *derived_key; + NTSTATUS status; + + if (!alg) return STATUS_NOT_SUPPORTED; + if (!(derived_key = malloc( derived_key_len ))) return STATUS_NO_MEMORY; + + params.privkey = secret->privkey; + params.pubkey = secret->pubkey; + params.output = derived_key; + params.output_len = derived_key_len; + params.ret_len = ret_len; + if ((status = UNIX_CALL( key_asymmetric_derive_key, ¶ms ))) + { + free( derived_key ); + return status; + } + + hash_len = builtin_algorithms[alg->id].hash_length; + assert( hash_len <= sizeof(hash_buf) ); + if (!(status = hash_single( alg, NULL, 0, derived_key, *params.ret_len, hash_buf, hash_len ))) + { + if (!output) *ret_len = hash_len; + else + { + *ret_len = min( hash_len, output_len ); + memcpy( output, hash_buf, *ret_len ); + } + } + + free( derived_key ); + return status; +} + +NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, BCryptBufferDesc *desc, + UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) { struct secret *secret = get_secret_object( handle );
- FIXME( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags ); + TRACE( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), desc, output, output_len, + ret_len, flags );
if (!secret) return STATUS_INVALID_HANDLE; - if (!kdf) return STATUS_INVALID_PARAMETER; + if (!kdf || !ret_len) return STATUS_INVALID_PARAMETER; + + if (!wcscmp(kdf, BCRYPT_KDF_RAW_SECRET)) + { + return derive_key_raw( secret, output, output_len, ret_len ); + } + else if (!wcscmp(kdf, BCRYPT_KDF_HASH)) + { + return derive_key_hash( secret, desc, output, output_len, ret_len ); + }
- return STATUS_INTERNAL_ERROR; + FIXME( "kdf %s not supportedi\n", debugstr_w(kdf) ); + return STATUS_NOT_SUPPORTED; }
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 5d8c71c78c5..81a6039ad4c 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -144,6 +144,10 @@ static void (*pgnutls_x509_spki_set_rsa_pss_params)(gnutls_x509_spki_t, gnutls_d static int (*pgnutls_pubkey_set_spki)(gnutls_pubkey_t, const gnutls_x509_spki_t, unsigned int); static int (*pgnutls_privkey_set_spki)(gnutls_privkey_t, const gnutls_x509_spki_t, unsigned int);
+/* Not present in gnutls version < 3.8.2 */ +static int (*pgnutls_privkey_derive_secret)(gnutls_privkey_t, gnutls_pubkey_t, const gnutls_datum_t *, + gnutls_datum_t *, unsigned int); + static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f MAKE_FUNCPTR(gnutls_cipher_decrypt2); @@ -302,6 +306,12 @@ static int compat_gnutls_privkey_set_spki(gnutls_privkey_t key, const gnutls_x50 return GNUTLS_E_UNKNOWN_PK_ALGORITHM; }
+static int compat_gnutls_privkey_derive_secret(gnutls_privkey_t privkey, gnutls_pubkey_t pubkey, const gnutls_datum_t *nonce, + gnutls_datum_t *secret, unsigned int flags) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + static void gnutls_log( int level, const char *msg ) { TRACE( "<%d> %s", level, msg ); @@ -365,6 +375,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR_OPT(gnutls_decode_rs_value) LOAD_FUNCPTR_OPT(gnutls_pk_to_sign) LOAD_FUNCPTR_OPT(gnutls_privkey_decrypt_data) + LOAD_FUNCPTR_OPT(gnutls_privkey_derive_secret) LOAD_FUNCPTR_OPT(gnutls_privkey_export_dsa_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_export_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_export_rsa_raw) @@ -2250,6 +2261,30 @@ static NTSTATUS key_asymmetric_encrypt( void *args ) return status; }
+static NTSTATUS key_asymmetric_derive_key( void *args ) +{ + const struct key_asymmetric_derive_key_params *params = args; + gnutls_datum_t s; + int ret; + + if ((ret = pgnutls_privkey_derive_secret( key_data(params->privkey)->a.privkey, + key_data(params->pubkey)->a.pubkey, NULL, &s, 0 ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + if (!params->output) *params->ret_len = s.size; + else + { + *params->ret_len = min( params->output_len, s.size ); + memcpy( params->output, s.data, *params->ret_len ); + } + + free( s.data ); + return STATUS_SUCCESS; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { gnutls_process_attach, @@ -2268,7 +2303,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = key_asymmetric_verify, key_asymmetric_destroy, key_asymmetric_export, - key_asymmetric_import + key_asymmetric_import, + key_asymmetric_derive_key, };
C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count ); @@ -2733,6 +2769,36 @@ static NTSTATUS wow64_key_asymmetric_import( void *args ) return ret; }
+static NTSTATUS wow64_key_asymmetric_derive_key( void *args ) +{ + struct + { + PTR32 privkey; + PTR32 pubkey; + PTR32 output; + ULONG output_len; + PTR32 ret_len; + } const *params32 = args; + + NTSTATUS ret; + struct key privkey, pubkey; + struct key32 *privkey32 = ULongToPtr( params32->privkey ); + struct key32 *pubkey32 = ULongToPtr( params32->pubkey ); + struct key_asymmetric_derive_key_params params = + { + get_asymmetric_key( privkey32, &privkey ), + get_asymmetric_key( pubkey32, &pubkey ), + ULongToPtr(params32->output), + params32->output_len, + ULongToPtr(params32->ret_len), + }; + + ret = key_asymmetric_derive_key( ¶ms ); + put_asymmetric_key32( &privkey, privkey32 ); + put_asymmetric_key32( &pubkey, pubkey32 ); + return ret; +} + const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { gnutls_process_attach, @@ -2751,7 +2817,8 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = wow64_key_asymmetric_verify, wow64_key_asymmetric_destroy, wow64_key_asymmetric_export, - wow64_key_asymmetric_import + wow64_key_asymmetric_import, + wow64_key_asymmetric_derive_key, };
C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count );
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_internal.h | 1 + dlls/bcrypt/bcrypt_main.c | 3 ++- dlls/bcrypt/gnutls.c | 5 +++++ dlls/bcrypt/tests/bcrypt.c | 17 +++++++++++++++++ include/bcrypt.h | 15 +++++++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index 2f66060ec8e..cfbc5d2ac83 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -132,6 +132,7 @@ enum alg_id ALG_ID_RSA,
/* secret agreement */ + ALG_ID_DH, ALG_ID_ECDH_P256, ALG_ID_ECDH_P384,
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 94e91fdc46a..6d266f112bd 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -114,6 +114,7 @@ builtin_algorithms[] = { BCRYPT_MD4_ALGORITHM, BCRYPT_HASH_INTERFACE, 270, 16, 512 }, { BCRYPT_MD2_ALGORITHM, BCRYPT_HASH_INTERFACE, 270, 16, 128 }, { BCRYPT_RSA_ALGORITHM, BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE, 0, 0, 0 }, + { BCRYPT_DH_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDH_P256_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDH_P384_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_RSA_SIGN_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, @@ -237,7 +238,7 @@ static const struct algorithm pseudo_algorithms[] = {{ 0 }}, /* RC2_CBC */ {{ 0 }}, /* RC2_ECB */ {{ 0 }}, /* RC2_CFB */ - {{ 0 }}, /* DH */ + {{ MAGIC_ALG }, ALG_ID_DH }, {{ 0 }}, /* ECDH */ {{ MAGIC_ALG }, ALG_ID_ECDH_P256 }, {{ MAGIC_ALG }, ALG_ID_ECDH_P384 }, diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 81a6039ad4c..c448ad68f2b 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -982,6 +982,11 @@ static NTSTATUS key_asymmetric_generate( void *args ) bitlen = key->u.a.bitlen; break;
+ case ALG_ID_DH: + pk_alg = GNUTLS_PK_DH; + bitlen = key->u.a.bitlen; + break; + case ALG_ID_DSA: pk_alg = GNUTLS_PK_DSA; bitlen = key->u.a.bitlen; diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 1ef25cc344f..e8431ea4a4a 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -3137,6 +3137,22 @@ derive_end: BCryptCloseAlgorithmProvider(alg, 0); }
+static void test_DH(void) +{ + BCRYPT_KEY_HANDLE key; + NTSTATUS status; + + key = NULL; + status = BCryptGenerateKeyPair(BCRYPT_DH_ALG_HANDLE, &key, 512, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(key != NULL, "key not set\n"); + + status = BCryptFinalizeKeyPair(key, 0); + todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + BCryptDestroyKey(key); +} + static void test_BCryptEnumContextFunctions(void) { CRYPT_CONTEXT_FUNCTIONS *buffer; @@ -3724,6 +3740,7 @@ START_TEST(bcrypt) test_RSA(); test_RSA_SIGN(); test_ECDH(); + test_DH(); test_BCryptEnumContextFunctions(); test_BCryptSignHash(); test_BCryptEnumAlgorithms(); diff --git a/include/bcrypt.h b/include/bcrypt.h index 15dad130892..7f768f61679 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -71,6 +71,8 @@ typedef LONG NTSTATUS; #define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB" #define BCRYPT_PUBLIC_KEY_BLOB L"PUBLICBLOB" #define BCRYPT_PRIVATE_KEY_BLOB L"PRIVATEBLOB" +#define BCRYPT_DH_PUBLIC_BLOB L"DHPUBLICBLOB" +#define BCRYPT_DH_PRIVATE_BLOB L"DHPRIVATEBLOB" #define LEGACY_DSA_PUBLIC_BLOB L"CAPIDSAPUBLICBLOB" #define LEGACY_DSA_PRIVATE_BLOB L"CAPIDSAPRIVATEBLOB" #define LEGACY_DSA_V2_PUBLIC_BLOB L"V2CAPIDSAPUBLICBLOB" @@ -84,6 +86,7 @@ typedef LONG NTSTATUS; #define BCRYPT_3DES_ALGORITHM L"3DES" #define BCRYPT_AES_ALGORITHM L"AES" #define BCRYPT_DES_ALGORITHM L"DES" +#define BCRYPT_DH_ALGORITHM L"DH" #define BCRYPT_DSA_ALGORITHM L"DSA" #define BCRYPT_ECDH_P256_ALGORITHM L"ECDH_P256" #define BCRYPT_ECDH_P384_ALGORITHM L"ECDH_P384" @@ -146,6 +149,8 @@ static const WCHAR BCRYPT_DSA_PUBLIC_BLOB[] = {'D','S','A','P','U','B','L','I',' 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 BCRYPT_DH_PUBLIC_BLOB[] = {'D','H','P','U','B','L','I','C','B','L','O','B',0}; +static const WCHAR BCRYPT_DH_PRIVATE_BLOB[] = {'D','H','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}; @@ -161,6 +166,7 @@ static const WCHAR MS_PLATFORM_CRYPTO_PROVIDER[] = \ static const WCHAR BCRYPT_3DES_ALGORITHM[] = {'3','D','E','S',0}; static const WCHAR BCRYPT_AES_ALGORITHM[] = {'A','E','S',0}; static const WCHAR BCRYPT_DES_ALGORITHM[] = {'D','E','S',0}; +static const WCHAR BCRYPT_DH_ALGORITHM[] = {'D','H',0}; static const WCHAR BCRYPT_DSA_ALGORITHM[] = {'D','S','A',0}; static const WCHAR BCRYPT_ECDH_P256_ALGORITHM[] = {'E','C','D','H','_','P','2','5','6',0}; static const WCHAR BCRYPT_ECDH_P384_ALGORITHM[] = {'E','C','D','H','_','P','3','8','4',0}; @@ -348,6 +354,15 @@ typedef struct _BCRYPT_DSA_KEY_BLOB_V2 UCHAR Count[4]; } BCRYPT_DSA_KEY_BLOB_V2, *PBCRYPT_DSA_KEY_BLOB_V2;
+#define BCRYPT_DH_PUBLIC_MAGIC 0x42504844 +#define BCRYPT_DH_PRIVATE_MAGIC 0x56504844 + +typedef struct _BCRYPT_DH_KEY_BLOB +{ + ULONG dwMagic; + ULONG cbKey; +} BCRYPT_DH_KEY_BLOB, *PBCRYPT_DH_KEY_BLOB; + #define BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION 1
#define BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG 0x00000001
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 5 +- dlls/bcrypt/gnutls.c | 131 +++++++++++++++++++++++++++++++++++++ dlls/bcrypt/tests/bcrypt.c | 22 +++++++ 3 files changed, 156 insertions(+), 2 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 6d266f112bd..25075e1c890 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1346,7 +1346,7 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_DSA_PRIVATE_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PRIVATE_BLOB ) || - !wcscmp( type, BCRYPT_ECCPRIVATE_BLOB )) + !wcscmp( type, BCRYPT_ECCPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB )) { params.key = key; params.flags = 0; @@ -1365,7 +1365,8 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U return UNIX_CALL( key_asymmetric_export, ¶ms ); } else if (!wcscmp( type, BCRYPT_DSA_PUBLIC_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PUBLIC_BLOB ) || - !wcscmp( type, BCRYPT_ECCPUBLIC_BLOB ) || !wcscmp( type, BCRYPT_RSAPUBLIC_BLOB )) + !wcscmp( type, BCRYPT_ECCPUBLIC_BLOB ) || !wcscmp( type, BCRYPT_RSAPUBLIC_BLOB ) || + !wcscmp( type, BCRYPT_DH_PUBLIC_BLOB )) { params.key = key; params.flags = KEY_EXPORT_FLAG_PUBLIC; diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index c448ad68f2b..a5ecae57da9 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -147,6 +147,9 @@ static int (*pgnutls_privkey_set_spki)(gnutls_privkey_t, const gnutls_x509_spki_ /* Not present in gnutls version < 3.8.2 */ static int (*pgnutls_privkey_derive_secret)(gnutls_privkey_t, gnutls_pubkey_t, const gnutls_datum_t *, gnutls_datum_t *, unsigned int); +static int (*pgnutls_privkey_export_dh_raw)(gnutls_privkey_t, gnutls_dh_params_t, gnutls_datum_t *, gnutls_datum_t *, + unsigned int); +static int (*pgnutls_pubkey_export_dh_raw)(gnutls_pubkey_t, gnutls_dh_params_t, gnutls_datum_t *, unsigned);
static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f @@ -154,6 +157,9 @@ MAKE_FUNCPTR(gnutls_cipher_decrypt2); MAKE_FUNCPTR(gnutls_cipher_deinit); MAKE_FUNCPTR(gnutls_cipher_encrypt2); MAKE_FUNCPTR(gnutls_cipher_init); +MAKE_FUNCPTR(gnutls_dh_params_deinit); +MAKE_FUNCPTR(gnutls_dh_params_export_raw); +MAKE_FUNCPTR(gnutls_dh_params_init); MAKE_FUNCPTR(gnutls_global_deinit); MAKE_FUNCPTR(gnutls_global_init); MAKE_FUNCPTR(gnutls_global_set_log_function); @@ -312,6 +318,18 @@ static int compat_gnutls_privkey_derive_secret(gnutls_privkey_t privkey, gnutls_ return GNUTLS_E_UNKNOWN_PK_ALGORITHM; }
+static int compat_gnutls_privkey_export_dh_raw(gnutls_privkey_t privkey, gnutls_dh_params_t params, gnutls_datum_t *y, + gnutls_datum_t *x, unsigned int flags ) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + +static int compat_gnutls_pubkey_export_dh_raw(gnutls_pubkey_t pubkey, gnutls_dh_params_t params, gnutls_datum_t *y, + unsigned flags) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + static void gnutls_log( int level, const char *msg ) { TRACE( "<%d> %s", level, msg ); @@ -349,6 +367,9 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR(gnutls_cipher_deinit) LOAD_FUNCPTR(gnutls_cipher_encrypt2) LOAD_FUNCPTR(gnutls_cipher_init) + LOAD_FUNCPTR(gnutls_dh_params_deinit) + LOAD_FUNCPTR(gnutls_dh_params_export_raw) + LOAD_FUNCPTR(gnutls_dh_params_init) LOAD_FUNCPTR(gnutls_global_deinit) LOAD_FUNCPTR(gnutls_global_init) LOAD_FUNCPTR(gnutls_global_set_log_function) @@ -376,6 +397,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR_OPT(gnutls_pk_to_sign) LOAD_FUNCPTR_OPT(gnutls_privkey_decrypt_data) LOAD_FUNCPTR_OPT(gnutls_privkey_derive_secret) + LOAD_FUNCPTR_OPT(gnutls_privkey_export_dh_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_export_dsa_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_export_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_export_rsa_raw) @@ -384,6 +406,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR_OPT(gnutls_privkey_import_rsa_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_set_spki) LOAD_FUNCPTR_OPT(gnutls_pubkey_encrypt_data) + LOAD_FUNCPTR_OPT(gnutls_pubkey_export_dh_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_dsa_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_rsa_raw) @@ -1540,6 +1563,109 @@ static NTSTATUS key_import_dsa_capi_public( struct key *key, UCHAR *buf, ULONG l return STATUS_SUCCESS; }
+static NTSTATUS key_export_dh_public( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len ) +{ + BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; + ULONG size = key->u.a.bitlen / 8; + gnutls_dh_params_t params; + gnutls_datum_t p, g, y, x = {0}; + UCHAR *dst; + int ret = GNUTLS_E_INVALID_REQUEST; + + if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + if (key_data(key)->a.pubkey) + ret = pgnutls_pubkey_export_dh_raw( key_data(key)->a.pubkey, params, &y, 0 ); + else if (key_data(key)->a.privkey) + ret = pgnutls_privkey_export_dh_raw( key_data(key)->a.privkey, params, &y, &x, 0 ); + + if (ret) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); + return STATUS_INTERNAL_ERROR; + } + + if ((ret = pgnutls_dh_params_export_raw( params, &p, &g, NULL )) < 0) + { + pgnutls_perror( ret ); + free( y.data ); free( x.data ); + pgnutls_dh_params_deinit( params ); + return STATUS_INTERNAL_ERROR; + } + + *ret_len = sizeof(*dh_blob) + EXPORT_SIZE(p, size, 1) + EXPORT_SIZE(g, size, 1) + EXPORT_SIZE(y, size, 1); + if (len >= *ret_len && buf) + { + dst = (UCHAR *)(dh_blob + 1); + dst += export_gnutls_datum( dst, size, &p, 1 ); + dst += export_gnutls_datum( dst, size, &g, 1 ); + dst += export_gnutls_datum( dst, size, &y, 1 ); + + dh_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC; + dh_blob->cbKey = size; + } + + free( p.data ); free( g.data ); free( y.data ); free( x.data ); + return STATUS_SUCCESS; +} + +static NTSTATUS key_export_dh( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len ) +{ + BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; + gnutls_datum_t p, g, y, x; + gnutls_dh_params_t params; + ULONG size = key->u.a.bitlen / 8; + UCHAR *dst; + int ret; + + if (!key_data(key)->a.privkey) return STATUS_INVALID_PARAMETER; + + if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + ret = pgnutls_privkey_export_dh_raw( key_data(key)->a.privkey, params, &y, &x, 0 ); + if (ret) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); + return STATUS_INTERNAL_ERROR; + } + + if ((ret = pgnutls_dh_params_export_raw( params, &p, &g, NULL )) < 0) + { + pgnutls_perror( ret ); + free( y.data ); free( x.data ); + pgnutls_dh_params_deinit( params ); + return STATUS_INTERNAL_ERROR; + } + + *ret_len = sizeof(*dh_blob) + EXPORT_SIZE(p, size, 1) + EXPORT_SIZE(g, size, 1) + + EXPORT_SIZE(y, size, 1) + EXPORT_SIZE(x, size, 1); + if (len >= *ret_len && buf) + { + dst = (UCHAR *)(dh_blob + 1); + dst += export_gnutls_datum( dst, size, &p, 1 ); + dst += export_gnutls_datum( dst, size, &g, 1 ); + dst += export_gnutls_datum( dst, size, &y, 1 ); + dst += export_gnutls_datum( dst, size, &x, 1 ); + + dh_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; + dh_blob->cbKey = size; + } + + free( p.data ); free( g.data ); free( y.data ); free( x.data ); + pgnutls_dh_params_deinit( params ); + return STATUS_SUCCESS; +} + static NTSTATUS key_asymmetric_export( void *args ) { const struct key_asymmetric_export_params *params = args; @@ -1573,6 +1699,11 @@ static NTSTATUS key_asymmetric_export( void *args ) return key_export_dsa_capi( key, params->buf, params->len, params->ret_len ); return STATUS_NOT_IMPLEMENTED;
+ case ALG_ID_DH: + if (flags & KEY_EXPORT_FLAG_PUBLIC) + return key_export_dh_public( key, params->buf, params->len, params->ret_len ); + return key_export_dh( key, params->buf, params->len, params->ret_len ); + default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index e8431ea4a4a..1337f253397 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -3140,7 +3140,10 @@ derive_end: static void test_DH(void) { BCRYPT_KEY_HANDLE key; + BCRYPT_DH_KEY_BLOB *dhkey; NTSTATUS status; + UCHAR *buf; + ULONG size;
key = NULL; status = BCryptGenerateKeyPair(BCRYPT_DH_ALG_HANDLE, &key, 512, 0); @@ -3149,7 +3152,26 @@ static void test_DH(void)
status = BCryptFinalizeKeyPair(key, 0); todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); + if (status != STATUS_SUCCESS) + { + BCryptDestroyKey(key); + return; + }
+ size = 0; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size, "size not set\n"); + + buf = malloc(size); + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + dhkey = (BCRYPT_DH_KEY_BLOB *)buf; + ok(dhkey->dwMagic == BCRYPT_DH_PUBLIC_MAGIC, "got %#lx\n", dhkey->dwMagic); + ok(dhkey->cbKey == 64, "got %lu\n", dhkey->cbKey); + ok(size == sizeof(*dhkey) + dhkey->cbKey * 3, "got %lu\n", size); + + free(buf); BCryptDestroyKey(key); }
Hans Leidekker wine@gitlab.winehq.org wrote:
+static NTSTATUS key_export_dh_public( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len ) +{
- BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)buf;
- ULONG size = key->u.a.bitlen / 8;
- gnutls_dh_params_t params;
- gnutls_datum_t p, g, y, x = {0};
- UCHAR *dst;
- int ret = GNUTLS_E_INVALID_REQUEST;
Initialization of 'ret' seems to be unnecessary.
- if ((ret = pgnutls_dh_params_init( ¶ms )) < 0)
- {
pgnutls_perror( ret );
return STATUS_INTERNAL_ERROR;
- }
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 46 +++++++++++++- dlls/bcrypt/gnutls.c | 128 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 1 deletion(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 25075e1c890..26472cbfe2b 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1819,7 +1819,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP BCRYPT_DSA_KEY_BLOB *dsa_blob = (BCRYPT_DSA_KEY_BLOB *)input;
if (input_len < sizeof(*dsa_blob)) return STATUS_INVALID_PARAMETER; - if ((alg->id != ALG_ID_DSA) || dsa_blob->dwMagic != BCRYPT_DSA_PUBLIC_MAGIC) + if (alg->id != ALG_ID_DSA || dsa_blob->dwMagic != BCRYPT_DSA_PUBLIC_MAGIC) return STATUS_NOT_SUPPORTED;
if ((status = key_asymmetric_create( alg->id, dsa_blob->cbKey * 8, &key ))) return status; @@ -1912,6 +1912,50 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP *ret_key = key; return STATUS_SUCCESS; } + else if (!wcscmp( type, BCRYPT_DH_PRIVATE_BLOB )) + { + BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)input; + + if (input_len < sizeof(*dh_blob)) return STATUS_INVALID_PARAMETER; + if (alg->id != ALG_ID_DH || dh_blob->dwMagic != BCRYPT_DH_PRIVATE_MAGIC) + return STATUS_NOT_SUPPORTED; + + if ((status = key_asymmetric_create( alg->id, dh_blob->cbKey * 8, &key ))) return status; + params.key = key; + params.flags = 0; + params.buf = input; + params.len = input_len; + if ((status = UNIX_CALL( key_asymmetric_import, ¶ms ))) + { + key_destroy( key ); + return status; + } + + *ret_key = key; + return STATUS_SUCCESS; + } + else if (!wcscmp( type, BCRYPT_DH_PUBLIC_BLOB )) + { + BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)input; + + if (input_len < sizeof(*dh_blob)) return STATUS_INVALID_PARAMETER; + if (alg->id != ALG_ID_DH || dh_blob->dwMagic != BCRYPT_DH_PUBLIC_MAGIC) + return STATUS_NOT_SUPPORTED; + + if ((status = key_asymmetric_create( alg->id, dh_blob->cbKey * 8, &key ))) return status; + params.key = key; + params.flags = KEY_IMPORT_FLAG_PUBLIC; + params.buf = input; + params.len = input_len; + if ((status = UNIX_CALL( key_asymmetric_import, ¶ms ))) + { + key_destroy( key ); + return status; + } + + *ret_key = key; + return STATUS_SUCCESS; + }
FIXME( "unsupported key type %s\n", debugstr_w(type) ); return STATUS_NOT_SUPPORTED; diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index a5ecae57da9..83b0076c434 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -150,6 +150,9 @@ static int (*pgnutls_privkey_derive_secret)(gnutls_privkey_t, gnutls_pubkey_t, c static int (*pgnutls_privkey_export_dh_raw)(gnutls_privkey_t, gnutls_dh_params_t, gnutls_datum_t *, gnutls_datum_t *, unsigned int); static int (*pgnutls_pubkey_export_dh_raw)(gnutls_pubkey_t, gnutls_dh_params_t, gnutls_datum_t *, unsigned); +static int (*pgnutls_privkey_import_dh_raw)(gnutls_privkey_t, const gnutls_dh_params_t, const gnutls_datum_t *, + const gnutls_datum_t *); +static int (*pgnutls_pubkey_import_dh_raw)(gnutls_pubkey_t, const gnutls_dh_params_t, const gnutls_datum_t *);
static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f @@ -159,6 +162,7 @@ MAKE_FUNCPTR(gnutls_cipher_encrypt2); MAKE_FUNCPTR(gnutls_cipher_init); MAKE_FUNCPTR(gnutls_dh_params_deinit); MAKE_FUNCPTR(gnutls_dh_params_export_raw); +MAKE_FUNCPTR(gnutls_dh_params_import_raw); MAKE_FUNCPTR(gnutls_dh_params_init); MAKE_FUNCPTR(gnutls_global_deinit); MAKE_FUNCPTR(gnutls_global_init); @@ -330,6 +334,18 @@ static int compat_gnutls_pubkey_export_dh_raw(gnutls_pubkey_t pubkey, gnutls_dh_ return GNUTLS_E_UNKNOWN_PK_ALGORITHM; }
+static int compat_gnutls_privkey_import_dh_raw(gnutls_privkey_t privkey, const gnutls_dh_params_t params, + const gnutls_datum_t *y, const gnutls_datum_t *x) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + +static int compat_gnutls_pubkey_import_dh_raw(gnutls_pubkey_t pubkey, const gnutls_dh_params_t params, + const gnutls_datum_t *y) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + static void gnutls_log( int level, const char *msg ) { TRACE( "<%d> %s", level, msg ); @@ -369,6 +385,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR(gnutls_cipher_init) LOAD_FUNCPTR(gnutls_dh_params_deinit) LOAD_FUNCPTR(gnutls_dh_params_export_raw) + LOAD_FUNCPTR(gnutls_dh_params_import_raw) LOAD_FUNCPTR(gnutls_dh_params_init) LOAD_FUNCPTR(gnutls_global_deinit) LOAD_FUNCPTR(gnutls_global_init) @@ -402,6 +419,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR_OPT(gnutls_privkey_export_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_export_rsa_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_generate) + LOAD_FUNCPTR_OPT(gnutls_privkey_import_dh_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_import_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_import_rsa_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_set_spki) @@ -410,6 +428,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_dsa_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_rsa_raw) + LOAD_FUNCPTR_OPT(gnutls_pubkey_import_dh_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_import_dsa_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_import_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_import_rsa_raw) @@ -1710,6 +1729,110 @@ static NTSTATUS key_asymmetric_export( void *args ) } }
+static NTSTATUS key_import_dh_public( struct key *key, UCHAR *buf, ULONG len ) +{ + BCRYPT_DH_KEY_BLOB *dh_blob; + gnutls_dh_params_t params; + gnutls_datum_t p, g, y; + gnutls_pubkey_t handle; + int ret; + + if ((ret = pgnutls_pubkey_init( &handle ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) + { + pgnutls_perror( ret ); + pgnutls_pubkey_deinit( handle ); + return STATUS_INTERNAL_ERROR; + } + + dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; + p.data = buf + sizeof(*dh_blob); + p.size = dh_blob->cbKey; + g.data = buf + sizeof(*dh_blob) + dh_blob->cbKey; + g.size = dh_blob->cbKey; + y.data = buf + sizeof(*dh_blob) + dh_blob->cbKey * 2; + y.size = dh_blob->cbKey; + + if ((ret = pgnutls_dh_params_import_raw( params, &p, &g )) < 0) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); + pgnutls_pubkey_deinit( handle ); + return STATUS_INTERNAL_ERROR; + } + + ret = pgnutls_pubkey_import_dh_raw( handle, params, &y ); + pgnutls_dh_params_deinit( params ); + if (ret < 0) + { + pgnutls_perror( ret ); + pgnutls_pubkey_deinit( handle ); + return STATUS_INTERNAL_ERROR; + } + + if (key_data(key)->a.pubkey) pgnutls_pubkey_deinit( key_data(key)->a.pubkey ); + key_data(key)->a.pubkey = handle; + return STATUS_SUCCESS; +} + +static NTSTATUS key_import_dh( struct key *key, UCHAR *buf, ULONG len ) +{ + BCRYPT_DH_KEY_BLOB *dh_blob; + gnutls_dh_params_t params; + gnutls_datum_t p, g, y, x; + gnutls_privkey_t handle; + int ret; + + if ((ret = pgnutls_privkey_init( &handle ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) + { + pgnutls_perror( ret ); + pgnutls_privkey_deinit( handle ); + return STATUS_INTERNAL_ERROR; + } + + dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; + p.data = buf + sizeof(*dh_blob); + p.size = dh_blob->cbKey; + g.data = buf + sizeof(*dh_blob) + dh_blob->cbKey; + g.size = dh_blob->cbKey; + y.data = buf + sizeof(*dh_blob) + dh_blob->cbKey * 2; + y.size = dh_blob->cbKey; + x.data = buf + sizeof(*dh_blob) + dh_blob->cbKey * 3; + x.size = dh_blob->cbKey; + + if ((ret = pgnutls_dh_params_import_raw( params, &p, &g )) < 0) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); + pgnutls_privkey_deinit( handle ); + return STATUS_INTERNAL_ERROR; + } + + ret = pgnutls_privkey_import_dh_raw( handle, params, &y, &x ); + pgnutls_dh_params_deinit( params ); + if (ret < 0) + { + pgnutls_perror( ret ); + pgnutls_privkey_deinit( handle ); + return STATUS_INTERNAL_ERROR; + } + + if (key_data(key)->a.privkey) pgnutls_privkey_deinit( key_data(key)->a.privkey ); + key_data(key)->a.privkey = handle; + return STATUS_SUCCESS; +} + static NTSTATUS key_asymmetric_import( void *args ) { const struct key_asymmetric_import_params *params = args; @@ -1751,6 +1874,11 @@ static NTSTATUS key_asymmetric_import( void *args ) FIXME( "DSA private key not supported\n" ); return STATUS_NOT_IMPLEMENTED;
+ case ALG_ID_DH: + if (flags & KEY_IMPORT_FLAG_PUBLIC) + return key_import_dh_public( key, params->buf, params->len ); + return key_import_dh( key, params->buf, params->len ); + default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED;
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/gnutls.c | 115 ++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 57 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 83b0076c434..68f84a553d2 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -2320,37 +2320,22 @@ static NTSTATUS dup_privkey( struct key *key_orig, struct key *key_copy ) case ALG_ID_RSA_SIGN: { gnutls_datum_t m, e, d, p, q, u, e1, e2; + if ((ret = pgnutls_privkey_export_rsa_raw( key_data(key_orig)->a.privkey, &m, &e, &d, &p, &q, &u, &e1, &e2 ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } + break; ret = pgnutls_privkey_import_rsa_raw( privkey, &m, &e, &d, &p, &q, &u, &e1, &e2 ); free( m.data ); free( e.data ); free( d.data ); free( p.data ); free( q.data ); free( u.data ); free( e1.data ); free( e2.data ); - if (ret) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } break; } case ALG_ID_DSA: { gnutls_datum_t p, q, g, y, x; - if ((ret = pgnutls_privkey_export_dsa_raw( key_data(key_orig)->a.privkey, &p, &q, &g, &y, &x ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } + + if ((ret = pgnutls_privkey_export_dsa_raw( key_data(key_orig)->a.privkey, &p, &q, &g, &y, &x ))) break; ret = pgnutls_privkey_import_dsa_raw( privkey, &p, &q, &g, &y, &x ); free( p.data ); free( q.data ); free( g.data ); free( y.data ); free( x.data ); - if (ret) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - key_copy->u.a.dss_seed = key_orig->u.a.dss_seed; + if (!ret) key_copy->u.a.dss_seed = key_orig->u.a.dss_seed; break; } case ALG_ID_ECDH_P256: @@ -2360,22 +2345,38 @@ static NTSTATUS dup_privkey( struct key *key_orig, struct key *key_copy ) { gnutls_ecc_curve_t curve; gnutls_datum_t x, y, k; - if ((ret = pgnutls_privkey_export_ecc_raw( key_data(key_orig)->a.privkey, &curve, &x, &y, &k ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } + + if ((ret = pgnutls_privkey_export_ecc_raw( key_data(key_orig)->a.privkey, &curve, &x, &y, &k ))) break; ret = pgnutls_privkey_import_ecc_raw( privkey, curve, &x, &y, &k ); free( x.data ); free( y.data ); free( k.data ); - if (ret) + break; + } + case ALG_ID_DH: + { + gnutls_dh_params_t params; + gnutls_datum_t y, x; + + if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) break; + if ((ret = pgnutls_privkey_export_dh_raw( key_data(key_orig)->a.privkey, params, &y, &x, 0 )) < 0) { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; + pgnutls_dh_params_deinit( params ); + break; } + ret = pgnutls_privkey_import_dh_raw( privkey, params, &y, &x ); + pgnutls_dh_params_deinit( params ); + free( x.data ); free( y.data ); break; } default: ERR( "unhandled algorithm %u\n", key_orig->alg_id ); + pgnutls_privkey_deinit( privkey ); + return STATUS_INTERNAL_ERROR; + } + + if (ret < 0) + { + pgnutls_perror( ret ); + pgnutls_privkey_deinit( privkey ); return STATUS_INTERNAL_ERROR; }
@@ -2400,36 +2401,20 @@ static NTSTATUS dup_pubkey( struct key *key_orig, struct key *key_copy ) 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 ); - return STATUS_INTERNAL_ERROR; - } + + if ((ret = pgnutls_pubkey_export_rsa_raw( key_data(key_orig)->a.pubkey, &m, &e ))) break; ret = pgnutls_pubkey_import_rsa_raw( pubkey, &m, &e ); free( m.data ); free( e.data ); - if (ret) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } 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; - } + + if ((ret = pgnutls_pubkey_export_dsa_raw( key_data(key_orig)->a.pubkey, &p, &q, &g, &y ))) break; 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; + if (!ret) key_copy->u.a.dss_seed = key_orig->u.a.dss_seed; break; } case ALG_ID_ECDH_P256: @@ -2439,22 +2424,38 @@ static NTSTATUS dup_pubkey( struct key *key_orig, struct key *key_copy ) { 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; - } + + if ((ret = pgnutls_pubkey_export_ecc_raw( key_data(key_orig)->a.pubkey, &curve, &x, &y ))) break; ret = pgnutls_pubkey_import_ecc_raw( pubkey, curve, &x, &y ); free( x.data ); free( y.data ); - if (ret) + break; + } + case ALG_ID_DH: + { + gnutls_dh_params_t params; + gnutls_datum_t y; + + if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) break; + if ((ret = pgnutls_pubkey_export_dh_raw( key_data(key_orig)->a.pubkey, params, &y, 0 )) < 0) { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; + pgnutls_dh_params_deinit( params ); + break; } + ret = pgnutls_pubkey_import_dh_raw( pubkey, params, &y ); + pgnutls_dh_params_deinit( params ); + free( y.data ); break; } default: ERR( "unhandled algorithm %u\n", key_orig->alg_id ); + pgnutls_pubkey_deinit( pubkey ); + return STATUS_INTERNAL_ERROR; + } + + if (ret < 0) + { + pgnutls_perror( ret ); + pgnutls_pubkey_deinit( pubkey ); return STATUS_INTERNAL_ERROR; }
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/tests/bcrypt.c | 229 ++++++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 1 deletion(-)
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 1337f253397..45e03e5d15b 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -3137,14 +3137,99 @@ derive_end: BCryptCloseAlgorithmProvider(alg, 0); }
+static BYTE dh_pubkey[] = +{ + /* BCRYPT_DH_KEY_BLOB */ + 0x44, 0x48, 0x50, 0x42, 0x40, 0x00, 0x00, 0x00, + /* p */ + 0xcf, 0x18, 0xe9, 0xa9, 0xb3, 0x97, 0x59, 0xae, 0x0d, 0xac, 0xf0, 0x99, 0x39, 0xdc, 0xd2, 0xfe, + 0x1e, 0xf3, 0xfc, 0x2c, 0x49, 0xdf, 0x76, 0x89, 0xff, 0x13, 0x57, 0xc7, 0xe6, 0xbd, 0xed, 0xa7, + 0x42, 0xc0, 0xc3, 0xd7, 0x8e, 0x84, 0xa8, 0xdf, 0xcd, 0x52, 0x50, 0x81, 0x73, 0x8a, 0x33, 0x60, + 0xde, 0x6d, 0x56, 0xeb, 0xd5, 0xec, 0x1f, 0x9f, 0x9f, 0xd6, 0x2c, 0xe4, 0x8f, 0xab, 0x58, 0x0b, + /* g */ + 0x5f, 0xc5, 0x50, 0x9a, 0xde, 0xf6, 0x84, 0x48, 0x39, 0xa9, 0xa7, 0xb1, 0x73, 0x0c, 0x56, 0xd4, + 0x28, 0xbb, 0x12, 0x93, 0x51, 0x44, 0x33, 0xdf, 0xa6, 0xe7, 0x7f, 0x0b, 0x3f, 0xe9, 0x41, 0xef, + 0x32, 0x80, 0xcd, 0x8e, 0x2b, 0x38, 0x85, 0x49, 0x4d, 0x0c, 0xcc, 0x74, 0x02, 0x07, 0x92, 0xd3, + 0xe4, 0x3e, 0x37, 0x84, 0x27, 0x1f, 0xa3, 0xad, 0x94, 0x8c, 0xc1, 0xc2, 0x22, 0x99, 0x36, 0xf0, + /* y */ + 0x22, 0xaf, 0x98, 0xeb, 0xd9, 0xc4, 0xb5, 0xbd, 0xe1, 0xab, 0x19, 0x1b, 0xe3, 0x36, 0x20, 0xca, + 0xff, 0xe8, 0x6c, 0x30, 0x96, 0x3c, 0x90, 0x77, 0x0e, 0xe0, 0x96, 0xae, 0xb1, 0x47, 0xd1, 0x52, + 0x2c, 0xc3, 0x65, 0x5e, 0x9b, 0x41, 0x9a, 0xa6, 0xfe, 0xab, 0x54, 0xa0, 0xf0, 0x71, 0xab, 0x6c, + 0xd0, 0x0e, 0x01, 0x08, 0x5b, 0x66, 0xe5, 0x62, 0xd2, 0xe5, 0x5d, 0xae, 0x9c, 0x60, 0xb2, 0xc6, +}; + +static BYTE dh_privkey[] = +{ + /* BCRYPT_DH_KEY_BLOB */ + 0x44, 0x48, 0x50, 0x56, 0x40, 0x00, 0x00, 0x00, + /* p */ + 0xcf, 0x18, 0xe9, 0xa9, 0xb3, 0x97, 0x59, 0xae, 0x0d, 0xac, 0xf0, 0x99, 0x39, 0xdc, 0xd2, 0xfe, + 0x1e, 0xf3, 0xfc, 0x2c, 0x49, 0xdf, 0x76, 0x89, 0xff, 0x13, 0x57, 0xc7, 0xe6, 0xbd, 0xed, 0xa7, + 0x42, 0xc0, 0xc3, 0xd7, 0x8e, 0x84, 0xa8, 0xdf, 0xcd, 0x52, 0x50, 0x81, 0x73, 0x8a, 0x33, 0x60, + 0xde, 0x6d, 0x56, 0xeb, 0xd5, 0xec, 0x1f, 0x9f, 0x9f, 0xd6, 0x2c, 0xe4, 0x8f, 0xab, 0x58, 0x0b, + /* g */ + 0x5f, 0xc5, 0x50, 0x9a, 0xde, 0xf6, 0x84, 0x48, 0x39, 0xa9, 0xa7, 0xb1, 0x73, 0x0c, 0x56, 0xd4, + 0x28, 0xbb, 0x12, 0x93, 0x51, 0x44, 0x33, 0xdf, 0xa6, 0xe7, 0x7f, 0x0b, 0x3f, 0xe9, 0x41, 0xef, + 0x32, 0x80, 0xcd, 0x8e, 0x2b, 0x38, 0x85, 0x49, 0x4d, 0x0c, 0xcc, 0x74, 0x02, 0x07, 0x92, 0xd3, + 0xe4, 0x3e, 0x37, 0x84, 0x27, 0x1f, 0xa3, 0xad, 0x94, 0x8c, 0xc1, 0xc2, 0x22, 0x99, 0x36, 0xf0, + /* y */ + 0x22, 0xaf, 0x98, 0xeb, 0xd9, 0xc4, 0xb5, 0xbd, 0xe1, 0xab, 0x19, 0x1b, 0xe3, 0x36, 0x20, 0xca, + 0xff, 0xe8, 0x6c, 0x30, 0x96, 0x3c, 0x90, 0x77, 0x0e, 0xe0, 0x96, 0xae, 0xb1, 0x47, 0xd1, 0x52, + 0x2c, 0xc3, 0x65, 0x5e, 0x9b, 0x41, 0x9a, 0xa6, 0xfe, 0xab, 0x54, 0xa0, 0xf0, 0x71, 0xab, 0x6c, + 0xd0, 0x0e, 0x01, 0x08, 0x5b, 0x66, 0xe5, 0x62, 0xd2, 0xe5, 0x5d, 0xae, 0x9c, 0x60, 0xb2, 0xc6, + /* x */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x71, 0x3e, 0x82, + 0x8b, 0xea, 0x11, 0x77, 0xc4, 0xb4, 0x62, 0xc7, 0x4d, 0xff, 0x0f, 0x63, 0xd9, 0xe2, 0xda, 0xab, +}; + +static BYTE dh_secret[] = +{ + 0x73, 0x84, 0x62, 0xc1, 0x9a, 0x9c, 0xc2, 0x91, 0x9f, 0xc1, 0xc2, 0x94, 0x0c, 0xa8, 0x2f, 0x58, + 0xac, 0x50, 0xcd, 0xd5, 0x29, 0x43, 0x41, 0x8e, 0x5d, 0xca, 0x73, 0x55, 0x4d, 0x46, 0x50, 0xe5, + 0xb7, 0x34, 0xa9, 0xcb, 0x3a, 0x18, 0x68, 0x99, 0x30, 0xef, 0x58, 0x26, 0xd3, 0x03, 0x61, 0x02, + 0x17, 0xb7, 0xba, 0x01, 0xbc, 0xae, 0xdf, 0x3f, 0xb5, 0xb5, 0x4a, 0xb0, 0x08, 0xe5, 0xea, 0xc3, +}; + +static BYTE dh_hashed_secret[] = +{ + 0xa7, 0xfc, 0xff, 0x21, 0xb3, 0xd1, 0x46, 0xb8, 0x21, 0x3d, 0xc6, 0xd4, 0xe3, 0x61, 0x97, 0x5e, + 0xb5, 0x0a, 0xfe, 0x8f, +}; + +BCryptBuffer dh_hash_param_buffers[] = +{ + { + sizeof(BCRYPT_SHA1_ALGORITHM), + KDF_HASH_ALGORITHM, + (void *)BCRYPT_SHA1_ALGORITHM, + } +}; + +BCryptBufferDesc dh_hash_params = +{ + BCRYPTBUFFER_VERSION, + ARRAY_SIZE(dh_hash_param_buffers), + dh_hash_param_buffers, +}; + static void test_DH(void) { - BCRYPT_KEY_HANDLE key; + UCHAR hash[20]; + BCRYPT_KEY_HANDLE key, pubkey, privkey; + BCRYPT_SECRET_HANDLE secret; BCRYPT_DH_KEY_BLOB *dhkey; NTSTATUS status; UCHAR *buf; ULONG size;
+ if (!pBCryptHash) /* < Win10 */ + { + win_skip("broken DH detected\n"); + return; + } + key = NULL; status = BCryptGenerateKeyPair(BCRYPT_DH_ALG_HANDLE, &key, 512, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); @@ -3171,8 +3256,117 @@ static void test_DH(void) ok(dhkey->cbKey == 64, "got %lu\n", dhkey->cbKey); ok(size == sizeof(*dhkey) + dhkey->cbKey * 3, "got %lu\n", size);
+ status = BCryptImportKeyPair(BCRYPT_DH_ALG_HANDLE, NULL, BCRYPT_DH_PUBLIC_BLOB, &pubkey, buf, size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); free(buf); + BCryptDestroyKey(pubkey); + + size = 0; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PRIVATE_BLOB, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size == sizeof(*dhkey) + 64 * 4, "size not set\n"); + + buf = calloc(1, size); + status = BCryptExportKey(key, NULL, BCRYPT_DH_PRIVATE_BLOB, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + dhkey = (BCRYPT_DH_KEY_BLOB *)buf; + ok(dhkey->dwMagic == BCRYPT_DH_PRIVATE_MAGIC, "got %#lx\n", dhkey->dwMagic); + ok(dhkey->cbKey == 64, "got %lu\n", dhkey->cbKey); + ok(size == sizeof(*dhkey) + dhkey->cbKey * 4, "got %lu\n", size); BCryptDestroyKey(key); + + status = BCryptImportKeyPair(BCRYPT_DH_ALG_HANDLE, NULL, BCRYPT_DH_PRIVATE_BLOB, &privkey, buf, size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + free(buf); + BCryptDestroyKey(privkey); + + status = BCryptImportKeyPair(BCRYPT_DH_ALG_HANDLE, NULL, BCRYPT_DH_PRIVATE_BLOB, &privkey, dh_privkey, + sizeof(dh_privkey), 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + size = 0; + status = BCryptExportKey(privkey, NULL, BCRYPT_DH_PRIVATE_BLOB, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size, "size not set\n"); + + buf = malloc(size); + status = BCryptExportKey(privkey, NULL, BCRYPT_DH_PRIVATE_BLOB, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size == sizeof(dh_privkey), "got %lu\n", size); + ok(!memcmp(buf, dh_privkey, size), "wrong data\n"); + free(buf); + + status = BCryptImportKeyPair(BCRYPT_DH_ALG_HANDLE, NULL, BCRYPT_DH_PUBLIC_BLOB, &pubkey, dh_pubkey, + sizeof(dh_pubkey), 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + size = 0; + status = BCryptExportKey(privkey, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size, "size not set\n"); + + buf = malloc(size); + status = BCryptExportKey(privkey, NULL, BCRYPT_DH_PUBLIC_BLOB, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size == sizeof(dh_pubkey), "got %lu\n", size); + ok(!memcmp(buf, dh_pubkey, size), "wrong data\n"); + free(buf); + + status = BCryptSignHash(privkey, NULL, hash, sizeof(hash), NULL, 0, &size, 0); + ok(status == STATUS_NOT_SUPPORTED, "got %#lx\n", status); + + status = BCryptEncrypt(privkey, NULL, 0, NULL, NULL, 0, NULL, 0, &size, 0); + ok(status == STATUS_NOT_SUPPORTED, "got %lx\n", status); + + status = BCryptSecretAgreement(privkey, pubkey, &secret, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + BCryptDestroyKey(pubkey); + BCryptDestroyKey(privkey); + + size = 0; + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &size, 0); + if (status == STATUS_NOT_SUPPORTED) + { + win_skip("BCRYPT_KDF_RAW_SECRET not supported\n"); /* < win10 */ + BCryptDestroySecret(secret); + return; + } + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size == 64, "got %lu\n", size); + + buf = calloc(1, size); + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(!memcmp(dh_secret, buf, size), "wrong data\n"); + free(buf); + + size = 0; + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, NULL, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size == 20, "got %lu\n", size); + + size = 0; + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &dh_hash_params, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(size == 20, "got %lu\n", size); + + buf = calloc(1, size); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &dh_hash_params, buf, size, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &dh_hash_params, buf, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(!memcmp(dh_hashed_secret, buf, size), "wrong data\n"); + ok(size == 20, "got %lu\n", size); + + memset(buf, 0, 20); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &dh_hash_params, buf, 10, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(!memcmp(dh_hashed_secret, buf, size), "wrong data\n"); + ok(size == 10, "got %lu\n", size); + free(buf); + + BCryptDestroySecret(secret); }
static void test_BCryptEnumContextFunctions(void) @@ -3703,6 +3897,39 @@ static void test_SecretAgreement(void)
status = BCryptCloseAlgorithmProvider(alg, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + /* DH */ + status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_DH_ALGORITHM, NULL, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + key = NULL; + status = BCryptGenerateKeyPair(alg, &key, 1024, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(key != NULL, "key not set\n"); + + status = BCryptFinalizeKeyPair(key, 0); + if (status == STATUS_INVALID_PARAMETER) + { + win_skip("broken DH detected\n"); + BCryptCloseAlgorithmProvider(alg, 0); + return; + } + todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + status = BCryptSecretAgreement(key, key, &secret, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); + todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + status = BCryptCloseAlgorithmProvider(alg, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); }
static void test_RC4(void)