blob: 4bff829c51b1ec4fd6dda0ad2f650a8656320202 [file] [log] [blame]
Filip Tehlar12b517b2020-04-26 18:05:05 +00001import os
Tom Jones800386a2024-02-07 13:26:41 +00002import socket
Filip Tehlar2008e312020-11-09 13:23:24 +00003import time
Filip Tehlarec112e52020-10-07 23:52:37 +00004from socket import inet_pton
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00005from cryptography import x509
Filip Tehlar12b517b2020-04-26 18:05:05 +00006from cryptography.hazmat.backends import default_backend
7from cryptography.hazmat.primitives import hashes, hmac
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00008from cryptography.hazmat.primitives.asymmetric import dh, padding
9from cryptography.hazmat.primitives.serialization import load_pem_private_key
Filip Tehlar12b517b2020-04-26 18:05:05 +000010from cryptography.hazmat.primitives.ciphers import (
11 Cipher,
12 algorithms,
13 modes,
14)
Filip Tehlar84962d12020-09-08 06:08:05 +000015from ipaddress import IPv4Address, IPv6Address, ip_address
Paul Vinciguerrae061dad2020-12-04 14:57:51 -050016import unittest
Klement Sekerab23ffd72021-05-31 16:08:53 +020017from config import config
Filip Tehlarbfeae8c2020-06-23 20:35:58 +000018from scapy.layers.ipsec import ESP
Filip Tehlar12b517b2020-04-26 18:05:05 +000019from scapy.layers.inet import IP, UDP, Ether
Filip Tehlar84962d12020-09-08 06:08:05 +000020from scapy.layers.inet6 import IPv6
Filip Tehlar12b517b2020-04-26 18:05:05 +000021from scapy.packet import raw, Raw
22from scapy.utils import long_converter
Dave Wallace8800f732023-08-31 00:47:44 -040023from framework import VppTestCase
24from asfframework import (
25 tag_fixme_vpp_workers,
Dave Wallace85ce9312024-08-19 18:47:55 -040026 tag_fixme_ubuntu2404,
Dave Wallace8800f732023-08-31 00:47:44 -040027 VppTestRunner,
28)
Filip Tehlarbfeae8c2020-06-23 20:35:58 +000029from vpp_ikev2 import Profile, IDType, AuthMethod
Filip Tehlar4f42a712020-07-01 08:56:59 +000030from vpp_papi import VppEnum
Filip Tehlar12b517b2020-04-26 18:05:05 +000031
Filip Tehlar84962d12020-09-08 06:08:05 +000032try:
33 text_type = unicode
34except NameError:
35 text_type = str
Filip Tehlar12b517b2020-04-26 18:05:05 +000036
37KEY_PAD = b"Key Pad for IKEv2"
Filip Tehlara7b963d2020-07-08 13:25:34 +000038SALT_SIZE = 4
39GCM_ICV_SIZE = 16
40GCM_IV_SIZE = 8
Filip Tehlar12b517b2020-04-26 18:05:05 +000041
42
43# defined in rfc3526
44# tuple structure is (p, g, key_len)
45DH = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020046 "2048MODPgr": (
47 long_converter(
48 """
Filip Tehlar12b517b2020-04-26 18:05:05 +000049 FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
50 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
51 EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
52 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
53 EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
54 C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
55 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
56 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
57 E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
58 DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020059 15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"""
60 ),
61 2,
62 256,
63 ),
64 "3072MODPgr": (
65 long_converter(
66 """
Filip Tehlar4f42a712020-07-01 08:56:59 +000067 FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
68 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
69 EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
70 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
71 EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
72 C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
73 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
74 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
75 E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
76 DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
77 15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
78 ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
79 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
80 F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
81 BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020082 43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"""
83 ),
84 2,
85 384,
86 ),
Filip Tehlar12b517b2020-04-26 18:05:05 +000087}
88
89
90class CryptoAlgo(object):
91 def __init__(self, name, cipher, mode):
92 self.name = name
93 self.cipher = cipher
94 self.mode = mode
95 if self.cipher is not None:
96 self.bs = self.cipher.block_size // 8
97
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020098 if self.name == "AES-GCM-16ICV":
Filip Tehlara7b963d2020-07-08 13:25:34 +000099 self.iv_len = GCM_IV_SIZE
100 else:
101 self.iv_len = self.bs
Filip Tehlar12b517b2020-04-26 18:05:05 +0000102
Filip Tehlara7b963d2020-07-08 13:25:34 +0000103 def encrypt(self, data, key, aad=None):
104 iv = os.urandom(self.iv_len)
105 if aad is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200106 encryptor = Cipher(
107 self.cipher(key), self.mode(iv), default_backend()
108 ).encryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000109 return iv + encryptor.update(data) + encryptor.finalize()
110 else:
111 salt = key[-SALT_SIZE:]
112 nonce = salt + iv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200113 encryptor = Cipher(
114 self.cipher(key[:-SALT_SIZE]), self.mode(nonce), default_backend()
115 ).encryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000116 encryptor.authenticate_additional_data(aad)
117 data = encryptor.update(data) + encryptor.finalize()
118 data += encryptor.tag[:GCM_ICV_SIZE]
119 return iv + data
120
121 def decrypt(self, data, key, aad=None, icv=None):
122 if aad is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200123 iv = data[: self.iv_len]
124 ct = data[self.iv_len :]
125 decryptor = Cipher(
126 algorithms.AES(key), self.mode(iv), default_backend()
127 ).decryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000128 return decryptor.update(ct) + decryptor.finalize()
129 else:
130 salt = key[-SALT_SIZE:]
131 nonce = salt + data[:GCM_IV_SIZE]
132 ct = data[GCM_IV_SIZE:]
133 key = key[:-SALT_SIZE]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200134 decryptor = Cipher(
135 algorithms.AES(key), self.mode(nonce, icv, len(icv)), default_backend()
136 ).decryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000137 decryptor.authenticate_additional_data(aad)
Filip Tehlaredf29002020-10-10 04:39:11 +0000138 return decryptor.update(ct) + decryptor.finalize()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000139
140 def pad(self, data):
141 pad_len = (len(data) // self.bs + 1) * self.bs - len(data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200142 data = data + b"\x00" * (pad_len - 1)
Filip Tehlar558607d2020-07-16 07:25:56 +0000143 return data + bytes([pad_len - 1])
Filip Tehlar12b517b2020-04-26 18:05:05 +0000144
145
146class AuthAlgo(object):
147 def __init__(self, name, mac, mod, key_len, trunc_len=None):
148 self.name = name
149 self.mac = mac
150 self.mod = mod
151 self.key_len = key_len
152 self.trunc_len = trunc_len or key_len
153
154
155CRYPTO_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200156 "NULL": CryptoAlgo("NULL", cipher=None, mode=None),
157 "AES-CBC": CryptoAlgo("AES-CBC", cipher=algorithms.AES, mode=modes.CBC),
158 "AES-GCM-16ICV": CryptoAlgo("AES-GCM-16ICV", cipher=algorithms.AES, mode=modes.GCM),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000159}
160
161AUTH_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200162 "NULL": AuthAlgo("NULL", mac=None, mod=None, key_len=0, trunc_len=0),
163 "HMAC-SHA1-96": AuthAlgo("HMAC-SHA1-96", hmac.HMAC, hashes.SHA1, 20, 12),
164 "SHA2-256-128": AuthAlgo("SHA2-256-128", hmac.HMAC, hashes.SHA256, 32, 16),
165 "SHA2-384-192": AuthAlgo("SHA2-384-192", hmac.HMAC, hashes.SHA256, 48, 24),
166 "SHA2-512-256": AuthAlgo("SHA2-512-256", hmac.HMAC, hashes.SHA256, 64, 32),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000167}
168
169PRF_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200170 "NULL": AuthAlgo("NULL", mac=None, mod=None, key_len=0, trunc_len=0),
171 "PRF_HMAC_SHA2_256": AuthAlgo("PRF_HMAC_SHA2_256", hmac.HMAC, hashes.SHA256, 32),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000172}
173
Filip Tehlar68ad6252020-10-30 05:28:11 +0000174CRYPTO_IDS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200175 12: "AES-CBC",
176 20: "AES-GCM-16ICV",
Filip Tehlar68ad6252020-10-30 05:28:11 +0000177}
178
179INTEG_IDS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200180 2: "HMAC-SHA1-96",
181 12: "SHA2-256-128",
182 13: "SHA2-384-192",
183 14: "SHA2-512-256",
Filip Tehlar68ad6252020-10-30 05:28:11 +0000184}
185
Filip Tehlar12b517b2020-04-26 18:05:05 +0000186
187class IKEv2ChildSA(object):
Filip Tehlar68ad6252020-10-30 05:28:11 +0000188 def __init__(self, local_ts, remote_ts, is_initiator):
189 spi = os.urandom(4)
190 if is_initiator:
191 self.ispi = spi
192 self.rspi = None
193 else:
194 self.rspi = spi
195 self.ispi = None
Filip Tehlar12b517b2020-04-26 18:05:05 +0000196 self.local_ts = local_ts
197 self.remote_ts = remote_ts
198
199
200class IKEv2SA(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200201 def __init__(
202 self,
203 test,
204 is_initiator=True,
205 i_id=None,
206 r_id=None,
207 spi=b"\x01\x02\x03\x04\x05\x06\x07\x08",
208 id_type="fqdn",
209 nonce=None,
210 auth_data=None,
211 local_ts=None,
212 remote_ts=None,
213 auth_method="shared-key",
214 priv_key=None,
215 i_natt=False,
216 r_natt=False,
217 udp_encap=False,
218 ):
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000219 self.udp_encap = udp_encap
Filip Tehlar027d8132020-12-04 17:38:11 +0000220 self.i_natt = i_natt
221 self.r_natt = r_natt
222 if i_natt or r_natt:
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000223 self.sport = 4500
224 self.dport = 4500
225 else:
226 self.sport = 500
227 self.dport = 500
Filip Tehlar558607d2020-07-16 07:25:56 +0000228 self.msg_id = 0
Filip Tehlar12b517b2020-04-26 18:05:05 +0000229 self.dh_params = None
230 self.test = test
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000231 self.priv_key = priv_key
Filip Tehlar12b517b2020-04-26 18:05:05 +0000232 self.is_initiator = is_initiator
233 nonce = nonce or os.urandom(32)
234 self.auth_data = auth_data
Filip Tehlar4128c7b2020-05-10 05:18:37 +0000235 self.i_id = i_id
236 self.r_id = r_id
Filip Tehlar12b517b2020-04-26 18:05:05 +0000237 if isinstance(id_type, str):
238 self.id_type = IDType.value(id_type)
239 else:
240 self.id_type = id_type
241 self.auth_method = auth_method
242 if self.is_initiator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200243 self.rspi = 8 * b"\x00"
Filip Tehlar12b517b2020-04-26 18:05:05 +0000244 self.ispi = spi
Filip Tehlar12b517b2020-04-26 18:05:05 +0000245 self.i_nonce = nonce
246 else:
247 self.rspi = spi
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200248 self.ispi = 8 * b"\x00"
Filip Tehlare7c83962020-09-23 11:20:12 +0000249 self.r_nonce = nonce
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200250 self.child_sas = [IKEv2ChildSA(local_ts, remote_ts, self.is_initiator)]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000251
Filip Tehlar558607d2020-07-16 07:25:56 +0000252 def new_msg_id(self):
253 self.msg_id += 1
254 return self.msg_id
255
Filip Tehlare7c83962020-09-23 11:20:12 +0000256 @property
257 def my_dh_pub_key(self):
258 if self.is_initiator:
259 return self.i_dh_data
260 return self.r_dh_data
261
262 @property
263 def peer_dh_pub_key(self):
264 if self.is_initiator:
265 return self.r_dh_data
Filip Tehlar12b517b2020-04-26 18:05:05 +0000266 return self.i_dh_data
267
Filip Tehlar027d8132020-12-04 17:38:11 +0000268 @property
269 def natt(self):
270 return self.i_natt or self.r_natt
271
Filip Tehlar12b517b2020-04-26 18:05:05 +0000272 def compute_secret(self):
273 priv = self.dh_private_key
Filip Tehlare7c83962020-09-23 11:20:12 +0000274 peer = self.peer_dh_pub_key
Filip Tehlar12b517b2020-04-26 18:05:05 +0000275 p, g, l = self.ike_group
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200276 return pow(
277 int.from_bytes(peer, "big"), int.from_bytes(priv, "big"), p
278 ).to_bytes(l, "big")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000279
280 def generate_dh_data(self):
281 # generate DH keys
Filip Tehlare7c83962020-09-23 11:20:12 +0000282 if self.ike_dh not in DH:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200283 raise NotImplementedError("%s not in DH group" % self.ike_dh)
Filip Tehlare7c83962020-09-23 11:20:12 +0000284
285 if self.dh_params is None:
286 dhg = DH[self.ike_dh]
287 pn = dh.DHParameterNumbers(dhg[0], dhg[1])
288 self.dh_params = pn.parameters(default_backend())
289
290 priv = self.dh_params.generate_private_key()
291 pub = priv.public_key()
292 x = priv.private_numbers().x
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200293 self.dh_private_key = x.to_bytes(priv.key_size // 8, "big")
Filip Tehlare7c83962020-09-23 11:20:12 +0000294 y = pub.public_numbers().y
295
Filip Tehlar12b517b2020-04-26 18:05:05 +0000296 if self.is_initiator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200297 self.i_dh_data = y.to_bytes(pub.key_size // 8, "big")
Filip Tehlare7c83962020-09-23 11:20:12 +0000298 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200299 self.r_dh_data = y.to_bytes(pub.key_size // 8, "big")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000300
301 def complete_dh_data(self):
302 self.dh_shared_secret = self.compute_secret()
303
Atzm Watanabec65921f2022-08-12 14:29:31 +0900304 def calc_child_keys(self, kex=False):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000305 prf = self.ike_prf_alg.mod()
306 s = self.i_nonce + self.r_nonce
Atzm Watanabec65921f2022-08-12 14:29:31 +0900307 if kex:
308 s = self.dh_shared_secret + s
Filip Tehlar12b517b2020-04-26 18:05:05 +0000309 c = self.child_sas[0]
310
311 encr_key_len = self.esp_crypto_key_len
Filip Tehlar4f42a712020-07-01 08:56:59 +0000312 integ_key_len = self.esp_integ_alg.key_len
313 salt_len = 0 if integ_key_len else 4
314
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200315 l = integ_key_len * 2 + encr_key_len * 2 + salt_len * 2
Filip Tehlar12b517b2020-04-26 18:05:05 +0000316 keymat = self.calc_prfplus(prf, self.sk_d, s, l)
317
318 pos = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200319 c.sk_ei = keymat[pos : pos + encr_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000320 pos += encr_key_len
321
Filip Tehlar4f42a712020-07-01 08:56:59 +0000322 if integ_key_len:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200323 c.sk_ai = keymat[pos : pos + integ_key_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000324 pos += integ_key_len
325 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200326 c.salt_ei = keymat[pos : pos + salt_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000327 pos += salt_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000328
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200329 c.sk_er = keymat[pos : pos + encr_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000330 pos += encr_key_len
331
Filip Tehlar4f42a712020-07-01 08:56:59 +0000332 if integ_key_len:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200333 c.sk_ar = keymat[pos : pos + integ_key_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000334 pos += integ_key_len
335 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200336 c.salt_er = keymat[pos : pos + salt_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000337 pos += salt_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000338
339 def calc_prfplus(self, prf, key, seed, length):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200340 r = b""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000341 t = None
342 x = 1
343 while len(r) < length and x < 255:
344 if t is not None:
345 s = t
346 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200347 s = b""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000348 s = s + seed + bytes([x])
349 t = self.calc_prf(prf, key, s)
350 r = r + t
351 x = x + 1
352
353 if x == 255:
354 return None
355 return r
356
357 def calc_prf(self, prf, key, data):
Filip Tehlara7b963d2020-07-08 13:25:34 +0000358 h = self.ike_prf_alg.mac(key, prf, backend=default_backend())
Filip Tehlar12b517b2020-04-26 18:05:05 +0000359 h.update(data)
360 return h.finalize()
361
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900362 def calc_keys(self, sk_d=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000363 prf = self.ike_prf_alg.mod()
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900364 if sk_d is None:
365 # SKEYSEED = prf(Ni | Nr, g^ir)
366 self.skeyseed = self.calc_prf(
367 prf, self.i_nonce + self.r_nonce, self.dh_shared_secret
368 )
369 else:
370 # SKEYSEED = prf(SK_d (old), g^ir (new) | Ni | Nr)
371 self.skeyseed = self.calc_prf(
372 prf, sk_d, self.dh_shared_secret + self.i_nonce + self.r_nonce
373 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000374
375 # calculate S = Ni | Nr | SPIi SPIr
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900376 s = self.i_nonce + self.r_nonce + self.ispi + self.rspi
Filip Tehlar12b517b2020-04-26 18:05:05 +0000377
378 prf_key_trunc = self.ike_prf_alg.trunc_len
379 encr_key_len = self.ike_crypto_key_len
380 tr_prf_key_len = self.ike_prf_alg.key_len
381 integ_key_len = self.ike_integ_alg.key_len
Filip Tehlara7b963d2020-07-08 13:25:34 +0000382 if integ_key_len == 0:
383 salt_size = 4
384 else:
385 salt_size = 0
386
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200387 l = (
388 prf_key_trunc
389 + integ_key_len * 2
390 + encr_key_len * 2
391 + tr_prf_key_len * 2
392 + salt_size * 2
393 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000394 keymat = self.calc_prfplus(prf, self.skeyseed, s, l)
395
396 pos = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200397 self.sk_d = keymat[: pos + prf_key_trunc]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000398 pos += prf_key_trunc
399
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200400 self.sk_ai = keymat[pos : pos + integ_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000401 pos += integ_key_len
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200402 self.sk_ar = keymat[pos : pos + integ_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000403 pos += integ_key_len
404
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200405 self.sk_ei = keymat[pos : pos + encr_key_len + salt_size]
Filip Tehlara7b963d2020-07-08 13:25:34 +0000406 pos += encr_key_len + salt_size
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200407 self.sk_er = keymat[pos : pos + encr_key_len + salt_size]
Filip Tehlara7b963d2020-07-08 13:25:34 +0000408 pos += encr_key_len + salt_size
Filip Tehlar12b517b2020-04-26 18:05:05 +0000409
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200410 self.sk_pi = keymat[pos : pos + tr_prf_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000411 pos += tr_prf_key_len
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200412 self.sk_pr = keymat[pos : pos + tr_prf_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000413
414 def generate_authmsg(self, prf, packet):
415 if self.is_initiator:
416 id = self.i_id
417 nonce = self.r_nonce
418 key = self.sk_pi
Filip Tehlare7c83962020-09-23 11:20:12 +0000419 else:
420 id = self.r_id
421 nonce = self.i_nonce
422 key = self.sk_pr
Filip Tehlar12b517b2020-04-26 18:05:05 +0000423 data = bytes([self.id_type, 0, 0, 0]) + id
424 id_hash = self.calc_prf(prf, key, data)
425 return packet + nonce + id_hash
426
427 def auth_init(self):
428 prf = self.ike_prf_alg.mod()
Filip Tehlare7c83962020-09-23 11:20:12 +0000429 if self.is_initiator:
430 packet = self.init_req_packet
431 else:
432 packet = self.init_resp_packet
433 authmsg = self.generate_authmsg(prf, raw(packet))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200434 if self.auth_method == "shared-key":
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000435 psk = self.calc_prf(prf, self.auth_data, KEY_PAD)
436 self.auth_data = self.calc_prf(prf, psk, authmsg)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200437 elif self.auth_method == "rsa-sig":
438 self.auth_data = self.priv_key.sign(
439 authmsg, padding.PKCS1v15(), hashes.SHA1()
440 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000441 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200442 raise TypeError("unknown auth method type!")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000443
Filip Tehlara7b963d2020-07-08 13:25:34 +0000444 def encrypt(self, data, aad=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000445 data = self.ike_crypto_alg.pad(data)
Filip Tehlara7b963d2020-07-08 13:25:34 +0000446 return self.ike_crypto_alg.encrypt(data, self.my_cryptokey, aad)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000447
448 @property
449 def peer_authkey(self):
450 if self.is_initiator:
451 return self.sk_ar
452 return self.sk_ai
453
454 @property
455 def my_authkey(self):
456 if self.is_initiator:
457 return self.sk_ai
458 return self.sk_ar
459
460 @property
461 def my_cryptokey(self):
462 if self.is_initiator:
463 return self.sk_ei
464 return self.sk_er
465
466 @property
467 def peer_cryptokey(self):
468 if self.is_initiator:
469 return self.sk_er
470 return self.sk_ei
471
Filip Tehlar4f42a712020-07-01 08:56:59 +0000472 def concat(self, alg, key_len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200473 return alg + "-" + str(key_len * 8)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000474
475 @property
476 def vpp_ike_cypto_alg(self):
477 return self.concat(self.ike_crypto, self.ike_crypto_key_len)
478
479 @property
480 def vpp_esp_cypto_alg(self):
481 return self.concat(self.esp_crypto, self.esp_crypto_key_len)
482
Filip Tehlar12b517b2020-04-26 18:05:05 +0000483 def verify_hmac(self, ikemsg):
484 integ_trunc = self.ike_integ_alg.trunc_len
485 exp_hmac = ikemsg[-integ_trunc:]
486 data = ikemsg[:-integ_trunc]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200487 computed_hmac = self.compute_hmac(
488 self.ike_integ_alg.mod(), self.peer_authkey, data
489 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000490 self.test.assertEqual(computed_hmac[:integ_trunc], exp_hmac)
491
492 def compute_hmac(self, integ, key, data):
493 h = self.ike_integ_alg.mac(key, integ, backend=default_backend())
494 h.update(data)
495 return h.finalize()
496
Filip Tehlara7b963d2020-07-08 13:25:34 +0000497 def decrypt(self, data, aad=None, icv=None):
498 return self.ike_crypto_alg.decrypt(data, self.peer_cryptokey, aad, icv)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000499
500 def hmac_and_decrypt(self, ike):
501 ep = ike[ikev2.IKEv2_payload_Encrypted]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200502 if self.ike_crypto == "AES-GCM-16ICV":
Filip Tehlara7b963d2020-07-08 13:25:34 +0000503 aad_len = len(ikev2.IKEv2_payload_Encrypted()) + len(ikev2.IKEv2())
504 ct = ep.load[:-GCM_ICV_SIZE]
505 tag = ep.load[-GCM_ICV_SIZE:]
Filip Tehlaredf29002020-10-10 04:39:11 +0000506 plain = self.decrypt(ct, raw(ike)[:aad_len], tag)
Filip Tehlara7b963d2020-07-08 13:25:34 +0000507 else:
508 self.verify_hmac(raw(ike))
509 integ_trunc = self.ike_integ_alg.trunc_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000510
Filip Tehlara7b963d2020-07-08 13:25:34 +0000511 # remove ICV and decrypt payload
512 ct = ep.load[:-integ_trunc]
Filip Tehlaredf29002020-10-10 04:39:11 +0000513 plain = self.decrypt(ct)
514 # remove padding
515 pad_len = plain[-1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200516 return plain[: -pad_len - 1]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000517
Filip Tehlar84962d12020-09-08 06:08:05 +0000518 def build_ts_addr(self, ts, version):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200519 return {
520 "starting_address_v" + version: ts["start_addr"],
521 "ending_address_v" + version: ts["end_addr"],
522 }
Filip Tehlar84962d12020-09-08 06:08:05 +0000523
524 def generate_ts(self, is_ip4):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000525 c = self.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200526 ts_data = {"IP_protocol_ID": 0, "start_port": 0, "end_port": 0xFFFF}
Filip Tehlar84962d12020-09-08 06:08:05 +0000527 if is_ip4:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200528 ts_data.update(self.build_ts_addr(c.local_ts, "4"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000529 ts1 = ikev2.IPv4TrafficSelector(**ts_data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200530 ts_data.update(self.build_ts_addr(c.remote_ts, "4"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000531 ts2 = ikev2.IPv4TrafficSelector(**ts_data)
532 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200533 ts_data.update(self.build_ts_addr(c.local_ts, "6"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000534 ts1 = ikev2.IPv6TrafficSelector(**ts_data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200535 ts_data.update(self.build_ts_addr(c.remote_ts, "6"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000536 ts2 = ikev2.IPv6TrafficSelector(**ts_data)
Filip Tehlare7c83962020-09-23 11:20:12 +0000537
538 if self.is_initiator:
539 return ([ts1], [ts2])
540 return ([ts2], [ts1])
Filip Tehlar12b517b2020-04-26 18:05:05 +0000541
542 def set_ike_props(self, crypto, crypto_key_len, integ, prf, dh):
543 if crypto not in CRYPTO_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200544 raise TypeError("unsupported encryption algo %r" % crypto)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000545 self.ike_crypto = crypto
546 self.ike_crypto_alg = CRYPTO_ALGOS[crypto]
547 self.ike_crypto_key_len = crypto_key_len
548
549 if integ not in AUTH_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200550 raise TypeError("unsupported auth algo %r" % integ)
551 self.ike_integ = None if integ == "NULL" else integ
Filip Tehlar12b517b2020-04-26 18:05:05 +0000552 self.ike_integ_alg = AUTH_ALGOS[integ]
553
554 if prf not in PRF_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200555 raise TypeError("unsupported prf algo %r" % prf)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000556 self.ike_prf = prf
557 self.ike_prf_alg = PRF_ALGOS[prf]
558 self.ike_dh = dh
559 self.ike_group = DH[self.ike_dh]
560
561 def set_esp_props(self, crypto, crypto_key_len, integ):
562 self.esp_crypto_key_len = crypto_key_len
563 if crypto not in CRYPTO_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200564 raise TypeError("unsupported encryption algo %r" % crypto)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000565 self.esp_crypto = crypto
566 self.esp_crypto_alg = CRYPTO_ALGOS[crypto]
567
568 if integ not in AUTH_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200569 raise TypeError("unsupported auth algo %r" % integ)
570 self.esp_integ = None if integ == "NULL" else integ
Filip Tehlar12b517b2020-04-26 18:05:05 +0000571 self.esp_integ_alg = AUTH_ALGOS[integ]
572
573 def crypto_attr(self, key_len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200574 if self.ike_crypto in ["AES-CBC", "AES-GCM-16ICV"]:
575 return (0x800E << 16 | key_len << 3, 12)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000576 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200577 raise Exception("unsupported attribute type")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000578
579 def ike_crypto_attr(self):
580 return self.crypto_attr(self.ike_crypto_key_len)
581
582 def esp_crypto_attr(self):
583 return self.crypto_attr(self.esp_crypto_key_len)
584
Filip Tehlarec112e52020-10-07 23:52:37 +0000585 def compute_nat_sha1(self, ip, port, rspi=None):
586 if rspi is None:
587 rspi = self.rspi
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200588 data = self.ispi + rspi + ip + (port).to_bytes(2, "big")
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000589 digest = hashes.Hash(hashes.SHA1(), backend=default_backend())
590 digest.update(data)
591 return digest.finalize()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000592
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900593 def clone(self, test, **kwargs):
594 if "spi" not in kwargs:
595 kwargs["spi"] = self.ispi if self.is_initiator else self.rspi
596 if "nonce" not in kwargs:
597 kwargs["nonce"] = self.i_nonce if self.is_initiator else self.r_nonce
598 if self.child_sas:
599 if "local_ts" not in kwargs:
600 kwargs["local_ts"] = self.child_sas[0].local_ts
601 if "remote_ts" not in kwargs:
602 kwargs["remote_ts"] = self.child_sas[0].remote_ts
603 sa = type(self)(
604 test,
605 is_initiator=self.is_initiator,
606 i_id=self.i_id,
607 r_id=self.r_id,
608 id_type=self.id_type,
609 auth_data=self.auth_data,
610 auth_method=self.auth_method,
611 priv_key=self.priv_key,
612 i_natt=self.i_natt,
613 r_natt=self.r_natt,
614 udp_encap=self.udp_encap,
615 **kwargs,
616 )
617 if sa.is_initiator:
618 sa.set_ike_props(
619 crypto=self.ike_crypto,
620 crypto_key_len=self.ike_crypto_key_len,
621 integ=self.ike_integ,
622 prf=self.ike_prf,
623 dh=self.ike_dh,
624 )
625 sa.set_esp_props(
626 crypto=self.esp_crypto,
627 crypto_key_len=self.esp_crypto_key_len,
628 integ=self.esp_integ,
629 )
630 return sa
631
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000632
Andrew Yourtchenkobc378782023-09-26 16:01:21 +0200633@unittest.skipIf("ikev2" in config.excluded_plugins, "Exclude IKEv2 plugin tests")
Filip Tehlare7c83962020-09-23 11:20:12 +0000634class IkePeer(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200635 """common class for initiator and responder"""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000636
637 @classmethod
638 def setUpClass(cls):
639 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200640
641 globals()["ikev2"] = _ikev2
Filip Tehlare7c83962020-09-23 11:20:12 +0000642 super(IkePeer, cls).setUpClass()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000643 cls.create_pg_interfaces(range(2))
644 for i in cls.pg_interfaces:
645 i.admin_up()
646 i.config_ip4()
647 i.resolve_arp()
Filip Tehlar84962d12020-09-08 06:08:05 +0000648 i.config_ip6()
649 i.resolve_ndp()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000650
651 @classmethod
652 def tearDownClass(cls):
Filip Tehlare7c83962020-09-23 11:20:12 +0000653 super(IkePeer, cls).tearDownClass()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000654
Filip Tehlaredf29002020-10-10 04:39:11 +0000655 def tearDown(self):
656 super(IkePeer, self).tearDown()
657 if self.del_sa_from_responder:
658 self.initiate_del_sa_from_responder()
659 else:
660 self.initiate_del_sa_from_initiator()
661 r = self.vapi.ikev2_sa_dump()
662 self.assertEqual(len(r), 0)
Denys Haryachyyf40a3542024-01-24 16:31:47 +0200663 r = self.vapi.ikev2_sa_v2_dump()
664 self.assertEqual(len(r), 0)
Filip Tehlaredf29002020-10-10 04:39:11 +0000665 sas = self.vapi.ipsec_sa_dump()
666 self.assertEqual(len(sas), 0)
667 self.p.remove_vpp_config()
668 self.assertIsNone(self.p.query_vpp_config())
669
Filip Tehlar12b517b2020-04-26 18:05:05 +0000670 def setUp(self):
Filip Tehlare7c83962020-09-23 11:20:12 +0000671 super(IkePeer, self).setUp()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000672 self.config_tc()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000673 self.p.add_vpp_config()
Filip Tehlar459d17b2020-07-06 15:40:08 +0000674 self.assertIsNotNone(self.p.query_vpp_config())
Filip Tehlar68ad6252020-10-30 05:28:11 +0000675 if self.sa.is_initiator:
676 self.sa.generate_dh_data()
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +0200677 self.vapi.cli("ikev2 set logging level 5")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200678 self.vapi.cli("event-lo clear")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000679
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200680 def assert_counter(self, count, name, version="ip4"):
681 node_name = "/err/ikev2-%s/" % version + name
Filip Tehlarfab5e7f2021-01-14 13:32:01 +0000682 self.assertEqual(count, self.statistics.get_err_counter(node_name))
683
Atzm Watanabec65921f2022-08-12 14:29:31 +0900684 def create_rekey_request(self, kex=False):
685 sa, first_payload = self.generate_auth_payload(is_rekey=True, kex=kex)
Filip Tehlar38340fa2020-11-19 21:34:48 +0000686 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200687 init_SPI=self.sa.ispi,
688 resp_SPI=self.sa.rspi,
689 id=self.sa.new_msg_id(),
690 flags="Initiator",
691 exch_type="CREATE_CHILD_SA",
692 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000693
694 ike_msg = self.encrypt_ike_msg(header, sa, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200695 return self.create_packet(
696 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
697 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000698
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900699 def create_sa_rekey_request(self, **kwargs):
700 sa = self.generate_sa_init_payload(**kwargs)
701 header = ikev2.IKEv2(
702 init_SPI=self.sa.ispi,
703 resp_SPI=self.sa.rspi,
704 id=self.sa.new_msg_id(),
705 flags="Initiator",
706 exch_type="CREATE_CHILD_SA",
707 )
708 ike_msg = self.encrypt_ike_msg(header, sa, "SA")
709 return self.create_packet(
710 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
711 )
712
Filip Tehlar38340fa2020-11-19 21:34:48 +0000713 def create_empty_request(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200714 header = ikev2.IKEv2(
715 init_SPI=self.sa.ispi,
716 resp_SPI=self.sa.rspi,
717 id=self.sa.new_msg_id(),
718 flags="Initiator",
719 exch_type="INFORMATIONAL",
720 next_payload="Encrypted",
721 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000722
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200723 msg = self.encrypt_ike_msg(header, b"", None)
724 return self.create_packet(
725 self.pg0, msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
726 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000727
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200728 def create_packet(
729 self, src_if, msg, sport=500, dport=500, natt=False, use_ip6=False
730 ):
Filip Tehlar84962d12020-09-08 06:08:05 +0000731 if use_ip6:
732 src_ip = src_if.remote_ip6
733 dst_ip = src_if.local_ip6
734 ip_layer = IPv6
735 else:
736 src_ip = src_if.remote_ip4
737 dst_ip = src_if.local_ip4
738 ip_layer = IP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200739 res = (
740 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
741 / ip_layer(src=src_ip, dst=dst_ip)
742 / UDP(sport=sport, dport=dport)
743 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000744 if natt:
745 # insert non ESP marker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200746 res = res / Raw(b"\x00" * 4)
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000747 return res / msg
Filip Tehlar12b517b2020-04-26 18:05:05 +0000748
Filip Tehlare7c83962020-09-23 11:20:12 +0000749 def verify_udp(self, udp):
750 self.assertEqual(udp.sport, self.sa.sport)
751 self.assertEqual(udp.dport, self.sa.dport)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000752
Filip Tehlare7c83962020-09-23 11:20:12 +0000753 def get_ike_header(self, packet):
754 try:
755 ih = packet[ikev2.IKEv2]
Filip Tehlar18107c92020-12-01 14:51:09 +0000756 ih = self.verify_and_remove_non_esp_marker(ih)
Filip Tehlare7c83962020-09-23 11:20:12 +0000757 except IndexError as e:
758 # this is a workaround for getting IKEv2 layer as both ikev2 and
759 # ipsec register for port 4500
760 esp = packet[ESP]
761 ih = self.verify_and_remove_non_esp_marker(esp)
762 self.assertEqual(ih.version, 0x20)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200763 self.assertNotIn("Version", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +0000764 return ih
Filip Tehlar12b517b2020-04-26 18:05:05 +0000765
Filip Tehlare7c83962020-09-23 11:20:12 +0000766 def verify_and_remove_non_esp_marker(self, packet):
767 if self.sa.natt:
768 # if we are in nat traversal mode check for non esp marker
769 # and remove it
770 data = raw(packet)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200771 self.assertEqual(data[:4], b"\x00" * 4)
Filip Tehlare7c83962020-09-23 11:20:12 +0000772 return ikev2.IKEv2(data[4:])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000773 else:
Filip Tehlare7c83962020-09-23 11:20:12 +0000774 return packet
Filip Tehlar12b517b2020-04-26 18:05:05 +0000775
Filip Tehlar558607d2020-07-16 07:25:56 +0000776 def encrypt_ike_msg(self, header, plain, first_payload):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200777 if self.sa.ike_crypto == "AES-GCM-16ICV":
Filip Tehlar558607d2020-07-16 07:25:56 +0000778 data = self.sa.ike_crypto_alg.pad(raw(plain))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200779 plen = (
780 len(data)
781 + GCM_IV_SIZE
782 + GCM_ICV_SIZE
783 + len(ikev2.IKEv2_payload_Encrypted())
784 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000785 tlen = plen + len(ikev2.IKEv2())
786
787 # prepare aad data
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200788 sk_p = ikev2.IKEv2_payload_Encrypted(
789 next_payload=first_payload, length=plen
790 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000791 header.length = tlen
792 res = header / sk_p
793 encr = self.sa.encrypt(raw(plain), raw(res))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200794 sk_p = ikev2.IKEv2_payload_Encrypted(
795 next_payload=first_payload, length=plen, load=encr
796 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000797 res = header / sk_p
798 else:
799 encr = self.sa.encrypt(raw(plain))
800 trunc_len = self.sa.ike_integ_alg.trunc_len
801 plen = len(encr) + len(ikev2.IKEv2_payload_Encrypted()) + trunc_len
802 tlen = plen + len(ikev2.IKEv2())
803
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200804 sk_p = ikev2.IKEv2_payload_Encrypted(
805 next_payload=first_payload, length=plen, load=encr
806 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000807 header.length = tlen
808 res = header / sk_p
809
810 integ_data = raw(res)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200811 hmac_data = self.sa.compute_hmac(
812 self.sa.ike_integ_alg.mod(), self.sa.my_authkey, integ_data
813 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000814 res = res / Raw(hmac_data[:trunc_len])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200815 assert len(res) == tlen
Filip Tehlar558607d2020-07-16 07:25:56 +0000816 return res
817
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000818 def verify_udp_encap(self, ipsec_sa):
819 e = VppEnum.vl_api_ipsec_sad_flags_t
820 if self.sa.udp_encap or self.sa.natt:
821 self.assertIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags)
822 else:
823 self.assertNotIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags)
824
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +0900825 def verify_ipsec_sas(self, is_rekey=False, sa_count=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000826 sas = self.vapi.ipsec_sa_dump()
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +0900827 if sa_count is None:
828 if is_rekey:
829 # after rekey there is a short period of time in which old
830 # inbound SA is still present
831 sa_count = 3
832 else:
833 sa_count = 2
Filip Tehlar68ad6252020-10-30 05:28:11 +0000834 self.assertEqual(len(sas), sa_count)
Filip Tehlare7c83962020-09-23 11:20:12 +0000835 if self.sa.is_initiator:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000836 if is_rekey:
837 sa0 = sas[0].entry
838 sa1 = sas[2].entry
839 else:
840 sa0 = sas[0].entry
841 sa1 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000842 else:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000843 if is_rekey:
844 sa0 = sas[2].entry
845 sa1 = sas[0].entry
846 else:
847 sa1 = sas[0].entry
848 sa0 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000849
Filip Tehlar12b517b2020-04-26 18:05:05 +0000850 c = self.sa.child_sas[0]
851
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000852 self.verify_udp_encap(sa0)
853 self.verify_udp_encap(sa1)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000854 vpp_crypto_alg = self.vpp_enums[self.sa.vpp_esp_cypto_alg]
855 self.assertEqual(sa0.crypto_algorithm, vpp_crypto_alg)
856 self.assertEqual(sa1.crypto_algorithm, vpp_crypto_alg)
857
858 if self.sa.esp_integ is None:
859 vpp_integ_alg = 0
860 else:
861 vpp_integ_alg = self.vpp_enums[self.sa.esp_integ]
862 self.assertEqual(sa0.integrity_algorithm, vpp_integ_alg)
863 self.assertEqual(sa1.integrity_algorithm, vpp_integ_alg)
864
Filip Tehlar12b517b2020-04-26 18:05:05 +0000865 # verify crypto keys
866 self.assertEqual(sa0.crypto_key.length, len(c.sk_er))
867 self.assertEqual(sa1.crypto_key.length, len(c.sk_ei))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200868 self.assertEqual(sa0.crypto_key.data[: len(c.sk_er)], c.sk_er)
869 self.assertEqual(sa1.crypto_key.data[: len(c.sk_ei)], c.sk_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000870
871 # verify integ keys
Filip Tehlar4f42a712020-07-01 08:56:59 +0000872 if vpp_integ_alg:
873 self.assertEqual(sa0.integrity_key.length, len(c.sk_ar))
874 self.assertEqual(sa1.integrity_key.length, len(c.sk_ai))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200875 self.assertEqual(sa0.integrity_key.data[: len(c.sk_ar)], c.sk_ar)
876 self.assertEqual(sa1.integrity_key.data[: len(c.sk_ai)], c.sk_ai)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000877 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200878 self.assertEqual(sa0.salt.to_bytes(4, "little"), c.salt_er)
879 self.assertEqual(sa1.salt.to_bytes(4, "little"), c.salt_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000880
jan_cavojskya340fe12020-07-08 09:24:12 +0200881 def verify_keymat(self, api_keys, keys, name):
882 km = getattr(keys, name)
883 api_km = getattr(api_keys, name)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200884 api_km_len = getattr(api_keys, name + "_len")
jan_cavojskya340fe12020-07-08 09:24:12 +0200885 self.assertEqual(len(km), api_km_len)
886 self.assertEqual(km, api_km[:api_km_len])
887
888 def verify_id(self, api_id, exp_id):
889 self.assertEqual(api_id.type, IDType.value(exp_id.type))
890 self.assertEqual(api_id.data_len, exp_id.data_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200891 self.assertEqual(bytes(api_id.data, "ascii"), exp_id.type)
jan_cavojskya340fe12020-07-08 09:24:12 +0200892
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900893 def verify_ike_sas(self, is_rekey=False):
jan_cavojskya340fe12020-07-08 09:24:12 +0200894 r = self.vapi.ikev2_sa_dump()
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900895 if is_rekey:
896 sa_count = 2
897 sa = r[1].sa
898 else:
899 sa_count = 1
900 sa = r[0].sa
901 self.assertEqual(len(r), sa_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200902 self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, "big"))
903 self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, "big"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000904 if self.ip6:
Filip Tehlare7c83962020-09-23 11:20:12 +0000905 if self.sa.is_initiator:
906 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6))
907 self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6))
908 else:
909 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.local_ip6))
910 self.assertEqual(sa.raddr, IPv6Address(self.pg0.remote_ip6))
Filip Tehlar84962d12020-09-08 06:08:05 +0000911 else:
Filip Tehlare7c83962020-09-23 11:20:12 +0000912 if self.sa.is_initiator:
913 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4))
914 self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4))
915 else:
916 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.local_ip4))
917 self.assertEqual(sa.raddr, IPv4Address(self.pg0.remote_ip4))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 self.verify_keymat(sa.keys, self.sa, "sk_d")
919 self.verify_keymat(sa.keys, self.sa, "sk_ai")
920 self.verify_keymat(sa.keys, self.sa, "sk_ar")
921 self.verify_keymat(sa.keys, self.sa, "sk_ei")
922 self.verify_keymat(sa.keys, self.sa, "sk_er")
923 self.verify_keymat(sa.keys, self.sa, "sk_pi")
924 self.verify_keymat(sa.keys, self.sa, "sk_pr")
jan_cavojskya340fe12020-07-08 09:24:12 +0200925
926 self.assertEqual(sa.i_id.type, self.sa.id_type)
927 self.assertEqual(sa.r_id.type, self.sa.id_type)
928 self.assertEqual(sa.i_id.data_len, len(self.sa.i_id))
Benoît Gannec7cceee2021-09-28 11:19:37 +0200929 self.assertEqual(sa.r_id.data_len, len(self.idr))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200930 self.assertEqual(bytes(sa.i_id.data, "ascii"), self.sa.i_id)
931 self.assertEqual(bytes(sa.r_id.data, "ascii"), self.idr)
jan_cavojskya340fe12020-07-08 09:24:12 +0200932
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900933 n = self.vapi.ikev2_nonce_get(is_initiator=True, sa_index=sa.sa_index)
934 self.verify_nonce(n, self.sa.i_nonce)
935 n = self.vapi.ikev2_nonce_get(is_initiator=False, sa_index=sa.sa_index)
936 self.verify_nonce(n, self.sa.r_nonce)
937
jan_cavojskya340fe12020-07-08 09:24:12 +0200938 r = self.vapi.ikev2_child_sa_dump(sa_index=sa.sa_index)
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900939 if is_rekey:
940 self.assertEqual(len(r), 0)
941 return
942
jan_cavojskya340fe12020-07-08 09:24:12 +0200943 self.assertEqual(len(r), 1)
944 csa = r[0].child_sa
945 self.assertEqual(csa.sa_index, sa.sa_index)
946 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200947 if hasattr(c, "sk_ai"):
948 self.verify_keymat(csa.keys, c, "sk_ai")
949 self.verify_keymat(csa.keys, c, "sk_ar")
950 self.verify_keymat(csa.keys, c, "sk_ei")
951 self.verify_keymat(csa.keys, c, "sk_er")
952 self.assertEqual(csa.i_spi.to_bytes(4, "big"), c.ispi)
953 self.assertEqual(csa.r_spi.to_bytes(4, "big"), c.rspi)
jan_cavojskya340fe12020-07-08 09:24:12 +0200954
Filip Tehlar84962d12020-09-08 06:08:05 +0000955 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
jan_cavojskya340fe12020-07-08 09:24:12 +0200956 tsi = tsi[0]
957 tsr = tsr[0]
958 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200959 is_initiator=True, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
960 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200961 self.assertEqual(len(r), 1)
962 ts = r[0].ts
963 self.verify_ts(r[0].ts, tsi[0], True)
964
965 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200966 is_initiator=False, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
967 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200968 self.assertEqual(len(r), 1)
969 self.verify_ts(r[0].ts, tsr[0], False)
970
Denys Haryachyyf40a3542024-01-24 16:31:47 +0200971 def verify_ike_sas_v2(self):
972 r = self.vapi.ikev2_sa_v2_dump()
973 self.assertEqual(len(r), 1)
974 sa = r[0].sa
975 self.assertEqual(self.p.profile_name, sa.profile_name)
976 self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, "big"))
977 self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, "big"))
978 if self.ip6:
979 if self.sa.is_initiator:
980 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6))
981 self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6))
982 else:
983 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.local_ip6))
984 self.assertEqual(sa.raddr, IPv6Address(self.pg0.remote_ip6))
985 else:
986 if self.sa.is_initiator:
987 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4))
988 self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4))
989 else:
990 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.local_ip4))
991 self.assertEqual(sa.raddr, IPv4Address(self.pg0.remote_ip4))
992 self.verify_keymat(sa.keys, self.sa, "sk_d")
993 self.verify_keymat(sa.keys, self.sa, "sk_ai")
994 self.verify_keymat(sa.keys, self.sa, "sk_ar")
995 self.verify_keymat(sa.keys, self.sa, "sk_ei")
996 self.verify_keymat(sa.keys, self.sa, "sk_er")
997 self.verify_keymat(sa.keys, self.sa, "sk_pi")
998 self.verify_keymat(sa.keys, self.sa, "sk_pr")
999
1000 self.assertEqual(sa.i_id.type, self.sa.id_type)
1001 self.assertEqual(sa.r_id.type, self.sa.id_type)
1002 self.assertEqual(sa.i_id.data_len, len(self.sa.i_id))
1003 self.assertEqual(sa.r_id.data_len, len(self.idr))
1004 self.assertEqual(bytes(sa.i_id.data, "ascii"), self.sa.i_id)
1005 self.assertEqual(bytes(sa.r_id.data, "ascii"), self.idr)
1006
1007 r = self.vapi.ikev2_child_sa_dump(sa_index=sa.sa_index)
1008 self.assertEqual(len(r), 1)
1009 csa = r[0].child_sa
1010 self.assertEqual(csa.sa_index, sa.sa_index)
1011 c = self.sa.child_sas[0]
1012 if hasattr(c, "sk_ai"):
1013 self.verify_keymat(csa.keys, c, "sk_ai")
1014 self.verify_keymat(csa.keys, c, "sk_ar")
1015 self.verify_keymat(csa.keys, c, "sk_ei")
1016 self.verify_keymat(csa.keys, c, "sk_er")
1017 self.assertEqual(csa.i_spi.to_bytes(4, "big"), c.ispi)
1018 self.assertEqual(csa.r_spi.to_bytes(4, "big"), c.rspi)
1019
1020 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
1021 tsi = tsi[0]
1022 tsr = tsr[0]
1023 r = self.vapi.ikev2_traffic_selector_dump(
1024 is_initiator=True, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
1025 )
1026 self.assertEqual(len(r), 1)
1027 ts = r[0].ts
1028 self.verify_ts(r[0].ts, tsi[0], True)
1029
1030 r = self.vapi.ikev2_traffic_selector_dump(
1031 is_initiator=False, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
1032 )
1033 self.assertEqual(len(r), 1)
1034 self.verify_ts(r[0].ts, tsr[0], False)
1035
1036 n = self.vapi.ikev2_nonce_get(is_initiator=True, sa_index=sa.sa_index)
1037 self.verify_nonce(n, self.sa.i_nonce)
1038 n = self.vapi.ikev2_nonce_get(is_initiator=False, sa_index=sa.sa_index)
1039 self.verify_nonce(n, self.sa.r_nonce)
1040
jan_cavojskya340fe12020-07-08 09:24:12 +02001041 def verify_nonce(self, api_nonce, nonce):
1042 self.assertEqual(api_nonce.data_len, len(nonce))
1043 self.assertEqual(api_nonce.nonce, nonce)
1044
1045 def verify_ts(self, api_ts, ts, is_initiator):
1046 if is_initiator:
1047 self.assertTrue(api_ts.is_local)
1048 else:
1049 self.assertFalse(api_ts.is_local)
Filip Tehlar84962d12020-09-08 06:08:05 +00001050
1051 if self.p.ts_is_ip4:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001052 self.assertEqual(api_ts.start_addr, IPv4Address(ts.starting_address_v4))
1053 self.assertEqual(api_ts.end_addr, IPv4Address(ts.ending_address_v4))
Filip Tehlar84962d12020-09-08 06:08:05 +00001054 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001055 self.assertEqual(api_ts.start_addr, IPv6Address(ts.starting_address_v6))
1056 self.assertEqual(api_ts.end_addr, IPv6Address(ts.ending_address_v6))
jan_cavojskya340fe12020-07-08 09:24:12 +02001057 self.assertEqual(api_ts.start_port, ts.start_port)
1058 self.assertEqual(api_ts.end_port, ts.end_port)
1059 self.assertEqual(api_ts.protocol_id, ts.IP_protocol_ID)
1060
Filip Tehlare7c83962020-09-23 11:20:12 +00001061
1062class TemplateInitiator(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001063 """initiator test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +00001064
Filip Tehlaredf29002020-10-10 04:39:11 +00001065 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001066 ispi = int.from_bytes(self.sa.ispi, "little")
Filip Tehlaredf29002020-10-10 04:39:11 +00001067 self.pg0.enable_capture()
1068 self.pg_start()
1069 self.vapi.ikev2_initiate_del_ike_sa(ispi=ispi)
1070 capture = self.pg0.get_capture(1)
1071 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001072 self.assertNotIn("Response", ih.flags)
1073 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001074 self.assertEqual(ih.init_SPI, self.sa.ispi)
1075 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1076 plain = self.sa.hmac_and_decrypt(ih)
1077 d = ikev2.IKEv2_payload_Delete(plain)
1078 self.assertEqual(d.proto, 1) # proto=IKEv2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001079 header = ikev2.IKEv2(
1080 init_SPI=self.sa.ispi,
1081 resp_SPI=self.sa.rspi,
1082 flags="Response",
1083 exch_type="INFORMATIONAL",
1084 id=ih.id,
1085 next_payload="Encrypted",
1086 )
1087 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +00001088 self.send_and_assert_no_replies(self.pg0, resp)
1089
1090 def verify_del_sa(self, packet):
1091 ih = self.get_ike_header(packet)
1092 self.assertEqual(ih.id, self.sa.msg_id)
1093 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001094 self.assertIn("Response", ih.flags)
1095 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001096 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001097 self.assertEqual(plain, b"")
Filip Tehlaredf29002020-10-10 04:39:11 +00001098
1099 def initiate_del_sa_from_responder(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001100 header = ikev2.IKEv2(
1101 init_SPI=self.sa.ispi,
1102 resp_SPI=self.sa.rspi,
1103 exch_type="INFORMATIONAL",
1104 id=self.sa.new_msg_id(),
1105 )
1106 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
1107 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
1108 packet = self.create_packet(
1109 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1110 )
Filip Tehlaredf29002020-10-10 04:39:11 +00001111 self.pg0.add_stream(packet)
1112 self.pg0.enable_capture()
1113 self.pg_start()
1114 capture = self.pg0.get_capture(1)
1115 self.verify_del_sa(capture[0])
Filip Tehlare7c83962020-09-23 11:20:12 +00001116
Filip Tehlarec112e52020-10-07 23:52:37 +00001117 @staticmethod
1118 def find_notify_payload(packet, notify_type):
1119 n = packet[ikev2.IKEv2_payload_Notify]
1120 while n is not None:
1121 if n.type == notify_type:
1122 return n
1123 n = n.payload
1124 return None
1125
1126 def verify_nat_detection(self, packet):
1127 if self.ip6:
1128 iph = packet[IPv6]
1129 else:
1130 iph = packet[IP]
1131 udp = packet[UDP]
1132
1133 # NAT_DETECTION_SOURCE_IP
1134 s = self.find_notify_payload(packet, 16388)
1135 self.assertIsNotNone(s)
1136 src_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001137 inet_pton(socket.AF_INET, iph.src), udp.sport, b"\x00" * 8
1138 )
Filip Tehlarec112e52020-10-07 23:52:37 +00001139 self.assertEqual(s.load, src_sha)
1140
1141 # NAT_DETECTION_DESTINATION_IP
1142 s = self.find_notify_payload(packet, 16389)
1143 self.assertIsNotNone(s)
1144 dst_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001145 inet_pton(socket.AF_INET, iph.dst), udp.dport, b"\x00" * 8
1146 )
Filip Tehlarec112e52020-10-07 23:52:37 +00001147 self.assertEqual(s.load, dst_sha)
1148
Filip Tehlare7c83962020-09-23 11:20:12 +00001149 def verify_sa_init_request(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001150 udp = packet[UDP]
1151 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001152 ih = packet[ikev2.IKEv2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001153 self.assertNotEqual(ih.init_SPI, 8 * b"\x00")
Filip Tehlare7c83962020-09-23 11:20:12 +00001154 self.assertEqual(ih.exch_type, 34) # SA_INIT
1155 self.sa.ispi = ih.init_SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001156 self.assertEqual(ih.resp_SPI, 8 * b"\x00")
1157 self.assertIn("Initiator", ih.flags)
1158 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001159 self.sa.i_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1160 self.sa.i_dh_data = ih[ikev2.IKEv2_payload_KE].load
1161
1162 prop = packet[ikev2.IKEv2_payload_Proposal]
1163 self.assertEqual(prop.proto, 1) # proto = ikev2
1164 self.assertEqual(prop.proposal, 1)
1165 self.assertEqual(prop.trans[0].transform_type, 1) # encryption
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001166 self.assertEqual(
1167 prop.trans[0].transform_id, self.p.ike_transforms["crypto_alg"]
1168 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001169 self.assertEqual(prop.trans[1].transform_type, 2) # prf
1170 self.assertEqual(prop.trans[1].transform_id, 5) # "hmac-sha2-256"
1171 self.assertEqual(prop.trans[2].transform_type, 4) # dh
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001172 self.assertEqual(prop.trans[2].transform_id, self.p.ike_transforms["dh_group"])
Filip Tehlare7c83962020-09-23 11:20:12 +00001173
Filip Tehlarec112e52020-10-07 23:52:37 +00001174 self.verify_nat_detection(packet)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001175 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001176 crypto="AES-GCM-16ICV",
1177 crypto_key_len=32,
1178 integ="NULL",
1179 prf="PRF_HMAC_SHA2_256",
1180 dh="3072MODPgr",
1181 )
1182 self.sa.set_esp_props(crypto="AES-CBC", crypto_key_len=32, integ="SHA2-256-128")
Filip Tehlar68ad6252020-10-30 05:28:11 +00001183 self.sa.generate_dh_data()
Filip Tehlare7c83962020-09-23 11:20:12 +00001184 self.sa.complete_dh_data()
1185 self.sa.calc_keys()
1186
Filip Tehlar68ad6252020-10-30 05:28:11 +00001187 def update_esp_transforms(self, trans, sa):
1188 while trans:
1189 if trans.transform_type == 1: # ecryption
1190 sa.esp_crypto = CRYPTO_IDS[trans.transform_id]
1191 elif trans.transform_type == 3: # integrity
1192 sa.esp_integ = INTEG_IDS[trans.transform_id]
1193 trans = trans.payload
1194
Filip Tehlare7c83962020-09-23 11:20:12 +00001195 def verify_sa_auth_req(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001196 udp = packet[UDP]
1197 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001198 ih = self.get_ike_header(packet)
1199 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1200 self.assertEqual(ih.init_SPI, self.sa.ispi)
1201 self.assertEqual(ih.exch_type, 35) # IKE_AUTH
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001202 self.assertIn("Initiator", ih.flags)
1203 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001204
1205 udp = packet[UDP]
1206 self.verify_udp(udp)
1207 self.assertEqual(ih.id, self.sa.msg_id + 1)
1208 self.sa.msg_id += 1
1209 plain = self.sa.hmac_and_decrypt(ih)
1210 idi = ikev2.IKEv2_payload_IDi(plain)
Filip Tehlare7c83962020-09-23 11:20:12 +00001211 self.assertEqual(idi.load, self.sa.i_id)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001212 if self.no_idr_auth:
1213 self.assertEqual(idi.next_payload, 39) # AUTH
1214 else:
Dave Wallacecf9356d2024-07-23 01:28:19 -04001215 idr = ikev2.IKEv2_payload_IDr(bytes(idi.payload))
Benoît Gannec7cceee2021-09-28 11:19:37 +02001216 self.assertEqual(idr.load, self.sa.r_id)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001217 prop = idi[ikev2.IKEv2_payload_Proposal]
1218 c = self.sa.child_sas[0]
1219 c.ispi = prop.SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001220 self.update_esp_transforms(prop[ikev2.IKEv2_payload_Transform], self.sa)
Filip Tehlare7c83962020-09-23 11:20:12 +00001221
1222 def send_init_response(self):
1223 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001224 trans = (
1225 ikev2.IKEv2_payload_Transform(
1226 transform_type="Encryption",
1227 transform_id=self.sa.ike_crypto,
1228 length=tr_attr[1],
1229 key_length=tr_attr[0],
1230 )
1231 / ikev2.IKEv2_payload_Transform(
1232 transform_type="Integrity", transform_id=self.sa.ike_integ
1233 )
1234 / ikev2.IKEv2_payload_Transform(
1235 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1236 )
1237 / ikev2.IKEv2_payload_Transform(
1238 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1239 )
1240 )
1241 props = ikev2.IKEv2_payload_Proposal(
1242 proposal=1, proto="IKEv2", trans_nb=4, trans=trans
1243 )
Filip Tehlar18107c92020-12-01 14:51:09 +00001244
1245 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
1246 if self.sa.natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001247 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar18107c92020-12-01 14:51:09 +00001248 else:
1249 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1250 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1251 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1252
Filip Tehlare7c83962020-09-23 11:20:12 +00001253 self.sa.init_resp_packet = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001254 ikev2.IKEv2(
1255 init_SPI=self.sa.ispi,
1256 resp_SPI=self.sa.rspi,
1257 exch_type="IKE_SA_INIT",
1258 flags="Response",
1259 )
1260 / ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
1261 / ikev2.IKEv2_payload_KE(
1262 next_payload="Nonce", group=self.sa.ike_dh, load=self.sa.my_dh_pub_key
1263 )
1264 / ikev2.IKEv2_payload_Nonce(load=self.sa.r_nonce, next_payload="Notify")
1265 / ikev2.IKEv2_payload_Notify(
1266 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1267 )
1268 / ikev2.IKEv2_payload_Notify(
1269 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1270 )
1271 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001272
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001273 ike_msg = self.create_packet(
1274 self.pg0,
1275 self.sa.init_resp_packet,
1276 self.sa.sport,
1277 self.sa.dport,
1278 False,
1279 self.ip6,
1280 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001281 self.pg_send(self.pg0, ike_msg)
1282 capture = self.pg0.get_capture(1)
1283 self.verify_sa_auth_req(capture[0])
1284
1285 def initiate_sa_init(self):
1286 self.pg0.enable_capture()
1287 self.pg_start()
1288 self.vapi.ikev2_initiate_sa_init(name=self.p.profile_name)
1289
1290 capture = self.pg0.get_capture(1)
1291 self.verify_sa_init_request(capture[0])
1292 self.send_init_response()
1293
1294 def send_auth_response(self):
1295 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001296 trans = (
1297 ikev2.IKEv2_payload_Transform(
1298 transform_type="Encryption",
1299 transform_id=self.sa.esp_crypto,
1300 length=tr_attr[1],
1301 key_length=tr_attr[0],
1302 )
1303 / ikev2.IKEv2_payload_Transform(
1304 transform_type="Integrity", transform_id=self.sa.esp_integ
1305 )
1306 / ikev2.IKEv2_payload_Transform(
1307 transform_type="Extended Sequence Number", transform_id="No ESN"
1308 )
1309 / ikev2.IKEv2_payload_Transform(
1310 transform_type="Extended Sequence Number", transform_id="ESN"
1311 )
1312 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001313
Filip Tehlar68ad6252020-10-30 05:28:11 +00001314 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001315 props = ikev2.IKEv2_payload_Proposal(
1316 proposal=1, proto="ESP", SPIsize=4, SPI=c.rspi, trans_nb=4, trans=trans
1317 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001318
1319 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001320 plain = (
1321 ikev2.IKEv2_payload_IDi(
1322 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1323 )
1324 / ikev2.IKEv2_payload_IDr(
1325 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1326 )
1327 / ikev2.IKEv2_payload_AUTH(
1328 next_payload="SA",
1329 auth_type=AuthMethod.value(self.sa.auth_method),
1330 load=self.sa.auth_data,
1331 )
1332 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1333 / ikev2.IKEv2_payload_TSi(
1334 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1335 )
1336 / ikev2.IKEv2_payload_TSr(
1337 next_payload="Notify", number_of_TSs=len(tsr), traffic_selector=tsr
1338 )
1339 / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
1340 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001341
1342 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001343 init_SPI=self.sa.ispi,
1344 resp_SPI=self.sa.rspi,
1345 id=self.sa.new_msg_id(),
1346 flags="Response",
1347 exch_type="IKE_AUTH",
1348 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001349
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001350 ike_msg = self.encrypt_ike_msg(header, plain, "IDi")
1351 packet = self.create_packet(
1352 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1353 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001354 self.pg_send(self.pg0, packet)
1355
1356 def test_initiator(self):
1357 self.initiate_sa_init()
1358 self.sa.auth_init()
1359 self.sa.calc_child_keys()
1360 self.send_auth_response()
1361 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02001362 self.verify_ike_sas_v2()
Filip Tehlare7c83962020-09-23 11:20:12 +00001363
1364
1365class TemplateResponder(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001366 """responder test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +00001367
Filip Tehlaredf29002020-10-10 04:39:11 +00001368 def initiate_del_sa_from_responder(self):
1369 self.pg0.enable_capture()
1370 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001371 self.vapi.ikev2_initiate_del_ike_sa(ispi=int.from_bytes(self.sa.ispi, "little"))
Filip Tehlaredf29002020-10-10 04:39:11 +00001372 capture = self.pg0.get_capture(1)
1373 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001374 self.assertNotIn("Response", ih.flags)
1375 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001376 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
1377 plain = self.sa.hmac_and_decrypt(ih)
1378 d = ikev2.IKEv2_payload_Delete(plain)
1379 self.assertEqual(d.proto, 1) # proto=IKEv2
1380 self.assertEqual(ih.init_SPI, self.sa.ispi)
1381 self.assertEqual(ih.resp_SPI, self.sa.rspi)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001382 header = ikev2.IKEv2(
1383 init_SPI=self.sa.ispi,
1384 resp_SPI=self.sa.rspi,
1385 flags="Initiator+Response",
1386 exch_type="INFORMATIONAL",
1387 id=ih.id,
1388 next_payload="Encrypted",
1389 )
1390 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +00001391 self.send_and_assert_no_replies(self.pg0, resp)
Filip Tehlare7c83962020-09-23 11:20:12 +00001392
1393 def verify_del_sa(self, packet):
1394 ih = self.get_ike_header(packet)
1395 self.assertEqual(ih.id, self.sa.msg_id)
1396 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001397 self.assertIn("Response", ih.flags)
1398 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001399 self.assertEqual(ih.next_payload, 46) # Encrypted
1400 self.assertEqual(ih.init_SPI, self.sa.ispi)
1401 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1402 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001403 self.assertEqual(plain, b"")
Filip Tehlare7c83962020-09-23 11:20:12 +00001404
Filip Tehlaredf29002020-10-10 04:39:11 +00001405 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001406 header = ikev2.IKEv2(
1407 init_SPI=self.sa.ispi,
1408 resp_SPI=self.sa.rspi,
1409 flags="Initiator",
1410 exch_type="INFORMATIONAL",
1411 id=self.sa.new_msg_id(),
1412 )
1413 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
1414 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
1415 packet = self.create_packet(
1416 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1417 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001418 self.pg0.add_stream(packet)
1419 self.pg0.enable_capture()
1420 self.pg_start()
1421 capture = self.pg0.get_capture(1)
1422 self.verify_del_sa(capture[0])
1423
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001424 def generate_sa_init_payload(
1425 self, spi=None, dh_pub_key=None, nonce=None, next_payload=None
1426 ):
Filip Tehlare7c83962020-09-23 11:20:12 +00001427 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001428 trans = (
1429 ikev2.IKEv2_payload_Transform(
1430 transform_type="Encryption",
1431 transform_id=self.sa.ike_crypto,
1432 length=tr_attr[1],
1433 key_length=tr_attr[0],
1434 )
1435 / ikev2.IKEv2_payload_Transform(
1436 transform_type="Integrity", transform_id=self.sa.ike_integ
1437 )
1438 / ikev2.IKEv2_payload_Transform(
1439 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1440 )
1441 / ikev2.IKEv2_payload_Transform(
1442 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1443 )
1444 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001445
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001446 if spi is None:
1447 pargs = {}
1448 else:
1449 pargs = {"SPI": spi, "SPIsize": len(spi)}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001450 props = ikev2.IKEv2_payload_Proposal(
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001451 proposal=1,
1452 proto="IKEv2",
1453 trans_nb=4,
1454 trans=trans,
1455 **pargs,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001456 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001457
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001458 return (
1459 ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001460 / ikev2.IKEv2_payload_KE(
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001461 next_payload="Nonce",
1462 group=self.sa.ike_dh,
1463 load=self.sa.my_dh_pub_key if dh_pub_key is None else dh_pub_key,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001464 )
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001465 / ikev2.IKEv2_payload_Nonce(
1466 next_payload=next_payload,
1467 load=self.sa.i_nonce if nonce is None else nonce,
1468 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001469 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001470
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001471 def send_sa_init_req(self):
1472 self.sa.init_req_packet = ikev2.IKEv2(
1473 init_SPI=self.sa.ispi, flags="Initiator", exch_type="IKE_SA_INIT"
1474 ) / self.generate_sa_init_payload(next_payload=None if self.ip6 else "Notify")
1475
Filip Tehlar027d8132020-12-04 17:38:11 +00001476 if not self.ip6:
1477 if self.sa.i_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001478 src_address = b"\x0a\x0a\x0a\x01"
Filip Tehlar027d8132020-12-04 17:38:11 +00001479 else:
1480 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
Filip Tehlare7c83962020-09-23 11:20:12 +00001481
Filip Tehlar027d8132020-12-04 17:38:11 +00001482 if self.sa.r_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001483 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar027d8132020-12-04 17:38:11 +00001484 else:
1485 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1486
1487 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1488 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1489 nat_src_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001490 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1491 )
Filip Tehlar027d8132020-12-04 17:38:11 +00001492 nat_dst_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001493 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1494 )
1495 self.sa.init_req_packet = (
1496 self.sa.init_req_packet / nat_src_detection / nat_dst_detection
1497 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001498
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001499 ike_msg = self.create_packet(
1500 self.pg0,
1501 self.sa.init_req_packet,
1502 self.sa.sport,
1503 self.sa.dport,
1504 self.sa.natt,
1505 self.ip6,
1506 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001507 self.pg0.add_stream(ike_msg)
1508 self.pg0.enable_capture()
1509 self.pg_start()
1510 capture = self.pg0.get_capture(1)
1511 self.verify_sa_init(capture[0])
1512
Atzm Watanabec65921f2022-08-12 14:29:31 +09001513 def generate_auth_payload(self, last_payload=None, is_rekey=False, kex=False):
Filip Tehlare7c83962020-09-23 11:20:12 +00001514 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001515 last_payload = last_payload or "Notify"
Atzm Watanabec65921f2022-08-12 14:29:31 +09001516 trans_nb = 4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001517 trans = (
1518 ikev2.IKEv2_payload_Transform(
1519 transform_type="Encryption",
1520 transform_id=self.sa.esp_crypto,
1521 length=tr_attr[1],
1522 key_length=tr_attr[0],
1523 )
1524 / ikev2.IKEv2_payload_Transform(
1525 transform_type="Integrity", transform_id=self.sa.esp_integ
1526 )
1527 / ikev2.IKEv2_payload_Transform(
1528 transform_type="Extended Sequence Number", transform_id="No ESN"
1529 )
1530 / ikev2.IKEv2_payload_Transform(
1531 transform_type="Extended Sequence Number", transform_id="ESN"
1532 )
1533 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001534
Atzm Watanabec65921f2022-08-12 14:29:31 +09001535 if kex:
1536 trans_nb += 1
1537 trans /= ikev2.IKEv2_payload_Transform(
1538 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1539 )
1540
Filip Tehlar68ad6252020-10-30 05:28:11 +00001541 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001542 props = ikev2.IKEv2_payload_Proposal(
Atzm Watanabec65921f2022-08-12 14:29:31 +09001543 proposal=1,
1544 proto="ESP",
1545 SPIsize=4,
1546 SPI=c.ispi,
1547 trans_nb=trans_nb,
1548 trans=trans,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001549 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001550
1551 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001552 plain = (
1553 ikev2.IKEv2_payload_AUTH(
1554 next_payload="SA",
1555 auth_type=AuthMethod.value(self.sa.auth_method),
1556 load=self.sa.auth_data,
1557 )
1558 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1559 / ikev2.IKEv2_payload_TSi(
1560 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1561 )
1562 / ikev2.IKEv2_payload_TSr(
1563 next_payload=last_payload, number_of_TSs=len(tsr), traffic_selector=tsr
1564 )
1565 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001566
Filip Tehlar68ad6252020-10-30 05:28:11 +00001567 if is_rekey:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001568 first_payload = "Nonce"
Atzm Watanabec65921f2022-08-12 14:29:31 +09001569 if kex:
1570 head = ikev2.IKEv2_payload_Nonce(
1571 load=self.sa.i_nonce, next_payload="KE"
1572 ) / ikev2.IKEv2_payload_KE(
1573 group=self.sa.ike_dh, load=self.sa.my_dh_pub_key, next_payload="SA"
1574 )
1575 else:
1576 head = ikev2.IKEv2_payload_Nonce(
1577 load=self.sa.i_nonce, next_payload="SA"
1578 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001579 plain = (
Atzm Watanabec65921f2022-08-12 14:29:31 +09001580 head
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001581 / plain
Atzm Watanabe03aae962022-08-08 15:45:36 +09001582 / ikev2.IKEv2_payload_Notify(
1583 type="REKEY_SA",
1584 proto="ESP",
1585 SPI=c.ispi,
1586 length=8 + len(c.ispi),
1587 next_payload="Notify",
1588 )
1589 / ikev2.IKEv2_payload_Notify(type="ESP_TFC_PADDING_NOT_SUPPORTED")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001590 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001591 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001592 first_payload = "IDi"
Benoît Gannec7cceee2021-09-28 11:19:37 +02001593 if self.no_idr_auth:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001594 ids = ikev2.IKEv2_payload_IDi(
1595 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.i_id
1596 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001597 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001598 ids = ikev2.IKEv2_payload_IDi(
1599 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1600 ) / ikev2.IKEv2_payload_IDr(
1601 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1602 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001603 plain = ids / plain
1604 return plain, first_payload
1605
1606 def send_sa_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001607 plain, first_payload = self.generate_auth_payload(last_payload="Notify")
1608 plain = plain / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
Filip Tehlare7c83962020-09-23 11:20:12 +00001609 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001610 init_SPI=self.sa.ispi,
1611 resp_SPI=self.sa.rspi,
1612 id=self.sa.new_msg_id(),
1613 flags="Initiator",
1614 exch_type="IKE_AUTH",
1615 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001616
Filip Tehlar68ad6252020-10-30 05:28:11 +00001617 ike_msg = self.encrypt_ike_msg(header, plain, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001618 packet = self.create_packet(
1619 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1620 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001621 self.pg0.add_stream(packet)
1622 self.pg0.enable_capture()
1623 self.pg_start()
1624 capture = self.pg0.get_capture(1)
1625 self.verify_sa_auth_resp(capture[0])
1626
1627 def verify_sa_init(self, packet):
1628 ih = self.get_ike_header(packet)
1629
1630 self.assertEqual(ih.id, self.sa.msg_id)
1631 self.assertEqual(ih.exch_type, 34)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001632 self.assertIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001633 self.assertEqual(ih.init_SPI, self.sa.ispi)
1634 self.assertNotEqual(ih.resp_SPI, 0)
1635 self.sa.rspi = ih.resp_SPI
1636 try:
1637 sa = ih[ikev2.IKEv2_payload_SA]
1638 self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1639 self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load
1640 except IndexError as e:
1641 self.logger.error("unexpected reply: SA/Nonce/KE payload found!")
1642 self.logger.error(ih.show())
1643 raise
1644 self.sa.complete_dh_data()
1645 self.sa.calc_keys()
1646 self.sa.auth_init()
1647
1648 def verify_sa_auth_resp(self, packet):
1649 ike = self.get_ike_header(packet)
1650 udp = packet[UDP]
1651 self.verify_udp(udp)
1652 self.assertEqual(ike.id, self.sa.msg_id)
1653 plain = self.sa.hmac_and_decrypt(ike)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001654 idr = ikev2.IKEv2_payload_IDr(plain)
1655 prop = idr[ikev2.IKEv2_payload_Proposal]
1656 self.assertEqual(prop.SPIsize, 4)
1657 self.sa.child_sas[0].rspi = prop.SPI
Filip Tehlare7c83962020-09-23 11:20:12 +00001658 self.sa.calc_child_keys()
1659
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001660 IKE_NODE_SUFFIX = "ip4"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001661
1662 def verify_counters(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001663 self.assert_counter(2, "processed", self.IKE_NODE_SUFFIX)
1664 self.assert_counter(1, "init_sa_req", self.IKE_NODE_SUFFIX)
1665 self.assert_counter(1, "ike_auth_req", self.IKE_NODE_SUFFIX)
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001666
Filip Tehlar68d27532021-01-25 10:09:27 +00001667 r = self.vapi.ikev2_sa_dump()
1668 s = r[0].sa.stats
1669 self.assertEqual(1, s.n_sa_auth_req)
1670 self.assertEqual(1, s.n_sa_init_req)
1671
Denys Haryachyyf40a3542024-01-24 16:31:47 +02001672 r = self.vapi.ikev2_sa_v2_dump()
1673 s = r[0].sa.stats
1674 self.assertEqual(1, s.n_sa_auth_req)
1675 self.assertEqual(1, s.n_sa_init_req)
1676
Filip Tehlar12b517b2020-04-26 18:05:05 +00001677 def test_responder(self):
Filip Tehlar027d8132020-12-04 17:38:11 +00001678 self.send_sa_init_req()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001679 self.send_sa_auth()
jan_cavojskya340fe12020-07-08 09:24:12 +02001680 self.verify_ipsec_sas()
1681 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02001682 self.verify_ike_sas_v2()
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001683 self.verify_counters()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001684
1685
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001686class Ikev2Params(object):
1687 def config_params(self, params={}):
Filip Tehlar4f42a712020-07-01 08:56:59 +00001688 ec = VppEnum.vl_api_ipsec_crypto_alg_t
1689 ei = VppEnum.vl_api_ipsec_integ_alg_t
1690 self.vpp_enums = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001691 "AES-CBC-128": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_128,
1692 "AES-CBC-192": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_192,
1693 "AES-CBC-256": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_256,
1694 "AES-GCM-16ICV-128": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_128,
1695 "AES-GCM-16ICV-192": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_192,
1696 "AES-GCM-16ICV-256": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_256,
1697 "HMAC-SHA1-96": ei.IPSEC_API_INTEG_ALG_SHA1_96,
1698 "SHA2-256-128": ei.IPSEC_API_INTEG_ALG_SHA_256_128,
1699 "SHA2-384-192": ei.IPSEC_API_INTEG_ALG_SHA_384_192,
1700 "SHA2-512-256": ei.IPSEC_API_INTEG_ALG_SHA_512_256,
1701 }
Filip Tehlar4f42a712020-07-01 08:56:59 +00001702
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001703 dpd_disabled = True if "dpd_disabled" not in params else params["dpd_disabled"]
Filip Tehlar2008e312020-11-09 13:23:24 +00001704 if dpd_disabled:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001705 self.vapi.cli("ikev2 dpd disable")
1706 self.del_sa_from_responder = (
1707 False
1708 if "del_sa_from_responder" not in params
1709 else params["del_sa_from_responder"]
1710 )
1711 i_natt = False if "i_natt" not in params else params["i_natt"]
1712 r_natt = False if "r_natt" not in params else params["r_natt"]
1713 self.p = Profile(self, "pr1")
1714 self.ip6 = False if "ip6" not in params else params["ip6"]
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001715
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001716 if "auth" in params and params["auth"] == "rsa-sig":
1717 auth_method = "rsa-sig"
Klement Sekerab23ffd72021-05-31 16:08:53 +02001718 work_dir = f"{config.vpp_ws_dir}/src/plugins/ikev2/test/certs/"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001719 self.vapi.ikev2_set_local_key(key_file=work_dir + params["server-key"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001720
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001721 client_file = work_dir + params["client-cert"]
1722 server_pem = open(work_dir + params["server-cert"]).read()
1723 client_priv = open(work_dir + params["client-key"]).read()
1724 client_priv = load_pem_private_key(
1725 str.encode(client_priv), None, default_backend()
1726 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001727 self.peer_cert = x509.load_pem_x509_certificate(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001728 str.encode(server_pem), default_backend()
1729 )
1730 self.p.add_auth(method="rsa-sig", data=str.encode(client_file))
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001731 auth_data = None
1732 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001733 auth_data = b"$3cr3tpa$$w0rd"
1734 self.p.add_auth(method="shared-key", data=auth_data)
1735 auth_method = "shared-key"
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001736 client_priv = None
1737
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001738 is_init = True if "is_initiator" not in params else params["is_initiator"]
1739 self.no_idr_auth = params.get("no_idr_in_auth", False)
Filip Tehlare7c83962020-09-23 11:20:12 +00001740
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001741 idr = {"id_type": "fqdn", "data": b"vpp.home"}
1742 idi = {"id_type": "fqdn", "data": b"roadwarrior.example.com"}
1743 r_id = self.idr = idr["data"]
1744 i_id = self.idi = idi["data"]
Filip Tehlare7c83962020-09-23 11:20:12 +00001745 if is_init:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001746 # scapy is initiator, VPP is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001747 self.p.add_local_id(**idr)
1748 self.p.add_remote_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001749 if self.no_idr_auth:
1750 r_id = None
Filip Tehlare7c83962020-09-23 11:20:12 +00001751 else:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001752 # VPP is initiator, scapy is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001753 self.p.add_local_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001754 if not self.no_idr_auth:
1755 self.p.add_remote_id(**idr)
Filip Tehlare7c83962020-09-23 11:20:12 +00001756
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001757 loc_ts = (
1758 {"start_addr": "10.10.10.0", "end_addr": "10.10.10.255"}
1759 if "loc_ts" not in params
1760 else params["loc_ts"]
1761 )
1762 rem_ts = (
1763 {"start_addr": "10.0.0.0", "end_addr": "10.0.0.255"}
1764 if "rem_ts" not in params
1765 else params["rem_ts"]
1766 )
Filip Tehlar84962d12020-09-08 06:08:05 +00001767 self.p.add_local_ts(**loc_ts)
1768 self.p.add_remote_ts(**rem_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001769 if "responder" in params:
1770 self.p.add_responder(params["responder"])
1771 if "ike_transforms" in params:
1772 self.p.add_ike_transforms(params["ike_transforms"])
1773 if "esp_transforms" in params:
1774 self.p.add_esp_transforms(params["esp_transforms"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001775
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001776 udp_encap = False if "udp_encap" not in params else params["udp_encap"]
Filip Tehlar67b8a7f2020-11-06 11:00:42 +00001777 if udp_encap:
1778 self.p.set_udp_encap(True)
1779
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001780 if "responder_hostname" in params:
1781 hn = params["responder_hostname"]
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001782 self.p.add_responder_hostname(hn)
1783
1784 # configure static dns record
1785 self.vapi.dns_name_server_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001786 is_ip6=0, is_add=1, server_address=IPv4Address("8.8.8.8").packed
1787 )
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001788 self.vapi.dns_enable_disable(enable=1)
1789
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001790 cmd = "dns cache add {} {}".format(hn["hostname"], self.pg0.remote_ip4)
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001791 self.vapi.cli(cmd)
1792
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001793 self.sa = IKEv2SA(
1794 self,
1795 i_id=i_id,
1796 r_id=r_id,
1797 is_initiator=is_init,
1798 id_type=self.p.local_id["id_type"],
1799 i_natt=i_natt,
1800 r_natt=r_natt,
1801 priv_key=client_priv,
1802 auth_method=auth_method,
1803 nonce=params.get("nonce"),
1804 auth_data=auth_data,
1805 udp_encap=udp_encap,
1806 local_ts=self.p.remote_ts,
1807 remote_ts=self.p.local_ts,
1808 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001809
Filip Tehlar68ad6252020-10-30 05:28:11 +00001810 if is_init:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001811 ike_crypto = (
1812 ("AES-CBC", 32) if "ike-crypto" not in params else params["ike-crypto"]
1813 )
1814 ike_integ = (
1815 "HMAC-SHA1-96" if "ike-integ" not in params else params["ike-integ"]
1816 )
1817 ike_dh = "2048MODPgr" if "ike-dh" not in params else params["ike-dh"]
Filip Tehlar4f42a712020-07-01 08:56:59 +00001818
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001819 esp_crypto = (
1820 ("AES-CBC", 32) if "esp-crypto" not in params else params["esp-crypto"]
1821 )
1822 esp_integ = (
1823 "HMAC-SHA1-96" if "esp-integ" not in params else params["esp-integ"]
1824 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00001825
Filip Tehlar68ad6252020-10-30 05:28:11 +00001826 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001827 crypto=ike_crypto[0],
1828 crypto_key_len=ike_crypto[1],
1829 integ=ike_integ,
1830 prf="PRF_HMAC_SHA2_256",
1831 dh=ike_dh,
1832 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001833 self.sa.set_esp_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001834 crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], integ=esp_integ
1835 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001836
1837
Andrew Yourtchenkobc378782023-09-26 16:01:21 +02001838@unittest.skipIf("ikev2" in config.excluded_plugins, "Exclude IKEv2 plugin tests")
Filip Tehlar459d17b2020-07-06 15:40:08 +00001839class TestApi(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001840 """Test IKEV2 API"""
1841
Filip Tehlar459d17b2020-07-06 15:40:08 +00001842 @classmethod
1843 def setUpClass(cls):
1844 super(TestApi, cls).setUpClass()
1845
1846 @classmethod
1847 def tearDownClass(cls):
1848 super(TestApi, cls).tearDownClass()
1849
1850 def tearDown(self):
1851 super(TestApi, self).tearDown()
1852 self.p1.remove_vpp_config()
1853 self.p2.remove_vpp_config()
1854 r = self.vapi.ikev2_profile_dump()
1855 self.assertEqual(len(r), 0)
1856
1857 def configure_profile(self, cfg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001858 p = Profile(self, cfg["name"])
1859 p.add_local_id(id_type=cfg["loc_id"][0], data=cfg["loc_id"][1])
1860 p.add_remote_id(id_type=cfg["rem_id"][0], data=cfg["rem_id"][1])
1861 p.add_local_ts(**cfg["loc_ts"])
1862 p.add_remote_ts(**cfg["rem_ts"])
1863 p.add_responder(cfg["responder"])
1864 p.add_ike_transforms(cfg["ike_ts"])
1865 p.add_esp_transforms(cfg["esp_ts"])
1866 p.add_auth(**cfg["auth"])
1867 p.set_udp_encap(cfg["udp_encap"])
1868 p.set_ipsec_over_udp_port(cfg["ipsec_over_udp_port"])
1869 if "lifetime_data" in cfg:
1870 p.set_lifetime_data(cfg["lifetime_data"])
1871 if "tun_itf" in cfg:
1872 p.set_tunnel_interface(cfg["tun_itf"])
1873 if "natt_disabled" in cfg and cfg["natt_disabled"]:
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001874 p.disable_natt()
Filip Tehlar459d17b2020-07-06 15:40:08 +00001875 p.add_vpp_config()
1876 return p
1877
1878 def test_profile_api(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001879 """test profile dump API"""
Filip Tehlar84962d12020-09-08 06:08:05 +00001880 loc_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001881 "proto": 8,
1882 "start_port": 1,
1883 "end_port": 19,
1884 "start_addr": "3.3.3.2",
1885 "end_addr": "3.3.3.3",
1886 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001887 rem_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001888 "proto": 9,
1889 "start_port": 10,
1890 "end_port": 119,
1891 "start_addr": "4.5.76.80",
1892 "end_addr": "2.3.4.6",
1893 }
Filip Tehlar459d17b2020-07-06 15:40:08 +00001894
Filip Tehlar84962d12020-09-08 06:08:05 +00001895 loc_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001896 "proto": 8,
1897 "start_port": 1,
1898 "end_port": 19,
1899 "start_addr": "ab::1",
1900 "end_addr": "ab::4",
1901 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001902 rem_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001903 "proto": 9,
1904 "start_port": 10,
1905 "end_port": 119,
1906 "start_addr": "cd::12",
1907 "end_addr": "cd::13",
1908 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001909
Filip Tehlar459d17b2020-07-06 15:40:08 +00001910 conf = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001911 "p1": {
1912 "name": "p1",
1913 "natt_disabled": True,
1914 "loc_id": ("fqdn", b"vpp.home"),
1915 "rem_id": ("fqdn", b"roadwarrior.example.com"),
1916 "loc_ts": loc_ts4,
1917 "rem_ts": rem_ts4,
1918 "responder": {"sw_if_index": 0, "addr": "5.6.7.8"},
1919 "ike_ts": {
1920 "crypto_alg": 20,
1921 "crypto_key_size": 32,
1922 "integ_alg": 0,
1923 "dh_group": 1,
1924 },
1925 "esp_ts": {"crypto_alg": 13, "crypto_key_size": 24, "integ_alg": 2},
1926 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1927 "udp_encap": True,
1928 "ipsec_over_udp_port": 4501,
1929 "lifetime_data": {
1930 "lifetime": 123,
1931 "lifetime_maxdata": 20192,
1932 "lifetime_jitter": 9,
1933 "handover": 132,
1934 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001935 },
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001936 "p2": {
1937 "name": "p2",
1938 "loc_id": ("ip4-addr", b"192.168.2.1"),
1939 "rem_id": ("ip6-addr", b"abcd::1"),
1940 "loc_ts": loc_ts6,
1941 "rem_ts": rem_ts6,
1942 "responder": {"sw_if_index": 4, "addr": "def::10"},
1943 "ike_ts": {
1944 "crypto_alg": 12,
1945 "crypto_key_size": 16,
1946 "integ_alg": 3,
1947 "dh_group": 3,
1948 },
1949 "esp_ts": {"crypto_alg": 9, "crypto_key_size": 24, "integ_alg": 4},
1950 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1951 "udp_encap": False,
1952 "ipsec_over_udp_port": 4600,
1953 "tun_itf": 0,
1954 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001955 }
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001956 self.p1 = self.configure_profile(conf["p1"])
1957 self.p2 = self.configure_profile(conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001958
1959 r = self.vapi.ikev2_profile_dump()
1960 self.assertEqual(len(r), 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001961 self.verify_profile(r[0].profile, conf["p1"])
1962 self.verify_profile(r[1].profile, conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001963
1964 def verify_id(self, api_id, cfg_id):
1965 self.assertEqual(api_id.type, IDType.value(cfg_id[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001966 self.assertEqual(bytes(api_id.data, "ascii"), cfg_id[1])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001967
1968 def verify_ts(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001969 self.assertEqual(api_ts.protocol_id, cfg_ts["proto"])
1970 self.assertEqual(api_ts.start_port, cfg_ts["start_port"])
1971 self.assertEqual(api_ts.end_port, cfg_ts["end_port"])
1972 self.assertEqual(api_ts.start_addr, ip_address(text_type(cfg_ts["start_addr"])))
1973 self.assertEqual(api_ts.end_addr, ip_address(text_type(cfg_ts["end_addr"])))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001974
1975 def verify_responder(self, api_r, cfg_r):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001976 self.assertEqual(api_r.sw_if_index, cfg_r["sw_if_index"])
1977 self.assertEqual(api_r.addr, ip_address(cfg_r["addr"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001978
1979 def verify_transforms(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001980 self.assertEqual(api_ts.crypto_alg, cfg_ts["crypto_alg"])
1981 self.assertEqual(api_ts.crypto_key_size, cfg_ts["crypto_key_size"])
1982 self.assertEqual(api_ts.integ_alg, cfg_ts["integ_alg"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001983
1984 def verify_ike_transforms(self, api_ts, cfg_ts):
1985 self.verify_transforms(api_ts, cfg_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001986 self.assertEqual(api_ts.dh_group, cfg_ts["dh_group"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001987
1988 def verify_esp_transforms(self, api_ts, cfg_ts):
1989 self.verify_transforms(api_ts, cfg_ts)
1990
1991 def verify_auth(self, api_auth, cfg_auth):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001992 self.assertEqual(api_auth.method, AuthMethod.value(cfg_auth["method"]))
1993 self.assertEqual(api_auth.data, cfg_auth["data"])
1994 self.assertEqual(api_auth.data_len, len(cfg_auth["data"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001995
1996 def verify_lifetime_data(self, p, ld):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001997 self.assertEqual(p.lifetime, ld["lifetime"])
1998 self.assertEqual(p.lifetime_maxdata, ld["lifetime_maxdata"])
1999 self.assertEqual(p.lifetime_jitter, ld["lifetime_jitter"])
2000 self.assertEqual(p.handover, ld["handover"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00002001
2002 def verify_profile(self, ap, cp):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002003 self.assertEqual(ap.name, cp["name"])
2004 self.assertEqual(ap.udp_encap, cp["udp_encap"])
2005 self.verify_id(ap.loc_id, cp["loc_id"])
2006 self.verify_id(ap.rem_id, cp["rem_id"])
2007 self.verify_ts(ap.loc_ts, cp["loc_ts"])
2008 self.verify_ts(ap.rem_ts, cp["rem_ts"])
2009 self.verify_responder(ap.responder, cp["responder"])
2010 self.verify_ike_transforms(ap.ike_ts, cp["ike_ts"])
2011 self.verify_esp_transforms(ap.esp_ts, cp["esp_ts"])
2012 self.verify_auth(ap.auth, cp["auth"])
2013 natt_dis = False if "natt_disabled" not in cp else cp["natt_disabled"]
Filip Tehlard7fc12f2020-10-30 04:47:44 +00002014 self.assertTrue(natt_dis == ap.natt_disabled)
2015
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002016 if "lifetime_data" in cp:
2017 self.verify_lifetime_data(ap, cp["lifetime_data"])
2018 self.assertEqual(ap.ipsec_over_udp_port, cp["ipsec_over_udp_port"])
2019 if "tun_itf" in cp:
2020 self.assertEqual(ap.tun_itf, cp["tun_itf"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00002021 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002022 self.assertEqual(ap.tun_itf, 0xFFFFFFFF)
Filip Tehlar459d17b2020-07-06 15:40:08 +00002023
2024
Filip Tehlar027d8132020-12-04 17:38:11 +00002025class TestResponderBehindNAT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002026 """test responder - responder behind NAT"""
Filip Tehlar027d8132020-12-04 17:38:11 +00002027
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002028 IKE_NODE_SUFFIX = "ip4-natt"
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002029 vpp_worker_count = 2
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002030
Filip Tehlar027d8132020-12-04 17:38:11 +00002031 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002032 self.config_params({"r_natt": True})
Filip Tehlar027d8132020-12-04 17:38:11 +00002033
2034
Filip Tehlar18107c92020-12-01 14:51:09 +00002035class TestInitiatorNATT(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002036 """test ikev2 initiator - NAT traversal (intitiator behind NAT)"""
Filip Tehlar18107c92020-12-01 14:51:09 +00002037
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002038 vpp_worker_count = 2
2039
Filip Tehlar18107c92020-12-01 14:51:09 +00002040 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002041 self.config_params(
2042 {
2043 "i_natt": True,
2044 "is_initiator": False, # seen from test case perspective
2045 # thus vpp is initiator
2046 "responder": {
2047 "sw_if_index": self.pg0.sw_if_index,
2048 "addr": self.pg0.remote_ip4,
2049 },
2050 "ike-crypto": ("AES-GCM-16ICV", 32),
2051 "ike-integ": "NULL",
2052 "ike-dh": "3072MODPgr",
2053 "ike_transforms": {
2054 "crypto_alg": 20, # "aes-gcm-16"
2055 "crypto_key_size": 256,
2056 "dh_group": 15, # "modp-3072"
2057 },
2058 "esp_transforms": {
2059 "crypto_alg": 12, # "aes-cbc"
2060 "crypto_key_size": 256,
2061 # "hmac-sha2-256-128"
2062 "integ_alg": 12,
2063 },
2064 }
2065 )
Filip Tehlar18107c92020-12-01 14:51:09 +00002066
2067
Filip Tehlare7c83962020-09-23 11:20:12 +00002068class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002069 """test ikev2 initiator - pre shared key auth"""
Filip Tehlaredf29002020-10-10 04:39:11 +00002070
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002071 vpp_worker_count = 2
2072
Filip Tehlare7c83962020-09-23 11:20:12 +00002073 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002074 self.config_params(
2075 {
2076 "is_initiator": False, # seen from test case perspective
2077 # thus vpp is initiator
2078 "ike-crypto": ("AES-GCM-16ICV", 32),
2079 "ike-integ": "NULL",
2080 "ike-dh": "3072MODPgr",
2081 "ike_transforms": {
2082 "crypto_alg": 20, # "aes-gcm-16"
2083 "crypto_key_size": 256,
2084 "dh_group": 15, # "modp-3072"
2085 },
2086 "esp_transforms": {
2087 "crypto_alg": 12, # "aes-cbc"
2088 "crypto_key_size": 256,
2089 # "hmac-sha2-256-128"
2090 "integ_alg": 12,
2091 },
2092 "responder_hostname": {
2093 "hostname": "vpp.responder.org",
2094 "sw_if_index": self.pg0.sw_if_index,
2095 },
2096 }
2097 )
Filip Tehlare7c83962020-09-23 11:20:12 +00002098
2099
Filip Tehlar38340fa2020-11-19 21:34:48 +00002100class TestInitiatorRequestWindowSize(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002101 """test initiator - request window size (1)"""
Filip Tehlar38340fa2020-11-19 21:34:48 +00002102
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002103 vpp_worker_count = 2
2104
Filip Tehlar38340fa2020-11-19 21:34:48 +00002105 def rekey_respond(self, req, update_child_sa_data):
2106 ih = self.get_ike_header(req)
2107 plain = self.sa.hmac_and_decrypt(ih)
2108 sa = ikev2.IKEv2_payload_SA(plain)
2109 if update_child_sa_data:
2110 prop = sa[ikev2.IKEv2_payload_Proposal]
2111 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2112 self.sa.r_nonce = self.sa.i_nonce
2113 self.sa.child_sas[0].ispi = prop.SPI
2114 self.sa.child_sas[0].rspi = prop.SPI
2115 self.sa.calc_child_keys()
2116
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002117 header = ikev2.IKEv2(
2118 init_SPI=self.sa.ispi,
2119 resp_SPI=self.sa.rspi,
2120 flags="Response",
2121 exch_type=36,
2122 id=ih.id,
2123 next_payload="Encrypted",
2124 )
2125 resp = self.encrypt_ike_msg(header, sa, "SA")
2126 packet = self.create_packet(
2127 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
2128 )
Filip Tehlar38340fa2020-11-19 21:34:48 +00002129 self.send_and_assert_no_replies(self.pg0, packet)
2130
2131 def test_initiator(self):
2132 super(TestInitiatorRequestWindowSize, self).test_initiator()
2133 self.pg0.enable_capture()
2134 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002135 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar38340fa2020-11-19 21:34:48 +00002136 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
2137 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
2138 capture = self.pg0.get_capture(2)
2139
2140 # reply in reverse order
2141 self.rekey_respond(capture[1], True)
2142 self.rekey_respond(capture[0], False)
2143
2144 # verify that only the second request was accepted
2145 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002146 self.verify_ike_sas_v2()
Filip Tehlar38340fa2020-11-19 21:34:48 +00002147 self.verify_ipsec_sas(is_rekey=True)
2148
2149
Filip Tehlar68ad6252020-10-30 05:28:11 +00002150class TestInitiatorRekey(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002151 """test ikev2 initiator - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00002152
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002153 vpp_worker_count = 2
2154
Filip Tehlar68ad6252020-10-30 05:28:11 +00002155 def rekey_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002156 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar68ad6252020-10-30 05:28:11 +00002157 self.pg0.enable_capture()
2158 self.pg_start()
2159 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
2160 capture = self.pg0.get_capture(1)
2161 ih = self.get_ike_header(capture[0])
2162 self.assertEqual(ih.exch_type, 36) # CHILD_SA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002163 self.assertNotIn("Response", ih.flags)
2164 self.assertIn("Initiator", ih.flags)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002165 plain = self.sa.hmac_and_decrypt(ih)
2166 sa = ikev2.IKEv2_payload_SA(plain)
2167 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00002168 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2169 self.sa.r_nonce = self.sa.i_nonce
2170 # update new responder SPI
2171 self.sa.child_sas[0].ispi = prop.SPI
2172 self.sa.child_sas[0].rspi = prop.SPI
2173 self.sa.calc_child_keys()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002174 header = ikev2.IKEv2(
2175 init_SPI=self.sa.ispi,
2176 resp_SPI=self.sa.rspi,
2177 flags="Response",
2178 exch_type=36,
2179 id=ih.id,
2180 next_payload="Encrypted",
2181 )
2182 resp = self.encrypt_ike_msg(header, sa, "SA")
2183 packet = self.create_packet(
2184 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
2185 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00002186 self.send_and_assert_no_replies(self.pg0, packet)
2187
2188 def test_initiator(self):
2189 super(TestInitiatorRekey, self).test_initiator()
2190 self.rekey_from_initiator()
2191 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002192 self.verify_ike_sas_v2()
Filip Tehlar68ad6252020-10-30 05:28:11 +00002193 self.verify_ipsec_sas(is_rekey=True)
2194
2195
Filip Tehlaredf29002020-10-10 04:39:11 +00002196class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002197 """test ikev2 initiator - delete IKE SA from responder"""
Filip Tehlaredf29002020-10-10 04:39:11 +00002198
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002199 vpp_worker_count = 2
2200
Filip Tehlaredf29002020-10-10 04:39:11 +00002201 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002202 self.config_params(
2203 {
2204 "del_sa_from_responder": True,
2205 "is_initiator": False, # seen from test case perspective
2206 # thus vpp is initiator
2207 "responder": {
2208 "sw_if_index": self.pg0.sw_if_index,
2209 "addr": self.pg0.remote_ip4,
2210 },
2211 "ike-crypto": ("AES-GCM-16ICV", 32),
2212 "ike-integ": "NULL",
2213 "ike-dh": "3072MODPgr",
2214 "ike_transforms": {
2215 "crypto_alg": 20, # "aes-gcm-16"
2216 "crypto_key_size": 256,
2217 "dh_group": 15, # "modp-3072"
2218 },
2219 "esp_transforms": {
2220 "crypto_alg": 12, # "aes-cbc"
2221 "crypto_key_size": 256,
2222 # "hmac-sha2-256-128"
2223 "integ_alg": 12,
2224 },
2225 "no_idr_in_auth": True,
2226 }
2227 )
Filip Tehlaredf29002020-10-10 04:39:11 +00002228
2229
Filip Tehlar027d8132020-12-04 17:38:11 +00002230class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002231 """test ikev2 responder - initiator behind NAT"""
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002232
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002233 IKE_NODE_SUFFIX = "ip4-natt"
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002234 vpp_worker_count = 2
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002235
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002236 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002237 self.config_params({"i_natt": True})
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002238
2239
2240class TestResponderPsk(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002241 """test ikev2 responder - pre shared key auth"""
2242
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002243 vpp_worker_count = 2
2244
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002245 def config_tc(self):
2246 self.config_params()
2247
2248
Filip Tehlar2008e312020-11-09 13:23:24 +00002249class TestResponderDpd(TestResponderPsk):
2250 """
2251 Dead peer detection test
2252 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002253
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002254 vpp_worker_count = 2
2255
Filip Tehlar2008e312020-11-09 13:23:24 +00002256 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002257 self.config_params({"dpd_disabled": False})
Filip Tehlar2008e312020-11-09 13:23:24 +00002258
2259 def tearDown(self):
2260 pass
2261
2262 def test_responder(self):
2263 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2264 super(TestResponderDpd, self).test_responder()
2265 self.pg0.enable_capture()
2266 self.pg_start()
2267 # capture empty request but don't reply
2268 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2269 ih = self.get_ike_header(capture[0])
2270 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2271 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002272 self.assertEqual(plain, b"")
Filip Tehlar2008e312020-11-09 13:23:24 +00002273 # wait for SA expiration
2274 time.sleep(3)
2275 ike_sas = self.vapi.ikev2_sa_dump()
2276 self.assertEqual(len(ike_sas), 0)
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002277 ike_sas = self.vapi.ikev2_sa_v2_dump()
2278 self.assertEqual(len(ike_sas), 0)
Filip Tehlar2008e312020-11-09 13:23:24 +00002279 ipsec_sas = self.vapi.ipsec_sa_dump()
2280 self.assertEqual(len(ipsec_sas), 0)
2281
2282
Filip Tehlar68ad6252020-10-30 05:28:11 +00002283class TestResponderRekey(TestResponderPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002284 """test ikev2 responder - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00002285
Atzm Watanabec65921f2022-08-12 14:29:31 +09002286 WITH_KEX = False
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002287 vpp_worker_count = 2
Atzm Watanabec65921f2022-08-12 14:29:31 +09002288
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002289 def send_rekey_from_initiator(self):
Atzm Watanabec65921f2022-08-12 14:29:31 +09002290 if self.WITH_KEX:
2291 self.sa.generate_dh_data()
2292 packet = self.create_rekey_request(kex=self.WITH_KEX)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002293 self.pg0.add_stream(packet)
2294 self.pg0.enable_capture()
2295 self.pg_start()
2296 capture = self.pg0.get_capture(1)
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002297 return capture
2298
2299 def process_rekey_response(self, capture):
Filip Tehlar68ad6252020-10-30 05:28:11 +00002300 ih = self.get_ike_header(capture[0])
2301 plain = self.sa.hmac_and_decrypt(ih)
2302 sa = ikev2.IKEv2_payload_SA(plain)
2303 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00002304 self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2305 # update new responder SPI
2306 self.sa.child_sas[0].rspi = prop.SPI
Atzm Watanabec65921f2022-08-12 14:29:31 +09002307 if self.WITH_KEX:
2308 self.sa.r_dh_data = sa[ikev2.IKEv2_payload_KE].load
2309 self.sa.complete_dh_data()
2310 self.sa.calc_child_keys(kex=self.WITH_KEX)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002311
2312 def test_responder(self):
2313 super(TestResponderRekey, self).test_responder()
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002314 self.process_rekey_response(self.send_rekey_from_initiator())
Filip Tehlar68ad6252020-10-30 05:28:11 +00002315 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002316 self.verify_ike_sas_v2()
Filip Tehlar68ad6252020-10-30 05:28:11 +00002317 self.verify_ipsec_sas(is_rekey=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002318 self.assert_counter(1, "rekey_req", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002319 r = self.vapi.ikev2_sa_dump()
2320 self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002321 r = self.vapi.ikev2_sa_v2_dump()
2322 self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002323
2324
Dave Wallace85ce9312024-08-19 18:47:55 -04002325@tag_fixme_ubuntu2404
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002326class TestResponderRekeyRepeat(TestResponderRekey):
2327 """test ikev2 responder - rekey repeat"""
2328
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002329 vpp_worker_count = 2
2330
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002331 def test_responder(self):
2332 super(TestResponderRekeyRepeat, self).test_responder()
2333 # rekey request is not accepted until old IPsec SA is expired
2334 capture = self.send_rekey_from_initiator()
2335 ih = self.get_ike_header(capture[0])
2336 plain = self.sa.hmac_and_decrypt(ih)
2337 notify = ikev2.IKEv2_payload_Notify(plain)
2338 self.assertEqual(notify.type, 43)
2339 self.assertEqual(len(self.vapi.ipsec_sa_dump()), 3)
2340 # rekey request is accepted after old IPsec SA was expired
2341 for _ in range(50):
2342 if len(self.vapi.ipsec_sa_dump()) != 3:
2343 break
2344 time.sleep(0.2)
2345 else:
2346 self.fail("old IPsec SA not expired")
2347 self.process_rekey_response(self.send_rekey_from_initiator())
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002348 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002349 self.verify_ike_sas_v2()
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002350 self.verify_ipsec_sas(sa_count=3)
2351
2352
Atzm Watanabec65921f2022-08-12 14:29:31 +09002353class TestResponderRekeyKEX(TestResponderRekey):
2354 """test ikev2 responder - rekey with key exchange"""
2355
2356 WITH_KEX = True
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002357 vpp_worker_count = 2
Atzm Watanabec65921f2022-08-12 14:29:31 +09002358
2359
Dave Wallace85ce9312024-08-19 18:47:55 -04002360@tag_fixme_ubuntu2404
Atzm Watanabec65921f2022-08-12 14:29:31 +09002361class TestResponderRekeyRepeatKEX(TestResponderRekeyRepeat):
2362 """test ikev2 responder - rekey repeat with key exchange"""
2363
2364 WITH_KEX = True
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002365 vpp_worker_count = 2
Atzm Watanabec65921f2022-08-12 14:29:31 +09002366
2367
Atzm Watanabed4f405a2022-08-18 17:57:53 +09002368class TestResponderRekeySA(TestResponderPsk):
2369 """test ikev2 responder - rekey IKE SA"""
2370
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002371 vpp_worker_count = 2
2372
Atzm Watanabed4f405a2022-08-18 17:57:53 +09002373 def send_rekey_from_initiator(self, newsa):
2374 packet = self.create_sa_rekey_request(
2375 spi=newsa.ispi,
2376 dh_pub_key=newsa.my_dh_pub_key,
2377 nonce=newsa.i_nonce,
2378 )
2379 self.pg0.add_stream(packet)
2380 self.pg0.enable_capture()
2381 self.pg_start()
2382 capture = self.pg0.get_capture(1)
2383 return capture
2384
2385 def process_rekey_response(self, newsa, capture):
2386 ih = self.get_ike_header(capture[0])
2387 plain = self.sa.hmac_and_decrypt(ih)
2388 sa = ikev2.IKEv2_payload_SA(plain)
2389 prop = sa[ikev2.IKEv2_payload_Proposal]
2390 newsa.rspi = prop.SPI
2391 newsa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2392 newsa.r_dh_data = sa[ikev2.IKEv2_payload_KE].load
2393 newsa.complete_dh_data()
2394 newsa.calc_keys(sk_d=self.sa.sk_d)
2395 newsa.child_sas = self.sa.child_sas
2396 self.sa.child_sas = []
2397
2398 def test_responder(self):
2399 super(TestResponderRekeySA, self).test_responder()
2400 newsa = self.sa.clone(self, spi=os.urandom(8))
2401 newsa.generate_dh_data()
2402 capture = self.send_rekey_from_initiator(newsa)
2403 self.process_rekey_response(newsa, capture)
2404 self.verify_ike_sas(is_rekey=True)
2405 self.assert_counter(1, "rekey_req", "ip4")
2406 r = self.vapi.ikev2_sa_dump()
2407 self.assertEqual(r[1].sa.stats.n_rekey_req, 1)
2408 self.initiate_del_sa_from_initiator()
2409 self.sa = newsa
2410 self.verify_ike_sas()
2411
2412
Filip Tehlard28196f2021-01-27 18:08:21 +00002413class TestResponderVrf(TestResponderPsk, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002414 """test ikev2 responder - non-default table id"""
Filip Tehlard28196f2021-01-27 18:08:21 +00002415
2416 @classmethod
2417 def setUpClass(cls):
2418 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002419
2420 globals()["ikev2"] = _ikev2
Filip Tehlard28196f2021-01-27 18:08:21 +00002421 super(IkePeer, cls).setUpClass()
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002422
Filip Tehlard28196f2021-01-27 18:08:21 +00002423 cls.create_pg_interfaces(range(1))
2424 cls.vapi.cli("ip table add 1")
2425 cls.vapi.cli("set interface ip table pg0 1")
2426 for i in cls.pg_interfaces:
2427 i.admin_up()
2428 i.config_ip4()
2429 i.resolve_arp()
2430 i.config_ip6()
2431 i.resolve_ndp()
2432
2433 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002434 self.config_params({"dpd_disabled": False})
Filip Tehlard28196f2021-01-27 18:08:21 +00002435
2436 def test_responder(self):
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002437 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=3)
Filip Tehlard28196f2021-01-27 18:08:21 +00002438 super(TestResponderVrf, self).test_responder()
2439 self.pg0.enable_capture()
2440 self.pg_start()
2441 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2442 ih = self.get_ike_header(capture[0])
2443 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2444 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002445 self.assertEqual(plain, b"")
Filip Tehlard28196f2021-01-27 18:08:21 +00002446
2447
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002448class TestResponderRsaSign(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002449 """test ikev2 responder - cert based auth"""
2450
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002451 vpp_worker_count = 2
2452
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002453 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002454 self.config_params(
2455 {
2456 "udp_encap": True,
2457 "auth": "rsa-sig",
2458 "server-key": "server-key.pem",
2459 "client-key": "client-key.pem",
2460 "client-cert": "client-cert.pem",
2461 "server-cert": "server-cert.pem",
2462 }
2463 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002464
Filip Tehlar4f42a712020-07-01 08:56:59 +00002465
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002466class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
2467 TemplateResponder, Ikev2Params
2468):
Filip Tehlar4f42a712020-07-01 08:56:59 +00002469 """
2470 IKE:AES_CBC_128_SHA256_128,DH=modp2048 ESP:AES_CBC_192_SHA_384_192
2471 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002472
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002473 vpp_worker_count = 2
2474
Filip Tehlar4f42a712020-07-01 08:56:59 +00002475 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002476 self.config_params(
2477 {
2478 "ike-crypto": ("AES-CBC", 16),
2479 "ike-integ": "SHA2-256-128",
2480 "esp-crypto": ("AES-CBC", 24),
2481 "esp-integ": "SHA2-384-192",
2482 "ike-dh": "2048MODPgr",
2483 "nonce": os.urandom(256),
2484 "no_idr_in_auth": True,
2485 }
2486 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002487
2488
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002489class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
2490 TemplateResponder, Ikev2Params
2491):
Filip Tehlar4f42a712020-07-01 08:56:59 +00002492 """
2493 IKE:AES_CBC_128_SHA256_128,DH=modp3072 ESP:AES_GCM_16
2494 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002495
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002496 vpp_worker_count = 2
2497
Filip Tehlar4f42a712020-07-01 08:56:59 +00002498 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002499 self.config_params(
2500 {
2501 "ike-crypto": ("AES-CBC", 32),
2502 "ike-integ": "SHA2-256-128",
2503 "esp-crypto": ("AES-GCM-16ICV", 32),
2504 "esp-integ": "NULL",
2505 "ike-dh": "3072MODPgr",
2506 }
2507 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002508
2509
Filip Tehlara7b963d2020-07-08 13:25:34 +00002510class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
2511 """
2512 IKE:AES_GCM_16_256
2513 """
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002514
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002515 IKE_NODE_SUFFIX = "ip6"
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002516 vpp_worker_count = 2
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002517
Filip Tehlara7b963d2020-07-08 13:25:34 +00002518 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002519 self.config_params(
2520 {
2521 "del_sa_from_responder": True,
2522 "ip6": True,
2523 "natt": True,
2524 "ike-crypto": ("AES-GCM-16ICV", 32),
2525 "ike-integ": "NULL",
2526 "ike-dh": "2048MODPgr",
2527 "loc_ts": {"start_addr": "ab:cd::0", "end_addr": "ab:cd::10"},
2528 "rem_ts": {"start_addr": "11::0", "end_addr": "11::100"},
2529 }
2530 )
Filip Tehlara7b963d2020-07-08 13:25:34 +00002531
2532
Filip Tehlar2008e312020-11-09 13:23:24 +00002533class TestInitiatorKeepaliveMsg(TestInitiatorPsk):
2534 """
2535 Test for keep alive messages
2536 """
2537
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002538 vpp_worker_count = 2
2539
Filip Tehlar2008e312020-11-09 13:23:24 +00002540 def send_empty_req_from_responder(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002541 packet = self.create_empty_request()
Filip Tehlar2008e312020-11-09 13:23:24 +00002542 self.pg0.add_stream(packet)
2543 self.pg0.enable_capture()
2544 self.pg_start()
2545 capture = self.pg0.get_capture(1)
2546 ih = self.get_ike_header(capture[0])
2547 self.assertEqual(ih.id, self.sa.msg_id)
2548 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002549 self.assertEqual(plain, b"")
2550 self.assert_counter(1, "keepalive", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002551 r = self.vapi.ikev2_sa_dump()
2552 self.assertEqual(1, r[0].sa.stats.n_keepalives)
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002553 r = self.vapi.ikev2_sa_v2_dump()
2554 self.assertEqual(1, r[0].sa.stats.n_keepalives)
Filip Tehlar2008e312020-11-09 13:23:24 +00002555
2556 def test_initiator(self):
2557 super(TestInitiatorKeepaliveMsg, self).test_initiator()
2558 self.send_empty_req_from_responder()
2559
2560
Filip Tehlar558607d2020-07-16 07:25:56 +00002561class TestMalformedMessages(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002562 """malformed packet test"""
Filip Tehlar558607d2020-07-16 07:25:56 +00002563
2564 def tearDown(self):
2565 pass
2566
2567 def config_tc(self):
2568 self.config_params()
2569
Filip Tehlar558607d2020-07-16 07:25:56 +00002570 def create_ike_init_msg(self, length=None, payload=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002571 msg = ikev2.IKEv2(
2572 length=length,
2573 init_SPI="\x11" * 8,
2574 flags="Initiator",
2575 exch_type="IKE_SA_INIT",
2576 )
Filip Tehlar558607d2020-07-16 07:25:56 +00002577 if payload is not None:
2578 msg /= payload
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002579 return self.create_packet(self.pg0, msg, self.sa.sport, self.sa.dport)
Filip Tehlar558607d2020-07-16 07:25:56 +00002580
2581 def verify_bad_packet_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002582 ike_msg = self.create_ike_init_msg(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002583 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002584 self.assert_counter(self.pkt_count, "bad_length")
Filip Tehlar558607d2020-07-16 07:25:56 +00002585
2586 def verify_bad_sa_payload_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002587 p = ikev2.IKEv2_payload_SA(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002588 ike_msg = self.create_ike_init_msg(payload=p)
2589 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002590 self.assert_counter(self.pkt_count, "malformed_packet")
Filip Tehlar558607d2020-07-16 07:25:56 +00002591
2592 def test_responder(self):
2593 self.pkt_count = 254
2594 self.verify_bad_packet_length()
2595 self.verify_bad_sa_payload_length()
2596
2597
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002598if __name__ == "__main__":
Filip Tehlar12b517b2020-04-26 18:05:05 +00002599 unittest.main(testRunner=VppTestRunner)