blob: 341556d12940102d6c65c3d4e284415de6884f19 [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 Wallace8800f732023-08-31 00:47:44 -040026 is_distro_ubuntu2204,
27 is_distro_debian11,
28 VppTestRunner,
29)
Filip Tehlarbfeae8c2020-06-23 20:35:58 +000030from vpp_ikev2 import Profile, IDType, AuthMethod
Filip Tehlar4f42a712020-07-01 08:56:59 +000031from vpp_papi import VppEnum
Filip Tehlar12b517b2020-04-26 18:05:05 +000032
Filip Tehlar84962d12020-09-08 06:08:05 +000033try:
34 text_type = unicode
35except NameError:
36 text_type = str
Filip Tehlar12b517b2020-04-26 18:05:05 +000037
38KEY_PAD = b"Key Pad for IKEv2"
Filip Tehlara7b963d2020-07-08 13:25:34 +000039SALT_SIZE = 4
40GCM_ICV_SIZE = 16
41GCM_IV_SIZE = 8
Filip Tehlar12b517b2020-04-26 18:05:05 +000042
43
44# defined in rfc3526
45# tuple structure is (p, g, key_len)
46DH = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020047 "2048MODPgr": (
48 long_converter(
49 """
Filip Tehlar12b517b2020-04-26 18:05:05 +000050 FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
51 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
52 EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
53 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
54 EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
55 C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
56 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
57 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
58 E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
59 DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020060 15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"""
61 ),
62 2,
63 256,
64 ),
65 "3072MODPgr": (
66 long_converter(
67 """
Filip Tehlar4f42a712020-07-01 08:56:59 +000068 FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
69 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
70 EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
71 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
72 EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
73 C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
74 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
75 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
76 E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
77 DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
78 15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
79 ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
80 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
81 F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
82 BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020083 43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"""
84 ),
85 2,
86 384,
87 ),
Filip Tehlar12b517b2020-04-26 18:05:05 +000088}
89
90
91class CryptoAlgo(object):
92 def __init__(self, name, cipher, mode):
93 self.name = name
94 self.cipher = cipher
95 self.mode = mode
96 if self.cipher is not None:
97 self.bs = self.cipher.block_size // 8
98
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020099 if self.name == "AES-GCM-16ICV":
Filip Tehlara7b963d2020-07-08 13:25:34 +0000100 self.iv_len = GCM_IV_SIZE
101 else:
102 self.iv_len = self.bs
Filip Tehlar12b517b2020-04-26 18:05:05 +0000103
Filip Tehlara7b963d2020-07-08 13:25:34 +0000104 def encrypt(self, data, key, aad=None):
105 iv = os.urandom(self.iv_len)
106 if aad is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200107 encryptor = Cipher(
108 self.cipher(key), self.mode(iv), default_backend()
109 ).encryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000110 return iv + encryptor.update(data) + encryptor.finalize()
111 else:
112 salt = key[-SALT_SIZE:]
113 nonce = salt + iv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200114 encryptor = Cipher(
115 self.cipher(key[:-SALT_SIZE]), self.mode(nonce), default_backend()
116 ).encryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000117 encryptor.authenticate_additional_data(aad)
118 data = encryptor.update(data) + encryptor.finalize()
119 data += encryptor.tag[:GCM_ICV_SIZE]
120 return iv + data
121
122 def decrypt(self, data, key, aad=None, icv=None):
123 if aad is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200124 iv = data[: self.iv_len]
125 ct = data[self.iv_len :]
126 decryptor = Cipher(
127 algorithms.AES(key), self.mode(iv), default_backend()
128 ).decryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000129 return decryptor.update(ct) + decryptor.finalize()
130 else:
131 salt = key[-SALT_SIZE:]
132 nonce = salt + data[:GCM_IV_SIZE]
133 ct = data[GCM_IV_SIZE:]
134 key = key[:-SALT_SIZE]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200135 decryptor = Cipher(
136 algorithms.AES(key), self.mode(nonce, icv, len(icv)), default_backend()
137 ).decryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000138 decryptor.authenticate_additional_data(aad)
Filip Tehlaredf29002020-10-10 04:39:11 +0000139 return decryptor.update(ct) + decryptor.finalize()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000140
141 def pad(self, data):
142 pad_len = (len(data) // self.bs + 1) * self.bs - len(data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200143 data = data + b"\x00" * (pad_len - 1)
Filip Tehlar558607d2020-07-16 07:25:56 +0000144 return data + bytes([pad_len - 1])
Filip Tehlar12b517b2020-04-26 18:05:05 +0000145
146
147class AuthAlgo(object):
148 def __init__(self, name, mac, mod, key_len, trunc_len=None):
149 self.name = name
150 self.mac = mac
151 self.mod = mod
152 self.key_len = key_len
153 self.trunc_len = trunc_len or key_len
154
155
156CRYPTO_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200157 "NULL": CryptoAlgo("NULL", cipher=None, mode=None),
158 "AES-CBC": CryptoAlgo("AES-CBC", cipher=algorithms.AES, mode=modes.CBC),
159 "AES-GCM-16ICV": CryptoAlgo("AES-GCM-16ICV", cipher=algorithms.AES, mode=modes.GCM),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000160}
161
162AUTH_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200163 "NULL": AuthAlgo("NULL", mac=None, mod=None, key_len=0, trunc_len=0),
164 "HMAC-SHA1-96": AuthAlgo("HMAC-SHA1-96", hmac.HMAC, hashes.SHA1, 20, 12),
165 "SHA2-256-128": AuthAlgo("SHA2-256-128", hmac.HMAC, hashes.SHA256, 32, 16),
166 "SHA2-384-192": AuthAlgo("SHA2-384-192", hmac.HMAC, hashes.SHA256, 48, 24),
167 "SHA2-512-256": AuthAlgo("SHA2-512-256", hmac.HMAC, hashes.SHA256, 64, 32),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000168}
169
170PRF_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200171 "NULL": AuthAlgo("NULL", mac=None, mod=None, key_len=0, trunc_len=0),
172 "PRF_HMAC_SHA2_256": AuthAlgo("PRF_HMAC_SHA2_256", hmac.HMAC, hashes.SHA256, 32),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000173}
174
Filip Tehlar68ad6252020-10-30 05:28:11 +0000175CRYPTO_IDS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200176 12: "AES-CBC",
177 20: "AES-GCM-16ICV",
Filip Tehlar68ad6252020-10-30 05:28:11 +0000178}
179
180INTEG_IDS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200181 2: "HMAC-SHA1-96",
182 12: "SHA2-256-128",
183 13: "SHA2-384-192",
184 14: "SHA2-512-256",
Filip Tehlar68ad6252020-10-30 05:28:11 +0000185}
186
Filip Tehlar12b517b2020-04-26 18:05:05 +0000187
188class IKEv2ChildSA(object):
Filip Tehlar68ad6252020-10-30 05:28:11 +0000189 def __init__(self, local_ts, remote_ts, is_initiator):
190 spi = os.urandom(4)
191 if is_initiator:
192 self.ispi = spi
193 self.rspi = None
194 else:
195 self.rspi = spi
196 self.ispi = None
Filip Tehlar12b517b2020-04-26 18:05:05 +0000197 self.local_ts = local_ts
198 self.remote_ts = remote_ts
199
200
201class IKEv2SA(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200202 def __init__(
203 self,
204 test,
205 is_initiator=True,
206 i_id=None,
207 r_id=None,
208 spi=b"\x01\x02\x03\x04\x05\x06\x07\x08",
209 id_type="fqdn",
210 nonce=None,
211 auth_data=None,
212 local_ts=None,
213 remote_ts=None,
214 auth_method="shared-key",
215 priv_key=None,
216 i_natt=False,
217 r_natt=False,
218 udp_encap=False,
219 ):
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000220 self.udp_encap = udp_encap
Filip Tehlar027d8132020-12-04 17:38:11 +0000221 self.i_natt = i_natt
222 self.r_natt = r_natt
223 if i_natt or r_natt:
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000224 self.sport = 4500
225 self.dport = 4500
226 else:
227 self.sport = 500
228 self.dport = 500
Filip Tehlar558607d2020-07-16 07:25:56 +0000229 self.msg_id = 0
Filip Tehlar12b517b2020-04-26 18:05:05 +0000230 self.dh_params = None
231 self.test = test
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000232 self.priv_key = priv_key
Filip Tehlar12b517b2020-04-26 18:05:05 +0000233 self.is_initiator = is_initiator
234 nonce = nonce or os.urandom(32)
235 self.auth_data = auth_data
Filip Tehlar4128c7b2020-05-10 05:18:37 +0000236 self.i_id = i_id
237 self.r_id = r_id
Filip Tehlar12b517b2020-04-26 18:05:05 +0000238 if isinstance(id_type, str):
239 self.id_type = IDType.value(id_type)
240 else:
241 self.id_type = id_type
242 self.auth_method = auth_method
243 if self.is_initiator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200244 self.rspi = 8 * b"\x00"
Filip Tehlar12b517b2020-04-26 18:05:05 +0000245 self.ispi = spi
Filip Tehlar12b517b2020-04-26 18:05:05 +0000246 self.i_nonce = nonce
247 else:
248 self.rspi = spi
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200249 self.ispi = 8 * b"\x00"
Filip Tehlare7c83962020-09-23 11:20:12 +0000250 self.r_nonce = nonce
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200251 self.child_sas = [IKEv2ChildSA(local_ts, remote_ts, self.is_initiator)]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000252
Filip Tehlar558607d2020-07-16 07:25:56 +0000253 def new_msg_id(self):
254 self.msg_id += 1
255 return self.msg_id
256
Filip Tehlare7c83962020-09-23 11:20:12 +0000257 @property
258 def my_dh_pub_key(self):
259 if self.is_initiator:
260 return self.i_dh_data
261 return self.r_dh_data
262
263 @property
264 def peer_dh_pub_key(self):
265 if self.is_initiator:
266 return self.r_dh_data
Filip Tehlar12b517b2020-04-26 18:05:05 +0000267 return self.i_dh_data
268
Filip Tehlar027d8132020-12-04 17:38:11 +0000269 @property
270 def natt(self):
271 return self.i_natt or self.r_natt
272
Filip Tehlar12b517b2020-04-26 18:05:05 +0000273 def compute_secret(self):
274 priv = self.dh_private_key
Filip Tehlare7c83962020-09-23 11:20:12 +0000275 peer = self.peer_dh_pub_key
Filip Tehlar12b517b2020-04-26 18:05:05 +0000276 p, g, l = self.ike_group
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200277 return pow(
278 int.from_bytes(peer, "big"), int.from_bytes(priv, "big"), p
279 ).to_bytes(l, "big")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000280
281 def generate_dh_data(self):
282 # generate DH keys
Filip Tehlare7c83962020-09-23 11:20:12 +0000283 if self.ike_dh not in DH:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200284 raise NotImplementedError("%s not in DH group" % self.ike_dh)
Filip Tehlare7c83962020-09-23 11:20:12 +0000285
286 if self.dh_params is None:
287 dhg = DH[self.ike_dh]
288 pn = dh.DHParameterNumbers(dhg[0], dhg[1])
289 self.dh_params = pn.parameters(default_backend())
290
291 priv = self.dh_params.generate_private_key()
292 pub = priv.public_key()
293 x = priv.private_numbers().x
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200294 self.dh_private_key = x.to_bytes(priv.key_size // 8, "big")
Filip Tehlare7c83962020-09-23 11:20:12 +0000295 y = pub.public_numbers().y
296
Filip Tehlar12b517b2020-04-26 18:05:05 +0000297 if self.is_initiator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200298 self.i_dh_data = y.to_bytes(pub.key_size // 8, "big")
Filip Tehlare7c83962020-09-23 11:20:12 +0000299 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200300 self.r_dh_data = y.to_bytes(pub.key_size // 8, "big")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000301
302 def complete_dh_data(self):
303 self.dh_shared_secret = self.compute_secret()
304
Atzm Watanabec65921f2022-08-12 14:29:31 +0900305 def calc_child_keys(self, kex=False):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000306 prf = self.ike_prf_alg.mod()
307 s = self.i_nonce + self.r_nonce
Atzm Watanabec65921f2022-08-12 14:29:31 +0900308 if kex:
309 s = self.dh_shared_secret + s
Filip Tehlar12b517b2020-04-26 18:05:05 +0000310 c = self.child_sas[0]
311
312 encr_key_len = self.esp_crypto_key_len
Filip Tehlar4f42a712020-07-01 08:56:59 +0000313 integ_key_len = self.esp_integ_alg.key_len
314 salt_len = 0 if integ_key_len else 4
315
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200316 l = integ_key_len * 2 + encr_key_len * 2 + salt_len * 2
Filip Tehlar12b517b2020-04-26 18:05:05 +0000317 keymat = self.calc_prfplus(prf, self.sk_d, s, l)
318
319 pos = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200320 c.sk_ei = keymat[pos : pos + encr_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000321 pos += encr_key_len
322
Filip Tehlar4f42a712020-07-01 08:56:59 +0000323 if integ_key_len:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200324 c.sk_ai = keymat[pos : pos + integ_key_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000325 pos += integ_key_len
326 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200327 c.salt_ei = keymat[pos : pos + salt_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000328 pos += salt_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000329
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200330 c.sk_er = keymat[pos : pos + encr_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000331 pos += encr_key_len
332
Filip Tehlar4f42a712020-07-01 08:56:59 +0000333 if integ_key_len:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200334 c.sk_ar = keymat[pos : pos + integ_key_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000335 pos += integ_key_len
336 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200337 c.salt_er = keymat[pos : pos + salt_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000338 pos += salt_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000339
340 def calc_prfplus(self, prf, key, seed, length):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200341 r = b""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000342 t = None
343 x = 1
344 while len(r) < length and x < 255:
345 if t is not None:
346 s = t
347 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200348 s = b""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000349 s = s + seed + bytes([x])
350 t = self.calc_prf(prf, key, s)
351 r = r + t
352 x = x + 1
353
354 if x == 255:
355 return None
356 return r
357
358 def calc_prf(self, prf, key, data):
Filip Tehlara7b963d2020-07-08 13:25:34 +0000359 h = self.ike_prf_alg.mac(key, prf, backend=default_backend())
Filip Tehlar12b517b2020-04-26 18:05:05 +0000360 h.update(data)
361 return h.finalize()
362
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900363 def calc_keys(self, sk_d=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000364 prf = self.ike_prf_alg.mod()
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900365 if sk_d is None:
366 # SKEYSEED = prf(Ni | Nr, g^ir)
367 self.skeyseed = self.calc_prf(
368 prf, self.i_nonce + self.r_nonce, self.dh_shared_secret
369 )
370 else:
371 # SKEYSEED = prf(SK_d (old), g^ir (new) | Ni | Nr)
372 self.skeyseed = self.calc_prf(
373 prf, sk_d, self.dh_shared_secret + self.i_nonce + self.r_nonce
374 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000375
376 # calculate S = Ni | Nr | SPIi SPIr
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900377 s = self.i_nonce + self.r_nonce + self.ispi + self.rspi
Filip Tehlar12b517b2020-04-26 18:05:05 +0000378
379 prf_key_trunc = self.ike_prf_alg.trunc_len
380 encr_key_len = self.ike_crypto_key_len
381 tr_prf_key_len = self.ike_prf_alg.key_len
382 integ_key_len = self.ike_integ_alg.key_len
Filip Tehlara7b963d2020-07-08 13:25:34 +0000383 if integ_key_len == 0:
384 salt_size = 4
385 else:
386 salt_size = 0
387
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200388 l = (
389 prf_key_trunc
390 + integ_key_len * 2
391 + encr_key_len * 2
392 + tr_prf_key_len * 2
393 + salt_size * 2
394 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000395 keymat = self.calc_prfplus(prf, self.skeyseed, s, l)
396
397 pos = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200398 self.sk_d = keymat[: pos + prf_key_trunc]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000399 pos += prf_key_trunc
400
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200401 self.sk_ai = keymat[pos : pos + integ_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000402 pos += integ_key_len
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200403 self.sk_ar = keymat[pos : pos + integ_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000404 pos += integ_key_len
405
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200406 self.sk_ei = keymat[pos : pos + encr_key_len + salt_size]
Filip Tehlara7b963d2020-07-08 13:25:34 +0000407 pos += encr_key_len + salt_size
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200408 self.sk_er = keymat[pos : pos + encr_key_len + salt_size]
Filip Tehlara7b963d2020-07-08 13:25:34 +0000409 pos += encr_key_len + salt_size
Filip Tehlar12b517b2020-04-26 18:05:05 +0000410
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200411 self.sk_pi = keymat[pos : pos + tr_prf_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000412 pos += tr_prf_key_len
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200413 self.sk_pr = keymat[pos : pos + tr_prf_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000414
415 def generate_authmsg(self, prf, packet):
416 if self.is_initiator:
417 id = self.i_id
418 nonce = self.r_nonce
419 key = self.sk_pi
Filip Tehlare7c83962020-09-23 11:20:12 +0000420 else:
421 id = self.r_id
422 nonce = self.i_nonce
423 key = self.sk_pr
Filip Tehlar12b517b2020-04-26 18:05:05 +0000424 data = bytes([self.id_type, 0, 0, 0]) + id
425 id_hash = self.calc_prf(prf, key, data)
426 return packet + nonce + id_hash
427
428 def auth_init(self):
429 prf = self.ike_prf_alg.mod()
Filip Tehlare7c83962020-09-23 11:20:12 +0000430 if self.is_initiator:
431 packet = self.init_req_packet
432 else:
433 packet = self.init_resp_packet
434 authmsg = self.generate_authmsg(prf, raw(packet))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200435 if self.auth_method == "shared-key":
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000436 psk = self.calc_prf(prf, self.auth_data, KEY_PAD)
437 self.auth_data = self.calc_prf(prf, psk, authmsg)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200438 elif self.auth_method == "rsa-sig":
439 self.auth_data = self.priv_key.sign(
440 authmsg, padding.PKCS1v15(), hashes.SHA1()
441 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000442 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200443 raise TypeError("unknown auth method type!")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000444
Filip Tehlara7b963d2020-07-08 13:25:34 +0000445 def encrypt(self, data, aad=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000446 data = self.ike_crypto_alg.pad(data)
Filip Tehlara7b963d2020-07-08 13:25:34 +0000447 return self.ike_crypto_alg.encrypt(data, self.my_cryptokey, aad)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000448
449 @property
450 def peer_authkey(self):
451 if self.is_initiator:
452 return self.sk_ar
453 return self.sk_ai
454
455 @property
456 def my_authkey(self):
457 if self.is_initiator:
458 return self.sk_ai
459 return self.sk_ar
460
461 @property
462 def my_cryptokey(self):
463 if self.is_initiator:
464 return self.sk_ei
465 return self.sk_er
466
467 @property
468 def peer_cryptokey(self):
469 if self.is_initiator:
470 return self.sk_er
471 return self.sk_ei
472
Filip Tehlar4f42a712020-07-01 08:56:59 +0000473 def concat(self, alg, key_len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200474 return alg + "-" + str(key_len * 8)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000475
476 @property
477 def vpp_ike_cypto_alg(self):
478 return self.concat(self.ike_crypto, self.ike_crypto_key_len)
479
480 @property
481 def vpp_esp_cypto_alg(self):
482 return self.concat(self.esp_crypto, self.esp_crypto_key_len)
483
Filip Tehlar12b517b2020-04-26 18:05:05 +0000484 def verify_hmac(self, ikemsg):
485 integ_trunc = self.ike_integ_alg.trunc_len
486 exp_hmac = ikemsg[-integ_trunc:]
487 data = ikemsg[:-integ_trunc]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200488 computed_hmac = self.compute_hmac(
489 self.ike_integ_alg.mod(), self.peer_authkey, data
490 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000491 self.test.assertEqual(computed_hmac[:integ_trunc], exp_hmac)
492
493 def compute_hmac(self, integ, key, data):
494 h = self.ike_integ_alg.mac(key, integ, backend=default_backend())
495 h.update(data)
496 return h.finalize()
497
Filip Tehlara7b963d2020-07-08 13:25:34 +0000498 def decrypt(self, data, aad=None, icv=None):
499 return self.ike_crypto_alg.decrypt(data, self.peer_cryptokey, aad, icv)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000500
501 def hmac_and_decrypt(self, ike):
502 ep = ike[ikev2.IKEv2_payload_Encrypted]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200503 if self.ike_crypto == "AES-GCM-16ICV":
Filip Tehlara7b963d2020-07-08 13:25:34 +0000504 aad_len = len(ikev2.IKEv2_payload_Encrypted()) + len(ikev2.IKEv2())
505 ct = ep.load[:-GCM_ICV_SIZE]
506 tag = ep.load[-GCM_ICV_SIZE:]
Filip Tehlaredf29002020-10-10 04:39:11 +0000507 plain = self.decrypt(ct, raw(ike)[:aad_len], tag)
Filip Tehlara7b963d2020-07-08 13:25:34 +0000508 else:
509 self.verify_hmac(raw(ike))
510 integ_trunc = self.ike_integ_alg.trunc_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000511
Filip Tehlara7b963d2020-07-08 13:25:34 +0000512 # remove ICV and decrypt payload
513 ct = ep.load[:-integ_trunc]
Filip Tehlaredf29002020-10-10 04:39:11 +0000514 plain = self.decrypt(ct)
515 # remove padding
516 pad_len = plain[-1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200517 return plain[: -pad_len - 1]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000518
Filip Tehlar84962d12020-09-08 06:08:05 +0000519 def build_ts_addr(self, ts, version):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200520 return {
521 "starting_address_v" + version: ts["start_addr"],
522 "ending_address_v" + version: ts["end_addr"],
523 }
Filip Tehlar84962d12020-09-08 06:08:05 +0000524
525 def generate_ts(self, is_ip4):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000526 c = self.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200527 ts_data = {"IP_protocol_ID": 0, "start_port": 0, "end_port": 0xFFFF}
Filip Tehlar84962d12020-09-08 06:08:05 +0000528 if is_ip4:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200529 ts_data.update(self.build_ts_addr(c.local_ts, "4"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000530 ts1 = ikev2.IPv4TrafficSelector(**ts_data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200531 ts_data.update(self.build_ts_addr(c.remote_ts, "4"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000532 ts2 = ikev2.IPv4TrafficSelector(**ts_data)
533 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200534 ts_data.update(self.build_ts_addr(c.local_ts, "6"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000535 ts1 = ikev2.IPv6TrafficSelector(**ts_data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200536 ts_data.update(self.build_ts_addr(c.remote_ts, "6"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000537 ts2 = ikev2.IPv6TrafficSelector(**ts_data)
Filip Tehlare7c83962020-09-23 11:20:12 +0000538
539 if self.is_initiator:
540 return ([ts1], [ts2])
541 return ([ts2], [ts1])
Filip Tehlar12b517b2020-04-26 18:05:05 +0000542
543 def set_ike_props(self, crypto, crypto_key_len, integ, prf, dh):
544 if crypto not in CRYPTO_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200545 raise TypeError("unsupported encryption algo %r" % crypto)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000546 self.ike_crypto = crypto
547 self.ike_crypto_alg = CRYPTO_ALGOS[crypto]
548 self.ike_crypto_key_len = crypto_key_len
549
550 if integ not in AUTH_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200551 raise TypeError("unsupported auth algo %r" % integ)
552 self.ike_integ = None if integ == "NULL" else integ
Filip Tehlar12b517b2020-04-26 18:05:05 +0000553 self.ike_integ_alg = AUTH_ALGOS[integ]
554
555 if prf not in PRF_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200556 raise TypeError("unsupported prf algo %r" % prf)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000557 self.ike_prf = prf
558 self.ike_prf_alg = PRF_ALGOS[prf]
559 self.ike_dh = dh
560 self.ike_group = DH[self.ike_dh]
561
562 def set_esp_props(self, crypto, crypto_key_len, integ):
563 self.esp_crypto_key_len = crypto_key_len
564 if crypto not in CRYPTO_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200565 raise TypeError("unsupported encryption algo %r" % crypto)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000566 self.esp_crypto = crypto
567 self.esp_crypto_alg = CRYPTO_ALGOS[crypto]
568
569 if integ not in AUTH_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200570 raise TypeError("unsupported auth algo %r" % integ)
571 self.esp_integ = None if integ == "NULL" else integ
Filip Tehlar12b517b2020-04-26 18:05:05 +0000572 self.esp_integ_alg = AUTH_ALGOS[integ]
573
574 def crypto_attr(self, key_len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200575 if self.ike_crypto in ["AES-CBC", "AES-GCM-16ICV"]:
576 return (0x800E << 16 | key_len << 3, 12)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000577 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200578 raise Exception("unsupported attribute type")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000579
580 def ike_crypto_attr(self):
581 return self.crypto_attr(self.ike_crypto_key_len)
582
583 def esp_crypto_attr(self):
584 return self.crypto_attr(self.esp_crypto_key_len)
585
Filip Tehlarec112e52020-10-07 23:52:37 +0000586 def compute_nat_sha1(self, ip, port, rspi=None):
587 if rspi is None:
588 rspi = self.rspi
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200589 data = self.ispi + rspi + ip + (port).to_bytes(2, "big")
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000590 digest = hashes.Hash(hashes.SHA1(), backend=default_backend())
591 digest.update(data)
592 return digest.finalize()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000593
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900594 def clone(self, test, **kwargs):
595 if "spi" not in kwargs:
596 kwargs["spi"] = self.ispi if self.is_initiator else self.rspi
597 if "nonce" not in kwargs:
598 kwargs["nonce"] = self.i_nonce if self.is_initiator else self.r_nonce
599 if self.child_sas:
600 if "local_ts" not in kwargs:
601 kwargs["local_ts"] = self.child_sas[0].local_ts
602 if "remote_ts" not in kwargs:
603 kwargs["remote_ts"] = self.child_sas[0].remote_ts
604 sa = type(self)(
605 test,
606 is_initiator=self.is_initiator,
607 i_id=self.i_id,
608 r_id=self.r_id,
609 id_type=self.id_type,
610 auth_data=self.auth_data,
611 auth_method=self.auth_method,
612 priv_key=self.priv_key,
613 i_natt=self.i_natt,
614 r_natt=self.r_natt,
615 udp_encap=self.udp_encap,
616 **kwargs,
617 )
618 if sa.is_initiator:
619 sa.set_ike_props(
620 crypto=self.ike_crypto,
621 crypto_key_len=self.ike_crypto_key_len,
622 integ=self.ike_integ,
623 prf=self.ike_prf,
624 dh=self.ike_dh,
625 )
626 sa.set_esp_props(
627 crypto=self.esp_crypto,
628 crypto_key_len=self.esp_crypto_key_len,
629 integ=self.esp_integ,
630 )
631 return sa
632
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000633
Andrew Yourtchenkobc378782023-09-26 16:01:21 +0200634@unittest.skipIf("ikev2" in config.excluded_plugins, "Exclude IKEv2 plugin tests")
Filip Tehlare7c83962020-09-23 11:20:12 +0000635class IkePeer(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200636 """common class for initiator and responder"""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000637
638 @classmethod
639 def setUpClass(cls):
640 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200641
642 globals()["ikev2"] = _ikev2
Filip Tehlare7c83962020-09-23 11:20:12 +0000643 super(IkePeer, cls).setUpClass()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000644 cls.create_pg_interfaces(range(2))
645 for i in cls.pg_interfaces:
646 i.admin_up()
647 i.config_ip4()
648 i.resolve_arp()
Filip Tehlar84962d12020-09-08 06:08:05 +0000649 i.config_ip6()
650 i.resolve_ndp()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000651
652 @classmethod
653 def tearDownClass(cls):
Filip Tehlare7c83962020-09-23 11:20:12 +0000654 super(IkePeer, cls).tearDownClass()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000655
Filip Tehlaredf29002020-10-10 04:39:11 +0000656 def tearDown(self):
657 super(IkePeer, self).tearDown()
658 if self.del_sa_from_responder:
659 self.initiate_del_sa_from_responder()
660 else:
661 self.initiate_del_sa_from_initiator()
662 r = self.vapi.ikev2_sa_dump()
663 self.assertEqual(len(r), 0)
Denys Haryachyyf40a3542024-01-24 16:31:47 +0200664 r = self.vapi.ikev2_sa_v2_dump()
665 self.assertEqual(len(r), 0)
Filip Tehlaredf29002020-10-10 04:39:11 +0000666 sas = self.vapi.ipsec_sa_dump()
667 self.assertEqual(len(sas), 0)
668 self.p.remove_vpp_config()
669 self.assertIsNone(self.p.query_vpp_config())
670
Filip Tehlar12b517b2020-04-26 18:05:05 +0000671 def setUp(self):
Filip Tehlare7c83962020-09-23 11:20:12 +0000672 super(IkePeer, self).setUp()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000673 self.config_tc()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000674 self.p.add_vpp_config()
Filip Tehlar459d17b2020-07-06 15:40:08 +0000675 self.assertIsNotNone(self.p.query_vpp_config())
Filip Tehlar68ad6252020-10-30 05:28:11 +0000676 if self.sa.is_initiator:
677 self.sa.generate_dh_data()
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +0200678 self.vapi.cli("ikev2 set logging level 5")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200679 self.vapi.cli("event-lo clear")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000680
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200681 def assert_counter(self, count, name, version="ip4"):
682 node_name = "/err/ikev2-%s/" % version + name
Filip Tehlarfab5e7f2021-01-14 13:32:01 +0000683 self.assertEqual(count, self.statistics.get_err_counter(node_name))
684
Atzm Watanabec65921f2022-08-12 14:29:31 +0900685 def create_rekey_request(self, kex=False):
686 sa, first_payload = self.generate_auth_payload(is_rekey=True, kex=kex)
Filip Tehlar38340fa2020-11-19 21:34:48 +0000687 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200688 init_SPI=self.sa.ispi,
689 resp_SPI=self.sa.rspi,
690 id=self.sa.new_msg_id(),
691 flags="Initiator",
692 exch_type="CREATE_CHILD_SA",
693 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000694
695 ike_msg = self.encrypt_ike_msg(header, sa, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200696 return self.create_packet(
697 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
698 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000699
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900700 def create_sa_rekey_request(self, **kwargs):
701 sa = self.generate_sa_init_payload(**kwargs)
702 header = ikev2.IKEv2(
703 init_SPI=self.sa.ispi,
704 resp_SPI=self.sa.rspi,
705 id=self.sa.new_msg_id(),
706 flags="Initiator",
707 exch_type="CREATE_CHILD_SA",
708 )
709 ike_msg = self.encrypt_ike_msg(header, sa, "SA")
710 return self.create_packet(
711 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
712 )
713
Filip Tehlar38340fa2020-11-19 21:34:48 +0000714 def create_empty_request(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 header = ikev2.IKEv2(
716 init_SPI=self.sa.ispi,
717 resp_SPI=self.sa.rspi,
718 id=self.sa.new_msg_id(),
719 flags="Initiator",
720 exch_type="INFORMATIONAL",
721 next_payload="Encrypted",
722 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000723
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200724 msg = self.encrypt_ike_msg(header, b"", None)
725 return self.create_packet(
726 self.pg0, msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
727 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000728
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200729 def create_packet(
730 self, src_if, msg, sport=500, dport=500, natt=False, use_ip6=False
731 ):
Filip Tehlar84962d12020-09-08 06:08:05 +0000732 if use_ip6:
733 src_ip = src_if.remote_ip6
734 dst_ip = src_if.local_ip6
735 ip_layer = IPv6
736 else:
737 src_ip = src_if.remote_ip4
738 dst_ip = src_if.local_ip4
739 ip_layer = IP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200740 res = (
741 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
742 / ip_layer(src=src_ip, dst=dst_ip)
743 / UDP(sport=sport, dport=dport)
744 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000745 if natt:
746 # insert non ESP marker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200747 res = res / Raw(b"\x00" * 4)
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000748 return res / msg
Filip Tehlar12b517b2020-04-26 18:05:05 +0000749
Filip Tehlare7c83962020-09-23 11:20:12 +0000750 def verify_udp(self, udp):
751 self.assertEqual(udp.sport, self.sa.sport)
752 self.assertEqual(udp.dport, self.sa.dport)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000753
Filip Tehlare7c83962020-09-23 11:20:12 +0000754 def get_ike_header(self, packet):
755 try:
756 ih = packet[ikev2.IKEv2]
Filip Tehlar18107c92020-12-01 14:51:09 +0000757 ih = self.verify_and_remove_non_esp_marker(ih)
Filip Tehlare7c83962020-09-23 11:20:12 +0000758 except IndexError as e:
759 # this is a workaround for getting IKEv2 layer as both ikev2 and
760 # ipsec register for port 4500
761 esp = packet[ESP]
762 ih = self.verify_and_remove_non_esp_marker(esp)
763 self.assertEqual(ih.version, 0x20)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200764 self.assertNotIn("Version", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +0000765 return ih
Filip Tehlar12b517b2020-04-26 18:05:05 +0000766
Filip Tehlare7c83962020-09-23 11:20:12 +0000767 def verify_and_remove_non_esp_marker(self, packet):
768 if self.sa.natt:
769 # if we are in nat traversal mode check for non esp marker
770 # and remove it
771 data = raw(packet)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200772 self.assertEqual(data[:4], b"\x00" * 4)
Filip Tehlare7c83962020-09-23 11:20:12 +0000773 return ikev2.IKEv2(data[4:])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000774 else:
Filip Tehlare7c83962020-09-23 11:20:12 +0000775 return packet
Filip Tehlar12b517b2020-04-26 18:05:05 +0000776
Filip Tehlar558607d2020-07-16 07:25:56 +0000777 def encrypt_ike_msg(self, header, plain, first_payload):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200778 if self.sa.ike_crypto == "AES-GCM-16ICV":
Filip Tehlar558607d2020-07-16 07:25:56 +0000779 data = self.sa.ike_crypto_alg.pad(raw(plain))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200780 plen = (
781 len(data)
782 + GCM_IV_SIZE
783 + GCM_ICV_SIZE
784 + len(ikev2.IKEv2_payload_Encrypted())
785 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000786 tlen = plen + len(ikev2.IKEv2())
787
788 # prepare aad data
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200789 sk_p = ikev2.IKEv2_payload_Encrypted(
790 next_payload=first_payload, length=plen
791 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000792 header.length = tlen
793 res = header / sk_p
794 encr = self.sa.encrypt(raw(plain), raw(res))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200795 sk_p = ikev2.IKEv2_payload_Encrypted(
796 next_payload=first_payload, length=plen, load=encr
797 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000798 res = header / sk_p
799 else:
800 encr = self.sa.encrypt(raw(plain))
801 trunc_len = self.sa.ike_integ_alg.trunc_len
802 plen = len(encr) + len(ikev2.IKEv2_payload_Encrypted()) + trunc_len
803 tlen = plen + len(ikev2.IKEv2())
804
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200805 sk_p = ikev2.IKEv2_payload_Encrypted(
806 next_payload=first_payload, length=plen, load=encr
807 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000808 header.length = tlen
809 res = header / sk_p
810
811 integ_data = raw(res)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200812 hmac_data = self.sa.compute_hmac(
813 self.sa.ike_integ_alg.mod(), self.sa.my_authkey, integ_data
814 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000815 res = res / Raw(hmac_data[:trunc_len])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200816 assert len(res) == tlen
Filip Tehlar558607d2020-07-16 07:25:56 +0000817 return res
818
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000819 def verify_udp_encap(self, ipsec_sa):
820 e = VppEnum.vl_api_ipsec_sad_flags_t
821 if self.sa.udp_encap or self.sa.natt:
822 self.assertIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags)
823 else:
824 self.assertNotIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags)
825
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +0900826 def verify_ipsec_sas(self, is_rekey=False, sa_count=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000827 sas = self.vapi.ipsec_sa_dump()
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +0900828 if sa_count is None:
829 if is_rekey:
830 # after rekey there is a short period of time in which old
831 # inbound SA is still present
832 sa_count = 3
833 else:
834 sa_count = 2
Filip Tehlar68ad6252020-10-30 05:28:11 +0000835 self.assertEqual(len(sas), sa_count)
Filip Tehlare7c83962020-09-23 11:20:12 +0000836 if self.sa.is_initiator:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000837 if is_rekey:
838 sa0 = sas[0].entry
839 sa1 = sas[2].entry
840 else:
841 sa0 = sas[0].entry
842 sa1 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000843 else:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000844 if is_rekey:
845 sa0 = sas[2].entry
846 sa1 = sas[0].entry
847 else:
848 sa1 = sas[0].entry
849 sa0 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000850
Filip Tehlar12b517b2020-04-26 18:05:05 +0000851 c = self.sa.child_sas[0]
852
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000853 self.verify_udp_encap(sa0)
854 self.verify_udp_encap(sa1)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000855 vpp_crypto_alg = self.vpp_enums[self.sa.vpp_esp_cypto_alg]
856 self.assertEqual(sa0.crypto_algorithm, vpp_crypto_alg)
857 self.assertEqual(sa1.crypto_algorithm, vpp_crypto_alg)
858
859 if self.sa.esp_integ is None:
860 vpp_integ_alg = 0
861 else:
862 vpp_integ_alg = self.vpp_enums[self.sa.esp_integ]
863 self.assertEqual(sa0.integrity_algorithm, vpp_integ_alg)
864 self.assertEqual(sa1.integrity_algorithm, vpp_integ_alg)
865
Filip Tehlar12b517b2020-04-26 18:05:05 +0000866 # verify crypto keys
867 self.assertEqual(sa0.crypto_key.length, len(c.sk_er))
868 self.assertEqual(sa1.crypto_key.length, len(c.sk_ei))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200869 self.assertEqual(sa0.crypto_key.data[: len(c.sk_er)], c.sk_er)
870 self.assertEqual(sa1.crypto_key.data[: len(c.sk_ei)], c.sk_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000871
872 # verify integ keys
Filip Tehlar4f42a712020-07-01 08:56:59 +0000873 if vpp_integ_alg:
874 self.assertEqual(sa0.integrity_key.length, len(c.sk_ar))
875 self.assertEqual(sa1.integrity_key.length, len(c.sk_ai))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200876 self.assertEqual(sa0.integrity_key.data[: len(c.sk_ar)], c.sk_ar)
877 self.assertEqual(sa1.integrity_key.data[: len(c.sk_ai)], c.sk_ai)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000878 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200879 self.assertEqual(sa0.salt.to_bytes(4, "little"), c.salt_er)
880 self.assertEqual(sa1.salt.to_bytes(4, "little"), c.salt_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000881
jan_cavojskya340fe12020-07-08 09:24:12 +0200882 def verify_keymat(self, api_keys, keys, name):
883 km = getattr(keys, name)
884 api_km = getattr(api_keys, name)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200885 api_km_len = getattr(api_keys, name + "_len")
jan_cavojskya340fe12020-07-08 09:24:12 +0200886 self.assertEqual(len(km), api_km_len)
887 self.assertEqual(km, api_km[:api_km_len])
888
889 def verify_id(self, api_id, exp_id):
890 self.assertEqual(api_id.type, IDType.value(exp_id.type))
891 self.assertEqual(api_id.data_len, exp_id.data_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200892 self.assertEqual(bytes(api_id.data, "ascii"), exp_id.type)
jan_cavojskya340fe12020-07-08 09:24:12 +0200893
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900894 def verify_ike_sas(self, is_rekey=False):
jan_cavojskya340fe12020-07-08 09:24:12 +0200895 r = self.vapi.ikev2_sa_dump()
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900896 if is_rekey:
897 sa_count = 2
898 sa = r[1].sa
899 else:
900 sa_count = 1
901 sa = r[0].sa
902 self.assertEqual(len(r), sa_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200903 self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, "big"))
904 self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, "big"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000905 if self.ip6:
Filip Tehlare7c83962020-09-23 11:20:12 +0000906 if self.sa.is_initiator:
907 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6))
908 self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6))
909 else:
910 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.local_ip6))
911 self.assertEqual(sa.raddr, IPv6Address(self.pg0.remote_ip6))
Filip Tehlar84962d12020-09-08 06:08:05 +0000912 else:
Filip Tehlare7c83962020-09-23 11:20:12 +0000913 if self.sa.is_initiator:
914 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4))
915 self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4))
916 else:
917 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.local_ip4))
918 self.assertEqual(sa.raddr, IPv4Address(self.pg0.remote_ip4))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200919 self.verify_keymat(sa.keys, self.sa, "sk_d")
920 self.verify_keymat(sa.keys, self.sa, "sk_ai")
921 self.verify_keymat(sa.keys, self.sa, "sk_ar")
922 self.verify_keymat(sa.keys, self.sa, "sk_ei")
923 self.verify_keymat(sa.keys, self.sa, "sk_er")
924 self.verify_keymat(sa.keys, self.sa, "sk_pi")
925 self.verify_keymat(sa.keys, self.sa, "sk_pr")
jan_cavojskya340fe12020-07-08 09:24:12 +0200926
927 self.assertEqual(sa.i_id.type, self.sa.id_type)
928 self.assertEqual(sa.r_id.type, self.sa.id_type)
929 self.assertEqual(sa.i_id.data_len, len(self.sa.i_id))
Benoît Gannec7cceee2021-09-28 11:19:37 +0200930 self.assertEqual(sa.r_id.data_len, len(self.idr))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200931 self.assertEqual(bytes(sa.i_id.data, "ascii"), self.sa.i_id)
932 self.assertEqual(bytes(sa.r_id.data, "ascii"), self.idr)
jan_cavojskya340fe12020-07-08 09:24:12 +0200933
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900934 n = self.vapi.ikev2_nonce_get(is_initiator=True, sa_index=sa.sa_index)
935 self.verify_nonce(n, self.sa.i_nonce)
936 n = self.vapi.ikev2_nonce_get(is_initiator=False, sa_index=sa.sa_index)
937 self.verify_nonce(n, self.sa.r_nonce)
938
jan_cavojskya340fe12020-07-08 09:24:12 +0200939 r = self.vapi.ikev2_child_sa_dump(sa_index=sa.sa_index)
Atzm Watanabed4f405a2022-08-18 17:57:53 +0900940 if is_rekey:
941 self.assertEqual(len(r), 0)
942 return
943
jan_cavojskya340fe12020-07-08 09:24:12 +0200944 self.assertEqual(len(r), 1)
945 csa = r[0].child_sa
946 self.assertEqual(csa.sa_index, sa.sa_index)
947 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200948 if hasattr(c, "sk_ai"):
949 self.verify_keymat(csa.keys, c, "sk_ai")
950 self.verify_keymat(csa.keys, c, "sk_ar")
951 self.verify_keymat(csa.keys, c, "sk_ei")
952 self.verify_keymat(csa.keys, c, "sk_er")
953 self.assertEqual(csa.i_spi.to_bytes(4, "big"), c.ispi)
954 self.assertEqual(csa.r_spi.to_bytes(4, "big"), c.rspi)
jan_cavojskya340fe12020-07-08 09:24:12 +0200955
Filip Tehlar84962d12020-09-08 06:08:05 +0000956 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
jan_cavojskya340fe12020-07-08 09:24:12 +0200957 tsi = tsi[0]
958 tsr = tsr[0]
959 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200960 is_initiator=True, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
961 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200962 self.assertEqual(len(r), 1)
963 ts = r[0].ts
964 self.verify_ts(r[0].ts, tsi[0], True)
965
966 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200967 is_initiator=False, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
968 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200969 self.assertEqual(len(r), 1)
970 self.verify_ts(r[0].ts, tsr[0], False)
971
Denys Haryachyyf40a3542024-01-24 16:31:47 +0200972 def verify_ike_sas_v2(self):
973 r = self.vapi.ikev2_sa_v2_dump()
974 self.assertEqual(len(r), 1)
975 sa = r[0].sa
976 self.assertEqual(self.p.profile_name, sa.profile_name)
977 self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, "big"))
978 self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, "big"))
979 if self.ip6:
980 if self.sa.is_initiator:
981 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6))
982 self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6))
983 else:
984 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.local_ip6))
985 self.assertEqual(sa.raddr, IPv6Address(self.pg0.remote_ip6))
986 else:
987 if self.sa.is_initiator:
988 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4))
989 self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4))
990 else:
991 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.local_ip4))
992 self.assertEqual(sa.raddr, IPv4Address(self.pg0.remote_ip4))
993 self.verify_keymat(sa.keys, self.sa, "sk_d")
994 self.verify_keymat(sa.keys, self.sa, "sk_ai")
995 self.verify_keymat(sa.keys, self.sa, "sk_ar")
996 self.verify_keymat(sa.keys, self.sa, "sk_ei")
997 self.verify_keymat(sa.keys, self.sa, "sk_er")
998 self.verify_keymat(sa.keys, self.sa, "sk_pi")
999 self.verify_keymat(sa.keys, self.sa, "sk_pr")
1000
1001 self.assertEqual(sa.i_id.type, self.sa.id_type)
1002 self.assertEqual(sa.r_id.type, self.sa.id_type)
1003 self.assertEqual(sa.i_id.data_len, len(self.sa.i_id))
1004 self.assertEqual(sa.r_id.data_len, len(self.idr))
1005 self.assertEqual(bytes(sa.i_id.data, "ascii"), self.sa.i_id)
1006 self.assertEqual(bytes(sa.r_id.data, "ascii"), self.idr)
1007
1008 r = self.vapi.ikev2_child_sa_dump(sa_index=sa.sa_index)
1009 self.assertEqual(len(r), 1)
1010 csa = r[0].child_sa
1011 self.assertEqual(csa.sa_index, sa.sa_index)
1012 c = self.sa.child_sas[0]
1013 if hasattr(c, "sk_ai"):
1014 self.verify_keymat(csa.keys, c, "sk_ai")
1015 self.verify_keymat(csa.keys, c, "sk_ar")
1016 self.verify_keymat(csa.keys, c, "sk_ei")
1017 self.verify_keymat(csa.keys, c, "sk_er")
1018 self.assertEqual(csa.i_spi.to_bytes(4, "big"), c.ispi)
1019 self.assertEqual(csa.r_spi.to_bytes(4, "big"), c.rspi)
1020
1021 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
1022 tsi = tsi[0]
1023 tsr = tsr[0]
1024 r = self.vapi.ikev2_traffic_selector_dump(
1025 is_initiator=True, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
1026 )
1027 self.assertEqual(len(r), 1)
1028 ts = r[0].ts
1029 self.verify_ts(r[0].ts, tsi[0], True)
1030
1031 r = self.vapi.ikev2_traffic_selector_dump(
1032 is_initiator=False, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
1033 )
1034 self.assertEqual(len(r), 1)
1035 self.verify_ts(r[0].ts, tsr[0], False)
1036
1037 n = self.vapi.ikev2_nonce_get(is_initiator=True, sa_index=sa.sa_index)
1038 self.verify_nonce(n, self.sa.i_nonce)
1039 n = self.vapi.ikev2_nonce_get(is_initiator=False, sa_index=sa.sa_index)
1040 self.verify_nonce(n, self.sa.r_nonce)
1041
jan_cavojskya340fe12020-07-08 09:24:12 +02001042 def verify_nonce(self, api_nonce, nonce):
1043 self.assertEqual(api_nonce.data_len, len(nonce))
1044 self.assertEqual(api_nonce.nonce, nonce)
1045
1046 def verify_ts(self, api_ts, ts, is_initiator):
1047 if is_initiator:
1048 self.assertTrue(api_ts.is_local)
1049 else:
1050 self.assertFalse(api_ts.is_local)
Filip Tehlar84962d12020-09-08 06:08:05 +00001051
1052 if self.p.ts_is_ip4:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001053 self.assertEqual(api_ts.start_addr, IPv4Address(ts.starting_address_v4))
1054 self.assertEqual(api_ts.end_addr, IPv4Address(ts.ending_address_v4))
Filip Tehlar84962d12020-09-08 06:08:05 +00001055 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001056 self.assertEqual(api_ts.start_addr, IPv6Address(ts.starting_address_v6))
1057 self.assertEqual(api_ts.end_addr, IPv6Address(ts.ending_address_v6))
jan_cavojskya340fe12020-07-08 09:24:12 +02001058 self.assertEqual(api_ts.start_port, ts.start_port)
1059 self.assertEqual(api_ts.end_port, ts.end_port)
1060 self.assertEqual(api_ts.protocol_id, ts.IP_protocol_ID)
1061
Filip Tehlare7c83962020-09-23 11:20:12 +00001062
1063class TemplateInitiator(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001064 """initiator test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +00001065
Filip Tehlaredf29002020-10-10 04:39:11 +00001066 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001067 ispi = int.from_bytes(self.sa.ispi, "little")
Filip Tehlaredf29002020-10-10 04:39:11 +00001068 self.pg0.enable_capture()
1069 self.pg_start()
1070 self.vapi.ikev2_initiate_del_ike_sa(ispi=ispi)
1071 capture = self.pg0.get_capture(1)
1072 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001073 self.assertNotIn("Response", ih.flags)
1074 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001075 self.assertEqual(ih.init_SPI, self.sa.ispi)
1076 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1077 plain = self.sa.hmac_and_decrypt(ih)
1078 d = ikev2.IKEv2_payload_Delete(plain)
1079 self.assertEqual(d.proto, 1) # proto=IKEv2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001080 header = ikev2.IKEv2(
1081 init_SPI=self.sa.ispi,
1082 resp_SPI=self.sa.rspi,
1083 flags="Response",
1084 exch_type="INFORMATIONAL",
1085 id=ih.id,
1086 next_payload="Encrypted",
1087 )
1088 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +00001089 self.send_and_assert_no_replies(self.pg0, resp)
1090
1091 def verify_del_sa(self, packet):
1092 ih = self.get_ike_header(packet)
1093 self.assertEqual(ih.id, self.sa.msg_id)
1094 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001095 self.assertIn("Response", ih.flags)
1096 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001097 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001098 self.assertEqual(plain, b"")
Filip Tehlaredf29002020-10-10 04:39:11 +00001099
1100 def initiate_del_sa_from_responder(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001101 header = ikev2.IKEv2(
1102 init_SPI=self.sa.ispi,
1103 resp_SPI=self.sa.rspi,
1104 exch_type="INFORMATIONAL",
1105 id=self.sa.new_msg_id(),
1106 )
1107 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
1108 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
1109 packet = self.create_packet(
1110 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1111 )
Filip Tehlaredf29002020-10-10 04:39:11 +00001112 self.pg0.add_stream(packet)
1113 self.pg0.enable_capture()
1114 self.pg_start()
1115 capture = self.pg0.get_capture(1)
1116 self.verify_del_sa(capture[0])
Filip Tehlare7c83962020-09-23 11:20:12 +00001117
Filip Tehlarec112e52020-10-07 23:52:37 +00001118 @staticmethod
1119 def find_notify_payload(packet, notify_type):
1120 n = packet[ikev2.IKEv2_payload_Notify]
1121 while n is not None:
1122 if n.type == notify_type:
1123 return n
1124 n = n.payload
1125 return None
1126
1127 def verify_nat_detection(self, packet):
1128 if self.ip6:
1129 iph = packet[IPv6]
1130 else:
1131 iph = packet[IP]
1132 udp = packet[UDP]
1133
1134 # NAT_DETECTION_SOURCE_IP
1135 s = self.find_notify_payload(packet, 16388)
1136 self.assertIsNotNone(s)
1137 src_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001138 inet_pton(socket.AF_INET, iph.src), udp.sport, b"\x00" * 8
1139 )
Filip Tehlarec112e52020-10-07 23:52:37 +00001140 self.assertEqual(s.load, src_sha)
1141
1142 # NAT_DETECTION_DESTINATION_IP
1143 s = self.find_notify_payload(packet, 16389)
1144 self.assertIsNotNone(s)
1145 dst_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001146 inet_pton(socket.AF_INET, iph.dst), udp.dport, b"\x00" * 8
1147 )
Filip Tehlarec112e52020-10-07 23:52:37 +00001148 self.assertEqual(s.load, dst_sha)
1149
Filip Tehlare7c83962020-09-23 11:20:12 +00001150 def verify_sa_init_request(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001151 udp = packet[UDP]
1152 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001153 ih = packet[ikev2.IKEv2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001154 self.assertNotEqual(ih.init_SPI, 8 * b"\x00")
Filip Tehlare7c83962020-09-23 11:20:12 +00001155 self.assertEqual(ih.exch_type, 34) # SA_INIT
1156 self.sa.ispi = ih.init_SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001157 self.assertEqual(ih.resp_SPI, 8 * b"\x00")
1158 self.assertIn("Initiator", ih.flags)
1159 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001160 self.sa.i_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1161 self.sa.i_dh_data = ih[ikev2.IKEv2_payload_KE].load
1162
1163 prop = packet[ikev2.IKEv2_payload_Proposal]
1164 self.assertEqual(prop.proto, 1) # proto = ikev2
1165 self.assertEqual(prop.proposal, 1)
1166 self.assertEqual(prop.trans[0].transform_type, 1) # encryption
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001167 self.assertEqual(
1168 prop.trans[0].transform_id, self.p.ike_transforms["crypto_alg"]
1169 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001170 self.assertEqual(prop.trans[1].transform_type, 2) # prf
1171 self.assertEqual(prop.trans[1].transform_id, 5) # "hmac-sha2-256"
1172 self.assertEqual(prop.trans[2].transform_type, 4) # dh
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001173 self.assertEqual(prop.trans[2].transform_id, self.p.ike_transforms["dh_group"])
Filip Tehlare7c83962020-09-23 11:20:12 +00001174
Filip Tehlarec112e52020-10-07 23:52:37 +00001175 self.verify_nat_detection(packet)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001176 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001177 crypto="AES-GCM-16ICV",
1178 crypto_key_len=32,
1179 integ="NULL",
1180 prf="PRF_HMAC_SHA2_256",
1181 dh="3072MODPgr",
1182 )
1183 self.sa.set_esp_props(crypto="AES-CBC", crypto_key_len=32, integ="SHA2-256-128")
Filip Tehlar68ad6252020-10-30 05:28:11 +00001184 self.sa.generate_dh_data()
Filip Tehlare7c83962020-09-23 11:20:12 +00001185 self.sa.complete_dh_data()
1186 self.sa.calc_keys()
1187
Filip Tehlar68ad6252020-10-30 05:28:11 +00001188 def update_esp_transforms(self, trans, sa):
1189 while trans:
1190 if trans.transform_type == 1: # ecryption
1191 sa.esp_crypto = CRYPTO_IDS[trans.transform_id]
1192 elif trans.transform_type == 3: # integrity
1193 sa.esp_integ = INTEG_IDS[trans.transform_id]
1194 trans = trans.payload
1195
Filip Tehlare7c83962020-09-23 11:20:12 +00001196 def verify_sa_auth_req(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001197 udp = packet[UDP]
1198 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001199 ih = self.get_ike_header(packet)
1200 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1201 self.assertEqual(ih.init_SPI, self.sa.ispi)
1202 self.assertEqual(ih.exch_type, 35) # IKE_AUTH
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001203 self.assertIn("Initiator", ih.flags)
1204 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001205
1206 udp = packet[UDP]
1207 self.verify_udp(udp)
1208 self.assertEqual(ih.id, self.sa.msg_id + 1)
1209 self.sa.msg_id += 1
1210 plain = self.sa.hmac_and_decrypt(ih)
1211 idi = ikev2.IKEv2_payload_IDi(plain)
Filip Tehlare7c83962020-09-23 11:20:12 +00001212 self.assertEqual(idi.load, self.sa.i_id)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001213 if self.no_idr_auth:
1214 self.assertEqual(idi.next_payload, 39) # AUTH
1215 else:
Dave Wallacecf9356d2024-07-23 01:28:19 -04001216 idr = ikev2.IKEv2_payload_IDr(bytes(idi.payload))
Benoît Gannec7cceee2021-09-28 11:19:37 +02001217 self.assertEqual(idr.load, self.sa.r_id)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001218 prop = idi[ikev2.IKEv2_payload_Proposal]
1219 c = self.sa.child_sas[0]
1220 c.ispi = prop.SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001221 self.update_esp_transforms(prop[ikev2.IKEv2_payload_Transform], self.sa)
Filip Tehlare7c83962020-09-23 11:20:12 +00001222
1223 def send_init_response(self):
1224 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001225 trans = (
1226 ikev2.IKEv2_payload_Transform(
1227 transform_type="Encryption",
1228 transform_id=self.sa.ike_crypto,
1229 length=tr_attr[1],
1230 key_length=tr_attr[0],
1231 )
1232 / ikev2.IKEv2_payload_Transform(
1233 transform_type="Integrity", transform_id=self.sa.ike_integ
1234 )
1235 / ikev2.IKEv2_payload_Transform(
1236 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1237 )
1238 / ikev2.IKEv2_payload_Transform(
1239 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1240 )
1241 )
1242 props = ikev2.IKEv2_payload_Proposal(
1243 proposal=1, proto="IKEv2", trans_nb=4, trans=trans
1244 )
Filip Tehlar18107c92020-12-01 14:51:09 +00001245
1246 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
1247 if self.sa.natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001248 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar18107c92020-12-01 14:51:09 +00001249 else:
1250 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1251 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1252 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1253
Filip Tehlare7c83962020-09-23 11:20:12 +00001254 self.sa.init_resp_packet = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001255 ikev2.IKEv2(
1256 init_SPI=self.sa.ispi,
1257 resp_SPI=self.sa.rspi,
1258 exch_type="IKE_SA_INIT",
1259 flags="Response",
1260 )
1261 / ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
1262 / ikev2.IKEv2_payload_KE(
1263 next_payload="Nonce", group=self.sa.ike_dh, load=self.sa.my_dh_pub_key
1264 )
1265 / ikev2.IKEv2_payload_Nonce(load=self.sa.r_nonce, next_payload="Notify")
1266 / ikev2.IKEv2_payload_Notify(
1267 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1268 )
1269 / ikev2.IKEv2_payload_Notify(
1270 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1271 )
1272 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001273
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001274 ike_msg = self.create_packet(
1275 self.pg0,
1276 self.sa.init_resp_packet,
1277 self.sa.sport,
1278 self.sa.dport,
1279 False,
1280 self.ip6,
1281 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001282 self.pg_send(self.pg0, ike_msg)
1283 capture = self.pg0.get_capture(1)
1284 self.verify_sa_auth_req(capture[0])
1285
1286 def initiate_sa_init(self):
1287 self.pg0.enable_capture()
1288 self.pg_start()
1289 self.vapi.ikev2_initiate_sa_init(name=self.p.profile_name)
1290
1291 capture = self.pg0.get_capture(1)
1292 self.verify_sa_init_request(capture[0])
1293 self.send_init_response()
1294
1295 def send_auth_response(self):
1296 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001297 trans = (
1298 ikev2.IKEv2_payload_Transform(
1299 transform_type="Encryption",
1300 transform_id=self.sa.esp_crypto,
1301 length=tr_attr[1],
1302 key_length=tr_attr[0],
1303 )
1304 / ikev2.IKEv2_payload_Transform(
1305 transform_type="Integrity", transform_id=self.sa.esp_integ
1306 )
1307 / ikev2.IKEv2_payload_Transform(
1308 transform_type="Extended Sequence Number", transform_id="No ESN"
1309 )
1310 / ikev2.IKEv2_payload_Transform(
1311 transform_type="Extended Sequence Number", transform_id="ESN"
1312 )
1313 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001314
Filip Tehlar68ad6252020-10-30 05:28:11 +00001315 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001316 props = ikev2.IKEv2_payload_Proposal(
1317 proposal=1, proto="ESP", SPIsize=4, SPI=c.rspi, trans_nb=4, trans=trans
1318 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001319
1320 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001321 plain = (
1322 ikev2.IKEv2_payload_IDi(
1323 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1324 )
1325 / ikev2.IKEv2_payload_IDr(
1326 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1327 )
1328 / ikev2.IKEv2_payload_AUTH(
1329 next_payload="SA",
1330 auth_type=AuthMethod.value(self.sa.auth_method),
1331 load=self.sa.auth_data,
1332 )
1333 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1334 / ikev2.IKEv2_payload_TSi(
1335 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1336 )
1337 / ikev2.IKEv2_payload_TSr(
1338 next_payload="Notify", number_of_TSs=len(tsr), traffic_selector=tsr
1339 )
1340 / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
1341 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001342
1343 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001344 init_SPI=self.sa.ispi,
1345 resp_SPI=self.sa.rspi,
1346 id=self.sa.new_msg_id(),
1347 flags="Response",
1348 exch_type="IKE_AUTH",
1349 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001350
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001351 ike_msg = self.encrypt_ike_msg(header, plain, "IDi")
1352 packet = self.create_packet(
1353 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1354 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001355 self.pg_send(self.pg0, packet)
1356
1357 def test_initiator(self):
1358 self.initiate_sa_init()
1359 self.sa.auth_init()
1360 self.sa.calc_child_keys()
1361 self.send_auth_response()
1362 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02001363 self.verify_ike_sas_v2()
Filip Tehlare7c83962020-09-23 11:20:12 +00001364
1365
1366class TemplateResponder(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001367 """responder test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +00001368
Filip Tehlaredf29002020-10-10 04:39:11 +00001369 def initiate_del_sa_from_responder(self):
1370 self.pg0.enable_capture()
1371 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001372 self.vapi.ikev2_initiate_del_ike_sa(ispi=int.from_bytes(self.sa.ispi, "little"))
Filip Tehlaredf29002020-10-10 04:39:11 +00001373 capture = self.pg0.get_capture(1)
1374 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001375 self.assertNotIn("Response", ih.flags)
1376 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001377 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
1378 plain = self.sa.hmac_and_decrypt(ih)
1379 d = ikev2.IKEv2_payload_Delete(plain)
1380 self.assertEqual(d.proto, 1) # proto=IKEv2
1381 self.assertEqual(ih.init_SPI, self.sa.ispi)
1382 self.assertEqual(ih.resp_SPI, self.sa.rspi)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001383 header = ikev2.IKEv2(
1384 init_SPI=self.sa.ispi,
1385 resp_SPI=self.sa.rspi,
1386 flags="Initiator+Response",
1387 exch_type="INFORMATIONAL",
1388 id=ih.id,
1389 next_payload="Encrypted",
1390 )
1391 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +00001392 self.send_and_assert_no_replies(self.pg0, resp)
Filip Tehlare7c83962020-09-23 11:20:12 +00001393
1394 def verify_del_sa(self, packet):
1395 ih = self.get_ike_header(packet)
1396 self.assertEqual(ih.id, self.sa.msg_id)
1397 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001398 self.assertIn("Response", ih.flags)
1399 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001400 self.assertEqual(ih.next_payload, 46) # Encrypted
1401 self.assertEqual(ih.init_SPI, self.sa.ispi)
1402 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1403 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001404 self.assertEqual(plain, b"")
Filip Tehlare7c83962020-09-23 11:20:12 +00001405
Filip Tehlaredf29002020-10-10 04:39:11 +00001406 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001407 header = ikev2.IKEv2(
1408 init_SPI=self.sa.ispi,
1409 resp_SPI=self.sa.rspi,
1410 flags="Initiator",
1411 exch_type="INFORMATIONAL",
1412 id=self.sa.new_msg_id(),
1413 )
1414 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
1415 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
1416 packet = self.create_packet(
1417 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1418 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001419 self.pg0.add_stream(packet)
1420 self.pg0.enable_capture()
1421 self.pg_start()
1422 capture = self.pg0.get_capture(1)
1423 self.verify_del_sa(capture[0])
1424
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001425 def generate_sa_init_payload(
1426 self, spi=None, dh_pub_key=None, nonce=None, next_payload=None
1427 ):
Filip Tehlare7c83962020-09-23 11:20:12 +00001428 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001429 trans = (
1430 ikev2.IKEv2_payload_Transform(
1431 transform_type="Encryption",
1432 transform_id=self.sa.ike_crypto,
1433 length=tr_attr[1],
1434 key_length=tr_attr[0],
1435 )
1436 / ikev2.IKEv2_payload_Transform(
1437 transform_type="Integrity", transform_id=self.sa.ike_integ
1438 )
1439 / ikev2.IKEv2_payload_Transform(
1440 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1441 )
1442 / ikev2.IKEv2_payload_Transform(
1443 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1444 )
1445 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001446
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001447 if spi is None:
1448 pargs = {}
1449 else:
1450 pargs = {"SPI": spi, "SPIsize": len(spi)}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001451 props = ikev2.IKEv2_payload_Proposal(
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001452 proposal=1,
1453 proto="IKEv2",
1454 trans_nb=4,
1455 trans=trans,
1456 **pargs,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001457 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001458
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001459 return (
1460 ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001461 / ikev2.IKEv2_payload_KE(
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001462 next_payload="Nonce",
1463 group=self.sa.ike_dh,
1464 load=self.sa.my_dh_pub_key if dh_pub_key is None else dh_pub_key,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001465 )
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001466 / ikev2.IKEv2_payload_Nonce(
1467 next_payload=next_payload,
1468 load=self.sa.i_nonce if nonce is None else nonce,
1469 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001470 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001471
Atzm Watanabed4f405a2022-08-18 17:57:53 +09001472 def send_sa_init_req(self):
1473 self.sa.init_req_packet = ikev2.IKEv2(
1474 init_SPI=self.sa.ispi, flags="Initiator", exch_type="IKE_SA_INIT"
1475 ) / self.generate_sa_init_payload(next_payload=None if self.ip6 else "Notify")
1476
Filip Tehlar027d8132020-12-04 17:38:11 +00001477 if not self.ip6:
1478 if self.sa.i_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001479 src_address = b"\x0a\x0a\x0a\x01"
Filip Tehlar027d8132020-12-04 17:38:11 +00001480 else:
1481 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
Filip Tehlare7c83962020-09-23 11:20:12 +00001482
Filip Tehlar027d8132020-12-04 17:38:11 +00001483 if self.sa.r_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001484 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar027d8132020-12-04 17:38:11 +00001485 else:
1486 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1487
1488 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1489 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1490 nat_src_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001491 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1492 )
Filip Tehlar027d8132020-12-04 17:38:11 +00001493 nat_dst_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001494 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1495 )
1496 self.sa.init_req_packet = (
1497 self.sa.init_req_packet / nat_src_detection / nat_dst_detection
1498 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001499
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001500 ike_msg = self.create_packet(
1501 self.pg0,
1502 self.sa.init_req_packet,
1503 self.sa.sport,
1504 self.sa.dport,
1505 self.sa.natt,
1506 self.ip6,
1507 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001508 self.pg0.add_stream(ike_msg)
1509 self.pg0.enable_capture()
1510 self.pg_start()
1511 capture = self.pg0.get_capture(1)
1512 self.verify_sa_init(capture[0])
1513
Atzm Watanabec65921f2022-08-12 14:29:31 +09001514 def generate_auth_payload(self, last_payload=None, is_rekey=False, kex=False):
Filip Tehlare7c83962020-09-23 11:20:12 +00001515 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001516 last_payload = last_payload or "Notify"
Atzm Watanabec65921f2022-08-12 14:29:31 +09001517 trans_nb = 4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001518 trans = (
1519 ikev2.IKEv2_payload_Transform(
1520 transform_type="Encryption",
1521 transform_id=self.sa.esp_crypto,
1522 length=tr_attr[1],
1523 key_length=tr_attr[0],
1524 )
1525 / ikev2.IKEv2_payload_Transform(
1526 transform_type="Integrity", transform_id=self.sa.esp_integ
1527 )
1528 / ikev2.IKEv2_payload_Transform(
1529 transform_type="Extended Sequence Number", transform_id="No ESN"
1530 )
1531 / ikev2.IKEv2_payload_Transform(
1532 transform_type="Extended Sequence Number", transform_id="ESN"
1533 )
1534 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001535
Atzm Watanabec65921f2022-08-12 14:29:31 +09001536 if kex:
1537 trans_nb += 1
1538 trans /= ikev2.IKEv2_payload_Transform(
1539 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1540 )
1541
Filip Tehlar68ad6252020-10-30 05:28:11 +00001542 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001543 props = ikev2.IKEv2_payload_Proposal(
Atzm Watanabec65921f2022-08-12 14:29:31 +09001544 proposal=1,
1545 proto="ESP",
1546 SPIsize=4,
1547 SPI=c.ispi,
1548 trans_nb=trans_nb,
1549 trans=trans,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001550 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001551
1552 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001553 plain = (
1554 ikev2.IKEv2_payload_AUTH(
1555 next_payload="SA",
1556 auth_type=AuthMethod.value(self.sa.auth_method),
1557 load=self.sa.auth_data,
1558 )
1559 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1560 / ikev2.IKEv2_payload_TSi(
1561 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1562 )
1563 / ikev2.IKEv2_payload_TSr(
1564 next_payload=last_payload, number_of_TSs=len(tsr), traffic_selector=tsr
1565 )
1566 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001567
Filip Tehlar68ad6252020-10-30 05:28:11 +00001568 if is_rekey:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001569 first_payload = "Nonce"
Atzm Watanabec65921f2022-08-12 14:29:31 +09001570 if kex:
1571 head = ikev2.IKEv2_payload_Nonce(
1572 load=self.sa.i_nonce, next_payload="KE"
1573 ) / ikev2.IKEv2_payload_KE(
1574 group=self.sa.ike_dh, load=self.sa.my_dh_pub_key, next_payload="SA"
1575 )
1576 else:
1577 head = ikev2.IKEv2_payload_Nonce(
1578 load=self.sa.i_nonce, next_payload="SA"
1579 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001580 plain = (
Atzm Watanabec65921f2022-08-12 14:29:31 +09001581 head
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001582 / plain
Atzm Watanabe03aae962022-08-08 15:45:36 +09001583 / ikev2.IKEv2_payload_Notify(
1584 type="REKEY_SA",
1585 proto="ESP",
1586 SPI=c.ispi,
1587 length=8 + len(c.ispi),
1588 next_payload="Notify",
1589 )
1590 / ikev2.IKEv2_payload_Notify(type="ESP_TFC_PADDING_NOT_SUPPORTED")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001591 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001592 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001593 first_payload = "IDi"
Benoît Gannec7cceee2021-09-28 11:19:37 +02001594 if self.no_idr_auth:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001595 ids = ikev2.IKEv2_payload_IDi(
1596 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.i_id
1597 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001598 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001599 ids = ikev2.IKEv2_payload_IDi(
1600 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1601 ) / ikev2.IKEv2_payload_IDr(
1602 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1603 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001604 plain = ids / plain
1605 return plain, first_payload
1606
1607 def send_sa_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001608 plain, first_payload = self.generate_auth_payload(last_payload="Notify")
1609 plain = plain / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
Filip Tehlare7c83962020-09-23 11:20:12 +00001610 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001611 init_SPI=self.sa.ispi,
1612 resp_SPI=self.sa.rspi,
1613 id=self.sa.new_msg_id(),
1614 flags="Initiator",
1615 exch_type="IKE_AUTH",
1616 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001617
Filip Tehlar68ad6252020-10-30 05:28:11 +00001618 ike_msg = self.encrypt_ike_msg(header, plain, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001619 packet = self.create_packet(
1620 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1621 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001622 self.pg0.add_stream(packet)
1623 self.pg0.enable_capture()
1624 self.pg_start()
1625 capture = self.pg0.get_capture(1)
1626 self.verify_sa_auth_resp(capture[0])
1627
1628 def verify_sa_init(self, packet):
1629 ih = self.get_ike_header(packet)
1630
1631 self.assertEqual(ih.id, self.sa.msg_id)
1632 self.assertEqual(ih.exch_type, 34)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001633 self.assertIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001634 self.assertEqual(ih.init_SPI, self.sa.ispi)
1635 self.assertNotEqual(ih.resp_SPI, 0)
1636 self.sa.rspi = ih.resp_SPI
1637 try:
1638 sa = ih[ikev2.IKEv2_payload_SA]
1639 self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1640 self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load
1641 except IndexError as e:
1642 self.logger.error("unexpected reply: SA/Nonce/KE payload found!")
1643 self.logger.error(ih.show())
1644 raise
1645 self.sa.complete_dh_data()
1646 self.sa.calc_keys()
1647 self.sa.auth_init()
1648
1649 def verify_sa_auth_resp(self, packet):
1650 ike = self.get_ike_header(packet)
1651 udp = packet[UDP]
1652 self.verify_udp(udp)
1653 self.assertEqual(ike.id, self.sa.msg_id)
1654 plain = self.sa.hmac_and_decrypt(ike)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001655 idr = ikev2.IKEv2_payload_IDr(plain)
1656 prop = idr[ikev2.IKEv2_payload_Proposal]
1657 self.assertEqual(prop.SPIsize, 4)
1658 self.sa.child_sas[0].rspi = prop.SPI
Filip Tehlare7c83962020-09-23 11:20:12 +00001659 self.sa.calc_child_keys()
1660
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001661 IKE_NODE_SUFFIX = "ip4"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001662
1663 def verify_counters(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001664 self.assert_counter(2, "processed", self.IKE_NODE_SUFFIX)
1665 self.assert_counter(1, "init_sa_req", self.IKE_NODE_SUFFIX)
1666 self.assert_counter(1, "ike_auth_req", self.IKE_NODE_SUFFIX)
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001667
Filip Tehlar68d27532021-01-25 10:09:27 +00001668 r = self.vapi.ikev2_sa_dump()
1669 s = r[0].sa.stats
1670 self.assertEqual(1, s.n_sa_auth_req)
1671 self.assertEqual(1, s.n_sa_init_req)
1672
Denys Haryachyyf40a3542024-01-24 16:31:47 +02001673 r = self.vapi.ikev2_sa_v2_dump()
1674 s = r[0].sa.stats
1675 self.assertEqual(1, s.n_sa_auth_req)
1676 self.assertEqual(1, s.n_sa_init_req)
1677
Filip Tehlar12b517b2020-04-26 18:05:05 +00001678 def test_responder(self):
Filip Tehlar027d8132020-12-04 17:38:11 +00001679 self.send_sa_init_req()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001680 self.send_sa_auth()
jan_cavojskya340fe12020-07-08 09:24:12 +02001681 self.verify_ipsec_sas()
1682 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02001683 self.verify_ike_sas_v2()
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001684 self.verify_counters()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001685
1686
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001687class Ikev2Params(object):
1688 def config_params(self, params={}):
Filip Tehlar4f42a712020-07-01 08:56:59 +00001689 ec = VppEnum.vl_api_ipsec_crypto_alg_t
1690 ei = VppEnum.vl_api_ipsec_integ_alg_t
1691 self.vpp_enums = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001692 "AES-CBC-128": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_128,
1693 "AES-CBC-192": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_192,
1694 "AES-CBC-256": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_256,
1695 "AES-GCM-16ICV-128": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_128,
1696 "AES-GCM-16ICV-192": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_192,
1697 "AES-GCM-16ICV-256": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_256,
1698 "HMAC-SHA1-96": ei.IPSEC_API_INTEG_ALG_SHA1_96,
1699 "SHA2-256-128": ei.IPSEC_API_INTEG_ALG_SHA_256_128,
1700 "SHA2-384-192": ei.IPSEC_API_INTEG_ALG_SHA_384_192,
1701 "SHA2-512-256": ei.IPSEC_API_INTEG_ALG_SHA_512_256,
1702 }
Filip Tehlar4f42a712020-07-01 08:56:59 +00001703
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001704 dpd_disabled = True if "dpd_disabled" not in params else params["dpd_disabled"]
Filip Tehlar2008e312020-11-09 13:23:24 +00001705 if dpd_disabled:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001706 self.vapi.cli("ikev2 dpd disable")
1707 self.del_sa_from_responder = (
1708 False
1709 if "del_sa_from_responder" not in params
1710 else params["del_sa_from_responder"]
1711 )
1712 i_natt = False if "i_natt" not in params else params["i_natt"]
1713 r_natt = False if "r_natt" not in params else params["r_natt"]
1714 self.p = Profile(self, "pr1")
1715 self.ip6 = False if "ip6" not in params else params["ip6"]
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001716
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001717 if "auth" in params and params["auth"] == "rsa-sig":
1718 auth_method = "rsa-sig"
Klement Sekerab23ffd72021-05-31 16:08:53 +02001719 work_dir = f"{config.vpp_ws_dir}/src/plugins/ikev2/test/certs/"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001720 self.vapi.ikev2_set_local_key(key_file=work_dir + params["server-key"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001721
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001722 client_file = work_dir + params["client-cert"]
1723 server_pem = open(work_dir + params["server-cert"]).read()
1724 client_priv = open(work_dir + params["client-key"]).read()
1725 client_priv = load_pem_private_key(
1726 str.encode(client_priv), None, default_backend()
1727 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001728 self.peer_cert = x509.load_pem_x509_certificate(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001729 str.encode(server_pem), default_backend()
1730 )
1731 self.p.add_auth(method="rsa-sig", data=str.encode(client_file))
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001732 auth_data = None
1733 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001734 auth_data = b"$3cr3tpa$$w0rd"
1735 self.p.add_auth(method="shared-key", data=auth_data)
1736 auth_method = "shared-key"
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001737 client_priv = None
1738
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001739 is_init = True if "is_initiator" not in params else params["is_initiator"]
1740 self.no_idr_auth = params.get("no_idr_in_auth", False)
Filip Tehlare7c83962020-09-23 11:20:12 +00001741
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001742 idr = {"id_type": "fqdn", "data": b"vpp.home"}
1743 idi = {"id_type": "fqdn", "data": b"roadwarrior.example.com"}
1744 r_id = self.idr = idr["data"]
1745 i_id = self.idi = idi["data"]
Filip Tehlare7c83962020-09-23 11:20:12 +00001746 if is_init:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001747 # scapy is initiator, VPP is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001748 self.p.add_local_id(**idr)
1749 self.p.add_remote_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001750 if self.no_idr_auth:
1751 r_id = None
Filip Tehlare7c83962020-09-23 11:20:12 +00001752 else:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001753 # VPP is initiator, scapy is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001754 self.p.add_local_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001755 if not self.no_idr_auth:
1756 self.p.add_remote_id(**idr)
Filip Tehlare7c83962020-09-23 11:20:12 +00001757
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001758 loc_ts = (
1759 {"start_addr": "10.10.10.0", "end_addr": "10.10.10.255"}
1760 if "loc_ts" not in params
1761 else params["loc_ts"]
1762 )
1763 rem_ts = (
1764 {"start_addr": "10.0.0.0", "end_addr": "10.0.0.255"}
1765 if "rem_ts" not in params
1766 else params["rem_ts"]
1767 )
Filip Tehlar84962d12020-09-08 06:08:05 +00001768 self.p.add_local_ts(**loc_ts)
1769 self.p.add_remote_ts(**rem_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001770 if "responder" in params:
1771 self.p.add_responder(params["responder"])
1772 if "ike_transforms" in params:
1773 self.p.add_ike_transforms(params["ike_transforms"])
1774 if "esp_transforms" in params:
1775 self.p.add_esp_transforms(params["esp_transforms"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001776
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001777 udp_encap = False if "udp_encap" not in params else params["udp_encap"]
Filip Tehlar67b8a7f2020-11-06 11:00:42 +00001778 if udp_encap:
1779 self.p.set_udp_encap(True)
1780
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001781 if "responder_hostname" in params:
1782 hn = params["responder_hostname"]
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001783 self.p.add_responder_hostname(hn)
1784
1785 # configure static dns record
1786 self.vapi.dns_name_server_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001787 is_ip6=0, is_add=1, server_address=IPv4Address("8.8.8.8").packed
1788 )
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001789 self.vapi.dns_enable_disable(enable=1)
1790
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001791 cmd = "dns cache add {} {}".format(hn["hostname"], self.pg0.remote_ip4)
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001792 self.vapi.cli(cmd)
1793
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001794 self.sa = IKEv2SA(
1795 self,
1796 i_id=i_id,
1797 r_id=r_id,
1798 is_initiator=is_init,
1799 id_type=self.p.local_id["id_type"],
1800 i_natt=i_natt,
1801 r_natt=r_natt,
1802 priv_key=client_priv,
1803 auth_method=auth_method,
1804 nonce=params.get("nonce"),
1805 auth_data=auth_data,
1806 udp_encap=udp_encap,
1807 local_ts=self.p.remote_ts,
1808 remote_ts=self.p.local_ts,
1809 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001810
Filip Tehlar68ad6252020-10-30 05:28:11 +00001811 if is_init:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001812 ike_crypto = (
1813 ("AES-CBC", 32) if "ike-crypto" not in params else params["ike-crypto"]
1814 )
1815 ike_integ = (
1816 "HMAC-SHA1-96" if "ike-integ" not in params else params["ike-integ"]
1817 )
1818 ike_dh = "2048MODPgr" if "ike-dh" not in params else params["ike-dh"]
Filip Tehlar4f42a712020-07-01 08:56:59 +00001819
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001820 esp_crypto = (
1821 ("AES-CBC", 32) if "esp-crypto" not in params else params["esp-crypto"]
1822 )
1823 esp_integ = (
1824 "HMAC-SHA1-96" if "esp-integ" not in params else params["esp-integ"]
1825 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00001826
Filip Tehlar68ad6252020-10-30 05:28:11 +00001827 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001828 crypto=ike_crypto[0],
1829 crypto_key_len=ike_crypto[1],
1830 integ=ike_integ,
1831 prf="PRF_HMAC_SHA2_256",
1832 dh=ike_dh,
1833 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001834 self.sa.set_esp_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001835 crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], integ=esp_integ
1836 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001837
1838
Andrew Yourtchenkobc378782023-09-26 16:01:21 +02001839@unittest.skipIf("ikev2" in config.excluded_plugins, "Exclude IKEv2 plugin tests")
Filip Tehlar459d17b2020-07-06 15:40:08 +00001840class TestApi(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001841 """Test IKEV2 API"""
1842
Filip Tehlar459d17b2020-07-06 15:40:08 +00001843 @classmethod
1844 def setUpClass(cls):
1845 super(TestApi, cls).setUpClass()
1846
1847 @classmethod
1848 def tearDownClass(cls):
1849 super(TestApi, cls).tearDownClass()
1850
1851 def tearDown(self):
1852 super(TestApi, self).tearDown()
1853 self.p1.remove_vpp_config()
1854 self.p2.remove_vpp_config()
1855 r = self.vapi.ikev2_profile_dump()
1856 self.assertEqual(len(r), 0)
1857
1858 def configure_profile(self, cfg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001859 p = Profile(self, cfg["name"])
1860 p.add_local_id(id_type=cfg["loc_id"][0], data=cfg["loc_id"][1])
1861 p.add_remote_id(id_type=cfg["rem_id"][0], data=cfg["rem_id"][1])
1862 p.add_local_ts(**cfg["loc_ts"])
1863 p.add_remote_ts(**cfg["rem_ts"])
1864 p.add_responder(cfg["responder"])
1865 p.add_ike_transforms(cfg["ike_ts"])
1866 p.add_esp_transforms(cfg["esp_ts"])
1867 p.add_auth(**cfg["auth"])
1868 p.set_udp_encap(cfg["udp_encap"])
1869 p.set_ipsec_over_udp_port(cfg["ipsec_over_udp_port"])
1870 if "lifetime_data" in cfg:
1871 p.set_lifetime_data(cfg["lifetime_data"])
1872 if "tun_itf" in cfg:
1873 p.set_tunnel_interface(cfg["tun_itf"])
1874 if "natt_disabled" in cfg and cfg["natt_disabled"]:
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001875 p.disable_natt()
Filip Tehlar459d17b2020-07-06 15:40:08 +00001876 p.add_vpp_config()
1877 return p
1878
1879 def test_profile_api(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001880 """test profile dump API"""
Filip Tehlar84962d12020-09-08 06:08:05 +00001881 loc_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001882 "proto": 8,
1883 "start_port": 1,
1884 "end_port": 19,
1885 "start_addr": "3.3.3.2",
1886 "end_addr": "3.3.3.3",
1887 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001888 rem_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001889 "proto": 9,
1890 "start_port": 10,
1891 "end_port": 119,
1892 "start_addr": "4.5.76.80",
1893 "end_addr": "2.3.4.6",
1894 }
Filip Tehlar459d17b2020-07-06 15:40:08 +00001895
Filip Tehlar84962d12020-09-08 06:08:05 +00001896 loc_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001897 "proto": 8,
1898 "start_port": 1,
1899 "end_port": 19,
1900 "start_addr": "ab::1",
1901 "end_addr": "ab::4",
1902 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001903 rem_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001904 "proto": 9,
1905 "start_port": 10,
1906 "end_port": 119,
1907 "start_addr": "cd::12",
1908 "end_addr": "cd::13",
1909 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001910
Filip Tehlar459d17b2020-07-06 15:40:08 +00001911 conf = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001912 "p1": {
1913 "name": "p1",
1914 "natt_disabled": True,
1915 "loc_id": ("fqdn", b"vpp.home"),
1916 "rem_id": ("fqdn", b"roadwarrior.example.com"),
1917 "loc_ts": loc_ts4,
1918 "rem_ts": rem_ts4,
1919 "responder": {"sw_if_index": 0, "addr": "5.6.7.8"},
1920 "ike_ts": {
1921 "crypto_alg": 20,
1922 "crypto_key_size": 32,
1923 "integ_alg": 0,
1924 "dh_group": 1,
1925 },
1926 "esp_ts": {"crypto_alg": 13, "crypto_key_size": 24, "integ_alg": 2},
1927 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1928 "udp_encap": True,
1929 "ipsec_over_udp_port": 4501,
1930 "lifetime_data": {
1931 "lifetime": 123,
1932 "lifetime_maxdata": 20192,
1933 "lifetime_jitter": 9,
1934 "handover": 132,
1935 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001936 },
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001937 "p2": {
1938 "name": "p2",
1939 "loc_id": ("ip4-addr", b"192.168.2.1"),
1940 "rem_id": ("ip6-addr", b"abcd::1"),
1941 "loc_ts": loc_ts6,
1942 "rem_ts": rem_ts6,
1943 "responder": {"sw_if_index": 4, "addr": "def::10"},
1944 "ike_ts": {
1945 "crypto_alg": 12,
1946 "crypto_key_size": 16,
1947 "integ_alg": 3,
1948 "dh_group": 3,
1949 },
1950 "esp_ts": {"crypto_alg": 9, "crypto_key_size": 24, "integ_alg": 4},
1951 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1952 "udp_encap": False,
1953 "ipsec_over_udp_port": 4600,
1954 "tun_itf": 0,
1955 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001956 }
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001957 self.p1 = self.configure_profile(conf["p1"])
1958 self.p2 = self.configure_profile(conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001959
1960 r = self.vapi.ikev2_profile_dump()
1961 self.assertEqual(len(r), 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001962 self.verify_profile(r[0].profile, conf["p1"])
1963 self.verify_profile(r[1].profile, conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001964
1965 def verify_id(self, api_id, cfg_id):
1966 self.assertEqual(api_id.type, IDType.value(cfg_id[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001967 self.assertEqual(bytes(api_id.data, "ascii"), cfg_id[1])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001968
1969 def verify_ts(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001970 self.assertEqual(api_ts.protocol_id, cfg_ts["proto"])
1971 self.assertEqual(api_ts.start_port, cfg_ts["start_port"])
1972 self.assertEqual(api_ts.end_port, cfg_ts["end_port"])
1973 self.assertEqual(api_ts.start_addr, ip_address(text_type(cfg_ts["start_addr"])))
1974 self.assertEqual(api_ts.end_addr, ip_address(text_type(cfg_ts["end_addr"])))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001975
1976 def verify_responder(self, api_r, cfg_r):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001977 self.assertEqual(api_r.sw_if_index, cfg_r["sw_if_index"])
1978 self.assertEqual(api_r.addr, ip_address(cfg_r["addr"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001979
1980 def verify_transforms(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001981 self.assertEqual(api_ts.crypto_alg, cfg_ts["crypto_alg"])
1982 self.assertEqual(api_ts.crypto_key_size, cfg_ts["crypto_key_size"])
1983 self.assertEqual(api_ts.integ_alg, cfg_ts["integ_alg"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001984
1985 def verify_ike_transforms(self, api_ts, cfg_ts):
1986 self.verify_transforms(api_ts, cfg_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001987 self.assertEqual(api_ts.dh_group, cfg_ts["dh_group"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001988
1989 def verify_esp_transforms(self, api_ts, cfg_ts):
1990 self.verify_transforms(api_ts, cfg_ts)
1991
1992 def verify_auth(self, api_auth, cfg_auth):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001993 self.assertEqual(api_auth.method, AuthMethod.value(cfg_auth["method"]))
1994 self.assertEqual(api_auth.data, cfg_auth["data"])
1995 self.assertEqual(api_auth.data_len, len(cfg_auth["data"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001996
1997 def verify_lifetime_data(self, p, ld):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001998 self.assertEqual(p.lifetime, ld["lifetime"])
1999 self.assertEqual(p.lifetime_maxdata, ld["lifetime_maxdata"])
2000 self.assertEqual(p.lifetime_jitter, ld["lifetime_jitter"])
2001 self.assertEqual(p.handover, ld["handover"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00002002
2003 def verify_profile(self, ap, cp):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002004 self.assertEqual(ap.name, cp["name"])
2005 self.assertEqual(ap.udp_encap, cp["udp_encap"])
2006 self.verify_id(ap.loc_id, cp["loc_id"])
2007 self.verify_id(ap.rem_id, cp["rem_id"])
2008 self.verify_ts(ap.loc_ts, cp["loc_ts"])
2009 self.verify_ts(ap.rem_ts, cp["rem_ts"])
2010 self.verify_responder(ap.responder, cp["responder"])
2011 self.verify_ike_transforms(ap.ike_ts, cp["ike_ts"])
2012 self.verify_esp_transforms(ap.esp_ts, cp["esp_ts"])
2013 self.verify_auth(ap.auth, cp["auth"])
2014 natt_dis = False if "natt_disabled" not in cp else cp["natt_disabled"]
Filip Tehlard7fc12f2020-10-30 04:47:44 +00002015 self.assertTrue(natt_dis == ap.natt_disabled)
2016
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002017 if "lifetime_data" in cp:
2018 self.verify_lifetime_data(ap, cp["lifetime_data"])
2019 self.assertEqual(ap.ipsec_over_udp_port, cp["ipsec_over_udp_port"])
2020 if "tun_itf" in cp:
2021 self.assertEqual(ap.tun_itf, cp["tun_itf"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00002022 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002023 self.assertEqual(ap.tun_itf, 0xFFFFFFFF)
Filip Tehlar459d17b2020-07-06 15:40:08 +00002024
2025
Filip Tehlar027d8132020-12-04 17:38:11 +00002026class TestResponderBehindNAT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002027 """test responder - responder behind NAT"""
Filip Tehlar027d8132020-12-04 17:38:11 +00002028
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002029 IKE_NODE_SUFFIX = "ip4-natt"
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002030 vpp_worker_count = 2
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002031
Filip Tehlar027d8132020-12-04 17:38:11 +00002032 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002033 self.config_params({"r_natt": True})
Filip Tehlar027d8132020-12-04 17:38:11 +00002034
2035
Filip Tehlar18107c92020-12-01 14:51:09 +00002036class TestInitiatorNATT(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002037 """test ikev2 initiator - NAT traversal (intitiator behind NAT)"""
Filip Tehlar18107c92020-12-01 14:51:09 +00002038
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002039 vpp_worker_count = 2
2040
Filip Tehlar18107c92020-12-01 14:51:09 +00002041 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002042 self.config_params(
2043 {
2044 "i_natt": True,
2045 "is_initiator": False, # seen from test case perspective
2046 # thus vpp is initiator
2047 "responder": {
2048 "sw_if_index": self.pg0.sw_if_index,
2049 "addr": self.pg0.remote_ip4,
2050 },
2051 "ike-crypto": ("AES-GCM-16ICV", 32),
2052 "ike-integ": "NULL",
2053 "ike-dh": "3072MODPgr",
2054 "ike_transforms": {
2055 "crypto_alg": 20, # "aes-gcm-16"
2056 "crypto_key_size": 256,
2057 "dh_group": 15, # "modp-3072"
2058 },
2059 "esp_transforms": {
2060 "crypto_alg": 12, # "aes-cbc"
2061 "crypto_key_size": 256,
2062 # "hmac-sha2-256-128"
2063 "integ_alg": 12,
2064 },
2065 }
2066 )
Filip Tehlar18107c92020-12-01 14:51:09 +00002067
2068
Filip Tehlare7c83962020-09-23 11:20:12 +00002069class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002070 """test ikev2 initiator - pre shared key auth"""
Filip Tehlaredf29002020-10-10 04:39:11 +00002071
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002072 vpp_worker_count = 2
2073
Filip Tehlare7c83962020-09-23 11:20:12 +00002074 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002075 self.config_params(
2076 {
2077 "is_initiator": False, # seen from test case perspective
2078 # thus vpp is initiator
2079 "ike-crypto": ("AES-GCM-16ICV", 32),
2080 "ike-integ": "NULL",
2081 "ike-dh": "3072MODPgr",
2082 "ike_transforms": {
2083 "crypto_alg": 20, # "aes-gcm-16"
2084 "crypto_key_size": 256,
2085 "dh_group": 15, # "modp-3072"
2086 },
2087 "esp_transforms": {
2088 "crypto_alg": 12, # "aes-cbc"
2089 "crypto_key_size": 256,
2090 # "hmac-sha2-256-128"
2091 "integ_alg": 12,
2092 },
2093 "responder_hostname": {
2094 "hostname": "vpp.responder.org",
2095 "sw_if_index": self.pg0.sw_if_index,
2096 },
2097 }
2098 )
Filip Tehlare7c83962020-09-23 11:20:12 +00002099
2100
Filip Tehlar38340fa2020-11-19 21:34:48 +00002101class TestInitiatorRequestWindowSize(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002102 """test initiator - request window size (1)"""
Filip Tehlar38340fa2020-11-19 21:34:48 +00002103
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002104 vpp_worker_count = 2
2105
Filip Tehlar38340fa2020-11-19 21:34:48 +00002106 def rekey_respond(self, req, update_child_sa_data):
2107 ih = self.get_ike_header(req)
2108 plain = self.sa.hmac_and_decrypt(ih)
2109 sa = ikev2.IKEv2_payload_SA(plain)
2110 if update_child_sa_data:
2111 prop = sa[ikev2.IKEv2_payload_Proposal]
2112 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2113 self.sa.r_nonce = self.sa.i_nonce
2114 self.sa.child_sas[0].ispi = prop.SPI
2115 self.sa.child_sas[0].rspi = prop.SPI
2116 self.sa.calc_child_keys()
2117
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002118 header = ikev2.IKEv2(
2119 init_SPI=self.sa.ispi,
2120 resp_SPI=self.sa.rspi,
2121 flags="Response",
2122 exch_type=36,
2123 id=ih.id,
2124 next_payload="Encrypted",
2125 )
2126 resp = self.encrypt_ike_msg(header, sa, "SA")
2127 packet = self.create_packet(
2128 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
2129 )
Filip Tehlar38340fa2020-11-19 21:34:48 +00002130 self.send_and_assert_no_replies(self.pg0, packet)
2131
2132 def test_initiator(self):
2133 super(TestInitiatorRequestWindowSize, self).test_initiator()
2134 self.pg0.enable_capture()
2135 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002136 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar38340fa2020-11-19 21:34:48 +00002137 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
2138 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
2139 capture = self.pg0.get_capture(2)
2140
2141 # reply in reverse order
2142 self.rekey_respond(capture[1], True)
2143 self.rekey_respond(capture[0], False)
2144
2145 # verify that only the second request was accepted
2146 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002147 self.verify_ike_sas_v2()
Filip Tehlar38340fa2020-11-19 21:34:48 +00002148 self.verify_ipsec_sas(is_rekey=True)
2149
2150
Filip Tehlar68ad6252020-10-30 05:28:11 +00002151class TestInitiatorRekey(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002152 """test ikev2 initiator - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00002153
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002154 vpp_worker_count = 2
2155
Filip Tehlar68ad6252020-10-30 05:28:11 +00002156 def rekey_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002157 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar68ad6252020-10-30 05:28:11 +00002158 self.pg0.enable_capture()
2159 self.pg_start()
2160 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
2161 capture = self.pg0.get_capture(1)
2162 ih = self.get_ike_header(capture[0])
2163 self.assertEqual(ih.exch_type, 36) # CHILD_SA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002164 self.assertNotIn("Response", ih.flags)
2165 self.assertIn("Initiator", ih.flags)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002166 plain = self.sa.hmac_and_decrypt(ih)
2167 sa = ikev2.IKEv2_payload_SA(plain)
2168 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00002169 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2170 self.sa.r_nonce = self.sa.i_nonce
2171 # update new responder SPI
2172 self.sa.child_sas[0].ispi = prop.SPI
2173 self.sa.child_sas[0].rspi = prop.SPI
2174 self.sa.calc_child_keys()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002175 header = ikev2.IKEv2(
2176 init_SPI=self.sa.ispi,
2177 resp_SPI=self.sa.rspi,
2178 flags="Response",
2179 exch_type=36,
2180 id=ih.id,
2181 next_payload="Encrypted",
2182 )
2183 resp = self.encrypt_ike_msg(header, sa, "SA")
2184 packet = self.create_packet(
2185 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
2186 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00002187 self.send_and_assert_no_replies(self.pg0, packet)
2188
2189 def test_initiator(self):
2190 super(TestInitiatorRekey, self).test_initiator()
2191 self.rekey_from_initiator()
2192 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002193 self.verify_ike_sas_v2()
Filip Tehlar68ad6252020-10-30 05:28:11 +00002194 self.verify_ipsec_sas(is_rekey=True)
2195
2196
Filip Tehlaredf29002020-10-10 04:39:11 +00002197class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002198 """test ikev2 initiator - delete IKE SA from responder"""
Filip Tehlaredf29002020-10-10 04:39:11 +00002199
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002200 vpp_worker_count = 2
2201
Filip Tehlaredf29002020-10-10 04:39:11 +00002202 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002203 self.config_params(
2204 {
2205 "del_sa_from_responder": True,
2206 "is_initiator": False, # seen from test case perspective
2207 # thus vpp is initiator
2208 "responder": {
2209 "sw_if_index": self.pg0.sw_if_index,
2210 "addr": self.pg0.remote_ip4,
2211 },
2212 "ike-crypto": ("AES-GCM-16ICV", 32),
2213 "ike-integ": "NULL",
2214 "ike-dh": "3072MODPgr",
2215 "ike_transforms": {
2216 "crypto_alg": 20, # "aes-gcm-16"
2217 "crypto_key_size": 256,
2218 "dh_group": 15, # "modp-3072"
2219 },
2220 "esp_transforms": {
2221 "crypto_alg": 12, # "aes-cbc"
2222 "crypto_key_size": 256,
2223 # "hmac-sha2-256-128"
2224 "integ_alg": 12,
2225 },
2226 "no_idr_in_auth": True,
2227 }
2228 )
Filip Tehlaredf29002020-10-10 04:39:11 +00002229
2230
Filip Tehlar027d8132020-12-04 17:38:11 +00002231class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002232 """test ikev2 responder - initiator behind NAT"""
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002233
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002234 IKE_NODE_SUFFIX = "ip4-natt"
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002235 vpp_worker_count = 2
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002236
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002237 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002238 self.config_params({"i_natt": True})
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002239
2240
2241class TestResponderPsk(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002242 """test ikev2 responder - pre shared key auth"""
2243
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002244 vpp_worker_count = 2
2245
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002246 def config_tc(self):
2247 self.config_params()
2248
2249
Filip Tehlar2008e312020-11-09 13:23:24 +00002250class TestResponderDpd(TestResponderPsk):
2251 """
2252 Dead peer detection test
2253 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002254
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002255 vpp_worker_count = 2
2256
Filip Tehlar2008e312020-11-09 13:23:24 +00002257 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002258 self.config_params({"dpd_disabled": False})
Filip Tehlar2008e312020-11-09 13:23:24 +00002259
2260 def tearDown(self):
2261 pass
2262
2263 def test_responder(self):
2264 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2265 super(TestResponderDpd, self).test_responder()
2266 self.pg0.enable_capture()
2267 self.pg_start()
2268 # capture empty request but don't reply
2269 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2270 ih = self.get_ike_header(capture[0])
2271 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2272 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002273 self.assertEqual(plain, b"")
Filip Tehlar2008e312020-11-09 13:23:24 +00002274 # wait for SA expiration
2275 time.sleep(3)
2276 ike_sas = self.vapi.ikev2_sa_dump()
2277 self.assertEqual(len(ike_sas), 0)
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002278 ike_sas = self.vapi.ikev2_sa_v2_dump()
2279 self.assertEqual(len(ike_sas), 0)
Filip Tehlar2008e312020-11-09 13:23:24 +00002280 ipsec_sas = self.vapi.ipsec_sa_dump()
2281 self.assertEqual(len(ipsec_sas), 0)
2282
2283
Filip Tehlar68ad6252020-10-30 05:28:11 +00002284class TestResponderRekey(TestResponderPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002285 """test ikev2 responder - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00002286
Atzm Watanabec65921f2022-08-12 14:29:31 +09002287 WITH_KEX = False
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002288 vpp_worker_count = 2
Atzm Watanabec65921f2022-08-12 14:29:31 +09002289
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002290 def send_rekey_from_initiator(self):
Atzm Watanabec65921f2022-08-12 14:29:31 +09002291 if self.WITH_KEX:
2292 self.sa.generate_dh_data()
2293 packet = self.create_rekey_request(kex=self.WITH_KEX)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002294 self.pg0.add_stream(packet)
2295 self.pg0.enable_capture()
2296 self.pg_start()
2297 capture = self.pg0.get_capture(1)
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002298 return capture
2299
2300 def process_rekey_response(self, capture):
Filip Tehlar68ad6252020-10-30 05:28:11 +00002301 ih = self.get_ike_header(capture[0])
2302 plain = self.sa.hmac_and_decrypt(ih)
2303 sa = ikev2.IKEv2_payload_SA(plain)
2304 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00002305 self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2306 # update new responder SPI
2307 self.sa.child_sas[0].rspi = prop.SPI
Atzm Watanabec65921f2022-08-12 14:29:31 +09002308 if self.WITH_KEX:
2309 self.sa.r_dh_data = sa[ikev2.IKEv2_payload_KE].load
2310 self.sa.complete_dh_data()
2311 self.sa.calc_child_keys(kex=self.WITH_KEX)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002312
2313 def test_responder(self):
2314 super(TestResponderRekey, self).test_responder()
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002315 self.process_rekey_response(self.send_rekey_from_initiator())
Filip Tehlar68ad6252020-10-30 05:28:11 +00002316 self.verify_ike_sas()
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002317 self.verify_ike_sas_v2()
Filip Tehlar68ad6252020-10-30 05:28:11 +00002318 self.verify_ipsec_sas(is_rekey=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002319 self.assert_counter(1, "rekey_req", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002320 r = self.vapi.ikev2_sa_dump()
2321 self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002322 r = self.vapi.ikev2_sa_v2_dump()
2323 self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002324
2325
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
Atzm Watanabec65921f2022-08-12 14:29:31 +09002360class TestResponderRekeyRepeatKEX(TestResponderRekeyRepeat):
2361 """test ikev2 responder - rekey repeat with key exchange"""
2362
2363 WITH_KEX = True
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002364 vpp_worker_count = 2
Atzm Watanabec65921f2022-08-12 14:29:31 +09002365
2366
Atzm Watanabed4f405a2022-08-18 17:57:53 +09002367class TestResponderRekeySA(TestResponderPsk):
2368 """test ikev2 responder - rekey IKE SA"""
2369
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002370 vpp_worker_count = 2
2371
Atzm Watanabed4f405a2022-08-18 17:57:53 +09002372 def send_rekey_from_initiator(self, newsa):
2373 packet = self.create_sa_rekey_request(
2374 spi=newsa.ispi,
2375 dh_pub_key=newsa.my_dh_pub_key,
2376 nonce=newsa.i_nonce,
2377 )
2378 self.pg0.add_stream(packet)
2379 self.pg0.enable_capture()
2380 self.pg_start()
2381 capture = self.pg0.get_capture(1)
2382 return capture
2383
2384 def process_rekey_response(self, newsa, capture):
2385 ih = self.get_ike_header(capture[0])
2386 plain = self.sa.hmac_and_decrypt(ih)
2387 sa = ikev2.IKEv2_payload_SA(plain)
2388 prop = sa[ikev2.IKEv2_payload_Proposal]
2389 newsa.rspi = prop.SPI
2390 newsa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2391 newsa.r_dh_data = sa[ikev2.IKEv2_payload_KE].load
2392 newsa.complete_dh_data()
2393 newsa.calc_keys(sk_d=self.sa.sk_d)
2394 newsa.child_sas = self.sa.child_sas
2395 self.sa.child_sas = []
2396
2397 def test_responder(self):
2398 super(TestResponderRekeySA, self).test_responder()
2399 newsa = self.sa.clone(self, spi=os.urandom(8))
2400 newsa.generate_dh_data()
2401 capture = self.send_rekey_from_initiator(newsa)
2402 self.process_rekey_response(newsa, capture)
2403 self.verify_ike_sas(is_rekey=True)
2404 self.assert_counter(1, "rekey_req", "ip4")
2405 r = self.vapi.ikev2_sa_dump()
2406 self.assertEqual(r[1].sa.stats.n_rekey_req, 1)
2407 self.initiate_del_sa_from_initiator()
2408 self.sa = newsa
2409 self.verify_ike_sas()
2410
2411
Filip Tehlard28196f2021-01-27 18:08:21 +00002412class TestResponderVrf(TestResponderPsk, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002413 """test ikev2 responder - non-default table id"""
Filip Tehlard28196f2021-01-27 18:08:21 +00002414
2415 @classmethod
2416 def setUpClass(cls):
2417 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002418
2419 globals()["ikev2"] = _ikev2
Filip Tehlard28196f2021-01-27 18:08:21 +00002420 super(IkePeer, cls).setUpClass()
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002421
Filip Tehlard28196f2021-01-27 18:08:21 +00002422 cls.create_pg_interfaces(range(1))
2423 cls.vapi.cli("ip table add 1")
2424 cls.vapi.cli("set interface ip table pg0 1")
2425 for i in cls.pg_interfaces:
2426 i.admin_up()
2427 i.config_ip4()
2428 i.resolve_arp()
2429 i.config_ip6()
2430 i.resolve_ndp()
2431
2432 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002433 self.config_params({"dpd_disabled": False})
Filip Tehlard28196f2021-01-27 18:08:21 +00002434
2435 def test_responder(self):
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002436 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=3)
Filip Tehlard28196f2021-01-27 18:08:21 +00002437 super(TestResponderVrf, self).test_responder()
2438 self.pg0.enable_capture()
2439 self.pg_start()
2440 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2441 ih = self.get_ike_header(capture[0])
2442 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2443 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002444 self.assertEqual(plain, b"")
Filip Tehlard28196f2021-01-27 18:08:21 +00002445
2446
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002447class TestResponderRsaSign(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002448 """test ikev2 responder - cert based auth"""
2449
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002450 vpp_worker_count = 2
2451
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002452 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002453 self.config_params(
2454 {
2455 "udp_encap": True,
2456 "auth": "rsa-sig",
2457 "server-key": "server-key.pem",
2458 "client-key": "client-key.pem",
2459 "client-cert": "client-cert.pem",
2460 "server-cert": "server-cert.pem",
2461 }
2462 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002463
Filip Tehlar4f42a712020-07-01 08:56:59 +00002464
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002465class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
2466 TemplateResponder, Ikev2Params
2467):
Filip Tehlar4f42a712020-07-01 08:56:59 +00002468 """
2469 IKE:AES_CBC_128_SHA256_128,DH=modp2048 ESP:AES_CBC_192_SHA_384_192
2470 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002471
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002472 vpp_worker_count = 2
2473
Filip Tehlar4f42a712020-07-01 08:56:59 +00002474 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002475 self.config_params(
2476 {
2477 "ike-crypto": ("AES-CBC", 16),
2478 "ike-integ": "SHA2-256-128",
2479 "esp-crypto": ("AES-CBC", 24),
2480 "esp-integ": "SHA2-384-192",
2481 "ike-dh": "2048MODPgr",
2482 "nonce": os.urandom(256),
2483 "no_idr_in_auth": True,
2484 }
2485 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002486
2487
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002488class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
2489 TemplateResponder, Ikev2Params
2490):
Filip Tehlar4f42a712020-07-01 08:56:59 +00002491 """
2492 IKE:AES_CBC_128_SHA256_128,DH=modp3072 ESP:AES_GCM_16
2493 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002494
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002495 vpp_worker_count = 2
2496
Filip Tehlar4f42a712020-07-01 08:56:59 +00002497 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002498 self.config_params(
2499 {
2500 "ike-crypto": ("AES-CBC", 32),
2501 "ike-integ": "SHA2-256-128",
2502 "esp-crypto": ("AES-GCM-16ICV", 32),
2503 "esp-integ": "NULL",
2504 "ike-dh": "3072MODPgr",
2505 }
2506 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002507
2508
Filip Tehlara7b963d2020-07-08 13:25:34 +00002509class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
2510 """
2511 IKE:AES_GCM_16_256
2512 """
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002513
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002514 IKE_NODE_SUFFIX = "ip6"
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002515 vpp_worker_count = 2
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002516
Filip Tehlara7b963d2020-07-08 13:25:34 +00002517 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002518 self.config_params(
2519 {
2520 "del_sa_from_responder": True,
2521 "ip6": True,
2522 "natt": True,
2523 "ike-crypto": ("AES-GCM-16ICV", 32),
2524 "ike-integ": "NULL",
2525 "ike-dh": "2048MODPgr",
2526 "loc_ts": {"start_addr": "ab:cd::0", "end_addr": "ab:cd::10"},
2527 "rem_ts": {"start_addr": "11::0", "end_addr": "11::100"},
2528 }
2529 )
Filip Tehlara7b963d2020-07-08 13:25:34 +00002530
2531
Filip Tehlar2008e312020-11-09 13:23:24 +00002532class TestInitiatorKeepaliveMsg(TestInitiatorPsk):
2533 """
2534 Test for keep alive messages
2535 """
2536
Stanislav Zaikin0f2c6cd2023-09-08 10:27:15 +02002537 vpp_worker_count = 2
2538
Filip Tehlar2008e312020-11-09 13:23:24 +00002539 def send_empty_req_from_responder(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002540 packet = self.create_empty_request()
Filip Tehlar2008e312020-11-09 13:23:24 +00002541 self.pg0.add_stream(packet)
2542 self.pg0.enable_capture()
2543 self.pg_start()
2544 capture = self.pg0.get_capture(1)
2545 ih = self.get_ike_header(capture[0])
2546 self.assertEqual(ih.id, self.sa.msg_id)
2547 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002548 self.assertEqual(plain, b"")
2549 self.assert_counter(1, "keepalive", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002550 r = self.vapi.ikev2_sa_dump()
2551 self.assertEqual(1, r[0].sa.stats.n_keepalives)
Denys Haryachyyf40a3542024-01-24 16:31:47 +02002552 r = self.vapi.ikev2_sa_v2_dump()
2553 self.assertEqual(1, r[0].sa.stats.n_keepalives)
Filip Tehlar2008e312020-11-09 13:23:24 +00002554
2555 def test_initiator(self):
2556 super(TestInitiatorKeepaliveMsg, self).test_initiator()
2557 self.send_empty_req_from_responder()
2558
2559
Filip Tehlar558607d2020-07-16 07:25:56 +00002560class TestMalformedMessages(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002561 """malformed packet test"""
Filip Tehlar558607d2020-07-16 07:25:56 +00002562
2563 def tearDown(self):
2564 pass
2565
2566 def config_tc(self):
2567 self.config_params()
2568
Filip Tehlar558607d2020-07-16 07:25:56 +00002569 def create_ike_init_msg(self, length=None, payload=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002570 msg = ikev2.IKEv2(
2571 length=length,
2572 init_SPI="\x11" * 8,
2573 flags="Initiator",
2574 exch_type="IKE_SA_INIT",
2575 )
Filip Tehlar558607d2020-07-16 07:25:56 +00002576 if payload is not None:
2577 msg /= payload
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002578 return self.create_packet(self.pg0, msg, self.sa.sport, self.sa.dport)
Filip Tehlar558607d2020-07-16 07:25:56 +00002579
2580 def verify_bad_packet_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002581 ike_msg = self.create_ike_init_msg(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002582 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002583 self.assert_counter(self.pkt_count, "bad_length")
Filip Tehlar558607d2020-07-16 07:25:56 +00002584
2585 def verify_bad_sa_payload_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002586 p = ikev2.IKEv2_payload_SA(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002587 ike_msg = self.create_ike_init_msg(payload=p)
2588 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002589 self.assert_counter(self.pkt_count, "malformed_packet")
Filip Tehlar558607d2020-07-16 07:25:56 +00002590
2591 def test_responder(self):
2592 self.pkt_count = 254
2593 self.verify_bad_packet_length()
2594 self.verify_bad_sa_payload_length()
2595
2596
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002597if __name__ == "__main__":
Filip Tehlar12b517b2020-04-26 18:05:05 +00002598 unittest.main(testRunner=VppTestRunner)