Skip to content

Commit edf2900

Browse files
Filip Tehlarbganne
authored andcommitted
ikev2: support sending requests from responder
Type: improvement Ticket: VPP-1894 Change-Id: I5a24a48416bca2ffbd346cdaa813fb25801e6c9b Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
1 parent 6ba4e41 commit edf2900

File tree

4 files changed

+146
-29
lines changed

4 files changed

+146
-29
lines changed

src/plugins/ikev2/ikev2.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,7 +2352,7 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa,
23522352
{
23532353
if (sa->del[0].protocol_id == IKEV2_PROTOCOL_IKE)
23542354
{
2355-
if (sa->is_initiator)
2355+
if (ike_hdr_is_request (ike))
23562356
ikev2_payload_add_delete (chain, sa->del);
23572357

23582358
/* The response to a request that deletes the IKE SA is an empty
@@ -2446,16 +2446,14 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa,
24462446
ike->version = IKE_VERSION_2;
24472447
ike->nextpayload = IKEV2_PAYLOAD_SK;
24482448
tlen = sizeof (*ike);
2449+
24492450
if (sa->is_initiator)
2451+
ike->flags |= IKEV2_HDR_FLAG_INITIATOR;
2452+
2453+
if (ike_hdr_is_request (ike))
24502454
{
2451-
ike->flags = IKEV2_HDR_FLAG_INITIATOR;
24522455
sa->last_init_msg_id = clib_net_to_host_u32 (ike->msgid);
24532456
}
2454-
else
2455-
{
2456-
ike->flags = IKEV2_HDR_FLAG_RESPONSE;
2457-
}
2458-
24592457

24602458
if (ike->exchange == IKEV2_EXCHANGE_SA_INIT)
24612459
{
@@ -2638,6 +2636,9 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr,
26382636
static u32
26392637
ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike)
26402638
{
2639+
if (ike_hdr_is_response (ike))
2640+
return 0;
2641+
26412642
u32 msg_id = clib_net_to_host_u32 (ike->msgid);
26422643

26432644
/* new req */
@@ -2852,7 +2853,7 @@ ikev2_node_internal (vlib_main_t * vm,
28522853
sa0 = &sa;
28532854
clib_memset (sa0, 0, sizeof (*sa0));
28542855

2855-
if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR)
2856+
if (ike_hdr_is_initiator (ike0))
28562857
{
28572858
if (ike0->rspi == 0)
28582859
{
@@ -2898,6 +2899,7 @@ ikev2_node_internal (vlib_main_t * vm,
28982899
if (sa0->state == IKEV2_STATE_SA_INIT
28992900
|| sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE)
29002901
{
2902+
ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
29012903
slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0);
29022904
if (~0 == slen)
29032905
vlib_node_increment_counter (vm, node->node_index,
@@ -2945,6 +2947,7 @@ ikev2_node_internal (vlib_main_t * vm,
29452947
ikev2_complete_sa_data (sa0, sai);
29462948
ikev2_calc_keys (sa0);
29472949
ikev2_sa_auth_init (sa0);
2950+
ike0->flags = IKEV2_HDR_FLAG_INITIATOR;
29482951
slen =
29492952
ikev2_generate_message (b0, sa0, ike0, 0, udp0);
29502953
if (~0 == slen)
@@ -3086,9 +3089,9 @@ ikev2_node_internal (vlib_main_t * vm,
30863089
}
30873090
}
30883091
}
3089-
if (!(ike0->flags & IKEV2_HDR_FLAG_RESPONSE))
3092+
if (ike_hdr_is_request (ike0))
30903093
{
3091-
ike0->flags |= IKEV2_HDR_FLAG_RESPONSE;
3094+
ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
30923095
slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0);
30933096
if (~0 == slen)
30943097
vlib_node_increment_counter (vm, node->node_index,
@@ -3149,6 +3152,7 @@ ikev2_node_internal (vlib_main_t * vm,
31493152
}
31503153
else
31513154
{
3155+
ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
31523156
slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0);
31533157
if (~0 == slen)
31543158
vlib_node_increment_counter (vm, node->node_index,
@@ -3615,7 +3619,7 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm,
36153619
ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL;
36163620
ike0->ispi = clib_host_to_net_u64 (sa->ispi);
36173621
ike0->rspi = clib_host_to_net_u64 (sa->rspi);
3618-
3622+
ike0->flags = 0;
36193623
ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1);
36203624
sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid);
36213625
len = ikev2_generate_message (b0, sa, ike0, 0, 0);
@@ -4269,6 +4273,7 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa,
42694273
ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL;
42704274
ike0->ispi = clib_host_to_net_u64 (sa->ispi);
42714275
ike0->rspi = clib_host_to_net_u64 (sa->rspi);
4276+
ike0->flags = 0;
42724277
vec_resize (sa->del, 1);
42734278
sa->del->protocol_id = IKEV2_PROTOCOL_ESP;
42744279
sa->del->spi = csa->i_proposals->spi;
@@ -4837,6 +4842,7 @@ ikev2_send_informational_request (ikev2_sa_t * sa)
48374842
ike0->ispi = clib_host_to_net_u64 (sa->ispi);
48384843
ike0->rspi = clib_host_to_net_u64 (sa->rspi);
48394844
ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1);
4845+
ike0->flags = 0;
48404846
sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid);
48414847
len = ikev2_generate_message (b0, sa, ike0, 0, 0);
48424848
if (~0 == len)

src/plugins/ikev2/ikev2.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ typedef CLIB_PACKED (struct {
4444
}) ike_header_t;
4545
/* *INDENT-ON* */
4646

47+
#define ike_hdr_is_response(_h) ((_h)->flags & IKEV2_HDR_FLAG_RESPONSE)
48+
#define ike_hdr_is_request(_h) (!ike_hdr_is_response(_h))
49+
#define ike_hdr_is_initiator(_h) ((_h)->flags & IKEV2_HDR_FLAG_INITIATOR)
50+
#define ike_hdr_is_responder(_h) (!(ike_hdr_is_initiator(_h)))
51+
4752
/* *INDENT-OFF* */
4853
typedef CLIB_PACKED (struct {
4954
u8 nextpayload;

src/plugins/ikev2/ikev2_priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,10 +400,12 @@ typedef struct
400400
u8 *last_sa_init_res_packet_data;
401401

402402
/* retransmit */
403+
/* message id expected in the request from the other peer */
403404
u32 last_msg_id;
404405
u8 *last_res_packet_data;
405406

406407
u8 is_initiator;
408+
/* last message id that was used for an initiated request */
407409
u32 last_init_msg_id;
408410
u32 profile_index;
409411
u8 is_tun_itf_set;

src/plugins/ikev2/test/test_ikev2.py

Lines changed: 122 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,7 @@ def decrypt(self, data, key, aad=None, icv=None):
113113
self.mode(nonce, icv, len(icv)),
114114
default_backend()).decryptor()
115115
decryptor.authenticate_additional_data(aad)
116-
pt = decryptor.update(ct) + decryptor.finalize()
117-
pad_len = pt[-1] + 1
118-
return pt[:-pad_len]
116+
return decryptor.update(ct) + decryptor.finalize()
119117

120118
def pad(self, data):
121119
pad_len = (len(data) // self.bs + 1) * self.bs - len(data)
@@ -435,14 +433,17 @@ def hmac_and_decrypt(self, ike):
435433
aad_len = len(ikev2.IKEv2_payload_Encrypted()) + len(ikev2.IKEv2())
436434
ct = ep.load[:-GCM_ICV_SIZE]
437435
tag = ep.load[-GCM_ICV_SIZE:]
438-
return self.decrypt(ct, raw(ike)[:aad_len], tag)
436+
plain = self.decrypt(ct, raw(ike)[:aad_len], tag)
439437
else:
440438
self.verify_hmac(raw(ike))
441439
integ_trunc = self.ike_integ_alg.trunc_len
442440

443441
# remove ICV and decrypt payload
444442
ct = ep.load[:-integ_trunc]
445-
return self.decrypt(ct)
443+
plain = self.decrypt(ct)
444+
# remove padding
445+
pad_len = plain[-1]
446+
return plain[:-pad_len - 1]
446447

447448
def build_ts_addr(self, ts, version):
448449
return {'starting_address_v' + version: ts['start_addr'],
@@ -540,6 +541,19 @@ def setUpClass(cls):
540541
def tearDownClass(cls):
541542
super(IkePeer, cls).tearDownClass()
542543

544+
def tearDown(self):
545+
super(IkePeer, self).tearDown()
546+
if self.del_sa_from_responder:
547+
self.initiate_del_sa_from_responder()
548+
else:
549+
self.initiate_del_sa_from_initiator()
550+
r = self.vapi.ikev2_sa_dump()
551+
self.assertEqual(len(r), 0)
552+
sas = self.vapi.ipsec_sa_dump()
553+
self.assertEqual(len(sas), 0)
554+
self.p.remove_vpp_config()
555+
self.assertIsNone(self.p.query_vpp_config())
556+
543557
def setUp(self):
544558
super(IkePeer, self).setUp()
545559
self.config_tc()
@@ -580,6 +594,7 @@ def get_ike_header(self, packet):
580594
esp = packet[ESP]
581595
ih = self.verify_and_remove_non_esp_marker(esp)
582596
self.assertEqual(ih.version, 0x20)
597+
self.assertNotIn('Version', ih.flags)
583598
return ih
584599

585600
def verify_and_remove_non_esp_marker(self, packet):
@@ -775,8 +790,49 @@ def verify_ts(self, api_ts, ts, is_initiator):
775790
class TemplateInitiator(IkePeer):
776791
""" initiator test template """
777792

778-
def tearDown(self):
779-
super(TemplateInitiator, self).tearDown()
793+
def initiate_del_sa_from_initiator(self):
794+
ispi = int.from_bytes(self.sa.ispi, 'little')
795+
self.pg0.enable_capture()
796+
self.pg_start()
797+
self.vapi.ikev2_initiate_del_ike_sa(ispi=ispi)
798+
capture = self.pg0.get_capture(1)
799+
ih = self.get_ike_header(capture[0])
800+
self.assertNotIn('Response', ih.flags)
801+
self.assertIn('Initiator', ih.flags)
802+
self.assertEqual(ih.init_SPI, self.sa.ispi)
803+
self.assertEqual(ih.resp_SPI, self.sa.rspi)
804+
plain = self.sa.hmac_and_decrypt(ih)
805+
d = ikev2.IKEv2_payload_Delete(plain)
806+
self.assertEqual(d.proto, 1) # proto=IKEv2
807+
header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi,
808+
flags='Response', exch_type='INFORMATIONAL',
809+
id=ih.id, next_payload='Encrypted')
810+
resp = self.encrypt_ike_msg(header, b'', None)
811+
self.send_and_assert_no_replies(self.pg0, resp)
812+
813+
def verify_del_sa(self, packet):
814+
ih = self.get_ike_header(packet)
815+
self.assertEqual(ih.id, self.sa.msg_id)
816+
self.assertEqual(ih.exch_type, 37) # exchange informational
817+
self.assertIn('Response', ih.flags)
818+
self.assertIn('Initiator', ih.flags)
819+
plain = self.sa.hmac_and_decrypt(ih)
820+
self.assertEqual(plain, b'')
821+
822+
def initiate_del_sa_from_responder(self):
823+
header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi,
824+
exch_type='INFORMATIONAL',
825+
id=self.sa.new_msg_id())
826+
del_sa = ikev2.IKEv2_payload_Delete(proto='IKEv2')
827+
ike_msg = self.encrypt_ike_msg(header, del_sa, 'Delete')
828+
packet = self.create_packet(self.pg0, ike_msg,
829+
self.sa.sport, self.sa.dport,
830+
self.sa.natt, self.ip6)
831+
self.pg0.add_stream(packet)
832+
self.pg0.enable_capture()
833+
self.pg_start()
834+
capture = self.pg0.get_capture(1)
835+
self.verify_del_sa(capture[0])
780836

781837
@staticmethod
782838
def find_notify_payload(packet, notify_type):
@@ -946,22 +1002,41 @@ def test_initiator(self):
9461002
class TemplateResponder(IkePeer):
9471003
""" responder test template """
9481004

949-
def tearDown(self):
950-
super(TemplateResponder, self).tearDown()
951-
if self.sa.is_initiator:
952-
self.initiate_del_sa()
953-
r = self.vapi.ikev2_sa_dump()
954-
self.assertEqual(len(r), 0)
955-
956-
self.p.remove_vpp_config()
957-
self.assertIsNone(self.p.query_vpp_config())
1005+
def initiate_del_sa_from_responder(self):
1006+
self.pg0.enable_capture()
1007+
self.pg_start()
1008+
self.vapi.ikev2_initiate_del_ike_sa(
1009+
ispi=int.from_bytes(self.sa.ispi, 'little'))
1010+
capture = self.pg0.get_capture(1)
1011+
ih = self.get_ike_header(capture[0])
1012+
self.assertNotIn('Response', ih.flags)
1013+
self.assertNotIn('Initiator', ih.flags)
1014+
self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
1015+
plain = self.sa.hmac_and_decrypt(ih)
1016+
d = ikev2.IKEv2_payload_Delete(plain)
1017+
self.assertEqual(d.proto, 1) # proto=IKEv2
1018+
self.assertEqual(ih.init_SPI, self.sa.ispi)
1019+
self.assertEqual(ih.resp_SPI, self.sa.rspi)
1020+
header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi,
1021+
flags='Initiator+Response',
1022+
exch_type='INFORMATIONAL',
1023+
id=ih.id, next_payload='Encrypted')
1024+
resp = self.encrypt_ike_msg(header, b'', None)
1025+
self.send_and_assert_no_replies(self.pg0, resp)
9581026

9591027
def verify_del_sa(self, packet):
9601028
ih = self.get_ike_header(packet)
9611029
self.assertEqual(ih.id, self.sa.msg_id)
9621030
self.assertEqual(ih.exch_type, 37) # exchange informational
1031+
self.assertIn('Response', ih.flags)
1032+
self.assertNotIn('Initiator', ih.flags)
1033+
self.assertEqual(ih.next_payload, 46) # Encrypted
1034+
self.assertEqual(ih.init_SPI, self.sa.ispi)
1035+
self.assertEqual(ih.resp_SPI, self.sa.rspi)
1036+
plain = self.sa.hmac_and_decrypt(ih)
1037+
self.assertEqual(plain, b'')
9631038

964-
def initiate_del_sa(self):
1039+
def initiate_del_sa_from_initiator(self):
9651040
header = ikev2.IKEv2(init_SPI=self.sa.ispi, resp_SPI=self.sa.rspi,
9661041
flags='Initiator', exch_type='INFORMATIONAL',
9671042
id=self.sa.new_msg_id())
@@ -1081,7 +1156,7 @@ def verify_sa_init(self, packet):
10811156

10821157
self.assertEqual(ih.id, self.sa.msg_id)
10831158
self.assertEqual(ih.exch_type, 34)
1084-
self.assertTrue('Response' in ih.flags)
1159+
self.assertIn('Response', ih.flags)
10851160
self.assertEqual(ih.init_SPI, self.sa.ispi)
10861161
self.assertNotEqual(ih.resp_SPI, 0)
10871162
self.sa.rspi = ih.resp_SPI
@@ -1129,6 +1204,8 @@ def config_params(self, params={}):
11291204
'SHA2-384-192': ei.IPSEC_API_INTEG_ALG_SHA_384_192,
11301205
'SHA2-512-256': ei.IPSEC_API_INTEG_ALG_SHA_512_256}
11311206

1207+
self.del_sa_from_responder = False if 'del_sa_from_responder'\
1208+
not in params else params['del_sa_from_responder']
11321209
is_natt = 'natt' in params and params['natt'] or False
11331210
self.p = Profile(self, 'pr1')
11341211
self.ip6 = False if 'ip6' not in params else params['ip6']
@@ -1392,8 +1469,34 @@ def verify_profile(self, ap, cp):
13921469

13931470
class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
13941471
""" test ikev2 initiator - pre shared key auth """
1472+
1473+
def config_tc(self):
1474+
self.config_params({
1475+
'is_initiator': False, # seen from test case perspective
1476+
# thus vpp is initiator
1477+
'responder': {'sw_if_index': self.pg0.sw_if_index,
1478+
'addr': self.pg0.remote_ip4},
1479+
'ike-crypto': ('AES-GCM-16ICV', 32),
1480+
'ike-integ': 'NULL',
1481+
'ike-dh': '3072MODPgr',
1482+
'ike_transforms': {
1483+
'crypto_alg': 20, # "aes-gcm-16"
1484+
'crypto_key_size': 256,
1485+
'dh_group': 15, # "modp-3072"
1486+
},
1487+
'esp_transforms': {
1488+
'crypto_alg': 12, # "aes-cbc"
1489+
'crypto_key_size': 256,
1490+
# "hmac-sha2-256-128"
1491+
'integ_alg': 12}})
1492+
1493+
1494+
class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
1495+
""" test ikev2 initiator - delete IKE SA from responder """
1496+
13951497
def config_tc(self):
13961498
self.config_params({
1499+
'del_sa_from_responder': True,
13971500
'is_initiator': False, # seen from test case perspective
13981501
# thus vpp is initiator
13991502
'responder': {'sw_if_index': self.pg0.sw_if_index,
@@ -1471,6 +1574,7 @@ class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
14711574
"""
14721575
def config_tc(self):
14731576
self.config_params({
1577+
'del_sa_from_responder': True,
14741578
'ip6': True,
14751579
'natt': True,
14761580
'ike-crypto': ('AES-GCM-16ICV', 32),

0 commit comments

Comments
 (0)