From: Hans Leidekker hans@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53972 --- dlls/bcrypt/gnutls.c | 175 +++++++++++++++++++++++++++++++------ dlls/bcrypt/tests/bcrypt.c | 47 ++++++---- include/bcrypt.h | 9 +- 3 files changed, 187 insertions(+), 44 deletions(-)
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index d5ffe88e2b4..9425cccd066 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -134,6 +134,11 @@ static int (*pgnutls_privkey_import_rsa_raw)(gnutls_privkey_t, const gnutls_datu
/* 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 *); +static void (*pgnutls_x509_spki_deinit)(gnutls_x509_spki_t); +static void (*pgnutls_x509_spki_set_rsa_pss_params)(gnutls_x509_spki_t, gnutls_digest_algorithm_t, unsigned int); +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);
static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f @@ -269,6 +274,30 @@ static int compat_gnutls_pubkey_encrypt_data(gnutls_pubkey_t key, unsigned int f return GNUTLS_E_UNKNOWN_PK_ALGORITHM; }
+static int compat_gnutls_x509_spki_init(gnutls_x509_spki_t *spki) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + +static void compat_gnutls_x509_spki_deinit(gnutls_x509_spki_t spki) +{ +} + +static void compat_gnutls_x509_spki_set_rsa_pss_params(gnutls_x509_spki_t spki, gnutls_digest_algorithm_t dig, + unsigned int salt_size) +{ +} + +static int compat_gnutls_pubkey_set_spki(gnutls_pubkey_t key, const gnutls_x509_spki_t spki, unsigned int flags) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + +static int compat_gnutls_privkey_set_spki(gnutls_privkey_t key, const gnutls_x509_spki_t spki, unsigned int flags) +{ + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; +} + static void gnutls_log( int level, const char *msg ) { TRACE( "<%d> %s", level, msg ); @@ -329,23 +358,29 @@ static NTSTATUS gnutls_process_attach( void *args )
LOAD_FUNCPTR_OPT(gnutls_cipher_tag) LOAD_FUNCPTR_OPT(gnutls_cipher_add_auth) + 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_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_import_ecc_raw) + 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_dsa_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_ecc_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_export_rsa_raw) + LOAD_FUNCPTR_OPT(gnutls_pubkey_import_dsa_raw) LOAD_FUNCPTR_OPT(gnutls_pubkey_import_ecc_raw) - LOAD_FUNCPTR_OPT(gnutls_privkey_export_rsa_raw) - LOAD_FUNCPTR_OPT(gnutls_privkey_export_ecc_raw) - LOAD_FUNCPTR_OPT(gnutls_privkey_import_ecc_raw) - LOAD_FUNCPTR_OPT(gnutls_privkey_export_dsa_raw) - LOAD_FUNCPTR_OPT(gnutls_pk_to_sign) - LOAD_FUNCPTR_OPT(gnutls_pubkey_verify_hash2) LOAD_FUNCPTR_OPT(gnutls_pubkey_import_rsa_raw) - LOAD_FUNCPTR_OPT(gnutls_pubkey_import_dsa_raw) - LOAD_FUNCPTR_OPT(gnutls_privkey_generate) - LOAD_FUNCPTR_OPT(gnutls_decode_rs_value) - LOAD_FUNCPTR_OPT(gnutls_privkey_import_rsa_raw) - LOAD_FUNCPTR_OPT(gnutls_privkey_decrypt_data) - LOAD_FUNCPTR_OPT(gnutls_pubkey_encrypt_data) + LOAD_FUNCPTR_OPT(gnutls_pubkey_set_spki) + LOAD_FUNCPTR_OPT(gnutls_pubkey_verify_hash2) + LOAD_FUNCPTR_OPT(gnutls_x509_spki_deinit) + LOAD_FUNCPTR_OPT(gnutls_x509_spki_init) + LOAD_FUNCPTR_OPT(gnutls_x509_spki_set_rsa_pss_params) + #undef LOAD_FUNCPTR_OPT
if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS) @@ -1631,6 +1666,27 @@ static gnutls_digest_algorithm_t get_digest_from_id( const WCHAR *alg_id ) return GNUTLS_DIG_UNKNOWN; }
+static NTSTATUS pubkey_set_rsa_pss_params( gnutls_pubkey_t key, gnutls_digest_algorithm_t dig, unsigned int salt_size ) +{ + gnutls_x509_spki_t spki; + int ret; + + if (((ret = pgnutls_x509_spki_init( &spki ) < 0))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + pgnutls_x509_spki_set_rsa_pss_params( spki, dig, salt_size ); + ret = pgnutls_pubkey_set_spki( key, spki, 0 ); + pgnutls_x509_spki_deinit( spki ); + if (ret < 0) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + return STATUS_SUCCESS; +} + static NTSTATUS key_asymmetric_verify( void *args ) { const struct key_asymmetric_verify_params *params = args; @@ -1667,17 +1723,34 @@ static NTSTATUS key_asymmetric_verify( void *args ) case ALG_ID_RSA: case ALG_ID_RSA_SIGN: { - BCRYPT_PKCS1_PADDING_INFO *info = params->padding; - - if (!(flags & BCRYPT_PAD_PKCS1) || !info) return STATUS_INVALID_PARAMETER; - if (!info->pszAlgId) return STATUS_INVALID_SIGNATURE; - - if ((hash_alg = get_digest_from_id(info->pszAlgId)) == GNUTLS_DIG_UNKNOWN) + if (flags & BCRYPT_PAD_PKCS1) { - FIXME( "hash algorithm %s not supported\n", debugstr_w(info->pszAlgId) ); - return STATUS_NOT_SUPPORTED; + BCRYPT_PKCS1_PADDING_INFO *info = params->padding; + + if (!info) return STATUS_INVALID_PARAMETER; + if (!info->pszAlgId) return STATUS_INVALID_SIGNATURE; + if ((hash_alg = get_digest_from_id(info->pszAlgId)) == GNUTLS_DIG_UNKNOWN) + { + FIXME( "hash algorithm %s not supported\n", debugstr_w(info->pszAlgId) ); + return STATUS_NOT_SUPPORTED; + } + pk_alg = GNUTLS_PK_RSA; } - pk_alg = GNUTLS_PK_RSA; + else if (flags & BCRYPT_PAD_PSS) + { + BCRYPT_PSS_PADDING_INFO *info = params->padding; + + if (!info) return STATUS_INVALID_PARAMETER; + if (!info->pszAlgId) return STATUS_INVALID_SIGNATURE; + if ((hash_alg = get_digest_from_id(info->pszAlgId)) == GNUTLS_DIG_UNKNOWN) + { + FIXME( "hash algorithm %s not supported\n", debugstr_w(info->pszAlgId) ); + return STATUS_NOT_SUPPORTED; + } + if ((status = pubkey_set_rsa_pss_params( key_data(key)->a.pubkey, hash_alg, info->cbSalt ))) return status; + pk_alg = GNUTLS_PK_RSA_PSS; + } + else return STATUS_INVALID_PARAMETER; break; } case ALG_ID_DSA: @@ -1777,12 +1850,32 @@ static NTSTATUS format_gnutls_signature( enum alg_id type, gnutls_datum_t signat } }
+static NTSTATUS privkey_set_rsa_pss_params( gnutls_privkey_t key, gnutls_digest_algorithm_t dig, unsigned int salt_size ) +{ + gnutls_x509_spki_t spki; + int ret; + + if (((ret = pgnutls_x509_spki_init( &spki ) < 0))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + pgnutls_x509_spki_set_rsa_pss_params( spki, dig, salt_size ); + ret = pgnutls_privkey_set_spki( key, spki, 0 ); + pgnutls_x509_spki_deinit( spki ); + if (ret < 0) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + return STATUS_SUCCESS; +} + static NTSTATUS key_asymmetric_sign( void *args ) { const struct key_asymmetric_sign_params *params = args; struct key *key = params->key; - unsigned flags = params->flags; - BCRYPT_PKCS1_PADDING_INFO *pad = params->padding; + unsigned int flags = params->flags, gnutls_flags = 0; gnutls_datum_t hash, signature; gnutls_digest_algorithm_t hash_alg; NTSTATUS status; @@ -1803,10 +1896,14 @@ static NTSTATUS key_asymmetric_sign( void *args ) return STATUS_INVALID_PARAMETER; }
- if (flags == BCRYPT_PAD_PKCS1 && pad && pad->pszAlgId && get_digest_from_id( pad->pszAlgId ) != hash_alg) + if (flags == BCRYPT_PAD_PKCS1) { - WARN( "incorrect hashing algorithm %s, expected %u\n", debugstr_w(pad->pszAlgId), hash_alg ); - return STATUS_INVALID_PARAMETER; + BCRYPT_PKCS1_PADDING_INFO *pad = params->padding; + if (pad && pad->pszAlgId && get_digest_from_id( pad->pszAlgId ) != hash_alg) + { + WARN( "incorrect hashing algorithm %s, expected %u\n", debugstr_w(pad->pszAlgId), hash_alg ); + return STATUS_INVALID_PARAMETER; + } } } else if (key->alg_id == ALG_ID_DSA) @@ -1821,17 +1918,41 @@ static NTSTATUS key_asymmetric_sign( void *args ) } else if (flags == BCRYPT_PAD_PKCS1) { + BCRYPT_PKCS1_PADDING_INFO *pad = params->padding; + if (!pad || !pad->pszAlgId) { WARN( "padding info not found\n" ); return STATUS_INVALID_PARAMETER; } + if ((hash_alg = get_digest_from_id( pad->pszAlgId )) == GNUTLS_DIG_UNKNOWN) + { + FIXME( "hash algorithm %s not recognized\n", debugstr_w(pad->pszAlgId) ); + return STATUS_NOT_SUPPORTED; + } + } + else if (flags == BCRYPT_PAD_PSS) + { + BCRYPT_PSS_PADDING_INFO *pad = params->padding;
+ if (!pad || !pad->pszAlgId) + { + WARN( "padding info not found\n" ); + return STATUS_INVALID_PARAMETER; + } + if (key->alg_id != ALG_ID_RSA && key->alg_id != ALG_ID_RSA_SIGN) + { + FIXME( "BCRYPT_PAD_PSS not supported for key algorithm %u\n", key->alg_id ); + return STATUS_NOT_SUPPORTED; + } if ((hash_alg = get_digest_from_id( pad->pszAlgId )) == GNUTLS_DIG_UNKNOWN) { FIXME( "hash algorithm %s not recognized\n", debugstr_w(pad->pszAlgId) ); return STATUS_NOT_SUPPORTED; } + + if ((status = privkey_set_rsa_pss_params( key_data(key)->a.privkey, hash_alg, pad->cbSalt ))) return status; + gnutls_flags = GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS; } else if (!flags) { @@ -1857,7 +1978,7 @@ static NTSTATUS key_asymmetric_sign( void *args ) signature.data = NULL; signature.size = 0;
- if ((ret = pgnutls_privkey_sign_hash( key_data(key)->a.privkey, hash_alg, 0, &hash, &signature ))) + if ((ret = pgnutls_privkey_sign_hash( key_data(key)->a.privkey, hash_alg, gnutls_flags, &hash, &signature ))) { pgnutls_perror( ret ); return STATUS_INTERNAL_ERROR; diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 1ad9cc3763c..39cdd015c90 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2386,11 +2386,16 @@ static void test_RSA(void) { static UCHAR hash[] = {0x7e,0xe3,0x74,0xe7,0xc5,0x0b,0x6b,0x70,0xdb,0xab,0x32,0x6d,0x1d,0x51,0xd6,0x74,0x79,0x8e,0x5b,0x4b}; + static UCHAR hash48[] = + {0x62,0xb2,0x1e,0x90,0xc9,0x02,0x2b,0x10,0x16,0x71,0xba,0x1f,0x80,0x8f,0x86,0x31,0xa8,0x14,0x9f,0x0f, + 0x12,0x90,0x40,0x55,0x83,0x9a,0x35,0xc1,0xca,0x78,0xae,0x53,0x1b,0xb3,0x36,0x06,0xba,0x90,0x89,0x12, + 0xa8,0x42,0x21,0x10,0x9d,0x29,0xcd,0x7e}; BCRYPT_PKCS1_PADDING_INFO pad; + BCRYPT_PSS_PADDING_INFO pad_pss; BCRYPT_ALG_HANDLE alg; BCRYPT_KEY_HANDLE key; BCRYPT_RSAKEY_BLOB *rsablob; - UCHAR sig[64]; + UCHAR sig[256], sig_pss[256]; ULONG len, size, size2, schemes; NTSTATUS ret; BYTE *buf; @@ -2441,7 +2446,7 @@ static void test_RSA(void) ret = BCryptGenerateKeyPair(alg, &key, 1024, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
- keylen = 512; + keylen = 2048; ret = BCryptSetProperty(key, BCRYPT_KEY_LENGTH, (UCHAR *)&keylen, 2, 0); ok(ret == STATUS_INVALID_PARAMETER, "got %#lx\n", ret); ret = BCryptSetProperty(key, BCRYPT_KEY_LENGTH, (UCHAR *)&keylen, sizeof(keylen), 0); @@ -2455,8 +2460,18 @@ static void test_RSA(void)
pad.pszAlgId = BCRYPT_SHA1_ALGORITHM; memset(sig, 0, sizeof(sig)); + len = 0; ret = BCryptSignHash(key, &pad, hash, sizeof(hash), sig, sizeof(sig), &len, BCRYPT_PAD_PKCS1); ok(!ret, "got %#lx\n", ret); + ok(len == 256, "got %lu\n", len); + + pad_pss.pszAlgId = BCRYPT_SHA384_ALGORITHM; + pad_pss.cbSalt = 48; + memset(sig_pss, 0, sizeof(sig_pss)); + len = 0; + ret = BCryptSignHash(key, &pad_pss, hash48, sizeof(hash48), sig_pss, sizeof(sig_pss), &len, BCRYPT_PAD_PSS); + ok(!ret, "got %#lx\n", ret); + ok(len == 256, "got %lu\n", len);
/* export private key */ size = 0; @@ -2469,11 +2484,11 @@ static void test_RSA(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); rsablob = (BCRYPT_RSAKEY_BLOB *)buf; ok(rsablob->Magic == BCRYPT_RSAPRIVATE_MAGIC, "got %#lx\n", rsablob->Magic); - ok(rsablob->BitLength == 512, "got %lu\n", rsablob->BitLength); + ok(rsablob->BitLength == 2048, "got %lu\n", rsablob->BitLength); ok(rsablob->cbPublicExp == 3, "got %lu\n", rsablob->cbPublicExp); - ok(rsablob->cbModulus == 64, "got %lu\n", rsablob->cbModulus); - ok(rsablob->cbPrime1 == 32, "got %lu\n", rsablob->cbPrime1); - ok(rsablob->cbPrime2 == 32, "got %lu\n", rsablob->cbPrime2); + ok(rsablob->cbModulus == 256, "got %lu\n", rsablob->cbModulus); + ok(rsablob->cbPrime1 == 128, "got %lu\n", rsablob->cbPrime1); + ok(rsablob->cbPrime2 == 128, "got %lu\n", rsablob->cbPrime2); size2 = sizeof(*rsablob) + rsablob->cbPublicExp + rsablob->cbModulus + rsablob->cbPrime1 + rsablob->cbPrime2; ok(size == size2, "got %lu expected %lu\n", size2, size); free(buf); @@ -2488,11 +2503,11 @@ static void test_RSA(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); rsablob = (BCRYPT_RSAKEY_BLOB *)buf; ok(rsablob->Magic == BCRYPT_RSAFULLPRIVATE_MAGIC, "got %#lx\n", rsablob->Magic); - ok(rsablob->BitLength == 512, "got %lu\n", rsablob->BitLength); + ok(rsablob->BitLength == 2048, "got %lu\n", rsablob->BitLength); ok(rsablob->cbPublicExp == 3, "got %lu\n", rsablob->cbPublicExp); - ok(rsablob->cbModulus == 64, "got %lu\n", rsablob->cbModulus); - ok(rsablob->cbPrime1 == 32, "got %lu\n", rsablob->cbPrime1); - ok(rsablob->cbPrime2 == 32, "got %lu\n", rsablob->cbPrime2); + ok(rsablob->cbModulus == 256, "got %lu\n", rsablob->cbModulus); + ok(rsablob->cbPrime1 == 128, "got %lu\n", rsablob->cbPrime1); + ok(rsablob->cbPrime2 == 128, "got %lu\n", rsablob->cbPrime2); size2 = sizeof(*rsablob) + rsablob->cbPublicExp + rsablob->cbModulus * 2 + rsablob->cbPrime1 * 3 + rsablob->cbPrime2 * 2; ok(size == size2, "got %lu expected %lu\n", size2, size); free(buf); @@ -2508,9 +2523,9 @@ static void test_RSA(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); rsablob = (BCRYPT_RSAKEY_BLOB *)buf; ok(rsablob->Magic == BCRYPT_RSAPUBLIC_MAGIC, "got %#lx\n", rsablob->Magic); - ok(rsablob->BitLength == 512, "got %lu\n", rsablob->BitLength); + ok(rsablob->BitLength == 2048, "got %lu\n", rsablob->BitLength); ok(rsablob->cbPublicExp == 3, "got %lu\n", rsablob->cbPublicExp); - ok(rsablob->cbModulus == 64, "got %lu\n", rsablob->cbModulus); + ok(rsablob->cbModulus == 256, "got %lu\n", rsablob->cbModulus); ok(!rsablob->cbPrime1, "got %lu\n", rsablob->cbPrime1); ok(!rsablob->cbPrime2, "got %lu\n", rsablob->cbPrime2); ok(size == sizeof(*rsablob) + rsablob->cbPublicExp + rsablob->cbModulus, "got %lu\n", size); @@ -2525,7 +2540,9 @@ static void test_RSA(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); free(buf);
- ret = BCryptVerifySignature(key, &pad, hash, sizeof(hash), sig, len, BCRYPT_PAD_PKCS1); + ret = BCryptVerifySignature(key, &pad, hash, sizeof(hash), sig, sizeof(sig), BCRYPT_PAD_PKCS1); + ok(!ret, "got %#lx\n", ret); + ret = BCryptVerifySignature(key, &pad_pss, hash48, sizeof(hash48), sig_pss, sizeof(sig_pss), BCRYPT_PAD_PSS); ok(!ret, "got %#lx\n", ret); ret = BCryptDestroyKey(key); ok(!ret, "got %#lx\n", ret); @@ -2561,9 +2578,6 @@ static void test_RSA(void)
ret = BCryptCloseAlgorithmProvider(alg, 0); ok(!ret, "got %#lx\n", ret); - - /* RSA encryption */ - test_rsa_encrypt(); }
static void test_RSA_SIGN(void) @@ -3457,6 +3471,7 @@ START_TEST(bcrypt) test_BcryptDeriveKeyCapi(); test_DSA(); test_SecretAgreement(); + test_rsa_encrypt();
FreeLibrary(module); } diff --git a/include/bcrypt.h b/include/bcrypt.h index 52cb3d21bb3..6822491ed36 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -286,7 +286,14 @@ typedef struct _BCRYPT_PKCS1_PADDING_INFO LPCWSTR pszAlgId; } BCRYPT_PKCS1_PADDING_INFO;
-typedef struct _BCRYPT_OAEP_PADDING_INFO { +typedef struct _BCRYPT_PSS_PADDING_INFO +{ + LPCWSTR pszAlgId; + ULONG cbSalt; +} BCRYPT_PSS_PADDING_INFO; + +typedef struct _BCRYPT_OAEP_PADDING_INFO +{ LPCWSTR pszAlgId; PUCHAR pbLabel; ULONG cbLabel;