signature-params: Add helper struct for signature scheme and parameters
authorTobias Brunner <tobias@strongswan.org>
Tue, 10 Oct 2017 13:52:19 +0000 (15:52 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 8 Nov 2017 15:48:10 +0000 (16:48 +0100)
src/libstrongswan/credentials/keys/signature_params.c
src/libstrongswan/credentials/keys/signature_params.h
src/libstrongswan/tests/suites/test_signature_params.c

index 72a61e1..e8ac75d 100644 (file)
 #include <asn1/asn1_parser.h>
 
 /**
+ * Determine the salt length in case it is not configured
+ */
+static ssize_t rsa_pss_salt_length(rsa_pss_params_t *pss)
+{
+       ssize_t salt_len = pss->salt_len;
+
+       if (salt_len <= RSA_PSS_SALT_LEN_DEFAULT)
+       {
+               salt_len = hasher_hash_size(pss->hash);
+               if (!salt_len)
+               {
+                       return -1;
+               }
+       }
+       return salt_len;
+}
+
+/**
+ * Compare two signature schemes and their parameters
+ */
+static bool compare_params(signature_params_t *a, signature_params_t *b,
+                                                  bool strict)
+{
+       if (!a && !b)
+       {
+               return TRUE;
+       }
+       if (!a || !b)
+       {
+               return FALSE;
+       }
+       if (a->scheme != b->scheme)
+       {
+               return FALSE;
+       }
+       if (!a->params && !b->params)
+       {
+               return TRUE;
+       }
+       if (a->params && b->params)
+       {
+               switch (a->scheme)
+               {
+                       case SIGN_RSA_EMSA_PSS:
+                       {
+                               rsa_pss_params_t *pss_a = a->params, *pss_b = b->params;
+
+                               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));
+                       }
+                       default:
+                               break;
+               }
+       }
+       return FALSE;
+}
+
+/*
+ * Described in header
+ */
+bool signature_params_equal(signature_params_t *a, signature_params_t *b)
+{
+       return compare_params(a, b, TRUE);
+}
+
+/*
+ * Described in header
+ */
+bool signature_params_comply(signature_params_t *c, signature_params_t *s)
+{      /* the salt is variable, so it does not necessarily have to be the same */
+       return compare_params(c, s, FALSE);
+}
+
+/*
+ * Described in header
+ */
+signature_params_t *signature_params_clone(signature_params_t *this)
+{
+       signature_params_t *clone;
+
+       if (!this)
+       {
+               return NULL;
+       }
+
+       INIT(clone,
+               .scheme = this->scheme,
+       );
+       if (this->params)
+       {
+               switch (this->scheme)
+               {
+                       case SIGN_RSA_EMSA_PSS:
+                       {
+                               rsa_pss_params_t *pss, *pss_clone;
+
+                               pss = this->params;
+                               INIT(pss_clone,
+                                       .hash = pss->hash,
+                                       .mgf1_hash = pss->mgf1_hash,
+                                       .salt_len = pss->salt_len,
+                                       /* ignore salt as only used for unit tests */
+                               );
+                               clone->params = pss_clone;
+                               break;
+                       }
+                       default:
+                               break;
+               }
+       }
+       return clone;
+}
+
+/*
+ * Described in header
+ */
+void signature_params_destroy(signature_params_t *this)
+{
+       if (this)
+       {
+               free(this->params);
+               free(this);
+       }
+}
+
+/*
+ * Described in header
+ */
+void signature_params_clear(signature_params_t *this)
+{
+       if (this)
+       {
+               free(this->params);
+               this->params = NULL;
+               this->scheme = SIGN_UNKNOWN;
+       }
+}
+
+/**
  * ASN.1 definition of RSASSA-PSS-params
  */
 static const asn1Object_t RSASSAPSSParamsObjects[] = {
@@ -119,6 +260,7 @@ 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)
@@ -141,23 +283,16 @@ bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1)
                mgf = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_MGF1),
                                                asn1_algorithmIdentifier(alg));
        }
-       if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
+       salt_len = rsa_pss_salt_length(params);
+       if (salt_len < 0)
        {
-               if (params->salt_len != HASH_SIZE_SHA1)
-               {
-                       slen = asn1_integer("m", asn1_integer_from_uint64(params->salt_len));
-               }
+               chunk_free(&hash);
+               chunk_free(&mgf);
+               return FALSE;
        }
-       else if (params->hash != HASH_SHA1)
+       else if (salt_len != HASH_SIZE_SHA1)
        {
-               size_t hlen = hasher_hash_size(params->hash);
-               if (!hlen)
-               {
-                       chunk_free(&hash);
-                       chunk_free(&mgf);
-                       return FALSE;
-               }
-               slen = asn1_integer("m", asn1_integer_from_uint64(hlen));
+               slen = asn1_integer("m", asn1_integer_from_uint64(salt_len));
        }
        *asn1 = asn1_wrap(ASN1_SEQUENCE, "mmm",
                                hash.len ? asn1_wrap(ASN1_CONTEXT_C_0, "m", hash) : chunk_empty,
index 52a7ad7..4cde94c 100644 (file)
 #ifndef SIGNATURE_PARAMS_H_
 #define SIGNATURE_PARAMS_H_
 
+typedef struct signature_params_t signature_params_t;
 typedef struct rsa_pss_params_t rsa_pss_params_t;
 
 #include <crypto/hashers/hasher.h>
 
 /**
+ * Signature scheme with parameters
+ */
+struct signature_params_t {
+       /** Signature scheme */
+       signature_scheme_t scheme;
+       /** Parameters, depending on scheme */
+       void *params;
+};
+
+/**
+ * Compare two signature schemes and their parameters
+ *
+ * @param a                    first scheme
+ * @param b                    second scheme
+ * @return                     TRUE if schemes and parameters are equal
+ */
+bool signature_params_equal(signature_params_t *a, signature_params_t *b);
+
+/**
+ * Compare two signature schemes and their parameters
+ *
+ * @param c                    constraint
+ * @param s                    scheme
+ * @return                     TRUE if scheme complies to constraint
+ */
+bool signature_params_comply(signature_params_t *c, signature_params_t *s);
+
+/**
+ * Clone the given scheme and parameters, if any
+ *
+ * @return                     cloned object
+ */
+signature_params_t *signature_params_clone(signature_params_t *this);
+
+/**
+ * Destroy the given scheme and parameters, if any
+ */
+void signature_params_destroy(signature_params_t *this);
+
+/**
+ * Clear the given parameters, if any, sets the scheme to SIGN_UNKNOWN
+ */
+void signature_params_clear(signature_params_t *this);
+
+/**
  * Parameters for SIGN_RSA_EMSA_PSS signature scheme
  */
 struct rsa_pss_params_t {
index 0b69880..0ac00c3 100644 (file)
@@ -19,7 +19,7 @@
 #include <asn1/asn1.h>
 #include <credentials/keys/signature_params.h>
 
-struct {
+static struct {
        chunk_t aid;
        rsa_pss_params_t params;
 } rsa_pss_parse_tests[] = {
@@ -125,7 +125,7 @@ START_TEST(test_rsa_pss_params_parse_invalid)
 }
 END_TEST
 
-struct {
+static struct {
        chunk_t aid;
        rsa_pss_params_t params;
 } rsa_pss_build_tests[] = {
@@ -209,6 +209,111 @@ START_TEST(test_rsa_pss_params_build_invalid)
 }
 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, };
+static rsa_pss_params_t rsa_pss_params_sha256_salt = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = 10, };
+
+static struct {
+       bool equal;
+       bool complies;
+       signature_params_t a;
+       signature_params_t b;
+} params_compare_tests[] = {
+       { TRUE, TRUE, { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, }, { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, }, },
+       { FALSE, FALSE, { .scheme = SIGN_RSA_EMSA_PKCS1_SHA1, }, { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, }, },
+       { TRUE, TRUE, { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 },
+                                 { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 }, },
+       { FALSE, FALSE, { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, .params = &rsa_pss_params_sha256 },
+                                       { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, .params = &rsa_pss_params_sha256 }, },
+       { FALSE, FALSE, { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 },
+                                       { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256_mgf1 }, },
+       { FALSE, TRUE, { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 },
+                                  { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256_salt }, },
+       { FALSE, FALSE, { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha1 },
+                                       { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 }, },
+       { FALSE, FALSE, { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 },
+                                       { .scheme = SIGN_RSA_EMSA_PSS, }, },
+};
+
+START_TEST(test_params_compare)
+{
+       bool res;
+
+       res = signature_params_equal(&params_compare_tests[_i].a,
+                                                                &params_compare_tests[_i].b);
+       ck_assert(res == params_compare_tests[_i].equal);
+       res = signature_params_comply(&params_compare_tests[_i].a,
+                                                                 &params_compare_tests[_i].b);
+       ck_assert(res == params_compare_tests[_i].complies);
+       res = signature_params_comply(&params_compare_tests[_i].b,
+                                                                 &params_compare_tests[_i].a);
+       ck_assert(res == params_compare_tests[_i].complies);
+}
+END_TEST
+
+START_TEST(test_params_compare_null)
+{
+       ck_assert(signature_params_equal(NULL, NULL));
+       ck_assert(!signature_params_equal(&params_compare_tests[0].a, NULL));
+       ck_assert(!signature_params_equal(NULL, &params_compare_tests[0].a));
+}
+END_TEST
+
+static struct {
+       signature_params_t src;
+       signature_params_t res;
+} params_clone_tests[] = {
+       { { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, }, { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, }, },
+       { { .scheme = SIGN_RSA_EMSA_PSS }, { .scheme = SIGN_RSA_EMSA_PSS }, },
+       { { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 },
+         { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256 }, },
+       { { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256_salt },
+         { .scheme = SIGN_RSA_EMSA_PSS, .params = &rsa_pss_params_sha256_salt }, },
+       { { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256, .params = &rsa_pss_params_sha256 },
+         { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256 }, },
+};
+
+START_TEST(test_params_clone)
+{
+       signature_params_t *clone = NULL;
+
+       clone = signature_params_clone(&params_clone_tests[_i].src);
+       ck_assert(signature_params_equal(clone, &params_clone_tests[_i].res));
+       signature_params_destroy(clone);
+}
+END_TEST
+
+START_TEST(test_params_clone_null)
+{
+       signature_params_t *clone = NULL;
+
+       clone = signature_params_clone(clone);
+       ck_assert(!clone);
+       signature_params_destroy(clone);
+}
+END_TEST
+
+START_TEST(test_params_clear)
+{
+       signature_params_t *clone;
+
+       clone = signature_params_clone(&params_clone_tests[_i].src);
+       signature_params_clear(clone);
+       ck_assert_int_eq(clone->scheme, SIGN_UNKNOWN);
+       ck_assert(!clone->params);
+       free(clone);
+}
+END_TEST
+
+START_TEST(test_params_clear_null)
+{
+       signature_params_t *clone = NULL;
+
+       signature_params_clear(clone);
+}
+END_TEST
+
 Suite *signature_params_suite_create()
 {
        Suite *s;
@@ -216,15 +321,30 @@ Suite *signature_params_suite_create()
 
        s = suite_create("signature params");
 
-       tc = tcase_create("parse");
+       tc = tcase_create("rsa/pss parse");
        tcase_add_loop_test(tc, test_rsa_pss_params_parse, 0, countof(rsa_pss_parse_tests));
        tcase_add_loop_test(tc, test_rsa_pss_params_parse_invalid, 0, countof(rsa_pss_parse_invalid_tests));
        suite_add_tcase(s, tc);
 
-       tc = tcase_create("build");
+       tc = tcase_create("rsa/pss build");
        tcase_add_loop_test(tc, test_rsa_pss_params_build, 0, countof(rsa_pss_build_tests));
        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("params compare");
+       tcase_add_loop_test(tc, test_params_compare, 0, countof(params_compare_tests));
+       tcase_add_test(tc, test_params_compare_null);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("params clone");
+       tcase_add_loop_test(tc, test_params_clone, 0, countof(params_clone_tests));
+       tcase_add_test(tc, test_params_clone_null);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("params clear");
+       tcase_add_loop_test(tc, test_params_clear, 0, countof(params_clone_tests));
+       tcase_add_test(tc, test_params_clear_null);
+       suite_add_tcase(s, tc);
+
        return s;
 }