aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAtzm Watanabe <atzmism@gmail.com>2022-08-09 14:00:03 +0900
committerBeno�t Ganne <bganne@cisco.com>2022-08-10 07:44:55 +0000
commit7e6ffba672875f1070348753890d023695d73be6 (patch)
treed231716d946b016d1051fd05db6bfab5e021d04d
parent5c7e579f77833537e27a265295773378835d4500 (diff)
ikev2: do not accept rekey until old SA is deleted
Type: fix Signed-off-by: Atzm Watanabe <atzmism@gmail.com> Change-Id: I11b6107492004a45104857dc2dae01b9a5a01e3b
-rw-r--r--src/plugins/ikev2/ikev2.c49
-rw-r--r--src/plugins/ikev2/ikev2_priv.h1
-rw-r--r--test/test_ikev2.py48
3 files changed, 75 insertions, 23 deletions
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c
index 20be89e1aaf..f8b9c6fb04b 100644
--- a/src/plugins/ikev2/ikev2.c
+++ b/src/plugins/ikev2/ikev2.c
@@ -1463,6 +1463,7 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm,
rekey = sa->rekey;
if (vec_len (rekey) == 0)
goto cleanup_and_exit;
+ rekey->notify_type = 0;
rekey->protocol_id = proposal->protocol_id;
rekey->i_proposal =
ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP);
@@ -1491,22 +1492,34 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm,
goto cleanup_and_exit;
}
vec_add2 (sa->rekey, rekey, 1);
+ rekey->notify_type = 0;
rekey->protocol_id = n->protocol_id;
rekey->spi = n->spi;
- rekey->i_proposal = proposal;
- rekey->r_proposal =
- ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP);
- /* update Ni */
- vec_reset_length (sa->i_nonce);
- vec_add (sa->i_nonce, nonce, nonce_len);
- /* generate new Nr */
- vec_validate (sa->r_nonce, nonce_len - 1);
- RAND_bytes ((u8 *) sa->r_nonce, nonce_len);
+ if (sa->old_remote_id_present)
+ {
+ rekey->notify_type = IKEV2_NOTIFY_MSG_TEMPORARY_FAILURE;
+ vec_free (proposal);
+ vec_free (tsr);
+ vec_free (tsi);
+ }
+ else
+ {
+ rekey->i_proposal = proposal;
+ rekey->r_proposal =
+ ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP);
+ /* update Ni */
+ vec_reset_length (sa->i_nonce);
+ vec_add (sa->i_nonce, nonce, nonce_len);
+ /* generate new Nr */
+ vec_validate (sa->r_nonce, nonce_len - 1);
+ RAND_bytes ((u8 *) sa->r_nonce, nonce_len);
+ }
}
else
{
/* create new child SA */
vec_add2 (sa->new_child, rekey, 1);
+ rekey->notify_type = 0;
rekey->i_proposal = proposal;
rekey->r_proposal =
ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP);
@@ -2555,10 +2568,17 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike,
}
else if (vec_len (sa->rekey) > 0)
{
- ikev2_payload_add_sa (chain, sa->rekey[0].r_proposal);
- ikev2_payload_add_nonce (chain, sa->r_nonce);
- ikev2_payload_add_ts (chain, sa->rekey[0].tsi, IKEV2_PAYLOAD_TSI);
- ikev2_payload_add_ts (chain, sa->rekey[0].tsr, IKEV2_PAYLOAD_TSR);
+ if (sa->rekey[0].notify_type)
+ ikev2_payload_add_notify (chain, sa->rekey[0].notify_type, 0);
+ else
+ {
+ ikev2_payload_add_sa (chain, sa->rekey[0].r_proposal);
+ ikev2_payload_add_nonce (chain, sa->r_nonce);
+ ikev2_payload_add_ts (chain, sa->rekey[0].tsi,
+ IKEV2_PAYLOAD_TSI);
+ ikev2_payload_add_ts (chain, sa->rekey[0].tsr,
+ IKEV2_PAYLOAD_TSR);
+ }
vec_del1 (sa->rekey, 0);
}
else if (vec_len (sa->new_child) > 0)
@@ -3320,7 +3340,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node,
if (sa0->rekey)
{
- if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE)
+ if (!sa0->rekey[0].notify_type &&
+ sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE)
{
if (sa0->childs)
ikev2_sa_free_all_child_sa (&sa0->childs);
diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h
index 0a6036891b2..379b68dbdfc 100644
--- a/src/plugins/ikev2/ikev2_priv.h
+++ b/src/plugins/ikev2/ikev2_priv.h
@@ -312,6 +312,7 @@ typedef struct
typedef struct
{
+ u16 notify_type;
u8 protocol_id;
u32 spi;
u32 ispi;
diff --git a/test/test_ikev2.py b/test/test_ikev2.py
index ac77a4163a1..3c588719581 100644
--- a/test/test_ikev2.py
+++ b/test/test_ikev2.py
@@ -752,14 +752,15 @@ class IkePeer(VppTestCase):
else:
self.assertNotIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags)
- def verify_ipsec_sas(self, is_rekey=False):
+ def verify_ipsec_sas(self, is_rekey=False, sa_count=None):
sas = self.vapi.ipsec_sa_dump()
- if is_rekey:
- # after rekey there is a short period of time in which old
- # inbound SA is still present
- sa_count = 3
- else:
- sa_count = 2
+ if sa_count is None:
+ if is_rekey:
+ # after rekey there is a short period of time in which old
+ # inbound SA is still present
+ sa_count = 3
+ else:
+ sa_count = 2
self.assertEqual(len(sas), sa_count)
if self.sa.is_initiator:
if is_rekey:
@@ -2078,12 +2079,15 @@ class TestResponderDpd(TestResponderPsk):
class TestResponderRekey(TestResponderPsk):
"""test ikev2 responder - rekey"""
- def rekey_from_initiator(self):
+ def send_rekey_from_initiator(self):
packet = self.create_rekey_request()
self.pg0.add_stream(packet)
self.pg0.enable_capture()
self.pg_start()
capture = self.pg0.get_capture(1)
+ return capture
+
+ def process_rekey_response(self, capture):
ih = self.get_ike_header(capture[0])
plain = self.sa.hmac_and_decrypt(ih)
sa = ikev2.IKEv2_payload_SA(plain)
@@ -2094,7 +2098,7 @@ class TestResponderRekey(TestResponderPsk):
def test_responder(self):
super(TestResponderRekey, self).test_responder()
- self.rekey_from_initiator()
+ self.process_rekey_response(self.send_rekey_from_initiator())
self.sa.calc_child_keys()
self.verify_ike_sas()
self.verify_ipsec_sas(is_rekey=True)
@@ -2103,6 +2107,32 @@ class TestResponderRekey(TestResponderPsk):
self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
+@tag_fixme_vpp_workers
+class TestResponderRekeyRepeat(TestResponderRekey):
+ """test ikev2 responder - rekey repeat"""
+
+ def test_responder(self):
+ super(TestResponderRekeyRepeat, self).test_responder()
+ # rekey request is not accepted until old IPsec SA is expired
+ capture = self.send_rekey_from_initiator()
+ ih = self.get_ike_header(capture[0])
+ plain = self.sa.hmac_and_decrypt(ih)
+ notify = ikev2.IKEv2_payload_Notify(plain)
+ self.assertEqual(notify.type, 43)
+ self.assertEqual(len(self.vapi.ipsec_sa_dump()), 3)
+ # rekey request is accepted after old IPsec SA was expired
+ for _ in range(50):
+ if len(self.vapi.ipsec_sa_dump()) != 3:
+ break
+ time.sleep(0.2)
+ else:
+ self.fail("old IPsec SA not expired")
+ self.process_rekey_response(self.send_rekey_from_initiator())
+ self.sa.calc_child_keys()
+ self.verify_ike_sas()
+ self.verify_ipsec_sas(sa_count=3)
+
+
class TestResponderVrf(TestResponderPsk, Ikev2Params):
"""test ikev2 responder - non-default table id"""