Commit 96692a2c authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

bcrypt: Add support for PSS padding.

parent 5308911a
......@@ -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:
{
if (flags & BCRYPT_PAD_PKCS1)
{
BCRYPT_PKCS1_PADDING_INFO *info = params->padding;
if (!(flags & BCRYPT_PAD_PKCS1) || !info) return STATUS_INVALID_PARAMETER;
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;
}
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,12 +1896,16 @@ 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)
{
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)
{
if (flags) FIXME( "flags %#x not supported\n", flags );
......@@ -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;
......
......@@ -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);
}
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment