Support for generating keys from known DH parameters is not included unfortunately because even the latest stable GnuTLS release doesn't have the necessary support. I have a patch that implements it using _gnutls_dh_generate_key() but that requires a special GnuTLS 3.8.2 build (--enable-fips140-mode). With that patch all included tests pass here.
Paul, can you take a look? I included your tests so please approve this MR if you think it's okay.
-- v3: bcrypt/tests: Add DH tests. bcrypt: Set dh_params in key_import_dh/_public(). bcrypt: Assume we have a public key in key_export_dh_public(). bcrypt: Make sure key_asymmetric_derive_key() returns correct size. bcrypt: Add support for generating DH keys from known parameters. bcrypt: Reject DH keys smaller than 512 bits. bcrypt: Make DH blob size validation more strict in key_import_pair(). bcrypt: Add helpers to create a public/private key pair. bcrypt: Allow or disallow some operations based on whether keys are finalized. bcrypt: Add support for retrieving DH parameters. bcrypt: Add support for setting DH parameters.
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_internal.h | 6 +++-- dlls/bcrypt/bcrypt_main.c | 15 +++++++++++++ dlls/bcrypt/gnutls.c | 41 ++++++++++++++++++++++++++++++++--- include/bcrypt.h | 13 +++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index cfbc5d2ac83..a31d170c621 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -187,7 +187,7 @@ struct key { struct object hdr; enum alg_id alg_id; - UINT64 private[2]; /* private data for backend */ + UINT64 private[3]; /* private data for backend */ union { struct key_symmetric s; @@ -294,7 +294,9 @@ struct key_asymmetric_export_params ULONG *ret_len; };
-#define KEY_IMPORT_FLAG_PUBLIC 0x00000001 +#define KEY_IMPORT_FLAG_PUBLIC 0x00000001 +#define KEY_IMPORT_FLAG_DH_PARAMETERS 0x00000002 + struct key_asymmetric_import_params { struct key *key; diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 26472cbfe2b..2f8fd75c06a 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -887,6 +887,21 @@ static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *val key->u.a.bitlen = *(DWORD*)value; return STATUS_SUCCESS; } + else if (!wcscmp( prop, BCRYPT_DH_PARAMETERS )) + { + BCRYPT_DH_PARAMETER_HEADER *hdr = (BCRYPT_DH_PARAMETER_HEADER *)value; + struct key_asymmetric_import_params params; + + if (key->alg_id != ALG_ID_DH || size < sizeof(*hdr) || hdr->cbLength != size || + hdr->dwMagic != BCRYPT_DH_PARAMETERS_MAGIC || hdr->cbKeyLength != key->u.a.bitlen / 8) + return STATUS_INVALID_PARAMETER; + + params.key = key; + params.flags = KEY_IMPORT_FLAG_DH_PARAMETERS; + params.buf = value; + params.len = size; + return UNIX_CALL( key_asymmetric_import, ¶ms ); + }
FIXME( "unsupported key property %s\n", debugstr_w(prop) ); return STATUS_NOT_IMPLEMENTED; diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 68f84a553d2..0d912e7a2d7 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -84,8 +84,9 @@ union key_data gnutls_cipher_hd_t cipher; struct { - gnutls_privkey_t privkey; - gnutls_pubkey_t pubkey; + gnutls_privkey_t privkey; + gnutls_pubkey_t pubkey; + gnutls_dh_params_t dh_params; } a; }; C_ASSERT( sizeof(union key_data) <= sizeof(((struct key *)0)->private) ); @@ -1833,6 +1834,36 @@ static NTSTATUS key_import_dh( struct key *key, UCHAR *buf, ULONG len ) return STATUS_SUCCESS; }
+static NTSTATUS key_import_dh_params( struct key *key, UCHAR *buf, ULONG len ) +{ + BCRYPT_DH_PARAMETER_HEADER *dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buf; + gnutls_dh_params_t params; + gnutls_datum_t p, g; + int ret; + + if ((ret = pgnutls_dh_params_init( ¶ms ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + p.data = (unsigned char *)(dh_header + 1); + p.size = dh_header->cbKeyLength; + g.data = p.data + dh_header->cbKeyLength; + g.size = dh_header->cbKeyLength; + + if ((ret = pgnutls_dh_params_import_raw( params, &p, &g ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); + return STATUS_INTERNAL_ERROR; + } + + if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); + key_data(key)->a.dh_params = params; + return STATUS_SUCCESS; +} + static NTSTATUS key_asymmetric_import( void *args ) { const struct key_asymmetric_import_params *params = args; @@ -1875,9 +1906,12 @@ static NTSTATUS key_asymmetric_import( void *args ) return STATUS_NOT_IMPLEMENTED;
case ALG_ID_DH: + if (flags & KEY_IMPORT_FLAG_DH_PARAMETERS) + return key_import_dh_params( key, params->buf, params->len ); 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 ); + ret = key_import_dh( key, params->buf, params->len ); + break;
default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); @@ -2300,6 +2334,7 @@ static NTSTATUS key_asymmetric_destroy( void *args )
if (key_data(key)->a.privkey) pgnutls_privkey_deinit( key_data(key)->a.privkey ); if (key_data(key)->a.pubkey) pgnutls_pubkey_deinit( key_data(key)->a.pubkey ); + if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); return STATUS_SUCCESS; }
diff --git a/include/bcrypt.h b/include/bcrypt.h index 7f768f61679..462c43a7021 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -118,6 +118,8 @@ typedef LONG NTSTATUS; #define BCRYPT_KDF_TLS_PRF L"TLS_PRF" #define BCRYPT_KDF_SP80056A_CONCAT L"SP800_56A_CONCAT" #define BCRYPT_KDF_RAW_SECRET L"TRUNCATE" + +#define BCRYPT_DH_PARAMETERS L"DHParameters" #else static const WCHAR BCRYPT_ALGORITHM_NAME[] = {'A','l','g','o','r','i','t','h','m','N','a','m','e',0}; static const WCHAR BCRYPT_AUTH_TAG_LENGTH[] = {'A','u','t','h','T','a','g','L','e','n','g','t','h',0}; @@ -198,6 +200,8 @@ static const WCHAR BCRYPT_KDF_HMAC[] = {'H','M','A','C',0}; static const WCHAR BCRYPT_KDF_TLS_PRF[] = {'T','L','S','_','P','R','F',0}; static const WCHAR BCRYPT_KDF_SP80056A_CONCAT[] = {'S','P','8','0','0','_','5','6','A','_','C','O','N','C','A','T',0}; static const WCHAR BCRYPT_KDF_RAW_SECRET[] = {'T','R','U','N','C','A','T','E',0}; + +static const WCHAR BCRYPT_DH_PARAMETERS[] = {'D','H','P','a','r','a','m','e','t','e','r','s',0}; #endif
#define BCRYPT_ECDSA_PUBLIC_P256_MAGIC 0x31534345 @@ -363,6 +367,15 @@ typedef struct _BCRYPT_DH_KEY_BLOB ULONG cbKey; } BCRYPT_DH_KEY_BLOB, *PBCRYPT_DH_KEY_BLOB;
+#define BCRYPT_DH_PARAMETERS_MAGIC 0x4d504844 + +typedef struct _BCRYPT_DH_PARAMETER_HEADER +{ + ULONG cbLength; + ULONG dwMagic; + ULONG cbKeyLength; +} BCRYPT_DH_PARAMETER_HEADER; + #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_internal.h | 6 +++-- dlls/bcrypt/bcrypt_main.c | 17 +++++++++++++++ dlls/bcrypt/gnutls.c | 41 ++++++++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index a31d170c621..a5dbeff4e8e 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -283,8 +283,10 @@ struct key_asymmetric_verify_params unsigned flags; };
-#define KEY_EXPORT_FLAG_PUBLIC 0x00000001 -#define KEY_EXPORT_FLAG_RSA_FULL 0x00000002 +#define KEY_EXPORT_FLAG_PUBLIC 0x00000001 +#define KEY_EXPORT_FLAG_RSA_FULL 0x00000002 +#define KEY_EXPORT_FLAG_DH_PARAMETERS 0x00000004 + struct key_asymmetric_export_params { struct key *key; diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 2f8fd75c06a..ab41867f649 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -917,6 +917,20 @@ static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, U return status; }
+static NTSTATUS get_dh_property( const struct key *key, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) +{ + struct key_asymmetric_export_params params; + + if (wcscmp( prop, BCRYPT_DH_PARAMETERS )) return STATUS_NOT_SUPPORTED; + + params.key = (struct key *)key; + params.flags = KEY_EXPORT_FLAG_DH_PARAMETERS; + params.buf = buf; + params.len = size; + params.ret_len = ret_size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); +} + static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) { if (!wcscmp( prop, BCRYPT_KEY_STRENGTH )) @@ -940,6 +954,9 @@ static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHA if (!wcscmp( prop, BCRYPT_AUTH_TAG_LENGTH )) return STATUS_NOT_SUPPORTED; return get_aes_property( key->u.s.mode, prop, buf, size, ret_size );
+ case ALG_ID_DH: + return get_dh_property( key, prop, buf, size, ret_size ); + default: FIXME( "unsupported algorithm %u\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 0d912e7a2d7..4183aad6cec 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -1651,8 +1651,7 @@ static NTSTATUS key_export_dh( struct key *key, UCHAR *buf, ULONG len, ULONG *re return STATUS_INTERNAL_ERROR; }
- ret = pgnutls_privkey_export_dh_raw( key_data(key)->a.privkey, params, &y, &x, 0 ); - if (ret) + if ((ret = pgnutls_privkey_export_dh_raw( key_data(key)->a.privkey, params, &y, &x, 0 ))) { pgnutls_perror( ret ); pgnutls_dh_params_deinit( params ); @@ -1686,6 +1685,40 @@ static NTSTATUS key_export_dh( struct key *key, UCHAR *buf, ULONG len, ULONG *re return STATUS_SUCCESS; }
+static NTSTATUS key_export_dh_params( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len ) +{ + BCRYPT_DH_PARAMETER_HEADER *hdr = (BCRYPT_DH_PARAMETER_HEADER *)buf; + unsigned int size = sizeof(*hdr) + key->u.a.bitlen / 8 * 2; + gnutls_datum_t p, g; + NTSTATUS status = STATUS_SUCCESS; + UCHAR *dst; + int ret; + + if (!key_data(key)->a.dh_params) return STATUS_INVALID_PARAMETER; + + if ((ret = pgnutls_dh_params_export_raw( key_data(key)->a.dh_params, &p, &g, NULL ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + *ret_len = size; + if (len < size) status = STATUS_BUFFER_TOO_SMALL; + else if (buf) + { + hdr->cbLength = size; + hdr->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; + hdr->cbKeyLength = key->u.a.bitlen / 8; + + dst = (UCHAR *)(hdr + 1); + dst += export_gnutls_datum( dst, hdr->cbKeyLength, &p, 1 ); + dst += export_gnutls_datum( dst, hdr->cbKeyLength, &g, 1 ); + } + + free( p.data ); free( g.data ); + return status; +} + static NTSTATUS key_asymmetric_export( void *args ) { const struct key_asymmetric_export_params *params = args; @@ -1720,7 +1753,9 @@ static NTSTATUS key_asymmetric_export( void *args ) return STATUS_NOT_IMPLEMENTED;
case ALG_ID_DH: - if (flags & KEY_EXPORT_FLAG_PUBLIC) + if (flags & KEY_EXPORT_FLAG_DH_PARAMETERS) + return key_export_dh_params( key, params->buf, params->len, params->ret_len ); + 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 );
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_internal.h | 1 + dlls/bcrypt/bcrypt_main.c | 47 +++++++++++++---------------------- dlls/bcrypt/gnutls.c | 2 ++ 3 files changed, 20 insertions(+), 30 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index a5dbeff4e8e..f6556eb2aaa 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -175,6 +175,7 @@ struct key_symmetric };
#define KEY_FLAG_LEGACY_DSA_V2 0x00000001 +#define KEY_FLAG_FINALIZED 0x00000002
struct key_asymmetric { diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index ab41867f649..f7a22634203 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -892,6 +892,7 @@ static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *val BCRYPT_DH_PARAMETER_HEADER *hdr = (BCRYPT_DH_PARAMETER_HEADER *)value; struct key_asymmetric_import_params params;
+ if (key->u.a.flags & KEY_FLAG_FINALIZED) return STATUS_INVALID_HANDLE; if (key->alg_id != ALG_ID_DH || size < sizeof(*hdr) || hdr->cbLength != size || hdr->dwMagic != BCRYPT_DH_PARAMETERS_MAGIC || hdr->cbKeyLength != key->u.a.bitlen / 8) return STATUS_INVALID_PARAMETER; @@ -922,6 +923,7 @@ static NTSTATUS get_dh_property( const struct key *key, const WCHAR *prop, UCHAR struct key_asymmetric_export_params params;
if (wcscmp( prop, BCRYPT_DH_PARAMETERS )) return STATUS_NOT_SUPPORTED; + if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_HANDLE;
params.key = (struct key *)key; params.flags = KEY_EXPORT_FLAG_DH_PARAMETERS; @@ -1735,9 +1737,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_ECCPRIVATE_BLOB )) { @@ -1782,9 +1781,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_RSAPUBLIC_BLOB )) { @@ -1807,9 +1803,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_RSAPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_RSAFULLPRIVATE_BLOB )) { @@ -1829,9 +1822,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, LEGACY_RSAPRIVATE_BLOB )) { @@ -1864,9 +1854,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, LEGACY_DSA_V2_PRIVATE_BLOB )) { @@ -1904,9 +1891,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, LEGACY_DSA_V2_PUBLIC_BLOB )) /* not supported on native */ { @@ -1940,9 +1924,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_DH_PRIVATE_BLOB )) { @@ -1962,9 +1943,6 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } - - *ret_key = key; - return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_DH_PUBLIC_BLOB )) { @@ -1984,13 +1962,19 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP key_destroy( key ); return status; } + } + else + { + FIXME( "unsupported key type %s\n", debugstr_w(type) ); + return STATUS_NOT_SUPPORTED; + }
+ if (!status) + { + key->u.a.flags |= KEY_FLAG_FINALIZED; *ret_key = key; - return STATUS_SUCCESS; } - - FIXME( "unsupported key type %s\n", debugstr_w(type) ); - return STATUS_NOT_SUPPORTED; + return status; }
NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE *ret_handle, @@ -2031,11 +2015,14 @@ NTSTATUS WINAPI BCryptGenerateKeyPair( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HAND NTSTATUS WINAPI BCryptFinalizeKeyPair( BCRYPT_KEY_HANDLE handle, ULONG flags ) { struct key *key = get_key_object( handle ); + NTSTATUS ret;
TRACE( "%p, %#lx\n", key, flags );
- if (!key) return STATUS_INVALID_HANDLE; - return UNIX_CALL( key_asymmetric_generate, key ); + if (!key || key->u.a.flags & KEY_FLAG_FINALIZED) return STATUS_INVALID_HANDLE; + + if (!(ret = UNIX_CALL( key_asymmetric_generate, key ))) key->u.a.flags |= KEY_FLAG_FINALIZED; + return ret; }
NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE decrypt_key, const WCHAR *type, diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 4183aad6cec..171895e94f5 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -1725,6 +1725,8 @@ static NTSTATUS key_asymmetric_export( void *args ) struct key *key = params->key; unsigned flags = params->flags;
+ if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_HANDLE; + switch (key->alg_id) { case ALG_ID_ECDH_P256:
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/gnutls.c | 67 +++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 23 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 171895e94f5..dbcfd723687 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -1005,6 +1005,48 @@ done: return status; }
+static gnutls_privkey_t create_privkey( gnutls_pk_algorithm_t pk_alg, unsigned int bitlen ) +{ + gnutls_privkey_t privkey; + int ret; + + if ((ret = pgnutls_privkey_init( &privkey ))) + { + pgnutls_perror( ret ); + return NULL; + } + + if ((ret = pgnutls_privkey_generate( privkey, pk_alg, bitlen, 0 ))) + { + pgnutls_perror( ret ); + pgnutls_privkey_deinit( privkey ); + return NULL; + } + + return privkey; +} + +static gnutls_pubkey_t create_pubkey_from_privkey( gnutls_privkey_t privkey ) +{ + gnutls_pubkey_t pubkey; + int ret; + + if ((ret = pgnutls_pubkey_init( &pubkey ))) + { + pgnutls_perror( ret ); + return NULL; + } + + if ((ret = pgnutls_pubkey_import_privkey( pubkey, privkey, 0, 0 ))) + { + pgnutls_perror( ret ); + pgnutls_pubkey_deinit( pubkey ); + return NULL; + } + + return pubkey; +} + static NTSTATUS key_asymmetric_generate( void *args ) { struct key *key = args; @@ -1012,7 +1054,6 @@ static NTSTATUS key_asymmetric_generate( void *args ) gnutls_privkey_t privkey; gnutls_pubkey_t pubkey; unsigned int bitlen; - int ret;
if (!libgnutls_handle) return STATUS_INTERNAL_ERROR; if (key_data(key)->a.privkey) return STATUS_INVALID_HANDLE; @@ -1052,30 +1093,10 @@ static NTSTATUS key_asymmetric_generate( void *args ) return STATUS_NOT_SUPPORTED; }
- if ((ret = pgnutls_privkey_init( &privkey ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - if ((ret = pgnutls_pubkey_init( &pubkey ))) - { - pgnutls_perror( ret ); - pgnutls_privkey_deinit( privkey ); - return STATUS_INTERNAL_ERROR; - } - - if ((ret = pgnutls_privkey_generate( privkey, pk_alg, bitlen, 0 ))) - { - pgnutls_perror( ret ); - pgnutls_privkey_deinit( privkey ); - pgnutls_pubkey_deinit( pubkey ); - return STATUS_INTERNAL_ERROR; - } - if ((ret = pgnutls_pubkey_import_privkey( pubkey, privkey, 0, 0 ))) + if (!(privkey = create_privkey( pk_alg, bitlen ))) return STATUS_INTERNAL_ERROR; + if (!(pubkey = create_pubkey_from_privkey( privkey ))) { - pgnutls_perror( ret ); pgnutls_privkey_deinit( privkey ); - pgnutls_pubkey_deinit( pubkey ); return STATUS_INTERNAL_ERROR; }
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index f7a22634203..274bb27d9e8 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1929,7 +1929,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP { BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)input;
- if (input_len < sizeof(*dh_blob)) return STATUS_INVALID_PARAMETER; + if (input_len != sizeof(*dh_blob) + dh_blob->cbKey * 4) return STATUS_INVALID_PARAMETER; if (alg->id != ALG_ID_DH || dh_blob->dwMagic != BCRYPT_DH_PRIVATE_MAGIC) return STATUS_NOT_SUPPORTED;
@@ -1948,7 +1948,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP { BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)input;
- if (input_len < sizeof(*dh_blob)) return STATUS_INVALID_PARAMETER; + if (input_len != sizeof(*dh_blob) + dh_blob->cbKey * 3) return STATUS_INVALID_PARAMETER; if (alg->id != ALG_ID_DH || dh_blob->dwMagic != BCRYPT_DH_PUBLIC_MAGIC) return STATUS_NOT_SUPPORTED;
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/bcrypt_main.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 274bb27d9e8..5bac53657c1 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1210,6 +1210,8 @@ static NTSTATUS key_asymmetric_create( enum alg_id alg_id, ULONG bitlen, struct return STATUS_NOT_IMPLEMENTED; }
+ if (alg_id == ALG_ID_DH && bitlen < 512) return STATUS_INVALID_PARAMETER; + if (!(key = calloc( 1, sizeof(*key) ))) return STATUS_NO_MEMORY; key->hdr.magic = MAGIC_KEY; key->alg_id = alg_id;
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/gnutls.c | 70 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 11 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index dbcfd723687..3592c685c56 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -79,6 +79,10 @@ typedef enum typedef struct gnutls_x509_spki_st *gnutls_x509_spki_t; #endif
+#if GUTLS_VERSION_MAJOR < 3 || (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR < 8) +#define GNUTLS_KEYGEN_DH 4 +#endif + union key_data { gnutls_cipher_hd_t cipher; @@ -132,11 +136,14 @@ static int (*pgnutls_privkey_export_rsa_raw)(gnutls_privkey_t, gnutls_datum_t *, gnutls_datum_t *); static int (*pgnutls_privkey_export_dsa_raw)(gnutls_privkey_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_import_rsa_raw)(gnutls_privkey_t, const gnutls_datum_t *, const gnutls_datum_t *, const gnutls_datum_t *, const gnutls_datum_t *, const gnutls_datum_t *, const gnutls_datum_t *, const gnutls_datum_t *, const gnutls_datum_t *);
+/* Not present in gnutls version < 3.5.0 */ +static int (*pgnutls_privkey_generate2)(gnutls_privkey_t, gnutls_pk_algorithm_t, unsigned int, unsigned int, + const gnutls_keygen_data_st *, unsigned); + /* Not present in gnutls version < 3.6.0 */ static int (*pgnutls_decode_rs_value)(const gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *); static int (*pgnutls_x509_spki_init)(gnutls_x509_spki_t *); @@ -263,12 +270,6 @@ static int compat_gnutls_pubkey_import_dsa_raw(gnutls_pubkey_t key, const gnutls return GNUTLS_E_UNKNOWN_PK_ALGORITHM; }
-static int compat_gnutls_privkey_generate(gnutls_privkey_t key, gnutls_pk_algorithm_t algo, unsigned int bits, - unsigned int flags) -{ - return GNUTLS_E_UNKNOWN_PK_ALGORITHM; -} - static int compat_gnutls_decode_rs_value(const gnutls_datum_t * sig_value, gnutls_datum_t * r, gnutls_datum_t * s) { return GNUTLS_E_INTERNAL_ERROR; @@ -347,6 +348,12 @@ static int compat_gnutls_pubkey_import_dh_raw(gnutls_pubkey_t pubkey, const gnut return GNUTLS_E_UNKNOWN_PK_ALGORITHM; }
+static int compat_gnutls_privkey_generate2(gnutls_privkey_t privkey, gnutls_pk_algorithm_t alg, unsigned int bits, + unsigned int flags, const gnutls_keygen_data_st *data, unsigned data_size) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + static void gnutls_log( int level, const char *msg ) { TRACE( "<%d> %s", level, msg ); @@ -419,7 +426,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR_OPT(gnutls_privkey_export_dsa_raw) 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_generate2) LOAD_FUNCPTR_OPT(gnutls_privkey_import_dh_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_import_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_privkey_import_rsa_raw) @@ -1005,7 +1012,8 @@ done: return status; }
-static gnutls_privkey_t create_privkey( gnutls_pk_algorithm_t pk_alg, unsigned int bitlen ) +static gnutls_privkey_t create_privkey( gnutls_pk_algorithm_t pk_alg, unsigned int bitlen, + const gnutls_keygen_data_st *data, unsigned int data_size ) { gnutls_privkey_t privkey; int ret; @@ -1016,7 +1024,7 @@ static gnutls_privkey_t create_privkey( gnutls_pk_algorithm_t pk_alg, unsigned i return NULL; }
- if ((ret = pgnutls_privkey_generate( privkey, pk_alg, bitlen, 0 ))) + if ((ret = pgnutls_privkey_generate2( privkey, pk_alg, bitlen, 0, data, data_size ))) { pgnutls_perror( ret ); pgnutls_privkey_deinit( privkey ); @@ -1047,6 +1055,29 @@ static gnutls_pubkey_t create_pubkey_from_privkey( gnutls_privkey_t privkey ) return pubkey; }
+static gnutls_dh_params_t get_dh_params( gnutls_privkey_t privkey ) +{ + gnutls_dh_params_t params; + gnutls_datum_t x; + int ret; + + if ((ret = pgnutls_dh_params_init( ¶ms ))) + { + pgnutls_perror( ret ); + return NULL; + } + + if ((ret = pgnutls_privkey_export_dh_raw( privkey, params, NULL, &x, 0 ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); + return NULL; + } + + free( x.data ); + return params; +} + static NTSTATUS key_asymmetric_generate( void *args ) { struct key *key = args; @@ -1093,7 +1124,24 @@ static NTSTATUS key_asymmetric_generate( void *args ) return STATUS_NOT_SUPPORTED; }
- if (!(privkey = create_privkey( pk_alg, bitlen ))) return STATUS_INTERNAL_ERROR; + if (key->alg_id == ALG_ID_DH && key_data(key)->a.dh_params) + { + gnutls_keygen_data_st data; + + data.type = GNUTLS_KEYGEN_DH; + data.data = (unsigned char *)key_data(key)->a.dh_params; + data.size = 0; + if (!(privkey = create_privkey( pk_alg, bitlen, &data, 1 ))) return STATUS_INTERNAL_ERROR; + } + else if (!(privkey = create_privkey( pk_alg, bitlen, NULL, 0 ))) return STATUS_INTERNAL_ERROR; + + if (key->alg_id == ALG_ID_DH && !key_data(key)->a.dh_params && + !(key_data(key)->a.dh_params = get_dh_params( privkey ))) + { + pgnutls_privkey_deinit( privkey ); + return STATUS_INTERNAL_ERROR; + } + if (!(pubkey = create_pubkey_from_privkey( privkey ))) { pgnutls_privkey_deinit( privkey );
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/gnutls.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 3592c685c56..1e5a81d9366 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -2671,6 +2671,7 @@ static NTSTATUS key_asymmetric_derive_key( void *args ) { const struct key_asymmetric_derive_key_params *params = args; gnutls_datum_t s; + NTSTATUS status = STATUS_SUCCESS; int ret;
if ((ret = pgnutls_privkey_derive_secret( key_data(params->privkey)->a.privkey, @@ -2680,15 +2681,15 @@ static NTSTATUS key_asymmetric_derive_key( void *args ) return STATUS_INTERNAL_ERROR; }
- if (!params->output) *params->ret_len = s.size; - else + *params->ret_len = EXPORT_SIZE( s, params->privkey->u.a.bitlen / 8, 1 ); + if (params->output) { - *params->ret_len = min( params->output_len, s.size ); - memcpy( params->output, s.data, *params->ret_len ); + if (params->output_len < *params->ret_len) status = STATUS_BUFFER_TOO_SMALL; + else export_gnutls_datum( params->output, *params->ret_len, &s, 1 ); }
free( s.data ); - return STATUS_SUCCESS; + return status; }
const unixlib_entry_t __wine_unix_call_funcs[] =
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/gnutls.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 1e5a81d9366..f7df47674c6 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -1657,7 +1657,7 @@ static NTSTATUS key_export_dh_public( struct key *key, UCHAR *buf, ULONG len, UL 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}; + gnutls_datum_t p, g, y; UCHAR *dst; int ret = GNUTLS_E_INVALID_REQUEST;
@@ -1667,12 +1667,7 @@ static NTSTATUS key_export_dh_public( struct key *key, UCHAR *buf, ULONG len, UL 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) + if ((ret = pgnutls_pubkey_export_dh_raw( key_data(key)->a.pubkey, params, &y, 0 ))) { pgnutls_perror( ret ); pgnutls_dh_params_deinit( params ); @@ -1682,7 +1677,7 @@ static NTSTATUS key_export_dh_public( struct key *key, UCHAR *buf, ULONG len, UL if ((ret = pgnutls_dh_params_export_raw( params, &p, &g, NULL )) < 0) { pgnutls_perror( ret ); - free( y.data ); free( x.data ); + free( y.data ); pgnutls_dh_params_deinit( params ); return STATUS_INTERNAL_ERROR; } @@ -1699,7 +1694,7 @@ static NTSTATUS key_export_dh_public( struct key *key, UCHAR *buf, ULONG len, UL dh_blob->cbKey = size; }
- free( p.data ); free( g.data ); free( y.data ); free( x.data ); + free( p.data ); free( g.data ); free( y.data ); return STATUS_SUCCESS; }
From: Hans Leidekker hans@codeweavers.com
--- dlls/bcrypt/gnutls.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index f7df47674c6..512731dfcd3 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -1868,17 +1868,19 @@ static NTSTATUS key_import_dh_public( struct key *key, UCHAR *buf, ULONG len ) return STATUS_INTERNAL_ERROR; }
- ret = pgnutls_pubkey_import_dh_raw( handle, params, &y ); - pgnutls_dh_params_deinit( params ); - if (ret < 0) + if ((ret = pgnutls_pubkey_import_dh_raw( handle, params, &y ))) { pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); 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; + + if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); + key_data(key)->a.dh_params = params; return STATUS_SUCCESS; }
@@ -1921,17 +1923,19 @@ static NTSTATUS key_import_dh( struct key *key, UCHAR *buf, ULONG len ) return STATUS_INTERNAL_ERROR; }
- ret = pgnutls_privkey_import_dh_raw( handle, params, &y, &x ); - pgnutls_dh_params_deinit( params ); - if (ret < 0) + if ((ret = pgnutls_privkey_import_dh_raw( handle, params, &y, &x ))) { pgnutls_perror( ret ); + pgnutls_dh_params_deinit( params ); 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; + + if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); + key_data(key)->a.dh_params = params; return STATUS_SUCCESS; }
From: Hans Leidekker hans@codeweavers.com
Mostly written by Paul Gofman. --- dlls/bcrypt/tests/bcrypt.c | 326 ++++++++++++++++++++++++++++++++++++- 1 file changed, 323 insertions(+), 3 deletions(-)
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 45e03e5d15b..5262130bbe7 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -3835,11 +3835,113 @@ static void test_DSA(void)
static void test_SecretAgreement(void) { - BCRYPT_SECRET_HANDLE secret; + static BCryptBuffer hash_param_buffers[] = + { + { + sizeof(BCRYPT_SHA256_ALGORITHM), + KDF_HASH_ALGORITHM, + (void *)BCRYPT_SHA256_ALGORITHM, + } + }; + static BCryptBufferDesc hash_params = + { + BCRYPTBUFFER_VERSION, + ARRAY_SIZE(hash_param_buffers), + hash_param_buffers, + }; + + static const ULONG dh_private_key[] = + { + 0xc4caf69c, 0x57b4db27, 0x36f7135f, 0x5ccba686, 0xc37b8819, 0x1d35c9b2, 0xbb07a1cf, 0x0c5d1c1b, + 0xc79acb10, 0x31dfdabb, 0x702e02b9, 0x1efab345, 0x262a8074, 0x5edf7698, 0x9b9dc630, 0x13c34b93, + 0xacbc928b, 0xb79eed8c, 0x7413dce9, 0xa5521280, 0x88d8e695, 0xa310269f, 0xca7c5719, 0xcd0c775b, + 0x9a6e2cf2, 0x9e235c51, 0xf49db62d, 0x28e72424, 0x4a44da5a, 0x3d98268d, 0x8e4d2be3, 0x254e44e6, + + 0x18a67e55, 0x572e13a1, 0x46f81ca8, 0xc331c9b9, 0xf8fe3dd4, 0x8a889e5a, 0x6c0505fd, 0xbd97a121, + 0xed2dbd67, 0xf39efa8e, 0x36f9c287, 0xf6bbfa6c, 0x461e42ad, 0x17dc170e, 0xc002dc2e, 0x4813d9a4, + 0x0b6fabb8, 0x6a9e1860, 0xa8a8cbd9, 0xb7ed6b5d, 0xabb34d23, 0xf2fbe1fd, 0x8670df1e, 0xba7fa4e6, + 0xf7039712, 0x94448f30, 0xe10c812e, 0x3e311976, 0xcfdd72c4, 0xbdbea98f, 0xc9a540d6, 0x89646d57, + + 0x7ab63b33, 0x03a1e9b6, 0x947f7a9b, 0x5ae59eeb, 0x1d12eb05, 0x3f425d92, 0xe028c6ba, 0xbf90ddc9, + 0xb554f55a, 0x7aeb88b6, 0x4a443a5f, 0xbab35111, 0x82c78a0c, 0x298dd482, 0x02937cb1, 0xc94cdc2e, + 0x59b010eb, 0x3bbc0a2b, 0xd845fee0, 0x04c1d0db, 0x0c8c9424, 0x1cafd4b2, 0x9aa7aed9, 0x6a478486, + 0xa8841fd7, 0xbfeff40a, 0x8fd7bcc5, 0x3bb28977, 0x2b9a7955, 0xa55cd2e4, 0x1b6ad657, 0x067cdf21, + + 0x06f36920, 0x63280e1b, 0xf17d930f, 0xa06e74a8, 0x463b3a6f, 0x2a464507, 0x93f8a982, 0x8f620a7d, + 0xeda32d11, 0x9706a6d4, 0x33dce588, 0x75a1c446, 0x048ab567, 0xd735aafa, 0x806f7c1c, 0xdcb9651a, + 0x26acf3b4, 0x45f91cc9, 0x2a0de6fc, 0xf3c03d0c, 0xf5aee0aa, 0x3eeaaf36, 0x18ccee61, 0x83faa783, + 0x4b2b5250, 0xf4ccea22, 0x5ac0714b, 0x3f0b2bc6, 0x481b13ce, 0x12040ea7, 0x66e0bbed, 0x158e1a67, + }; + static const ULONG dh_private_key2[] = + { + 0xffffffff, 0xffffffff, 0xa2da0fc9, 0x34c26821, 0x8b62c6c4, 0xd11cdc80, 0x084e0229, 0x74cc678a, + 0xa6be0b02, 0x229b133b, 0x79084a51, 0xdd04348e, 0xb31995ef, 0x1b433acd, 0x6d0a2b30, 0x37145ff2, + 0x6d35e14f, 0x45c2516d, 0x76b585e4, 0xc67e5e62, 0xe9424cf4, 0x6bed37a6, 0xb65cff0b, 0xedb706f4, + 0xfb6b38ee, 0xa59f895a, 0x11249fae, 0xe61f4b7c, 0x51662849, 0x8153e6ec, 0xffffffff, 0xffffffff, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, + + 0xa0c3c734, 0xc130c92d, 0x5265abf8, 0xff409f17, 0xbcdce187, 0xff64dae3, 0x170560aa, 0xb2423ed8, + 0x9ee5a8b9, 0x92548030, 0x02bba1f9, 0x823e39a4, 0x69c438f5, 0xf91016ac, 0x89bfd166, 0x7f996446, + 0x86224203, 0x15bf689c, 0x619354a4, 0x0c1d3a1f, 0x11bcf3d2, 0x58aae029, 0x41c69824, 0x3fafc179, + 0xa742747c, 0x60658c7a, 0xd3b0bde4, 0x78d3f08b, 0x6cefa061, 0x33752536, 0xe84d4901, 0x48cd73f4, + + 0x8d449700, 0x1f95120e, 0xceb31745, 0x3663177b, 0xbd9bb2d5, 0x9c23c0d9, 0x814d34f8, 0xbc54edb0, + 0xb874659a, 0x3bac8a30, 0xa1f3dd46, 0x1705c900, 0xbc46fefe, 0x7d13875b, 0x3064351a, 0x4bd89a1c, + 0x9e938761, 0x931949db, 0x34490719, 0x84fb08ca, 0xa9dd355a, 0x5b3f5061, 0x2ac96663, 0xc594429e, + 0xbe58395d, 0x2f7d872a, 0x303d37b3, 0xa3a9b606, 0x735a6732, 0xa095bd95, 0x3d55a7c3, 0x00e54635, + }; + static const ULONG dh_peer_key[] = + { + 0xffffffff, 0xffffffff, 0xa2da0fc9, 0x34c26821, 0x8b62c6c4, 0xd11cdc80, 0x084e0229, 0x74cc678a, + 0xa6be0b02, 0x229b133b, 0x79084a51, 0xdd04348e, 0xb31995ef, 0x1b433acd, 0x6d0a2b30, 0x37145ff2, + 0x6d35e14f, 0x45c2516d, 0x76b585e4, 0xc67e5e62, 0xe9424cf4, 0x6bed37a6, 0xb65cff0b, 0xedb706f4, + 0xfb6b38ee, 0xa59f895a, 0x11249fae, 0xe61f4b7c, 0x51662849, 0x8153e6ec, 0xffffffff, 0xffffffff, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, + + 0x3bf7404b, 0x6284fffe, 0x97c0d565, 0xd830c658, 0xcc21bf39, 0xcae45bb6, 0x019df7df, 0xbf4cd293, + 0x6bf1989d, 0x78a81f52, 0xa4ed861c, 0x6bacf493, 0xa3e700d1, 0xd06cc206, 0x411b9727, 0x01e9c9ab, + 0x9b7e6efa, 0xf46bb25d, 0xd1027242, 0x6130787c, 0xa7b87d8b, 0xfee41492, 0x50db6213, 0x321199b6, + 0x7dace53a, 0xe8b1ec51, 0x2181b113, 0x3b33e3c0, 0x5b3a2d67, 0xbd34f0c1, 0x7037c542, 0x4a8d5540, + }; + static const ULONG dh_shared_secret_raw[] = + { + 0x375d89b5, 0x35a9c270, 0xfbc5ba82, 0x09eb3069, 0xd50965b0, 0xace510f7, 0x981e8731, 0x80a76115, + 0xf386d348, 0xca17b8df, 0x0b0e84ec, 0xf81f756e, 0x5030fa20, 0x03113b71, 0x97b7e879, 0x899b5fae, + 0xe6913299, 0x09270076, 0x39bc813a, 0xde3ef070, 0x65ad5b3a, 0x2b7c4ba4, 0x86c98ef9, 0x3236feaf, + 0x3e0253f7, 0x0489d2dd, 0x97669a3d, 0x50242fca, 0x5d4aecb1, 0xcf2d805f, 0x2258afff, 0x750e92cd, + }; + static const ULONG dh_shared_secret_raw2[] = + { + 0x0815f37d, 0x19ee74ab, 0x9f63f123, 0xe1b3f10c, 0xbcc9be83, 0xaddf5b9d, 0x28174e72, 0xf8a33825, + 0xfc74e47d, 0x2c950888, 0xf5b776d9, 0xfc712fef, 0x5b213b32, 0x489a9829, 0xfc0a4d1d, 0x6e641d3b, + 0x3bb2ff57, 0x63500318, 0x081ee54f, 0xf33a2805, 0xb3759e98, 0xa9a64afe, 0x964b8897, 0x04691bbc, + 0x80f4aae1, 0x617405ee, 0xab71724d, 0x6c10c214, 0x6f60b96f, 0xdc777b0b, 0x22f40d4f, 0x8a1c4eb5, + }; + static const ULONG dh_shared_secret_sha1[] = + { + 0x0babba9c, 0x0bdeacbd, 0x04e36574, 0xdd504dcd, 0x0cd88db0, + }; + static const ULONG dh_shared_secret_sha256[] = + { + 0x3213db5b, 0x8cc8250b, 0xc829eaab, 0x00933709, 0x68160aa9, 0xfb9f1e20, 0xf92368e6, 0x2b8e18eb, + }; + static const ULONG length = 1024; + BCRYPT_DH_PARAMETER_HEADER *dh_header; + BCRYPT_DH_KEY_BLOB *dh_key_blob; + BCRYPT_SECRET_HANDLE secret, secret2; BCRYPT_ALG_HANDLE alg; - BCRYPT_KEY_HANDLE key; + BCRYPT_KEY_HANDLE key, key2; + UCHAR buffer[2048]; NTSTATUS status; - ULONG size; + ULONG size, i;
status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDH_P256_ALGORITHM, NULL, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); @@ -3928,6 +4030,224 @@ static void test_SecretAgreement(void) status = BCryptDestroySecret(secret); ok(status == STATUS_SUCCESS, "got %#lx\n", status);
+ key = NULL; + status = BCryptGenerateKeyPair(alg, &key, 256, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptGenerateKeyPair(alg, &key, length, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(key != NULL, "key not set\n"); + + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptFinalizeKeyPair(key, 0); + if (status != STATUS_SUCCESS) + { + BCryptDestroyKey(key); + BCryptCloseAlgorithmProvider(alg, 0); + return; + } + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptFinalizeKeyPair(key, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, NULL, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, 28, &size, 0); + ok(status == STATUS_BUFFER_TOO_SMALL, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buffer; + ok(dh_header->cbLength == sizeof(*dh_header) + length / 8 * 2, "Got unexpected length %lu.\n", dh_header->cbLength); + ok(dh_header->cbKeyLength == length / 8, "Got unexpected length %lu.\n", dh_header->cbKeyLength); + ok(dh_header->dwMagic == BCRYPT_DH_PARAMETERS_MAGIC, "Got unexpected magic %#lx.\n", dh_header->dwMagic); + + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, dh_private_key, sizeof(dh_private_key)); + size = sizeof(buffer); + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + size = sizeof(*dh_key_blob) + length / 8 * 4; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + memset(buffer, 0xcc, sizeof(buffer)); + size = 0xdeadbeef; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + ok(dh_key_blob->dwMagic == BCRYPT_DH_PUBLIC_MAGIC, "Got unexpected magic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, dh_private_key, length / 8 * 3), "Key data does not match.\n"); + + status = BCryptGenerateKeyPair(alg, &key2, length, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buffer; + dh_header->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; + dh_header->cbLength = sizeof(*dh_header) + length / 8 * 2; + dh_header->cbKeyLength = length / 8; + memcpy(dh_header + 1, dh_private_key, length / 8 * 2); + status = BCryptSetProperty(key2, BCRYPT_DH_PARAMETERS, buffer, dh_header->cbLength, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptFinalizeKeyPair(key2, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptExportKey(key2, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + ok(dh_key_blob->dwMagic == BCRYPT_DH_PUBLIC_MAGIC, "Got unexpected dwMagic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + todo_wine ok(!memcmp(dh_key_blob + 1, dh_private_key, length / 8 * 2), "DH parameters do not match.\n"); + ok(memcmp((BYTE *)(dh_key_blob + 1) + length / 8 * 2, (BYTE *)dh_private_key + length / 8 * 2, length / 8), + "Random public key data matches.\n"); + + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptExportKey(key, NULL, BCRYPT_DH_PRIVATE_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 4, "Got unexpected size %lu.\n", size); + ok(dh_key_blob->dwMagic == BCRYPT_DH_PRIVATE_MAGIC, "Got unexpected dwMagic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, dh_private_key, length / 8 * 4), "Private key data does not match.\n"); + + status = BCryptSecretAgreement(NULL, key, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, NULL, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(NULL, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDeriveKey(key, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, NULL, NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + size = 0xdeadbeef; + status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == 20, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, dh_shared_secret_raw, size), "Raw shared secret data does not match.\n"); + + size = sizeof(buffer); + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == 20, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, dh_shared_secret_sha1, sizeof(dh_shared_secret_sha1)), + "sha1 shared secret data does not match.\n"); + + size = sizeof(buffer); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, buffer, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == 32, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, dh_shared_secret_sha256, sizeof(dh_shared_secret_sha256)), + "sha256 shared secret data does not match.\n"); + + for (i = size; i < sizeof(buffer); ++i) + if (buffer[i] != 0xcc) break; + ok(i == sizeof(buffer), "Buffer modified at %lu, value %#x.\n", i, buffer[i]); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key2, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptSecretAgreement(key2, key, &secret2, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer + size, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(!memcmp(buffer, buffer + size, size), "Shared secrets do not match.\n"); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroySecret(secret2); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key2); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, dh_private_key2, sizeof(dh_private_key2)); + + size = sizeof(*dh_key_blob) + length / 8 * 4; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, dh_peer_key, sizeof(dh_peer_key)); + + size = sizeof(*dh_key_blob) + length / 8 * 3; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PUBLIC_BLOB, &key2, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key2, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, dh_shared_secret_raw2, size), "Raw shared secret data does not match.\n"); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key2); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptCloseAlgorithmProvider(alg, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); }
This merge request was approved by Paul Gofman.
On Mon Dec 11 15:28:19 2023 +0000, Hans Leidekker wrote:
key_import_dh() does set the public key but you are right that dh_params isn't set in key_import_dh/_public(). I'll fix that.
Yes, sorry, I missed that key_import_dh() is breaking to the common pubkey initialization.