signature-params: Provide option for maximum RSA/PSS salt length
authorTobias Brunner <tobias@strongswan.org>
Fri, 12 Oct 2018 10:11:51 +0000 (12:11 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 26 Oct 2018 07:03:26 +0000 (09:03 +0200)
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.

15 files changed:
src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c
src/libstrongswan/credentials/auth_cfg.c
src/libstrongswan/credentials/keys/public_key.c
src/libstrongswan/credentials/keys/signature_params.c
src/libstrongswan/credentials/keys/signature_params.h
src/libstrongswan/plugins/botan/botan_rsa_private_key.c
src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c
src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c
src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
src/libstrongswan/tests/suites/test_rsa.c
src/libstrongswan/tests/suites/test_signature_params.c
src/pki/pki.c

index 21043f6..e1059a8 100644 (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)
        {
index 278c674..b04627e 100644 (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;
index 89fa9b3..3ef6981 100644 (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);
index 8f42fb9..d89bd2c 100644 (file)
 #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 FALSE;
+               }
+
+               switch (params->salt_len)
                {
-                       return -1;
+                       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,
index 6934c5e..b4169a8 100644 (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_ @}*/
index bb723ff..da7dd06 100644 (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;
 }
 
 /**
index c06f433..394b87c 100644 (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);
index 9e2ac12..bbfa5e2 100644 (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);
index a255a40..2d2d5c6 100644 (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;
index 9b5ee67..f9bd1d3 100644 (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 ||
index 401a51a..8a9fdfe 100644 (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;
index 20bf30a..38b4eda 100644 (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;
index e6dc774..a71fa0c 100644 (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,
 };
 
 /**
index 38cb580..cbf1a28 100644 (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);
index e647cea..d03e96f 100644 (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