First: I'm aware that this setup is probably not very common, but it
pops up in the wild and therefore concerns uns.

Setup:
One or more site-to-site PSK-connections based on hostnames (DynDNS)
A roadwarrior connection also based on PSK (e.g. for a small group)

Example configuration:
ipsec.conf:
conn "S2S1_5"
        ...
        keyexchange="ikev1"
        leftauth="psk"
        rightauth="psk"
        left="%any"
        right="foo.bar.org"
        leftid="172.16.5.55"
        rightid="@foo.bar.org"
        ...

conn "RW1_0"
        ...
        keyexchange="ikev1"
        leftauth="psk"
        rightauth="psk"
        compress="no"
        left="%any"
        ...

ipsec.secrets:
172.16.5.55 @foo.bar.org : PSK "PSK-S2S"
%any : PSK "PSK-RW"

I'm aware that it is not possible with IKEv1 to match the PSK directly
by the FQDN, because only the IP address of the remote peer is available.
However, strongswan is able to find the correct config by resolving the
FQDN to the correct address when remotely initiating the S2S1_5 connection:

277587|7587|2017-01-04T10:19:13.000+01:00|charon||04[CFG] looking for an ike config for 172.16.5.55...172.16.5.109 277588|7588|2017-01-04T10:19:13.000+01:00|charon||04[CFG] candidate: %any...foo.bar.org, prio 2076 277589|7589|2017-01-04T10:19:13.000+01:00|charon||04[CFG] candidate: %any...%any, prio 28 277590|7590|2017-01-04T10:19:13.000+01:00|charon||04[CFG] found matching ike config: %any...foo.bar.org with prio 2076

But then shortly afterwards fails to lookup the correct PSK:
277601|7601|2017-01-04T10:19:13.000+01:00|charon||04[CFG] selected proposal: IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048 277602|7602|2017-01-04T10:19:13.000+01:00|charon||04[ENC] generating ID_PROT response 0 [ SA V V V ] 277603|7603|2017-01-04T10:19:13.000+01:00|charon||04[ENC] generating ID_PROT response 0 [ SA V V V ] 277604|7604|2017-01-04T10:19:13.000+01:00|charon||03[ENC] parsed ID_PROT request 0 [ KE No NAT-D NAT-D ] 277605|7605|2017-01-04T10:19:13.000+01:00|charon||03[ENC] parsed ID_PROT request 0 [ KE No NAT-D NAT-D ] 277606|7606|2017-01-04T10:19:13.000+01:00|charon||03[ENC] generating ID_PROT response 0 [ KE No NAT-D NAT-D ] 277607|7607|2017-01-04T10:19:13.000+01:00|charon||03[ENC] generating ID_PROT response 0 [ KE No NAT-D NAT-D ] 277608|7608|2017-01-04T10:19:13.000+01:00|charon||02[ENC] invalid ID_V1 payload length, decryption failed? 277609|7609|2017-01-04T10:19:13.000+01:00|charon||02[ENC] invalid ID_V1 payload length, decryption failed? 277610|7610|2017-01-04T10:19:13.000+01:00|charon||02[ENC] could not decrypt payloads 277611|7611|2017-01-04T10:19:13.000+01:00|charon||02[ENC] could not decrypt payloads 277612|7612|2017-01-04T10:19:13.000+01:00|charon||02[IKE] message parsing failed

I delved into the sources and as far as I can see, the problem
results from the order in which different methods to lookup the shared
key are applied in src/libcharon/sa/ikev1/phase1.c in the
lookup_shared_key function.

First, the ID selectors from the ipsec.secrets file are directly
matched against the local and remote IP address. If a match is found,
the key is found and returned. With the setup above, the %any of the
roadwarrior setup is always matched, the "PSK-RW" key is chosen and
consequently the decryption of the third phase-1 message fails at
the responder.

However, in the same function, there is also a lookup implemented using
the rightid of the config identified by resolving the hostname, it is
just not used because charon thinks it has already found the correct PSK.

My suggestion is to change the order of lookup methods to first consider
the rightid derived from a correctly identified config (using the
resolved IP address) and only use the plain IP address matching if no
PSK is found that way. See the attached patch.

With our setups, this solves the problem of charon picking the wrong PSK
for the given setup and as far as I can see should not have any negative
impact (but I probably do not see very far or clear). Are there any
implications I am missing that can harm the operation for
other configurations or open up security problems in any way?

Kind Regards
Andreas Weigel

--
Mit freundlichem Gruß / Best regards,

Andreas Weigel
UTM Backend Developer

Securepoint GmbH
Salzstrasse 1
D-21335 Lüneburg

https://www.securepoint.de

Tel.: +49(0)413124010
Fax: +49(0)4131240118

Geschäftsführer: Lutz Hausmann, Claudia Hausmann
Amtsgericht Lüneburg HRB 1776
USt.-ID-Nr.: DE 188 528 597

>From 157b889c1fa6c6e66975d2d3dc829ce8dfb978a8 Mon Sep 17 00:00:00 2001
From: Andreas Weigel <andrea...@securepoint.de>
Date: Mon, 9 Jan 2017 15:53:45 +0100
Subject: [PATCH] Reorder IKEv1 PSK lookup

Make raw lookup by plain remote IP to occur only after trying to match
rightid entries from a config that was matched (e.g., via a resolved
hostname).

Solves choosing of the wrong PSK in setups with a selector "%any" in
the ipsec.secrets (e.g., for a Roadwarrior PSK setup) that is used
alongside PSK setups using hostnames as identification. This kind of
setup used to work with pluto (strongswan 4.6.3) but not with charon
(strongswan > 5.0)
---
 src/libcharon/sa/ikev1/phase1.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c
index c968b2a..75ca1ed 100644
--- a/src/libcharon/sa/ikev1/phase1.c
+++ b/src/libcharon/sa/ikev1/phase1.c
@@ -113,22 +113,8 @@ static shared_key_t *lookup_shared_key(private_phase1_t *this,
 	auth_cfg_t *my_auth, *other_auth;
 	enumerator_t *enumerator;
 
-	/* try to get a PSK for IP addresses */
 	me = this->ike_sa->get_my_host(this->ike_sa);
 	other = this->ike_sa->get_other_host(this->ike_sa);
-	my_id = identification_create_from_sockaddr(me->get_sockaddr(me));
-	other_id = identification_create_from_sockaddr(other->get_sockaddr(other));
-	if (my_id && other_id)
-	{
-		shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE,
-											  my_id, other_id);
-	}
-	DESTROY_IF(my_id);
-	DESTROY_IF(other_id);
-	if (shared_key)
-	{
-		return shared_key;
-	}
 
 	if (peer_cfg)
 	{	/* as initiator or aggressive responder, use identities */
@@ -158,7 +144,9 @@ static shared_key_t *lookup_shared_key(private_phase1_t *this,
 		}
 		return shared_key;
 	}
-	/* as responder, we try to find a config by IP */
+
+	/* as responder, we try to find a config by IP address and use the ID
+	 * given in the config to find the PSK */
 	enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
 												me, other, NULL, NULL, IKEV1);
 	while (enumerator->enumerate(enumerator, &peer_cfg))
@@ -185,6 +173,22 @@ static shared_key_t *lookup_shared_key(private_phase1_t *this,
 			}
 		}
 	}
+	if (shared_key)
+	{
+		return shared_key;
+	}
+
+	/* if other methods fail, fallback to lookup by IP address directly */
+	my_id = identification_create_from_sockaddr(me->get_sockaddr(me));
+	other_id = identification_create_from_sockaddr(other->get_sockaddr(other));
+	if (my_id && other_id)
+	{
+		shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE,
+											  my_id, other_id);
+	}
+	DESTROY_IF(my_id);
+	DESTROY_IF(other_id);
+
 	enumerator->destroy(enumerator);
 	if (!shared_key)
 	{
-- 
2.7.4

_______________________________________________
Dev mailing list
Dev@lists.strongswan.org
https://lists.strongswan.org/mailman/listinfo/dev

Reply via email to