@@ -151,10 +151,28 @@ def __init__(self, name, mac, mod, key_len, trunc_len=None):
151151 hashes .SHA256 , 32 ),
152152}
153153
154+ CRYPTO_IDS = {
155+ 12 : 'AES-CBC' ,
156+ 20 : 'AES-GCM-16ICV' ,
157+ }
158+
159+ INTEG_IDS = {
160+ 2 : 'HMAC-SHA1-96' ,
161+ 12 : 'SHA2-256-128' ,
162+ 13 : 'SHA2-384-192' ,
163+ 14 : 'SHA2-512-256' ,
164+ }
165+
154166
155167class IKEv2ChildSA (object ):
156- def __init__ (self , local_ts , remote_ts , spi = None ):
157- self .spi = spi or os .urandom (4 )
168+ def __init__ (self , local_ts , remote_ts , is_initiator ):
169+ spi = os .urandom (4 )
170+ if is_initiator :
171+ self .ispi = spi
172+ self .rspi = None
173+ else :
174+ self .rspi = spi
175+ self .ispi = None
158176 self .local_ts = local_ts
159177 self .remote_ts = remote_ts
160178
@@ -193,7 +211,8 @@ def __init__(self, test, is_initiator=True, i_id=None, r_id=None,
193211 self .rspi = spi
194212 self .ispi = 8 * b'\x00 '
195213 self .r_nonce = nonce
196- self .child_sas = [IKEv2ChildSA (local_ts , remote_ts )]
214+ self .child_sas = [IKEv2ChildSA (local_ts , remote_ts ,
215+ self .is_initiator )]
197216
198217 def new_msg_id (self ):
199218 self .msg_id += 1
@@ -559,9 +578,11 @@ def setUp(self):
559578 self .config_tc ()
560579 self .p .add_vpp_config ()
561580 self .assertIsNotNone (self .p .query_vpp_config ())
562- self .sa .generate_dh_data ()
581+ if self .sa .is_initiator :
582+ self .sa .generate_dh_data ()
563583 self .vapi .cli ('ikev2 set logging level 4' )
564584 self .vapi .cli ('event-lo clear' )
585+ self .vapi .cli ('ikev2 dpd disable' )
565586
566587 def create_packet (self , src_if , msg , sport = 500 , dport = 500 , natt = False ,
567588 use_ip6 = False ):
@@ -641,16 +662,30 @@ def encrypt_ike_msg(self, header, plain, first_payload):
641662 assert (len (res ) == tlen )
642663 return res
643664
644- def verify_ipsec_sas (self ):
665+ def verify_ipsec_sas (self , is_rekey = False ):
645666 sas = self .vapi .ipsec_sa_dump ()
646- self .assertEqual (len (sas ), 2 )
667+ if is_rekey :
668+ # after rekey there is a short period of time in which old
669+ # inbound SA is still present
670+ sa_count = 3
671+ else :
672+ sa_count = 2
673+ self .assertEqual (len (sas ), sa_count )
647674 e = VppEnum .vl_api_ipsec_sad_flags_t
648675 if self .sa .is_initiator :
649- sa0 = sas [0 ].entry
650- sa1 = sas [1 ].entry
676+ if is_rekey :
677+ sa0 = sas [0 ].entry
678+ sa1 = sas [2 ].entry
679+ else :
680+ sa0 = sas [0 ].entry
681+ sa1 = sas [1 ].entry
651682 else :
652- sa1 = sas [0 ].entry
653- sa0 = sas [1 ].entry
683+ if is_rekey :
684+ sa0 = sas [2 ].entry
685+ sa1 = sas [0 ].entry
686+ else :
687+ sa1 = sas [0 ].entry
688+ sa0 = sas [1 ].entry
654689
655690 c = self .sa .child_sas [0 ]
656691
@@ -738,6 +773,8 @@ def verify_ike_sas(self):
738773 self .verify_keymat (csa .keys , c , 'sk_ar' )
739774 self .verify_keymat (csa .keys , c , 'sk_ei' )
740775 self .verify_keymat (csa .keys , c , 'sk_er' )
776+ self .assertEqual (csa .i_spi .to_bytes (4 , 'big' ), c .ispi )
777+ self .assertEqual (csa .r_spi .to_bytes (4 , 'big' ), c .rspi )
741778
742779 tsi , tsr = self .sa .generate_ts (self .p .ts_is_ip4 )
743780 tsi = tsi [0 ]
@@ -888,9 +925,23 @@ def verify_sa_init_request(self, packet):
888925 self .p .ike_transforms ['dh_group' ])
889926
890927 self .verify_nat_detection (packet )
928+ self .sa .set_ike_props (
929+ crypto = 'AES-GCM-16ICV' , crypto_key_len = 32 ,
930+ integ = 'NULL' , prf = 'PRF_HMAC_SHA2_256' , dh = '3072MODPgr' )
931+ self .sa .set_esp_props (crypto = 'AES-CBC' , crypto_key_len = 32 ,
932+ integ = 'SHA2-256-128' )
933+ self .sa .generate_dh_data ()
891934 self .sa .complete_dh_data ()
892935 self .sa .calc_keys ()
893936
937+ def update_esp_transforms (self , trans , sa ):
938+ while trans :
939+ if trans .transform_type == 1 : # ecryption
940+ sa .esp_crypto = CRYPTO_IDS [trans .transform_id ]
941+ elif trans .transform_type == 3 : # integrity
942+ sa .esp_integ = INTEG_IDS [trans .transform_id ]
943+ trans = trans .payload
944+
894945 def verify_sa_auth_req (self , packet ):
895946 ih = self .get_ike_header (packet )
896947 self .assertEqual (ih .resp_SPI , self .sa .rspi )
@@ -908,6 +959,11 @@ def verify_sa_auth_req(self, packet):
908959 idr = ikev2 .IKEv2_payload_IDr (idi .payload )
909960 self .assertEqual (idi .load , self .sa .i_id )
910961 self .assertEqual (idr .load , self .sa .r_id )
962+ prop = idi [ikev2 .IKEv2_payload_Proposal ]
963+ c = self .sa .child_sas [0 ]
964+ c .ispi = prop .SPI
965+ self .update_esp_transforms (
966+ prop [ikev2 .IKEv2_payload_Transform ], self .sa )
911967
912968 def send_init_response (self ):
913969 tr_attr = self .sa .ike_crypto_attr ()
@@ -961,8 +1017,9 @@ def send_auth_response(self):
9611017 transform_type = 'Extended Sequence Number' ,
9621018 transform_id = 'ESN' ))
9631019
1020+ c = self .sa .child_sas [0 ]
9641021 props = (ikev2 .IKEv2_payload_Proposal (proposal = 1 , proto = 'ESP' ,
965- SPIsize = 4 , SPI = os . urandom ( 4 ) , trans_nb = 4 , trans = trans ))
1022+ SPIsize = 4 , SPI = c . rspi , trans_nb = 4 , trans = trans ))
9661023
9671024 tsi , tsr = self .sa .generate_ts (self .p .ts_is_ip4 )
9681025 plain = (ikev2 .IKEv2_payload_IDi (next_payload = 'IDr' ,
@@ -1103,8 +1160,9 @@ def send_sa_init_req(self, behind_nat=False):
11031160 capture = self .pg0 .get_capture (1 )
11041161 self .verify_sa_init (capture [0 ])
11051162
1106- def send_sa_auth (self ):
1163+ def generate_auth_payload (self , last_payload = None , is_rekey = False ):
11071164 tr_attr = self .sa .esp_crypto_attr ()
1165+ last_payload = last_payload or 'Notify'
11081166 trans = (ikev2 .IKEv2_payload_Transform (transform_type = 'Encryption' ,
11091167 transform_id = self .sa .esp_crypto , length = tr_attr [1 ],
11101168 key_length = tr_attr [0 ]) /
@@ -1117,32 +1175,45 @@ def send_sa_auth(self):
11171175 transform_type = 'Extended Sequence Number' ,
11181176 transform_id = 'ESN' ))
11191177
1178+ c = self .sa .child_sas [0 ]
11201179 props = (ikev2 .IKEv2_payload_Proposal (proposal = 1 , proto = 'ESP' ,
1121- SPIsize = 4 , SPI = os . urandom ( 4 ) , trans_nb = 4 , trans = trans ))
1180+ SPIsize = 4 , SPI = c . ispi , trans_nb = 4 , trans = trans ))
11221181
11231182 tsi , tsr = self .sa .generate_ts (self .p .ts_is_ip4 )
1124- plain = (ikev2 .IKEv2_payload_IDi (next_payload = 'IDr' ,
1125- IDtype = self .sa .id_type , load = self .sa .i_id ) /
1126- ikev2 .IKEv2_payload_IDr (next_payload = 'AUTH' ,
1127- IDtype = self .sa .id_type , load = self .sa .r_id ) /
1128- ikev2 .IKEv2_payload_AUTH (next_payload = 'SA' ,
1183+ plain = (ikev2 .IKEv2_payload_AUTH (next_payload = 'SA' ,
11291184 auth_type = AuthMethod .value (self .sa .auth_method ),
11301185 load = self .sa .auth_data ) /
11311186 ikev2 .IKEv2_payload_SA (next_payload = 'TSi' , prop = props ) /
11321187 ikev2 .IKEv2_payload_TSi (next_payload = 'TSr' ,
1133- number_of_TSs = len (tsi ),
1134- traffic_selector = tsi ) /
1135- ikev2 .IKEv2_payload_TSr (next_payload = 'Notify' ,
1136- number_of_TSs = len (tsr ),
1137- traffic_selector = tsr ) /
1138- ikev2 .IKEv2_payload_Notify (type = 'INITIAL_CONTACT' ))
1188+ number_of_TSs = len (tsi ), traffic_selector = tsi ) /
1189+ ikev2 .IKEv2_payload_TSr (next_payload = last_payload ,
1190+ number_of_TSs = len (tsr ), traffic_selector = tsr ))
1191+
1192+ if is_rekey :
1193+ first_payload = 'Nonce'
1194+ plain = (ikev2 .IKEv2_payload_Nonce (load = self .sa .i_nonce ,
1195+ next_payload = 'SA' ) / plain /
1196+ ikev2 .IKEv2_payload_Notify (type = 'REKEY_SA' ,
1197+ proto = 'ESP' , SPI = c .ispi ))
1198+ else :
1199+ first_payload = 'IDi'
1200+ ids = (ikev2 .IKEv2_payload_IDi (next_payload = 'IDr' ,
1201+ IDtype = self .sa .id_type , load = self .sa .i_id ) /
1202+ ikev2 .IKEv2_payload_IDr (next_payload = 'AUTH' ,
1203+ IDtype = self .sa .id_type , load = self .sa .r_id ))
1204+ plain = ids / plain
1205+ return plain , first_payload
11391206
1207+ def send_sa_auth (self ):
1208+ plain , first_payload = self .generate_auth_payload (
1209+ last_payload = 'Notify' )
1210+ plain = plain / ikev2 .IKEv2_payload_Notify (type = 'INITIAL_CONTACT' )
11401211 header = ikev2 .IKEv2 (
11411212 init_SPI = self .sa .ispi ,
11421213 resp_SPI = self .sa .rspi , id = self .sa .new_msg_id (),
11431214 flags = 'Initiator' , exch_type = 'IKE_AUTH' )
11441215
1145- ike_msg = self .encrypt_ike_msg (header , plain , 'IDi' )
1216+ ike_msg = self .encrypt_ike_msg (header , plain , first_payload )
11461217 packet = self .create_packet (self .pg0 , ike_msg , self .sa .sport ,
11471218 self .sa .dport , self .sa .natt , self .ip6 )
11481219 self .pg0 .add_stream (packet )
@@ -1178,6 +1249,10 @@ def verify_sa_auth_resp(self, packet):
11781249 self .verify_udp (udp )
11791250 self .assertEqual (ike .id , self .sa .msg_id )
11801251 plain = self .sa .hmac_and_decrypt (ike )
1252+ idr = ikev2 .IKEv2_payload_IDr (plain )
1253+ prop = idr [ikev2 .IKEv2_payload_Proposal ]
1254+ self .assertEqual (prop .SPIsize , 4 )
1255+ self .sa .child_sas [0 ].rspi = prop .SPI
11811256 self .sa .calc_child_keys ()
11821257
11831258 def test_responder (self ):
@@ -1264,24 +1339,25 @@ def config_params(self, params={}):
12641339 auth_data = auth_data ,
12651340 local_ts = self .p .remote_ts , remote_ts = self .p .local_ts )
12661341
1267- ike_crypto = ('AES-CBC' , 32 ) if 'ike-crypto' not in params else \
1268- params ['ike-crypto' ]
1269- ike_integ = 'HMAC-SHA1-96' if 'ike-integ' not in params else \
1270- params ['ike-integ' ]
1271- ike_dh = '2048MODPgr' if 'ike-dh' not in params else \
1272- params ['ike-dh' ]
1273-
1274- esp_crypto = ('AES-CBC' , 32 ) if 'esp-crypto' not in params else \
1275- params ['esp-crypto' ]
1276- esp_integ = 'HMAC-SHA1-96' if 'esp-integ' not in params else \
1277- params ['esp-integ' ]
1278-
1279- self .sa .set_ike_props (
1280- crypto = ike_crypto [0 ], crypto_key_len = ike_crypto [1 ],
1281- integ = ike_integ , prf = 'PRF_HMAC_SHA2_256' , dh = ike_dh )
1282- self .sa .set_esp_props (
1283- crypto = esp_crypto [0 ], crypto_key_len = esp_crypto [1 ],
1284- integ = esp_integ )
1342+ if is_init :
1343+ ike_crypto = ('AES-CBC' , 32 ) if 'ike-crypto' not in params else \
1344+ params ['ike-crypto' ]
1345+ ike_integ = 'HMAC-SHA1-96' if 'ike-integ' not in params else \
1346+ params ['ike-integ' ]
1347+ ike_dh = '2048MODPgr' if 'ike-dh' not in params else \
1348+ params ['ike-dh' ]
1349+
1350+ esp_crypto = ('AES-CBC' , 32 ) if 'esp-crypto' not in params else \
1351+ params ['esp-crypto' ]
1352+ esp_integ = 'HMAC-SHA1-96' if 'esp-integ' not in params else \
1353+ params ['esp-integ' ]
1354+
1355+ self .sa .set_ike_props (
1356+ crypto = ike_crypto [0 ], crypto_key_len = ike_crypto [1 ],
1357+ integ = ike_integ , prf = 'PRF_HMAC_SHA2_256' , dh = ike_dh )
1358+ self .sa .set_esp_props (
1359+ crypto = esp_crypto [0 ], crypto_key_len = esp_crypto [1 ],
1360+ integ = esp_integ )
12851361
12861362
12871363class TestApi (VppTestCase ):
@@ -1491,6 +1567,44 @@ def config_tc(self):
14911567 'integ_alg' : 12 }})
14921568
14931569
1570+ class TestInitiatorRekey (TestInitiatorPsk ):
1571+ """ test ikev2 initiator - rekey """
1572+
1573+ def rekey_from_initiator (self ):
1574+ ispi = int .from_bytes (self .sa .child_sas [0 ].ispi , 'little' )
1575+ self .pg0 .enable_capture ()
1576+ self .pg_start ()
1577+ self .vapi .ikev2_initiate_rekey_child_sa (ispi = ispi )
1578+ capture = self .pg0 .get_capture (1 )
1579+ ih = self .get_ike_header (capture [0 ])
1580+ self .assertEqual (ih .exch_type , 36 ) # CHILD_SA
1581+ self .assertNotIn ('Response' , ih .flags )
1582+ self .assertIn ('Initiator' , ih .flags )
1583+ plain = self .sa .hmac_and_decrypt (ih )
1584+ sa = ikev2 .IKEv2_payload_SA (plain )
1585+ prop = sa [ikev2 .IKEv2_payload_Proposal ]
1586+ nonce = sa [ikev2 .IKEv2_payload_Nonce ]
1587+ self .sa .i_nonce = sa [ikev2 .IKEv2_payload_Nonce ].load
1588+ self .sa .r_nonce = self .sa .i_nonce
1589+ # update new responder SPI
1590+ self .sa .child_sas [0 ].ispi = prop .SPI
1591+ self .sa .child_sas [0 ].rspi = prop .SPI
1592+ self .sa .calc_child_keys ()
1593+ header = ikev2 .IKEv2 (init_SPI = self .sa .ispi , resp_SPI = self .sa .rspi ,
1594+ flags = 'Response' , exch_type = 36 ,
1595+ id = ih .id , next_payload = 'Encrypted' )
1596+ resp = self .encrypt_ike_msg (header , sa , 'SA' )
1597+ packet = self .create_packet (self .pg0 , resp , self .sa .sport ,
1598+ self .sa .dport , self .sa .natt , self .ip6 )
1599+ self .send_and_assert_no_replies (self .pg0 , packet )
1600+
1601+ def test_initiator (self ):
1602+ super (TestInitiatorRekey , self ).test_initiator ()
1603+ self .rekey_from_initiator ()
1604+ self .verify_ike_sas ()
1605+ self .verify_ipsec_sas (is_rekey = True )
1606+
1607+
14941608class TestInitiatorDelSAFromResponder (TemplateInitiator , Ikev2Params ):
14951609 """ test ikev2 initiator - delete IKE SA from responder """
14961610
@@ -1529,6 +1643,40 @@ def config_tc(self):
15291643 self .config_params ()
15301644
15311645
1646+ class TestResponderRekey (TestResponderPsk ):
1647+ """ test ikev2 responder - rekey """
1648+
1649+ def rekey_from_initiator (self ):
1650+ sa , first_payload = self .generate_auth_payload (is_rekey = True )
1651+ header = ikev2 .IKEv2 (
1652+ init_SPI = self .sa .ispi ,
1653+ resp_SPI = self .sa .rspi , id = self .sa .new_msg_id (),
1654+ flags = 'Initiator' , exch_type = 'CREATE_CHILD_SA' )
1655+
1656+ ike_msg = self .encrypt_ike_msg (header , sa , first_payload )
1657+ packet = self .create_packet (self .pg0 , ike_msg , self .sa .sport ,
1658+ self .sa .dport , self .sa .natt , self .ip6 )
1659+ self .pg0 .add_stream (packet )
1660+ self .pg0 .enable_capture ()
1661+ self .pg_start ()
1662+ capture = self .pg0 .get_capture (1 )
1663+ ih = self .get_ike_header (capture [0 ])
1664+ plain = self .sa .hmac_and_decrypt (ih )
1665+ sa = ikev2 .IKEv2_payload_SA (plain )
1666+ prop = sa [ikev2 .IKEv2_payload_Proposal ]
1667+ nonce = sa [ikev2 .IKEv2_payload_Nonce ]
1668+ self .sa .r_nonce = sa [ikev2 .IKEv2_payload_Nonce ].load
1669+ # update new responder SPI
1670+ self .sa .child_sas [0 ].rspi = prop .SPI
1671+
1672+ def test_responder (self ):
1673+ super (TestResponderRekey , self ).test_responder ()
1674+ self .rekey_from_initiator ()
1675+ self .sa .calc_child_keys ()
1676+ self .verify_ike_sas ()
1677+ self .verify_ipsec_sas (is_rekey = True )
1678+
1679+
15321680class TestResponderRsaSign (TemplateResponder , Ikev2Params ):
15331681 """ test ikev2 responder - cert based auth """
15341682 def config_tc (self ):
0 commit comments