This is needed because BCryptFinalizeKey doesn't change the pubkey_len member based on the keylen member. Also it doesn't reallocate the pubkey buffer. If we don't do this programs get an error when trying to generate a key by setting the length using BCryptSetProperty.
Signed-off-by: Santino Mazza mazzasantino1206@gmail.com --- dlls/bcrypt/bcrypt_main.c | 19 ++++++++++++++++++- dlls/bcrypt/tests/bcrypt.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 5df4da009a4..2b3ceb803a0 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -704,7 +704,24 @@ static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *val else if (!wcscmp( prop, BCRYPT_KEY_LENGTH )) { if (size < sizeof(DWORD)) return STATUS_INVALID_PARAMETER; - key->u.a.bitlen = *(DWORD*)value; + if (key->u.a.bitlen == *(DWORD *)value) return STATUS_SUCCESS; + + key->u.a.bitlen = *(DWORD *)value; + switch (key->alg_id) + { + case ALG_ID_RSA: + case ALG_ID_RSA_SIGN: + key->u.a.pubkey_len = sizeof(BCRYPT_RSAKEY_BLOB) + 2 * key->u.a.bitlen / 8; + break; + case ALG_ID_DSA: + key->u.a.pubkey_len = sizeof(BCRYPT_DSA_KEY_BLOB) + 3 * key->u.a.bitlen / 8; + break; + default: + FIXME( "algorithm %u not supported\n", key->alg_id ); + return STATUS_NOT_SUPPORTED; + } + + key->u.a.pubkey = realloc( key->u.a.pubkey, key->u.a.pubkey_len ); return STATUS_SUCCESS; }
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index efb5843fa4e..3b4fd3e31e7 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2182,6 +2182,19 @@ static void test_RSA(void) HeapFree(GetProcessHeap(), 0, buf); BCryptDestroyKey(key);
+ /* generate rsa keys setting the key len by using properties */ + key = NULL; + ret = BCryptGenerateKeyPair(alg, &key, 1024, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(key != NULL, "got null handle\n"); + + keylen = 2048; + BCryptSetProperty(key, BCRYPT_KEY_LENGTH, (UCHAR *)&keylen, sizeof(keylen), 0); + + ret = BCryptFinalizeKeyPair(key, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + if(key) BCryptDestroyKey(key); + ret = BCryptCloseAlgorithmProvider(alg, 0); ok(!ret, "got %#lx\n", ret); } @@ -2867,6 +2880,7 @@ static void test_DSA(void) BCRYPT_DSA_KEY_BLOB *dsablob; UCHAR sig[40], schemes; ULONG len, size; + DWORD keylen; NTSTATUS ret; BYTE *buf;
@@ -2945,6 +2959,21 @@ static void test_DSA(void) ret = BCryptDestroyKey(key); ok(!ret, "got %#lx\n", ret);
+ /* generate dsa key by setting the key length */ + key = NULL; + ret = BCryptGenerateKeyPair(alg, &key, 512, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + + keylen = 1024; + ret = BCryptSetProperty(key, BCRYPT_KEY_LENGTH, (UCHAR *)&keylen, sizeof(keylen), 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + + ret = BCryptFinalizeKeyPair(key, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + + ret = BCryptDestroyKey(key); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ret = BCryptCloseAlgorithmProvider(alg, 0); ok(!ret, "got %#lx\n", ret); }
On Wed, 2022-03-16 at 22:24 -0300, Santino Mazza wrote:
This is needed because BCryptFinalizeKey doesn't change the pubkey_len member based on the keylen member. Also it doesn't reallocate the pubkey buffer. If we don't do this programs get an error when trying to generate a key by setting the length using BCryptSetProperty.
The deeper problem is that we're allocating the pubkey buffer too early. Avoiding that will take some restructuring. I'll take a look.