proposal: Don't fail DH proposal matching if peer includes NONE
authorTobias Brunner <tobias@strongswan.org>
Fri, 28 Feb 2014 14:27:52 +0000 (15:27 +0100)
committerTobias Brunner <tobias@strongswan.org>
Mon, 31 Mar 2014 12:32:44 +0000 (14:32 +0200)
The DH transform is optional for ESP/AH proposals. The initiator can
include NONE (0) in its proposal to indicate that while it prefers to
do a DH exchange, the responder may still decide to not do so.

Fixes #532.

src/libcharon/config/proposal.c

index 891d1be..2ecdb4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008-2014 Tobias Brunner
  * Copyright (C) 2006-2010 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -193,7 +193,7 @@ static bool select_algo(private_proposal_t *this, proposal_t *other,
 {
        enumerator_t *e1, *e2;
        u_int16_t alg1, alg2, ks1, ks2;
-       bool found = FALSE;
+       bool found = FALSE, optional = FALSE;
 
        if (type == INTEGRITY_ALGORITHM &&
                selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
@@ -202,12 +202,27 @@ static bool select_algo(private_proposal_t *this, proposal_t *other,
                /* no integrity algorithm required, we have an AEAD */
                return TRUE;
        }
+       if (type == DIFFIE_HELLMAN_GROUP)
+       {
+               optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
+       }
 
        e1 = create_enumerator(this, type);
        e2 = other->create_enumerator(other, type);
-       if (!e1->enumerate(e1, NULL, NULL) && !e2->enumerate(e2, NULL, NULL))
+       if (!e1->enumerate(e1, NULL, NULL))
        {
-               found = TRUE;
+               if (!e2->enumerate(e2, &alg2, NULL))
+               {
+                       found = TRUE;
+               }
+               else if (optional)
+               {
+                       do
+                       {       /* if the other peer proposes NONE, we accept the proposal */
+                               found = !alg2;
+                       }
+                       while (!found && e2->enumerate(e2, &alg2, NULL));
+               }
        }
 
        e1->destroy(e1);