]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
proposal: Add method to check if two proposals match
authorTobias Brunner <tobias@strongswan.org>
Tue, 29 May 2018 14:02:21 +0000 (16:02 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 28 Jun 2018 16:46:41 +0000 (18:46 +0200)
Similar to select() but does not return a proposal and does not log
anything.

src/libstrongswan/crypto/proposal/proposal.c
src/libstrongswan/crypto/proposal/proposal.h
src/libstrongswan/tests/suites/test_proposal.c

index d671879c084590fc4154b8ebea1e3d42354f21c8..952608997485a2e3435d8246fcc5430178918072 100644 (file)
@@ -335,22 +335,16 @@ METHOD(proposal_t, strip_dh, void,
 }
 
 /**
- * Select a matching proposal from this and other, insert into selected.
+ * Select a matching proposal from this and other.
  */
 static bool select_algo(private_proposal_t *this, proposal_t *other,
-                                               proposal_t *selected, transform_type_t type, bool priv)
+                                               transform_type_t type, bool priv, bool log,
+                                               uint16_t *alg, uint16_t *ks)
 {
        enumerator_t *e1, *e2;
        uint16_t alg1, alg2, ks1, ks2;
        bool found = FALSE, optional = FALSE;
 
-       if (type == INTEGRITY_ALGORITHM &&
-               selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
-               encryption_algorithm_is_aead(alg1))
-       {
-               /* no integrity algorithm required, we have an AEAD */
-               return TRUE;
-       }
        if (type == DIFFIE_HELLMAN_GROUP)
        {
                optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
@@ -398,26 +392,79 @@ static bool select_algo(private_proposal_t *this, proposal_t *other,
                        {
                                if (!priv && alg1 >= 1024)
                                {
-                                       /* accept private use algorithms only if requested */
-                                       DBG1(DBG_CFG, "an algorithm from private space would match, "
-                                                "but peer implementation is unknown, skipped");
+                                       if (log)
+                                       {
+                                               DBG1(DBG_CFG, "an algorithm from private space would "
+                                                        "match, but peer implementation is unknown, "
+                                                        "skipped");
+                                       }
                                        continue;
                                }
-                               selected->add_algorithm(selected, type, alg1, ks1);
+                               *alg = alg1;
+                               *ks = ks1;
                                found = TRUE;
                                break;
                        }
                }
        }
-       /* no match in all comparisons */
        e1->destroy(e1);
        e2->destroy(e2);
+       return found;
+}
 
-       if (!found)
+/**
+ * Select algorithms from the given proposals, if selected is given, the result
+ * is stored there and errors are logged.
+ */
+static bool select_algos(private_proposal_t *this, proposal_t *other,
+                                                proposal_t *selected, bool private)
+{
+       transform_type_t type;
+       array_t *types;
+       bool skip_integrity = FALSE;
+       int i;
+
+       types = merge_types(this, (private_proposal_t*)other);
+       for (i = 0; i < array_count(types); i++)
        {
-               DBG2(DBG_CFG, "  no acceptable %N found", transform_type_names, type);
+               uint16_t alg = 0, ks = 0;
+
+               array_get(types, i, &type);
+               if (type == INTEGRITY_ALGORITHM && skip_integrity)
+               {
+                       continue;
+               }
+               if (select_algo(this, other, type, private, selected != NULL, &alg, &ks))
+               {
+                       if (alg == 0 && type != EXTENDED_SEQUENCE_NUMBERS)
+                       {       /* 0 is "valid" for extended sequence numbers, for other
+                                * transforms it either means NONE or is reserved */
+                               continue;
+                       }
+                       if (selected)
+                       {
+                               selected->add_algorithm(selected, type, alg, ks);
+                       }
+                       if (type == ENCRYPTION_ALGORITHM &&
+                               encryption_algorithm_is_aead(alg))
+                       {
+                               /* no integrity algorithm required, we have an AEAD */
+                               skip_integrity = TRUE;
+                       }
+               }
+               else
+               {
+                       if (selected)
+                       {
+                               DBG2(DBG_CFG, "  no acceptable %N found", transform_type_names,
+                                        type);
+                       }
+                       array_destroy(types);
+                       return FALSE;
+               }
        }
-       return found;
+       array_destroy(types);
+       return TRUE;
 }
 
 METHOD(proposal_t, select_proposal, proposal_t*,
@@ -425,9 +472,6 @@ METHOD(proposal_t, select_proposal, proposal_t*,
        bool private)
 {
        proposal_t *selected;
-       transform_type_t type;
-       array_t *types;
-       int i;
 
        DBG2(DBG_CFG, "selecting proposal:");
 
@@ -448,23 +492,25 @@ METHOD(proposal_t, select_proposal, proposal_t*,
                selected->set_spi(selected, this->spi);
        }
 
-       types = merge_types(this, (private_proposal_t*)other);
-       for (i = 0; i < array_count(types); i++)
+       if (!select_algos(this, other, selected, private))
        {
-               array_get(types, i, &type);
-               if (!select_algo(this, other, selected, type, private))
-               {
-                       selected->destroy(selected);
-                       array_destroy(types);
-                       return NULL;
-               }
+               selected->destroy(selected);
+               return NULL;
        }
-       array_destroy(types);
-
        DBG2(DBG_CFG, "  proposal matches");
        return selected;
 }
 
+METHOD(proposal_t, matches, bool,
+       private_proposal_t *this, proposal_t *other, bool private)
+{
+       if (this->protocol != other->get_protocol(other))
+       {
+               return FALSE;
+       }
+       return select_algos(this, other, NULL, private);
+}
+
 METHOD(proposal_t, get_protocol, protocol_id_t,
        private_proposal_t *this)
 {
@@ -910,6 +956,7 @@ proposal_t *proposal_create(protocol_id_t protocol, u_int number)
                        .promote_dh_group = _promote_dh_group,
                        .strip_dh = _strip_dh,
                        .select = _select_proposal,
+                       .matches = _matches,
                        .get_protocol = _get_protocol,
                        .set_spi = _set_spi,
                        .get_spi = _get_spi,
index 0052674b902a318abdb9a2f6a31a56fb89363179..3383243264fb9e7849a1ddd1ea31bf1d98402440 100644 (file)
@@ -34,7 +34,6 @@ typedef struct proposal_t proposal_t;
 #include <crypto/crypters/crypter.h>
 #include <crypto/signers/signer.h>
 #include <crypto/diffie_hellman.h>
-#include <selectors/traffic_selector.h>
 
 /**
  * Protocol ID of a proposal.
@@ -143,6 +142,17 @@ struct proposal_t {
        proposal_t *(*select)(proposal_t *this, proposal_t *other,
                                                  bool other_remote, bool private);
 
+       /**
+        * Check if the given proposal matches this proposal.
+        *
+        * This is similar to select, but no resulting proposal is selected.
+        *
+        * @param other                 proposal to compare against
+        * @param private               accepts algorithms allocated in a private range
+        * @return                              TRUE if the proposals match
+        */
+       bool (*matches)(proposal_t *this, proposal_t *other, bool private);
+
        /**
         * Get the protocol ID of the proposal.
         *
index 938fa38aa8c2f50e01e6d7c2771132021283f3ce..099cd19c7fe4d2d2e536e344aa899e7f2b11b4dc 100644 (file)
@@ -102,7 +102,12 @@ static struct {
        { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256", "aes128-sha256" },
        { PROTO_ESP, "aes128-sha256", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
        { PROTO_ESP, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072" },
-       { PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modpnone" },
+       { PROTO_ESP, "aes128-sha256-modpnone-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256" },
+       { PROTO_ESP, "aes128-sha256-esn", "aes128-sha256-esn", "aes128-sha256-esn" },
+       { PROTO_ESP, "aes128-sha256-noesn", "aes128-sha256-esn", NULL },
+       { PROTO_ESP, "aes128-sha256-noesn-esn", "aes128-sha256-esn", "aes128-sha256-esn" },
+       { PROTO_ESP, "aes128-sha256-noesn-esn", "aes128-sha256", "aes128-sha256" },
+       { PROTO_ESP, "aes128-sha256-esn-noesn", "aes128-sha256-noesn-esn", "aes128-sha256-esn" },
        { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
        { PROTO_IKE, "aes128-sha256-modp3072", "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072" },
        { PROTO_IKE, "aes128-sha256-modp3072-modpnone", "aes128-sha256-modp3072", "aes128-sha256-modp3072" },
@@ -159,6 +164,29 @@ START_TEST(test_select_spi)
 }
 END_TEST
 
+START_TEST(test_matches)
+{
+       proposal_t *self, *other;
+
+       self = proposal_create_from_string(select_data[_i].proto,
+                                                                          select_data[_i].self);
+       other = proposal_create_from_string(select_data[_i].proto,
+                                                                               select_data[_i].other);
+       if (select_data[_i].expected)
+       {
+               ck_assert(self->matches(self, other, FALSE));
+               ck_assert(other->matches(other, self, FALSE));
+       }
+       else
+       {
+               ck_assert(!self->matches(self, other, FALSE));
+               ck_assert(!other->matches(other, self, FALSE));
+       }
+       other->destroy(other);
+       self->destroy(self);
+}
+END_TEST
+
 START_TEST(test_promote_dh_group)
 {
        proposal_t *proposal;
@@ -312,6 +340,10 @@ Suite *proposal_suite_create()
        tcase_add_test(tc, test_select_spi);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("matches");
+       tcase_add_loop_test(tc, test_matches, 0, countof(select_data));
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("promote_dh_group");
        tcase_add_test(tc, test_promote_dh_group);
        tcase_add_test(tc, test_promote_dh_group_already_front);