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:
Tobias Brunner 2018-10-12 12:11:51 +02:00
parent dd4bd21c5a
commit ecfe67550d
15 changed files with 119 additions and 71 deletions

View File

@ -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)
{

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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_ @}*/

View File

@ -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;
}
/**

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 ||

View File

@ -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;

View File

@ -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;

View File

@ -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,
};
/**

View File

@ -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);

View File

@ -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