signature-params: Provide option for maximum RSA/PSS salt length
However, the length now has to be resolved early, so we don't operate on the negative constant values e.g. when generating the encoding.
This commit is contained in:
parent
dd4bd21c5a
commit
ecfe67550d
|
@ -135,11 +135,7 @@ static bool set_pss_params(private_private_key_t *this, JNIEnv *env,
|
|||
{
|
||||
return FALSE;
|
||||
}
|
||||
slen = hasher_hash_size(pss->hash);
|
||||
if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
slen = pss->salt_len;
|
||||
}
|
||||
slen = pss->salt_len;
|
||||
obj = (*env)->NewObject(env, cls, method_id, jhash, jmgf1, obj, slen, 1);
|
||||
if (!obj)
|
||||
{
|
||||
|
|
|
@ -551,6 +551,7 @@ static signature_params_t *create_rsa_pss_constraint(char *token)
|
|||
.scheme = SIGN_RSA_EMSA_PSS,
|
||||
.params = &pss,
|
||||
};
|
||||
rsa_pss_params_set_salt_len(&pss, 0);
|
||||
params = signature_params_clone(&pss_params);
|
||||
}
|
||||
return params;
|
||||
|
|
|
@ -250,7 +250,7 @@ int signature_scheme_to_oid(signature_scheme_t scheme)
|
|||
#define PSS_PARAMS(bits) static rsa_pss_params_t pss_params_sha##bits = { \
|
||||
.hash = HASH_SHA##bits, \
|
||||
.mgf1_hash = HASH_SHA##bits, \
|
||||
.salt_len = RSA_PSS_SALT_LEN_DEFAULT, \
|
||||
.salt_len = HASH_SIZE_SHA##bits, \
|
||||
}
|
||||
|
||||
PSS_PARAMS(256);
|
||||
|
|
|
@ -18,22 +18,43 @@
|
|||
#include <asn1/oid.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
|
||||
/**
|
||||
* Determine the salt length in case it is not configured
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
static ssize_t rsa_pss_salt_length(rsa_pss_params_t *pss)
|
||||
bool rsa_pss_params_set_salt_len(rsa_pss_params_t *params, size_t modbits)
|
||||
{
|
||||
ssize_t salt_len = pss->salt_len;
|
||||
size_t hash_len;
|
||||
|
||||
if (salt_len <= RSA_PSS_SALT_LEN_DEFAULT)
|
||||
if (params->salt_len < 0)
|
||||
{
|
||||
salt_len = hasher_hash_size(pss->hash);
|
||||
if (!salt_len)
|
||||
hash_len = hasher_hash_size(params->hash);
|
||||
if (!hash_len)
|
||||
{
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (params->salt_len)
|
||||
{
|
||||
case RSA_PSS_SALT_LEN_DEFAULT:
|
||||
params->salt_len = hash_len;
|
||||
break;
|
||||
case RSA_PSS_SALT_LEN_MAX:
|
||||
if (modbits)
|
||||
{
|
||||
/* emBits = modBits - 1 */
|
||||
modbits -= 1;
|
||||
/* emLen = ceil(emBits/8) */
|
||||
modbits = (modbits+7) / BITS_PER_BYTE;
|
||||
/* account for 0x01 separator in DB, 0xbc trailing byte */
|
||||
params->salt_len = max(0, (ssize_t)(modbits - hash_len - 2));
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return salt_len;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,8 +89,7 @@ static bool compare_params(signature_params_t *a, signature_params_t *b,
|
|||
|
||||
return pss_a->hash == pss_b->hash &&
|
||||
pss_a->mgf1_hash == pss_b->mgf1_hash &&
|
||||
(!strict ||
|
||||
rsa_pss_salt_length(pss_a) == rsa_pss_salt_length(pss_b));
|
||||
(!strict || pss_a->salt_len == pss_b->salt_len);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
@ -328,7 +348,6 @@ end:
|
|||
bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1)
|
||||
{
|
||||
chunk_t hash = chunk_empty, mgf = chunk_empty, slen = chunk_empty;
|
||||
ssize_t salt_len;
|
||||
int alg;
|
||||
|
||||
if (params->hash != HASH_SHA1)
|
||||
|
@ -351,16 +370,15 @@ bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1)
|
|||
mgf = asn1_algorithmIdentifier_params(OID_MGF1,
|
||||
asn1_algorithmIdentifier(alg));
|
||||
}
|
||||
salt_len = rsa_pss_salt_length(params);
|
||||
if (salt_len < 0)
|
||||
if (params->salt_len < 0)
|
||||
{
|
||||
chunk_free(&hash);
|
||||
chunk_free(&mgf);
|
||||
return FALSE;
|
||||
}
|
||||
else if (salt_len != HASH_SIZE_SHA1)
|
||||
else if (params->salt_len != HASH_SIZE_SHA1)
|
||||
{
|
||||
slen = asn1_integer("m", asn1_integer_from_uint64(salt_len));
|
||||
slen = asn1_integer("m", asn1_integer_from_uint64(params->salt_len));
|
||||
}
|
||||
*asn1 = asn1_wrap(ASN1_SEQUENCE, "mmm",
|
||||
hash.len ? asn1_wrap(ASN1_CONTEXT_C_0, "m", hash) : chunk_empty,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Tobias Brunner
|
||||
* Copyright (C) 2017-2018 Tobias Brunner
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -100,11 +100,15 @@ struct rsa_pss_params_t {
|
|||
hash_algorithm_t hash;
|
||||
/** Hash for the MGF1 function */
|
||||
hash_algorithm_t mgf1_hash;
|
||||
/** Salt length, use RSA_PSS_SALT_LEN_DEFAULT for length equal to hash */
|
||||
/** Salt length, use the constants below for special lengths resolved
|
||||
* via rsa_pss_params_set_salt_len() */
|
||||
ssize_t salt_len;
|
||||
/** Salt value, for unit tests (not all implementations support this) */
|
||||
chunk_t salt;
|
||||
/** Use a salt length equal to the length of the hash */
|
||||
#define RSA_PSS_SALT_LEN_DEFAULT -1
|
||||
/** Use the maximum salt length depending on the hash and key length */
|
||||
#define RSA_PSS_SALT_LEN_MAX -2
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -126,4 +130,15 @@ bool rsa_pss_params_parse(chunk_t asn1, int level0, rsa_pss_params_t *params);
|
|||
*/
|
||||
bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1);
|
||||
|
||||
/**
|
||||
* Determine and set the salt length for the given params in case constants
|
||||
* are used
|
||||
*
|
||||
* @param params parameters to update
|
||||
* @param modbits RSA modulus length in bits (required if RSA_PSS_SALT_LEN_MAX
|
||||
* is used)
|
||||
* @return salt length to use, negative on error
|
||||
*/
|
||||
bool rsa_pss_params_set_salt_len(rsa_pss_params_t *params, size_t modbits);
|
||||
|
||||
#endif /** SIGNATURE_PARAMS_H_ @}*/
|
||||
|
|
|
@ -84,13 +84,8 @@ bool botan_emsa_pss_identifier(rsa_pss_params_t *params, char *id, size_t len)
|
|||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
return snprintf(id, len, "EMSA-PSS(%s,MGF1,%zd)", hash,
|
||||
params->salt_len) < len;
|
||||
}
|
||||
return snprintf(id, len, "EMSA-PSS(%s,MGF1)", hash) < len;
|
||||
return snprintf(id, len, "EMSA-PSS(%s,MGF1,%zd)", hash,
|
||||
params->salt_len) < len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -187,11 +187,7 @@ static bool sign_pkcs1(private_gcrypt_rsa_private_key_t *this,
|
|||
}
|
||||
else
|
||||
{
|
||||
u_int slen = hasher_hash_size(hash_algorithm);
|
||||
if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
slen = pss->salt_len;
|
||||
}
|
||||
u_int slen = pss->salt_len;
|
||||
err = gcry_sexp_build(&in, NULL,
|
||||
"(data(flags pss)(salt-length %u)(hash %s %b))",
|
||||
slen, hash_name, hash.len, hash.ptr);
|
||||
|
|
|
@ -139,11 +139,7 @@ static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
|
|||
|
||||
if (pss)
|
||||
{
|
||||
u_int slen = hasher_hash_size(algorithm);
|
||||
if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
slen = pss->salt_len;
|
||||
}
|
||||
u_int slen = pss->salt_len;
|
||||
err = gcry_sexp_build(&in, NULL,
|
||||
"(data(flags pss)(salt-length %u)(hash %s %b))",
|
||||
slen, hash_name, hash.len, hash.ptr);
|
||||
|
|
|
@ -393,15 +393,11 @@ static bool build_emsa_pss_signature(private_gmp_rsa_private_key_t *this,
|
|||
goto error;
|
||||
}
|
||||
|
||||
salt.len = hash.len;
|
||||
salt.len = params->salt_len;
|
||||
if (params->salt.len)
|
||||
{
|
||||
salt = params->salt;
|
||||
}
|
||||
else if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
salt.len = params->salt_len;
|
||||
}
|
||||
if (emlen < (hash.len + salt.len + 2))
|
||||
{ /* too long */
|
||||
goto error;
|
||||
|
|
|
@ -205,12 +205,7 @@ static bool verify_emsa_pss_signature(private_gmp_rsa_public_key_t *this,
|
|||
{
|
||||
goto error;
|
||||
}
|
||||
/* determine salt length */
|
||||
salt.len = hash.len;
|
||||
if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
salt.len = params->salt_len;
|
||||
}
|
||||
salt.len = params->salt_len;
|
||||
/* verify general structure of EM */
|
||||
maskbits = (8 * em.len) - embits;
|
||||
if (em.len < (hash.len + salt.len + 2) || em.ptr[em.len-1] != 0xbc ||
|
||||
|
|
|
@ -103,13 +103,8 @@ static bool build_signature(private_openssl_rsa_private_key_t *this,
|
|||
if (pss)
|
||||
{
|
||||
const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash);
|
||||
int slen = EVP_MD_size(md);
|
||||
if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
slen = pss->salt_len;
|
||||
}
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, pss->salt_len) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0)
|
||||
{
|
||||
goto error;
|
||||
|
|
|
@ -95,13 +95,8 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this,
|
|||
if (pss)
|
||||
{
|
||||
const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash);
|
||||
int slen = EVP_MD_size(md);
|
||||
if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
|
||||
{
|
||||
slen = pss->salt_len;
|
||||
}
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, pss->salt_len) <= 0 ||
|
||||
EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0)
|
||||
{
|
||||
goto error;
|
||||
|
|
|
@ -40,7 +40,7 @@ static signature_scheme_t schemes[] = {
|
|||
static rsa_pss_params_t default_pss_params = {
|
||||
.hash = HASH_SHA256,
|
||||
.mgf1_hash = HASH_SHA256,
|
||||
.salt_len = RSA_PSS_SALT_LEN_DEFAULT,
|
||||
.salt_len = HASH_SIZE_SHA256,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Tobias Brunner
|
||||
* Copyright (C) 2017-2018 Tobias Brunner
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -138,27 +138,27 @@ static struct {
|
|||
0xa1,0x1c,0x30,0x1a,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x08,0x30,
|
||||
0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0xa2,0x03,
|
||||
0x02,0x01,0x20),
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = HASH_SIZE_SHA256, }},
|
||||
/* default salt length: SHA-1 */
|
||||
{ chunk_from_chars(0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x00),
|
||||
{ .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
|
||||
{ .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, }},
|
||||
/* default salt length: SHA-224 */
|
||||
{ chunk_from_chars(0x30,0x23,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x16,0xa0,
|
||||
0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,
|
||||
0xa2,0x03,0x02,0x01,0x1c),
|
||||
{ .hash = HASH_SHA224, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
|
||||
{ .hash = HASH_SHA224, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA224, }},
|
||||
/* default salt length: SHA-384 */
|
||||
{ chunk_from_chars(0x30,0x23,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x16,0xa0,
|
||||
0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,
|
||||
0xa2,0x03,0x02,0x01,0x30),
|
||||
{ .hash = HASH_SHA384, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
|
||||
{ .hash = HASH_SHA384, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA384, }},
|
||||
/* SHA-512 */
|
||||
{ chunk_from_chars(0x30,0x41,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x34,0xa0,
|
||||
0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,
|
||||
0xa1,0x1c,0x30,0x1a,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x08,0x30,
|
||||
0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0xa2,0x03,
|
||||
0x02,0x01,0x40),
|
||||
{ .hash = HASH_SHA512, .mgf1_hash = HASH_SHA512, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
|
||||
{ .hash = HASH_SHA512, .mgf1_hash = HASH_SHA512, .salt_len = HASH_SIZE_SHA512, }},
|
||||
/* SHA-256, no salt */
|
||||
{ chunk_from_chars(0x30,0x41,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x34,0xa0,
|
||||
0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,
|
||||
|
@ -199,6 +199,8 @@ rsa_pss_params_t rsa_pss_build_invalid_tests[] = {
|
|||
{ .hash = HASH_UNKNOWN, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, },
|
||||
/* invalid mgf */
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_UNKNOWN, .salt_len = HASH_SIZE_SHA256, },
|
||||
/* undetermined salt */
|
||||
{ .hash = HASH_UNKNOWN, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, },
|
||||
};
|
||||
|
||||
START_TEST(test_rsa_pss_params_build_invalid)
|
||||
|
@ -209,6 +211,49 @@ START_TEST(test_rsa_pss_params_build_invalid)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
static struct {
|
||||
ssize_t expected;
|
||||
size_t modbits;
|
||||
rsa_pss_params_t params;
|
||||
} rsa_pss_salt_len_tests[] = {
|
||||
{ HASH_SIZE_SHA256, 0,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
|
||||
{ HASH_SIZE_SHA256, 3072,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }},
|
||||
{ -1, 0,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
|
||||
{ 0, 256,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
|
||||
{ 350, 3071,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
|
||||
{ 350, 3072,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
|
||||
{ 350, 3073,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
|
||||
{ 478, 4096,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }},
|
||||
{ 10, 0,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = 10, }},
|
||||
{ 10, 3072,
|
||||
{ .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = 10, }},
|
||||
};
|
||||
|
||||
START_TEST(test_rsa_pss_params_set_salt_len)
|
||||
{
|
||||
if (rsa_pss_params_set_salt_len(&rsa_pss_salt_len_tests[_i].params,
|
||||
rsa_pss_salt_len_tests[_i].modbits))
|
||||
{
|
||||
ck_assert_int_eq(rsa_pss_salt_len_tests[_i].expected,
|
||||
rsa_pss_salt_len_tests[_i].params.salt_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
ck_assert(rsa_pss_salt_len_tests[_i].expected < 0);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static rsa_pss_params_t rsa_pss_params_sha1 = { .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, };
|
||||
static rsa_pss_params_t rsa_pss_params_sha256 = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = HASH_SIZE_SHA256, };
|
||||
static rsa_pss_params_t rsa_pss_params_sha256_mgf1 = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA512, .salt_len = HASH_SIZE_SHA256, };
|
||||
|
@ -430,6 +475,10 @@ Suite *signature_params_suite_create()
|
|||
tcase_add_loop_test(tc, test_rsa_pss_params_build_invalid, 0, countof(rsa_pss_build_invalid_tests));
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("rsa/pss salt len");
|
||||
tcase_add_loop_test(tc, test_rsa_pss_params_set_salt_len, 0, countof(rsa_pss_salt_len_tests));
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("params compare");
|
||||
tcase_add_loop_test(tc, test_params_compare, 0, countof(params_compare_tests));
|
||||
tcase_add_test(tc, test_params_compare_null);
|
||||
|
|
|
@ -304,6 +304,7 @@ signature_params_t *get_signature_scheme(private_key_t *private,
|
|||
.scheme = SIGN_RSA_EMSA_PSS,
|
||||
.params = &pss_params,
|
||||
};
|
||||
rsa_pss_params_set_salt_len(&pss_params, 0);
|
||||
scheme = signature_params_clone(&pss_scheme);
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue