diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c index 21043f6f4..e1059a8f4 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c @@ -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) { diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 278c67405..b04627e63 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -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; diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c index 89fa9b348..3ef6981f6 100644 --- a/src/libstrongswan/credentials/keys/public_key.c +++ b/src/libstrongswan/credentials/keys/public_key.c @@ -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); diff --git a/src/libstrongswan/credentials/keys/signature_params.c b/src/libstrongswan/credentials/keys/signature_params.c index 8f42fb940..d89bd2c96 100644 --- a/src/libstrongswan/credentials/keys/signature_params.c +++ b/src/libstrongswan/credentials/keys/signature_params.c @@ -18,22 +18,43 @@ #include #include -/** - * 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, diff --git a/src/libstrongswan/credentials/keys/signature_params.h b/src/libstrongswan/credentials/keys/signature_params.h index 6934c5e88..b4169a829 100644 --- a/src/libstrongswan/credentials/keys/signature_params.h +++ b/src/libstrongswan/credentials/keys/signature_params.h @@ -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_ @}*/ diff --git a/src/libstrongswan/plugins/botan/botan_rsa_private_key.c b/src/libstrongswan/plugins/botan/botan_rsa_private_key.c index bb723ff95..da7dd064f 100644 --- a/src/libstrongswan/plugins/botan/botan_rsa_private_key.c +++ b/src/libstrongswan/plugins/botan/botan_rsa_private_key.c @@ -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; } /** diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c index c06f43348..394b87c27 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c @@ -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); diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c index 9e2ac1287..bbfa5e298 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c @@ -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); diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c index a255a40ab..2d2d5c6fb 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -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; diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c index 9b5ee67fa..f9bd1d314 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -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 || diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index 401a51a0b..8a9fdfe25 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -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; diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 20bf30ae9..38b4eda35 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -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; diff --git a/src/libstrongswan/tests/suites/test_rsa.c b/src/libstrongswan/tests/suites/test_rsa.c index e6dc7744a..a71fa0ce5 100644 --- a/src/libstrongswan/tests/suites/test_rsa.c +++ b/src/libstrongswan/tests/suites/test_rsa.c @@ -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, }; /** diff --git a/src/libstrongswan/tests/suites/test_signature_params.c b/src/libstrongswan/tests/suites/test_signature_params.c index 38cb5803f..cbf1a2861 100644 --- a/src/libstrongswan/tests/suites/test_signature_params.c +++ b/src/libstrongswan/tests/suites/test_signature_params.c @@ -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); diff --git a/src/pki/pki.c b/src/pki/pki.c index e647cea69..d03e96f9b 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -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