blob: 3c5887195810b152d98467813e50aa3ccacf8680 [file] [log] [blame]
Filip Tehlar12b517b2020-04-26 18:05:05 +00001import os
Filip Tehlar2008e312020-11-09 13:23:24 +00002import time
Filip Tehlarec112e52020-10-07 23:52:37 +00003from socket import inet_pton
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00004from cryptography import x509
Filip Tehlar12b517b2020-04-26 18:05:05 +00005from cryptography.hazmat.backends import default_backend
6from cryptography.hazmat.primitives import hashes, hmac
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00007from cryptography.hazmat.primitives.asymmetric import dh, padding
8from cryptography.hazmat.primitives.serialization import load_pem_private_key
Filip Tehlar12b517b2020-04-26 18:05:05 +00009from cryptography.hazmat.primitives.ciphers import (
10 Cipher,
11 algorithms,
12 modes,
13)
Filip Tehlar84962d12020-09-08 06:08:05 +000014from ipaddress import IPv4Address, IPv6Address, ip_address
Paul Vinciguerrae061dad2020-12-04 14:57:51 -050015import unittest
Klement Sekerab23ffd72021-05-31 16:08:53 +020016from config import config
Filip Tehlarbfeae8c2020-06-23 20:35:58 +000017from scapy.layers.ipsec import ESP
Filip Tehlar12b517b2020-04-26 18:05:05 +000018from scapy.layers.inet import IP, UDP, Ether
Filip Tehlar84962d12020-09-08 06:08:05 +000019from scapy.layers.inet6 import IPv6
Filip Tehlar12b517b2020-04-26 18:05:05 +000020from scapy.packet import raw, Raw
21from scapy.utils import long_converter
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +000022from framework import tag_fixme_vpp_workers
Filip Tehlar12b517b2020-04-26 18:05:05 +000023from framework import VppTestCase, VppTestRunner
Filip Tehlarbfeae8c2020-06-23 20:35:58 +000024from vpp_ikev2 import Profile, IDType, AuthMethod
Filip Tehlar4f42a712020-07-01 08:56:59 +000025from vpp_papi import VppEnum
Filip Tehlar12b517b2020-04-26 18:05:05 +000026
Filip Tehlar84962d12020-09-08 06:08:05 +000027try:
28 text_type = unicode
29except NameError:
30 text_type = str
Filip Tehlar12b517b2020-04-26 18:05:05 +000031
32KEY_PAD = b"Key Pad for IKEv2"
Filip Tehlara7b963d2020-07-08 13:25:34 +000033SALT_SIZE = 4
34GCM_ICV_SIZE = 16
35GCM_IV_SIZE = 8
Filip Tehlar12b517b2020-04-26 18:05:05 +000036
37
38# defined in rfc3526
39# tuple structure is (p, g, key_len)
40DH = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020041 "2048MODPgr": (
42 long_converter(
43 """
Filip Tehlar12b517b2020-04-26 18:05:05 +000044 FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
45 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
46 EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
47 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
48 EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
49 C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
50 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
51 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
52 E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
53 DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020054 15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"""
55 ),
56 2,
57 256,
58 ),
59 "3072MODPgr": (
60 long_converter(
61 """
Filip Tehlar4f42a712020-07-01 08:56:59 +000062 FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
63 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
64 EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
65 E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
66 EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
67 C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
68 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
69 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
70 E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
71 DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
72 15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
73 ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
74 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
75 F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
76 BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020077 43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"""
78 ),
79 2,
80 384,
81 ),
Filip Tehlar12b517b2020-04-26 18:05:05 +000082}
83
84
85class CryptoAlgo(object):
86 def __init__(self, name, cipher, mode):
87 self.name = name
88 self.cipher = cipher
89 self.mode = mode
90 if self.cipher is not None:
91 self.bs = self.cipher.block_size // 8
92
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020093 if self.name == "AES-GCM-16ICV":
Filip Tehlara7b963d2020-07-08 13:25:34 +000094 self.iv_len = GCM_IV_SIZE
95 else:
96 self.iv_len = self.bs
Filip Tehlar12b517b2020-04-26 18:05:05 +000097
Filip Tehlara7b963d2020-07-08 13:25:34 +000098 def encrypt(self, data, key, aad=None):
99 iv = os.urandom(self.iv_len)
100 if aad is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200101 encryptor = Cipher(
102 self.cipher(key), self.mode(iv), default_backend()
103 ).encryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000104 return iv + encryptor.update(data) + encryptor.finalize()
105 else:
106 salt = key[-SALT_SIZE:]
107 nonce = salt + iv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200108 encryptor = Cipher(
109 self.cipher(key[:-SALT_SIZE]), self.mode(nonce), default_backend()
110 ).encryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000111 encryptor.authenticate_additional_data(aad)
112 data = encryptor.update(data) + encryptor.finalize()
113 data += encryptor.tag[:GCM_ICV_SIZE]
114 return iv + data
115
116 def decrypt(self, data, key, aad=None, icv=None):
117 if aad is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200118 iv = data[: self.iv_len]
119 ct = data[self.iv_len :]
120 decryptor = Cipher(
121 algorithms.AES(key), self.mode(iv), default_backend()
122 ).decryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000123 return decryptor.update(ct) + decryptor.finalize()
124 else:
125 salt = key[-SALT_SIZE:]
126 nonce = salt + data[:GCM_IV_SIZE]
127 ct = data[GCM_IV_SIZE:]
128 key = key[:-SALT_SIZE]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200129 decryptor = Cipher(
130 algorithms.AES(key), self.mode(nonce, icv, len(icv)), default_backend()
131 ).decryptor()
Filip Tehlara7b963d2020-07-08 13:25:34 +0000132 decryptor.authenticate_additional_data(aad)
Filip Tehlaredf29002020-10-10 04:39:11 +0000133 return decryptor.update(ct) + decryptor.finalize()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000134
135 def pad(self, data):
136 pad_len = (len(data) // self.bs + 1) * self.bs - len(data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200137 data = data + b"\x00" * (pad_len - 1)
Filip Tehlar558607d2020-07-16 07:25:56 +0000138 return data + bytes([pad_len - 1])
Filip Tehlar12b517b2020-04-26 18:05:05 +0000139
140
141class AuthAlgo(object):
142 def __init__(self, name, mac, mod, key_len, trunc_len=None):
143 self.name = name
144 self.mac = mac
145 self.mod = mod
146 self.key_len = key_len
147 self.trunc_len = trunc_len or key_len
148
149
150CRYPTO_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200151 "NULL": CryptoAlgo("NULL", cipher=None, mode=None),
152 "AES-CBC": CryptoAlgo("AES-CBC", cipher=algorithms.AES, mode=modes.CBC),
153 "AES-GCM-16ICV": CryptoAlgo("AES-GCM-16ICV", cipher=algorithms.AES, mode=modes.GCM),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000154}
155
156AUTH_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200157 "NULL": AuthAlgo("NULL", mac=None, mod=None, key_len=0, trunc_len=0),
158 "HMAC-SHA1-96": AuthAlgo("HMAC-SHA1-96", hmac.HMAC, hashes.SHA1, 20, 12),
159 "SHA2-256-128": AuthAlgo("SHA2-256-128", hmac.HMAC, hashes.SHA256, 32, 16),
160 "SHA2-384-192": AuthAlgo("SHA2-384-192", hmac.HMAC, hashes.SHA256, 48, 24),
161 "SHA2-512-256": AuthAlgo("SHA2-512-256", hmac.HMAC, hashes.SHA256, 64, 32),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000162}
163
164PRF_ALGOS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200165 "NULL": AuthAlgo("NULL", mac=None, mod=None, key_len=0, trunc_len=0),
166 "PRF_HMAC_SHA2_256": AuthAlgo("PRF_HMAC_SHA2_256", hmac.HMAC, hashes.SHA256, 32),
Filip Tehlar12b517b2020-04-26 18:05:05 +0000167}
168
Filip Tehlar68ad6252020-10-30 05:28:11 +0000169CRYPTO_IDS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200170 12: "AES-CBC",
171 20: "AES-GCM-16ICV",
Filip Tehlar68ad6252020-10-30 05:28:11 +0000172}
173
174INTEG_IDS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200175 2: "HMAC-SHA1-96",
176 12: "SHA2-256-128",
177 13: "SHA2-384-192",
178 14: "SHA2-512-256",
Filip Tehlar68ad6252020-10-30 05:28:11 +0000179}
180
Filip Tehlar12b517b2020-04-26 18:05:05 +0000181
182class IKEv2ChildSA(object):
Filip Tehlar68ad6252020-10-30 05:28:11 +0000183 def __init__(self, local_ts, remote_ts, is_initiator):
184 spi = os.urandom(4)
185 if is_initiator:
186 self.ispi = spi
187 self.rspi = None
188 else:
189 self.rspi = spi
190 self.ispi = None
Filip Tehlar12b517b2020-04-26 18:05:05 +0000191 self.local_ts = local_ts
192 self.remote_ts = remote_ts
193
194
195class IKEv2SA(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200196 def __init__(
197 self,
198 test,
199 is_initiator=True,
200 i_id=None,
201 r_id=None,
202 spi=b"\x01\x02\x03\x04\x05\x06\x07\x08",
203 id_type="fqdn",
204 nonce=None,
205 auth_data=None,
206 local_ts=None,
207 remote_ts=None,
208 auth_method="shared-key",
209 priv_key=None,
210 i_natt=False,
211 r_natt=False,
212 udp_encap=False,
213 ):
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000214 self.udp_encap = udp_encap
Filip Tehlar027d8132020-12-04 17:38:11 +0000215 self.i_natt = i_natt
216 self.r_natt = r_natt
217 if i_natt or r_natt:
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000218 self.sport = 4500
219 self.dport = 4500
220 else:
221 self.sport = 500
222 self.dport = 500
Filip Tehlar558607d2020-07-16 07:25:56 +0000223 self.msg_id = 0
Filip Tehlar12b517b2020-04-26 18:05:05 +0000224 self.dh_params = None
225 self.test = test
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000226 self.priv_key = priv_key
Filip Tehlar12b517b2020-04-26 18:05:05 +0000227 self.is_initiator = is_initiator
228 nonce = nonce or os.urandom(32)
229 self.auth_data = auth_data
Filip Tehlar4128c7b2020-05-10 05:18:37 +0000230 self.i_id = i_id
231 self.r_id = r_id
Filip Tehlar12b517b2020-04-26 18:05:05 +0000232 if isinstance(id_type, str):
233 self.id_type = IDType.value(id_type)
234 else:
235 self.id_type = id_type
236 self.auth_method = auth_method
237 if self.is_initiator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200238 self.rspi = 8 * b"\x00"
Filip Tehlar12b517b2020-04-26 18:05:05 +0000239 self.ispi = spi
Filip Tehlar12b517b2020-04-26 18:05:05 +0000240 self.i_nonce = nonce
241 else:
242 self.rspi = spi
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200243 self.ispi = 8 * b"\x00"
Filip Tehlare7c83962020-09-23 11:20:12 +0000244 self.r_nonce = nonce
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200245 self.child_sas = [IKEv2ChildSA(local_ts, remote_ts, self.is_initiator)]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000246
Filip Tehlar558607d2020-07-16 07:25:56 +0000247 def new_msg_id(self):
248 self.msg_id += 1
249 return self.msg_id
250
Filip Tehlare7c83962020-09-23 11:20:12 +0000251 @property
252 def my_dh_pub_key(self):
253 if self.is_initiator:
254 return self.i_dh_data
255 return self.r_dh_data
256
257 @property
258 def peer_dh_pub_key(self):
259 if self.is_initiator:
260 return self.r_dh_data
Filip Tehlar12b517b2020-04-26 18:05:05 +0000261 return self.i_dh_data
262
Filip Tehlar027d8132020-12-04 17:38:11 +0000263 @property
264 def natt(self):
265 return self.i_natt or self.r_natt
266
Filip Tehlar12b517b2020-04-26 18:05:05 +0000267 def compute_secret(self):
268 priv = self.dh_private_key
Filip Tehlare7c83962020-09-23 11:20:12 +0000269 peer = self.peer_dh_pub_key
Filip Tehlar12b517b2020-04-26 18:05:05 +0000270 p, g, l = self.ike_group
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200271 return pow(
272 int.from_bytes(peer, "big"), int.from_bytes(priv, "big"), p
273 ).to_bytes(l, "big")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000274
275 def generate_dh_data(self):
276 # generate DH keys
Filip Tehlare7c83962020-09-23 11:20:12 +0000277 if self.ike_dh not in DH:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200278 raise NotImplementedError("%s not in DH group" % self.ike_dh)
Filip Tehlare7c83962020-09-23 11:20:12 +0000279
280 if self.dh_params is None:
281 dhg = DH[self.ike_dh]
282 pn = dh.DHParameterNumbers(dhg[0], dhg[1])
283 self.dh_params = pn.parameters(default_backend())
284
285 priv = self.dh_params.generate_private_key()
286 pub = priv.public_key()
287 x = priv.private_numbers().x
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200288 self.dh_private_key = x.to_bytes(priv.key_size // 8, "big")
Filip Tehlare7c83962020-09-23 11:20:12 +0000289 y = pub.public_numbers().y
290
Filip Tehlar12b517b2020-04-26 18:05:05 +0000291 if self.is_initiator:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200292 self.i_dh_data = y.to_bytes(pub.key_size // 8, "big")
Filip Tehlare7c83962020-09-23 11:20:12 +0000293 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200294 self.r_dh_data = y.to_bytes(pub.key_size // 8, "big")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000295
296 def complete_dh_data(self):
297 self.dh_shared_secret = self.compute_secret()
298
299 def calc_child_keys(self):
300 prf = self.ike_prf_alg.mod()
301 s = self.i_nonce + self.r_nonce
302 c = self.child_sas[0]
303
304 encr_key_len = self.esp_crypto_key_len
Filip Tehlar4f42a712020-07-01 08:56:59 +0000305 integ_key_len = self.esp_integ_alg.key_len
306 salt_len = 0 if integ_key_len else 4
307
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200308 l = integ_key_len * 2 + encr_key_len * 2 + salt_len * 2
Filip Tehlar12b517b2020-04-26 18:05:05 +0000309 keymat = self.calc_prfplus(prf, self.sk_d, s, l)
310
311 pos = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200312 c.sk_ei = keymat[pos : pos + encr_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000313 pos += encr_key_len
314
Filip Tehlar4f42a712020-07-01 08:56:59 +0000315 if integ_key_len:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200316 c.sk_ai = keymat[pos : pos + integ_key_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000317 pos += integ_key_len
318 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200319 c.salt_ei = keymat[pos : pos + salt_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000320 pos += salt_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000321
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200322 c.sk_er = keymat[pos : pos + encr_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000323 pos += encr_key_len
324
Filip Tehlar4f42a712020-07-01 08:56:59 +0000325 if integ_key_len:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200326 c.sk_ar = keymat[pos : pos + integ_key_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000327 pos += integ_key_len
328 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200329 c.salt_er = keymat[pos : pos + salt_len]
Filip Tehlar4f42a712020-07-01 08:56:59 +0000330 pos += salt_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000331
332 def calc_prfplus(self, prf, key, seed, length):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200333 r = b""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000334 t = None
335 x = 1
336 while len(r) < length and x < 255:
337 if t is not None:
338 s = t
339 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200340 s = b""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000341 s = s + seed + bytes([x])
342 t = self.calc_prf(prf, key, s)
343 r = r + t
344 x = x + 1
345
346 if x == 255:
347 return None
348 return r
349
350 def calc_prf(self, prf, key, data):
Filip Tehlara7b963d2020-07-08 13:25:34 +0000351 h = self.ike_prf_alg.mac(key, prf, backend=default_backend())
Filip Tehlar12b517b2020-04-26 18:05:05 +0000352 h.update(data)
353 return h.finalize()
354
355 def calc_keys(self):
356 prf = self.ike_prf_alg.mod()
357 # SKEYSEED = prf(Ni | Nr, g^ir)
358 s = self.i_nonce + self.r_nonce
359 self.skeyseed = self.calc_prf(prf, s, self.dh_shared_secret)
360
361 # calculate S = Ni | Nr | SPIi SPIr
362 s = s + self.ispi + self.rspi
363
364 prf_key_trunc = self.ike_prf_alg.trunc_len
365 encr_key_len = self.ike_crypto_key_len
366 tr_prf_key_len = self.ike_prf_alg.key_len
367 integ_key_len = self.ike_integ_alg.key_len
Filip Tehlara7b963d2020-07-08 13:25:34 +0000368 if integ_key_len == 0:
369 salt_size = 4
370 else:
371 salt_size = 0
372
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200373 l = (
374 prf_key_trunc
375 + integ_key_len * 2
376 + encr_key_len * 2
377 + tr_prf_key_len * 2
378 + salt_size * 2
379 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000380 keymat = self.calc_prfplus(prf, self.skeyseed, s, l)
381
382 pos = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200383 self.sk_d = keymat[: pos + prf_key_trunc]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000384 pos += prf_key_trunc
385
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200386 self.sk_ai = keymat[pos : pos + integ_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000387 pos += integ_key_len
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200388 self.sk_ar = keymat[pos : pos + integ_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000389 pos += integ_key_len
390
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200391 self.sk_ei = keymat[pos : pos + encr_key_len + salt_size]
Filip Tehlara7b963d2020-07-08 13:25:34 +0000392 pos += encr_key_len + salt_size
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200393 self.sk_er = keymat[pos : pos + encr_key_len + salt_size]
Filip Tehlara7b963d2020-07-08 13:25:34 +0000394 pos += encr_key_len + salt_size
Filip Tehlar12b517b2020-04-26 18:05:05 +0000395
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200396 self.sk_pi = keymat[pos : pos + tr_prf_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000397 pos += tr_prf_key_len
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200398 self.sk_pr = keymat[pos : pos + tr_prf_key_len]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000399
400 def generate_authmsg(self, prf, packet):
401 if self.is_initiator:
402 id = self.i_id
403 nonce = self.r_nonce
404 key = self.sk_pi
Filip Tehlare7c83962020-09-23 11:20:12 +0000405 else:
406 id = self.r_id
407 nonce = self.i_nonce
408 key = self.sk_pr
Filip Tehlar12b517b2020-04-26 18:05:05 +0000409 data = bytes([self.id_type, 0, 0, 0]) + id
410 id_hash = self.calc_prf(prf, key, data)
411 return packet + nonce + id_hash
412
413 def auth_init(self):
414 prf = self.ike_prf_alg.mod()
Filip Tehlare7c83962020-09-23 11:20:12 +0000415 if self.is_initiator:
416 packet = self.init_req_packet
417 else:
418 packet = self.init_resp_packet
419 authmsg = self.generate_authmsg(prf, raw(packet))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200420 if self.auth_method == "shared-key":
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000421 psk = self.calc_prf(prf, self.auth_data, KEY_PAD)
422 self.auth_data = self.calc_prf(prf, psk, authmsg)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200423 elif self.auth_method == "rsa-sig":
424 self.auth_data = self.priv_key.sign(
425 authmsg, padding.PKCS1v15(), hashes.SHA1()
426 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000427 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200428 raise TypeError("unknown auth method type!")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000429
Filip Tehlara7b963d2020-07-08 13:25:34 +0000430 def encrypt(self, data, aad=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000431 data = self.ike_crypto_alg.pad(data)
Filip Tehlara7b963d2020-07-08 13:25:34 +0000432 return self.ike_crypto_alg.encrypt(data, self.my_cryptokey, aad)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000433
434 @property
435 def peer_authkey(self):
436 if self.is_initiator:
437 return self.sk_ar
438 return self.sk_ai
439
440 @property
441 def my_authkey(self):
442 if self.is_initiator:
443 return self.sk_ai
444 return self.sk_ar
445
446 @property
447 def my_cryptokey(self):
448 if self.is_initiator:
449 return self.sk_ei
450 return self.sk_er
451
452 @property
453 def peer_cryptokey(self):
454 if self.is_initiator:
455 return self.sk_er
456 return self.sk_ei
457
Filip Tehlar4f42a712020-07-01 08:56:59 +0000458 def concat(self, alg, key_len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200459 return alg + "-" + str(key_len * 8)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000460
461 @property
462 def vpp_ike_cypto_alg(self):
463 return self.concat(self.ike_crypto, self.ike_crypto_key_len)
464
465 @property
466 def vpp_esp_cypto_alg(self):
467 return self.concat(self.esp_crypto, self.esp_crypto_key_len)
468
Filip Tehlar12b517b2020-04-26 18:05:05 +0000469 def verify_hmac(self, ikemsg):
470 integ_trunc = self.ike_integ_alg.trunc_len
471 exp_hmac = ikemsg[-integ_trunc:]
472 data = ikemsg[:-integ_trunc]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200473 computed_hmac = self.compute_hmac(
474 self.ike_integ_alg.mod(), self.peer_authkey, data
475 )
Filip Tehlar12b517b2020-04-26 18:05:05 +0000476 self.test.assertEqual(computed_hmac[:integ_trunc], exp_hmac)
477
478 def compute_hmac(self, integ, key, data):
479 h = self.ike_integ_alg.mac(key, integ, backend=default_backend())
480 h.update(data)
481 return h.finalize()
482
Filip Tehlara7b963d2020-07-08 13:25:34 +0000483 def decrypt(self, data, aad=None, icv=None):
484 return self.ike_crypto_alg.decrypt(data, self.peer_cryptokey, aad, icv)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000485
486 def hmac_and_decrypt(self, ike):
487 ep = ike[ikev2.IKEv2_payload_Encrypted]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200488 if self.ike_crypto == "AES-GCM-16ICV":
Filip Tehlara7b963d2020-07-08 13:25:34 +0000489 aad_len = len(ikev2.IKEv2_payload_Encrypted()) + len(ikev2.IKEv2())
490 ct = ep.load[:-GCM_ICV_SIZE]
491 tag = ep.load[-GCM_ICV_SIZE:]
Filip Tehlaredf29002020-10-10 04:39:11 +0000492 plain = self.decrypt(ct, raw(ike)[:aad_len], tag)
Filip Tehlara7b963d2020-07-08 13:25:34 +0000493 else:
494 self.verify_hmac(raw(ike))
495 integ_trunc = self.ike_integ_alg.trunc_len
Filip Tehlar12b517b2020-04-26 18:05:05 +0000496
Filip Tehlara7b963d2020-07-08 13:25:34 +0000497 # remove ICV and decrypt payload
498 ct = ep.load[:-integ_trunc]
Filip Tehlaredf29002020-10-10 04:39:11 +0000499 plain = self.decrypt(ct)
500 # remove padding
501 pad_len = plain[-1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200502 return plain[: -pad_len - 1]
Filip Tehlar12b517b2020-04-26 18:05:05 +0000503
Filip Tehlar84962d12020-09-08 06:08:05 +0000504 def build_ts_addr(self, ts, version):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200505 return {
506 "starting_address_v" + version: ts["start_addr"],
507 "ending_address_v" + version: ts["end_addr"],
508 }
Filip Tehlar84962d12020-09-08 06:08:05 +0000509
510 def generate_ts(self, is_ip4):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000511 c = self.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200512 ts_data = {"IP_protocol_ID": 0, "start_port": 0, "end_port": 0xFFFF}
Filip Tehlar84962d12020-09-08 06:08:05 +0000513 if is_ip4:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200514 ts_data.update(self.build_ts_addr(c.local_ts, "4"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000515 ts1 = ikev2.IPv4TrafficSelector(**ts_data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200516 ts_data.update(self.build_ts_addr(c.remote_ts, "4"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000517 ts2 = ikev2.IPv4TrafficSelector(**ts_data)
518 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200519 ts_data.update(self.build_ts_addr(c.local_ts, "6"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000520 ts1 = ikev2.IPv6TrafficSelector(**ts_data)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200521 ts_data.update(self.build_ts_addr(c.remote_ts, "6"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000522 ts2 = ikev2.IPv6TrafficSelector(**ts_data)
Filip Tehlare7c83962020-09-23 11:20:12 +0000523
524 if self.is_initiator:
525 return ([ts1], [ts2])
526 return ([ts2], [ts1])
Filip Tehlar12b517b2020-04-26 18:05:05 +0000527
528 def set_ike_props(self, crypto, crypto_key_len, integ, prf, dh):
529 if crypto not in CRYPTO_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200530 raise TypeError("unsupported encryption algo %r" % crypto)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000531 self.ike_crypto = crypto
532 self.ike_crypto_alg = CRYPTO_ALGOS[crypto]
533 self.ike_crypto_key_len = crypto_key_len
534
535 if integ not in AUTH_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200536 raise TypeError("unsupported auth algo %r" % integ)
537 self.ike_integ = None if integ == "NULL" else integ
Filip Tehlar12b517b2020-04-26 18:05:05 +0000538 self.ike_integ_alg = AUTH_ALGOS[integ]
539
540 if prf not in PRF_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200541 raise TypeError("unsupported prf algo %r" % prf)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000542 self.ike_prf = prf
543 self.ike_prf_alg = PRF_ALGOS[prf]
544 self.ike_dh = dh
545 self.ike_group = DH[self.ike_dh]
546
547 def set_esp_props(self, crypto, crypto_key_len, integ):
548 self.esp_crypto_key_len = crypto_key_len
549 if crypto not in CRYPTO_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200550 raise TypeError("unsupported encryption algo %r" % crypto)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000551 self.esp_crypto = crypto
552 self.esp_crypto_alg = CRYPTO_ALGOS[crypto]
553
554 if integ not in AUTH_ALGOS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200555 raise TypeError("unsupported auth algo %r" % integ)
556 self.esp_integ = None if integ == "NULL" else integ
Filip Tehlar12b517b2020-04-26 18:05:05 +0000557 self.esp_integ_alg = AUTH_ALGOS[integ]
558
559 def crypto_attr(self, key_len):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200560 if self.ike_crypto in ["AES-CBC", "AES-GCM-16ICV"]:
561 return (0x800E << 16 | key_len << 3, 12)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000562 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200563 raise Exception("unsupported attribute type")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000564
565 def ike_crypto_attr(self):
566 return self.crypto_attr(self.ike_crypto_key_len)
567
568 def esp_crypto_attr(self):
569 return self.crypto_attr(self.esp_crypto_key_len)
570
Filip Tehlarec112e52020-10-07 23:52:37 +0000571 def compute_nat_sha1(self, ip, port, rspi=None):
572 if rspi is None:
573 rspi = self.rspi
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200574 data = self.ispi + rspi + ip + (port).to_bytes(2, "big")
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000575 digest = hashes.Hash(hashes.SHA1(), backend=default_backend())
576 digest.update(data)
577 return digest.finalize()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000578
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000579
Filip Tehlare7c83962020-09-23 11:20:12 +0000580class IkePeer(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200581 """common class for initiator and responder"""
Filip Tehlar12b517b2020-04-26 18:05:05 +0000582
583 @classmethod
584 def setUpClass(cls):
585 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200586
587 globals()["ikev2"] = _ikev2
Filip Tehlare7c83962020-09-23 11:20:12 +0000588 super(IkePeer, cls).setUpClass()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000589 cls.create_pg_interfaces(range(2))
590 for i in cls.pg_interfaces:
591 i.admin_up()
592 i.config_ip4()
593 i.resolve_arp()
Filip Tehlar84962d12020-09-08 06:08:05 +0000594 i.config_ip6()
595 i.resolve_ndp()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000596
597 @classmethod
598 def tearDownClass(cls):
Filip Tehlare7c83962020-09-23 11:20:12 +0000599 super(IkePeer, cls).tearDownClass()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000600
Filip Tehlaredf29002020-10-10 04:39:11 +0000601 def tearDown(self):
602 super(IkePeer, self).tearDown()
603 if self.del_sa_from_responder:
604 self.initiate_del_sa_from_responder()
605 else:
606 self.initiate_del_sa_from_initiator()
607 r = self.vapi.ikev2_sa_dump()
608 self.assertEqual(len(r), 0)
609 sas = self.vapi.ipsec_sa_dump()
610 self.assertEqual(len(sas), 0)
611 self.p.remove_vpp_config()
612 self.assertIsNone(self.p.query_vpp_config())
613
Filip Tehlar12b517b2020-04-26 18:05:05 +0000614 def setUp(self):
Filip Tehlare7c83962020-09-23 11:20:12 +0000615 super(IkePeer, self).setUp()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000616 self.config_tc()
Filip Tehlar12b517b2020-04-26 18:05:05 +0000617 self.p.add_vpp_config()
Filip Tehlar459d17b2020-07-06 15:40:08 +0000618 self.assertIsNotNone(self.p.query_vpp_config())
Filip Tehlar68ad6252020-10-30 05:28:11 +0000619 if self.sa.is_initiator:
620 self.sa.generate_dh_data()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200621 self.vapi.cli("ikev2 set logging level 4")
622 self.vapi.cli("event-lo clear")
Filip Tehlar12b517b2020-04-26 18:05:05 +0000623
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200624 def assert_counter(self, count, name, version="ip4"):
625 node_name = "/err/ikev2-%s/" % version + name
Filip Tehlarfab5e7f2021-01-14 13:32:01 +0000626 self.assertEqual(count, self.statistics.get_err_counter(node_name))
627
Filip Tehlar38340fa2020-11-19 21:34:48 +0000628 def create_rekey_request(self):
629 sa, first_payload = self.generate_auth_payload(is_rekey=True)
630 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200631 init_SPI=self.sa.ispi,
632 resp_SPI=self.sa.rspi,
633 id=self.sa.new_msg_id(),
634 flags="Initiator",
635 exch_type="CREATE_CHILD_SA",
636 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000637
638 ike_msg = self.encrypt_ike_msg(header, sa, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200639 return self.create_packet(
640 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
641 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000642
643 def create_empty_request(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200644 header = ikev2.IKEv2(
645 init_SPI=self.sa.ispi,
646 resp_SPI=self.sa.rspi,
647 id=self.sa.new_msg_id(),
648 flags="Initiator",
649 exch_type="INFORMATIONAL",
650 next_payload="Encrypted",
651 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000652
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 msg = self.encrypt_ike_msg(header, b"", None)
654 return self.create_packet(
655 self.pg0, msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
656 )
Filip Tehlar38340fa2020-11-19 21:34:48 +0000657
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200658 def create_packet(
659 self, src_if, msg, sport=500, dport=500, natt=False, use_ip6=False
660 ):
Filip Tehlar84962d12020-09-08 06:08:05 +0000661 if use_ip6:
662 src_ip = src_if.remote_ip6
663 dst_ip = src_if.local_ip6
664 ip_layer = IPv6
665 else:
666 src_ip = src_if.remote_ip4
667 dst_ip = src_if.local_ip4
668 ip_layer = IP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200669 res = (
670 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
671 / ip_layer(src=src_ip, dst=dst_ip)
672 / UDP(sport=sport, dport=dport)
673 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000674 if natt:
675 # insert non ESP marker
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200676 res = res / Raw(b"\x00" * 4)
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000677 return res / msg
Filip Tehlar12b517b2020-04-26 18:05:05 +0000678
Filip Tehlare7c83962020-09-23 11:20:12 +0000679 def verify_udp(self, udp):
680 self.assertEqual(udp.sport, self.sa.sport)
681 self.assertEqual(udp.dport, self.sa.dport)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000682
Filip Tehlare7c83962020-09-23 11:20:12 +0000683 def get_ike_header(self, packet):
684 try:
685 ih = packet[ikev2.IKEv2]
Filip Tehlar18107c92020-12-01 14:51:09 +0000686 ih = self.verify_and_remove_non_esp_marker(ih)
Filip Tehlare7c83962020-09-23 11:20:12 +0000687 except IndexError as e:
688 # this is a workaround for getting IKEv2 layer as both ikev2 and
689 # ipsec register for port 4500
690 esp = packet[ESP]
691 ih = self.verify_and_remove_non_esp_marker(esp)
692 self.assertEqual(ih.version, 0x20)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200693 self.assertNotIn("Version", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +0000694 return ih
Filip Tehlar12b517b2020-04-26 18:05:05 +0000695
Filip Tehlare7c83962020-09-23 11:20:12 +0000696 def verify_and_remove_non_esp_marker(self, packet):
697 if self.sa.natt:
698 # if we are in nat traversal mode check for non esp marker
699 # and remove it
700 data = raw(packet)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200701 self.assertEqual(data[:4], b"\x00" * 4)
Filip Tehlare7c83962020-09-23 11:20:12 +0000702 return ikev2.IKEv2(data[4:])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +0000703 else:
Filip Tehlare7c83962020-09-23 11:20:12 +0000704 return packet
Filip Tehlar12b517b2020-04-26 18:05:05 +0000705
Filip Tehlar558607d2020-07-16 07:25:56 +0000706 def encrypt_ike_msg(self, header, plain, first_payload):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200707 if self.sa.ike_crypto == "AES-GCM-16ICV":
Filip Tehlar558607d2020-07-16 07:25:56 +0000708 data = self.sa.ike_crypto_alg.pad(raw(plain))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200709 plen = (
710 len(data)
711 + GCM_IV_SIZE
712 + GCM_ICV_SIZE
713 + len(ikev2.IKEv2_payload_Encrypted())
714 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000715 tlen = plen + len(ikev2.IKEv2())
716
717 # prepare aad data
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200718 sk_p = ikev2.IKEv2_payload_Encrypted(
719 next_payload=first_payload, length=plen
720 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000721 header.length = tlen
722 res = header / sk_p
723 encr = self.sa.encrypt(raw(plain), raw(res))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200724 sk_p = ikev2.IKEv2_payload_Encrypted(
725 next_payload=first_payload, length=plen, load=encr
726 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000727 res = header / sk_p
728 else:
729 encr = self.sa.encrypt(raw(plain))
730 trunc_len = self.sa.ike_integ_alg.trunc_len
731 plen = len(encr) + len(ikev2.IKEv2_payload_Encrypted()) + trunc_len
732 tlen = plen + len(ikev2.IKEv2())
733
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200734 sk_p = ikev2.IKEv2_payload_Encrypted(
735 next_payload=first_payload, length=plen, load=encr
736 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000737 header.length = tlen
738 res = header / sk_p
739
740 integ_data = raw(res)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200741 hmac_data = self.sa.compute_hmac(
742 self.sa.ike_integ_alg.mod(), self.sa.my_authkey, integ_data
743 )
Filip Tehlar558607d2020-07-16 07:25:56 +0000744 res = res / Raw(hmac_data[:trunc_len])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200745 assert len(res) == tlen
Filip Tehlar558607d2020-07-16 07:25:56 +0000746 return res
747
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000748 def verify_udp_encap(self, ipsec_sa):
749 e = VppEnum.vl_api_ipsec_sad_flags_t
750 if self.sa.udp_encap or self.sa.natt:
751 self.assertIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags)
752 else:
753 self.assertNotIn(e.IPSEC_API_SAD_FLAG_UDP_ENCAP, ipsec_sa.flags)
754
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +0900755 def verify_ipsec_sas(self, is_rekey=False, sa_count=None):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000756 sas = self.vapi.ipsec_sa_dump()
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +0900757 if sa_count is None:
758 if is_rekey:
759 # after rekey there is a short period of time in which old
760 # inbound SA is still present
761 sa_count = 3
762 else:
763 sa_count = 2
Filip Tehlar68ad6252020-10-30 05:28:11 +0000764 self.assertEqual(len(sas), sa_count)
Filip Tehlare7c83962020-09-23 11:20:12 +0000765 if self.sa.is_initiator:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000766 if is_rekey:
767 sa0 = sas[0].entry
768 sa1 = sas[2].entry
769 else:
770 sa0 = sas[0].entry
771 sa1 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000772 else:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000773 if is_rekey:
774 sa0 = sas[2].entry
775 sa1 = sas[0].entry
776 else:
777 sa1 = sas[0].entry
778 sa0 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000779
Filip Tehlar12b517b2020-04-26 18:05:05 +0000780 c = self.sa.child_sas[0]
781
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000782 self.verify_udp_encap(sa0)
783 self.verify_udp_encap(sa1)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000784 vpp_crypto_alg = self.vpp_enums[self.sa.vpp_esp_cypto_alg]
785 self.assertEqual(sa0.crypto_algorithm, vpp_crypto_alg)
786 self.assertEqual(sa1.crypto_algorithm, vpp_crypto_alg)
787
788 if self.sa.esp_integ is None:
789 vpp_integ_alg = 0
790 else:
791 vpp_integ_alg = self.vpp_enums[self.sa.esp_integ]
792 self.assertEqual(sa0.integrity_algorithm, vpp_integ_alg)
793 self.assertEqual(sa1.integrity_algorithm, vpp_integ_alg)
794
Filip Tehlar12b517b2020-04-26 18:05:05 +0000795 # verify crypto keys
796 self.assertEqual(sa0.crypto_key.length, len(c.sk_er))
797 self.assertEqual(sa1.crypto_key.length, len(c.sk_ei))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200798 self.assertEqual(sa0.crypto_key.data[: len(c.sk_er)], c.sk_er)
799 self.assertEqual(sa1.crypto_key.data[: len(c.sk_ei)], c.sk_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000800
801 # verify integ keys
Filip Tehlar4f42a712020-07-01 08:56:59 +0000802 if vpp_integ_alg:
803 self.assertEqual(sa0.integrity_key.length, len(c.sk_ar))
804 self.assertEqual(sa1.integrity_key.length, len(c.sk_ai))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200805 self.assertEqual(sa0.integrity_key.data[: len(c.sk_ar)], c.sk_ar)
806 self.assertEqual(sa1.integrity_key.data[: len(c.sk_ai)], c.sk_ai)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000807 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200808 self.assertEqual(sa0.salt.to_bytes(4, "little"), c.salt_er)
809 self.assertEqual(sa1.salt.to_bytes(4, "little"), c.salt_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000810
jan_cavojskya340fe12020-07-08 09:24:12 +0200811 def verify_keymat(self, api_keys, keys, name):
812 km = getattr(keys, name)
813 api_km = getattr(api_keys, name)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200814 api_km_len = getattr(api_keys, name + "_len")
jan_cavojskya340fe12020-07-08 09:24:12 +0200815 self.assertEqual(len(km), api_km_len)
816 self.assertEqual(km, api_km[:api_km_len])
817
818 def verify_id(self, api_id, exp_id):
819 self.assertEqual(api_id.type, IDType.value(exp_id.type))
820 self.assertEqual(api_id.data_len, exp_id.data_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200821 self.assertEqual(bytes(api_id.data, "ascii"), exp_id.type)
jan_cavojskya340fe12020-07-08 09:24:12 +0200822
823 def verify_ike_sas(self):
824 r = self.vapi.ikev2_sa_dump()
825 self.assertEqual(len(r), 1)
826 sa = r[0].sa
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200827 self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, "big"))
828 self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, "big"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000829 if self.ip6:
Filip Tehlare7c83962020-09-23 11:20:12 +0000830 if self.sa.is_initiator:
831 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6))
832 self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6))
833 else:
834 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.local_ip6))
835 self.assertEqual(sa.raddr, IPv6Address(self.pg0.remote_ip6))
Filip Tehlar84962d12020-09-08 06:08:05 +0000836 else:
Filip Tehlare7c83962020-09-23 11:20:12 +0000837 if self.sa.is_initiator:
838 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4))
839 self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4))
840 else:
841 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.local_ip4))
842 self.assertEqual(sa.raddr, IPv4Address(self.pg0.remote_ip4))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200843 self.verify_keymat(sa.keys, self.sa, "sk_d")
844 self.verify_keymat(sa.keys, self.sa, "sk_ai")
845 self.verify_keymat(sa.keys, self.sa, "sk_ar")
846 self.verify_keymat(sa.keys, self.sa, "sk_ei")
847 self.verify_keymat(sa.keys, self.sa, "sk_er")
848 self.verify_keymat(sa.keys, self.sa, "sk_pi")
849 self.verify_keymat(sa.keys, self.sa, "sk_pr")
jan_cavojskya340fe12020-07-08 09:24:12 +0200850
851 self.assertEqual(sa.i_id.type, self.sa.id_type)
852 self.assertEqual(sa.r_id.type, self.sa.id_type)
853 self.assertEqual(sa.i_id.data_len, len(self.sa.i_id))
Benoît Gannec7cceee2021-09-28 11:19:37 +0200854 self.assertEqual(sa.r_id.data_len, len(self.idr))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200855 self.assertEqual(bytes(sa.i_id.data, "ascii"), self.sa.i_id)
856 self.assertEqual(bytes(sa.r_id.data, "ascii"), self.idr)
jan_cavojskya340fe12020-07-08 09:24:12 +0200857
858 r = self.vapi.ikev2_child_sa_dump(sa_index=sa.sa_index)
859 self.assertEqual(len(r), 1)
860 csa = r[0].child_sa
861 self.assertEqual(csa.sa_index, sa.sa_index)
862 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200863 if hasattr(c, "sk_ai"):
864 self.verify_keymat(csa.keys, c, "sk_ai")
865 self.verify_keymat(csa.keys, c, "sk_ar")
866 self.verify_keymat(csa.keys, c, "sk_ei")
867 self.verify_keymat(csa.keys, c, "sk_er")
868 self.assertEqual(csa.i_spi.to_bytes(4, "big"), c.ispi)
869 self.assertEqual(csa.r_spi.to_bytes(4, "big"), c.rspi)
jan_cavojskya340fe12020-07-08 09:24:12 +0200870
Filip Tehlar84962d12020-09-08 06:08:05 +0000871 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
jan_cavojskya340fe12020-07-08 09:24:12 +0200872 tsi = tsi[0]
873 tsr = tsr[0]
874 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200875 is_initiator=True, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
876 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200877 self.assertEqual(len(r), 1)
878 ts = r[0].ts
879 self.verify_ts(r[0].ts, tsi[0], True)
880
881 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200882 is_initiator=False, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
883 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200884 self.assertEqual(len(r), 1)
885 self.verify_ts(r[0].ts, tsr[0], False)
886
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200887 n = self.vapi.ikev2_nonce_get(is_initiator=True, sa_index=sa.sa_index)
jan_cavojskya340fe12020-07-08 09:24:12 +0200888 self.verify_nonce(n, self.sa.i_nonce)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200889 n = self.vapi.ikev2_nonce_get(is_initiator=False, sa_index=sa.sa_index)
jan_cavojskya340fe12020-07-08 09:24:12 +0200890 self.verify_nonce(n, self.sa.r_nonce)
891
892 def verify_nonce(self, api_nonce, nonce):
893 self.assertEqual(api_nonce.data_len, len(nonce))
894 self.assertEqual(api_nonce.nonce, nonce)
895
896 def verify_ts(self, api_ts, ts, is_initiator):
897 if is_initiator:
898 self.assertTrue(api_ts.is_local)
899 else:
900 self.assertFalse(api_ts.is_local)
Filip Tehlar84962d12020-09-08 06:08:05 +0000901
902 if self.p.ts_is_ip4:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200903 self.assertEqual(api_ts.start_addr, IPv4Address(ts.starting_address_v4))
904 self.assertEqual(api_ts.end_addr, IPv4Address(ts.ending_address_v4))
Filip Tehlar84962d12020-09-08 06:08:05 +0000905 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200906 self.assertEqual(api_ts.start_addr, IPv6Address(ts.starting_address_v6))
907 self.assertEqual(api_ts.end_addr, IPv6Address(ts.ending_address_v6))
jan_cavojskya340fe12020-07-08 09:24:12 +0200908 self.assertEqual(api_ts.start_port, ts.start_port)
909 self.assertEqual(api_ts.end_port, ts.end_port)
910 self.assertEqual(api_ts.protocol_id, ts.IP_protocol_ID)
911
Filip Tehlare7c83962020-09-23 11:20:12 +0000912
913class TemplateInitiator(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 """initiator test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +0000915
Filip Tehlaredf29002020-10-10 04:39:11 +0000916 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200917 ispi = int.from_bytes(self.sa.ispi, "little")
Filip Tehlaredf29002020-10-10 04:39:11 +0000918 self.pg0.enable_capture()
919 self.pg_start()
920 self.vapi.ikev2_initiate_del_ike_sa(ispi=ispi)
921 capture = self.pg0.get_capture(1)
922 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200923 self.assertNotIn("Response", ih.flags)
924 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +0000925 self.assertEqual(ih.init_SPI, self.sa.ispi)
926 self.assertEqual(ih.resp_SPI, self.sa.rspi)
927 plain = self.sa.hmac_and_decrypt(ih)
928 d = ikev2.IKEv2_payload_Delete(plain)
929 self.assertEqual(d.proto, 1) # proto=IKEv2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200930 header = ikev2.IKEv2(
931 init_SPI=self.sa.ispi,
932 resp_SPI=self.sa.rspi,
933 flags="Response",
934 exch_type="INFORMATIONAL",
935 id=ih.id,
936 next_payload="Encrypted",
937 )
938 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +0000939 self.send_and_assert_no_replies(self.pg0, resp)
940
941 def verify_del_sa(self, packet):
942 ih = self.get_ike_header(packet)
943 self.assertEqual(ih.id, self.sa.msg_id)
944 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200945 self.assertIn("Response", ih.flags)
946 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +0000947 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200948 self.assertEqual(plain, b"")
Filip Tehlaredf29002020-10-10 04:39:11 +0000949
950 def initiate_del_sa_from_responder(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200951 header = ikev2.IKEv2(
952 init_SPI=self.sa.ispi,
953 resp_SPI=self.sa.rspi,
954 exch_type="INFORMATIONAL",
955 id=self.sa.new_msg_id(),
956 )
957 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
958 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
959 packet = self.create_packet(
960 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
961 )
Filip Tehlaredf29002020-10-10 04:39:11 +0000962 self.pg0.add_stream(packet)
963 self.pg0.enable_capture()
964 self.pg_start()
965 capture = self.pg0.get_capture(1)
966 self.verify_del_sa(capture[0])
Filip Tehlare7c83962020-09-23 11:20:12 +0000967
Filip Tehlarec112e52020-10-07 23:52:37 +0000968 @staticmethod
969 def find_notify_payload(packet, notify_type):
970 n = packet[ikev2.IKEv2_payload_Notify]
971 while n is not None:
972 if n.type == notify_type:
973 return n
974 n = n.payload
975 return None
976
977 def verify_nat_detection(self, packet):
978 if self.ip6:
979 iph = packet[IPv6]
980 else:
981 iph = packet[IP]
982 udp = packet[UDP]
983
984 # NAT_DETECTION_SOURCE_IP
985 s = self.find_notify_payload(packet, 16388)
986 self.assertIsNotNone(s)
987 src_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200988 inet_pton(socket.AF_INET, iph.src), udp.sport, b"\x00" * 8
989 )
Filip Tehlarec112e52020-10-07 23:52:37 +0000990 self.assertEqual(s.load, src_sha)
991
992 # NAT_DETECTION_DESTINATION_IP
993 s = self.find_notify_payload(packet, 16389)
994 self.assertIsNotNone(s)
995 dst_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200996 inet_pton(socket.AF_INET, iph.dst), udp.dport, b"\x00" * 8
997 )
Filip Tehlarec112e52020-10-07 23:52:37 +0000998 self.assertEqual(s.load, dst_sha)
999
Filip Tehlare7c83962020-09-23 11:20:12 +00001000 def verify_sa_init_request(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001001 udp = packet[UDP]
1002 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001003 ih = packet[ikev2.IKEv2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001004 self.assertNotEqual(ih.init_SPI, 8 * b"\x00")
Filip Tehlare7c83962020-09-23 11:20:12 +00001005 self.assertEqual(ih.exch_type, 34) # SA_INIT
1006 self.sa.ispi = ih.init_SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001007 self.assertEqual(ih.resp_SPI, 8 * b"\x00")
1008 self.assertIn("Initiator", ih.flags)
1009 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001010 self.sa.i_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1011 self.sa.i_dh_data = ih[ikev2.IKEv2_payload_KE].load
1012
1013 prop = packet[ikev2.IKEv2_payload_Proposal]
1014 self.assertEqual(prop.proto, 1) # proto = ikev2
1015 self.assertEqual(prop.proposal, 1)
1016 self.assertEqual(prop.trans[0].transform_type, 1) # encryption
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 self.assertEqual(
1018 prop.trans[0].transform_id, self.p.ike_transforms["crypto_alg"]
1019 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001020 self.assertEqual(prop.trans[1].transform_type, 2) # prf
1021 self.assertEqual(prop.trans[1].transform_id, 5) # "hmac-sha2-256"
1022 self.assertEqual(prop.trans[2].transform_type, 4) # dh
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001023 self.assertEqual(prop.trans[2].transform_id, self.p.ike_transforms["dh_group"])
Filip Tehlare7c83962020-09-23 11:20:12 +00001024
Filip Tehlarec112e52020-10-07 23:52:37 +00001025 self.verify_nat_detection(packet)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001026 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001027 crypto="AES-GCM-16ICV",
1028 crypto_key_len=32,
1029 integ="NULL",
1030 prf="PRF_HMAC_SHA2_256",
1031 dh="3072MODPgr",
1032 )
1033 self.sa.set_esp_props(crypto="AES-CBC", crypto_key_len=32, integ="SHA2-256-128")
Filip Tehlar68ad6252020-10-30 05:28:11 +00001034 self.sa.generate_dh_data()
Filip Tehlare7c83962020-09-23 11:20:12 +00001035 self.sa.complete_dh_data()
1036 self.sa.calc_keys()
1037
Filip Tehlar68ad6252020-10-30 05:28:11 +00001038 def update_esp_transforms(self, trans, sa):
1039 while trans:
1040 if trans.transform_type == 1: # ecryption
1041 sa.esp_crypto = CRYPTO_IDS[trans.transform_id]
1042 elif trans.transform_type == 3: # integrity
1043 sa.esp_integ = INTEG_IDS[trans.transform_id]
1044 trans = trans.payload
1045
Filip Tehlare7c83962020-09-23 11:20:12 +00001046 def verify_sa_auth_req(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001047 udp = packet[UDP]
1048 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001049 ih = self.get_ike_header(packet)
1050 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1051 self.assertEqual(ih.init_SPI, self.sa.ispi)
1052 self.assertEqual(ih.exch_type, 35) # IKE_AUTH
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001053 self.assertIn("Initiator", ih.flags)
1054 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001055
1056 udp = packet[UDP]
1057 self.verify_udp(udp)
1058 self.assertEqual(ih.id, self.sa.msg_id + 1)
1059 self.sa.msg_id += 1
1060 plain = self.sa.hmac_and_decrypt(ih)
1061 idi = ikev2.IKEv2_payload_IDi(plain)
Filip Tehlare7c83962020-09-23 11:20:12 +00001062 self.assertEqual(idi.load, self.sa.i_id)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001063 if self.no_idr_auth:
1064 self.assertEqual(idi.next_payload, 39) # AUTH
1065 else:
1066 idr = ikev2.IKEv2_payload_IDr(idi.payload)
1067 self.assertEqual(idr.load, self.sa.r_id)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001068 prop = idi[ikev2.IKEv2_payload_Proposal]
1069 c = self.sa.child_sas[0]
1070 c.ispi = prop.SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001071 self.update_esp_transforms(prop[ikev2.IKEv2_payload_Transform], self.sa)
Filip Tehlare7c83962020-09-23 11:20:12 +00001072
1073 def send_init_response(self):
1074 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001075 trans = (
1076 ikev2.IKEv2_payload_Transform(
1077 transform_type="Encryption",
1078 transform_id=self.sa.ike_crypto,
1079 length=tr_attr[1],
1080 key_length=tr_attr[0],
1081 )
1082 / ikev2.IKEv2_payload_Transform(
1083 transform_type="Integrity", transform_id=self.sa.ike_integ
1084 )
1085 / ikev2.IKEv2_payload_Transform(
1086 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1087 )
1088 / ikev2.IKEv2_payload_Transform(
1089 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1090 )
1091 )
1092 props = ikev2.IKEv2_payload_Proposal(
1093 proposal=1, proto="IKEv2", trans_nb=4, trans=trans
1094 )
Filip Tehlar18107c92020-12-01 14:51:09 +00001095
1096 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
1097 if self.sa.natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001098 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar18107c92020-12-01 14:51:09 +00001099 else:
1100 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1101 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1102 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1103
Filip Tehlare7c83962020-09-23 11:20:12 +00001104 self.sa.init_resp_packet = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001105 ikev2.IKEv2(
1106 init_SPI=self.sa.ispi,
1107 resp_SPI=self.sa.rspi,
1108 exch_type="IKE_SA_INIT",
1109 flags="Response",
1110 )
1111 / ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
1112 / ikev2.IKEv2_payload_KE(
1113 next_payload="Nonce", group=self.sa.ike_dh, load=self.sa.my_dh_pub_key
1114 )
1115 / ikev2.IKEv2_payload_Nonce(load=self.sa.r_nonce, next_payload="Notify")
1116 / ikev2.IKEv2_payload_Notify(
1117 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1118 )
1119 / ikev2.IKEv2_payload_Notify(
1120 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1121 )
1122 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001123
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001124 ike_msg = self.create_packet(
1125 self.pg0,
1126 self.sa.init_resp_packet,
1127 self.sa.sport,
1128 self.sa.dport,
1129 False,
1130 self.ip6,
1131 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001132 self.pg_send(self.pg0, ike_msg)
1133 capture = self.pg0.get_capture(1)
1134 self.verify_sa_auth_req(capture[0])
1135
1136 def initiate_sa_init(self):
1137 self.pg0.enable_capture()
1138 self.pg_start()
1139 self.vapi.ikev2_initiate_sa_init(name=self.p.profile_name)
1140
1141 capture = self.pg0.get_capture(1)
1142 self.verify_sa_init_request(capture[0])
1143 self.send_init_response()
1144
1145 def send_auth_response(self):
1146 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001147 trans = (
1148 ikev2.IKEv2_payload_Transform(
1149 transform_type="Encryption",
1150 transform_id=self.sa.esp_crypto,
1151 length=tr_attr[1],
1152 key_length=tr_attr[0],
1153 )
1154 / ikev2.IKEv2_payload_Transform(
1155 transform_type="Integrity", transform_id=self.sa.esp_integ
1156 )
1157 / ikev2.IKEv2_payload_Transform(
1158 transform_type="Extended Sequence Number", transform_id="No ESN"
1159 )
1160 / ikev2.IKEv2_payload_Transform(
1161 transform_type="Extended Sequence Number", transform_id="ESN"
1162 )
1163 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001164
Filip Tehlar68ad6252020-10-30 05:28:11 +00001165 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001166 props = ikev2.IKEv2_payload_Proposal(
1167 proposal=1, proto="ESP", SPIsize=4, SPI=c.rspi, trans_nb=4, trans=trans
1168 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001169
1170 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001171 plain = (
1172 ikev2.IKEv2_payload_IDi(
1173 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1174 )
1175 / ikev2.IKEv2_payload_IDr(
1176 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1177 )
1178 / ikev2.IKEv2_payload_AUTH(
1179 next_payload="SA",
1180 auth_type=AuthMethod.value(self.sa.auth_method),
1181 load=self.sa.auth_data,
1182 )
1183 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1184 / ikev2.IKEv2_payload_TSi(
1185 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1186 )
1187 / ikev2.IKEv2_payload_TSr(
1188 next_payload="Notify", number_of_TSs=len(tsr), traffic_selector=tsr
1189 )
1190 / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
1191 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001192
1193 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001194 init_SPI=self.sa.ispi,
1195 resp_SPI=self.sa.rspi,
1196 id=self.sa.new_msg_id(),
1197 flags="Response",
1198 exch_type="IKE_AUTH",
1199 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001200
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001201 ike_msg = self.encrypt_ike_msg(header, plain, "IDi")
1202 packet = self.create_packet(
1203 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1204 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001205 self.pg_send(self.pg0, packet)
1206
1207 def test_initiator(self):
1208 self.initiate_sa_init()
1209 self.sa.auth_init()
1210 self.sa.calc_child_keys()
1211 self.send_auth_response()
1212 self.verify_ike_sas()
1213
1214
1215class TemplateResponder(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001216 """responder test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +00001217
Filip Tehlaredf29002020-10-10 04:39:11 +00001218 def initiate_del_sa_from_responder(self):
1219 self.pg0.enable_capture()
1220 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001221 self.vapi.ikev2_initiate_del_ike_sa(ispi=int.from_bytes(self.sa.ispi, "little"))
Filip Tehlaredf29002020-10-10 04:39:11 +00001222 capture = self.pg0.get_capture(1)
1223 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001224 self.assertNotIn("Response", ih.flags)
1225 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001226 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
1227 plain = self.sa.hmac_and_decrypt(ih)
1228 d = ikev2.IKEv2_payload_Delete(plain)
1229 self.assertEqual(d.proto, 1) # proto=IKEv2
1230 self.assertEqual(ih.init_SPI, self.sa.ispi)
1231 self.assertEqual(ih.resp_SPI, self.sa.rspi)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001232 header = ikev2.IKEv2(
1233 init_SPI=self.sa.ispi,
1234 resp_SPI=self.sa.rspi,
1235 flags="Initiator+Response",
1236 exch_type="INFORMATIONAL",
1237 id=ih.id,
1238 next_payload="Encrypted",
1239 )
1240 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +00001241 self.send_and_assert_no_replies(self.pg0, resp)
Filip Tehlare7c83962020-09-23 11:20:12 +00001242
1243 def verify_del_sa(self, packet):
1244 ih = self.get_ike_header(packet)
1245 self.assertEqual(ih.id, self.sa.msg_id)
1246 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001247 self.assertIn("Response", ih.flags)
1248 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001249 self.assertEqual(ih.next_payload, 46) # Encrypted
1250 self.assertEqual(ih.init_SPI, self.sa.ispi)
1251 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1252 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001253 self.assertEqual(plain, b"")
Filip Tehlare7c83962020-09-23 11:20:12 +00001254
Filip Tehlaredf29002020-10-10 04:39:11 +00001255 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001256 header = ikev2.IKEv2(
1257 init_SPI=self.sa.ispi,
1258 resp_SPI=self.sa.rspi,
1259 flags="Initiator",
1260 exch_type="INFORMATIONAL",
1261 id=self.sa.new_msg_id(),
1262 )
1263 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
1264 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
1265 packet = self.create_packet(
1266 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1267 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001268 self.pg0.add_stream(packet)
1269 self.pg0.enable_capture()
1270 self.pg_start()
1271 capture = self.pg0.get_capture(1)
1272 self.verify_del_sa(capture[0])
1273
Filip Tehlar027d8132020-12-04 17:38:11 +00001274 def send_sa_init_req(self):
Filip Tehlare7c83962020-09-23 11:20:12 +00001275 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001276 trans = (
1277 ikev2.IKEv2_payload_Transform(
1278 transform_type="Encryption",
1279 transform_id=self.sa.ike_crypto,
1280 length=tr_attr[1],
1281 key_length=tr_attr[0],
1282 )
1283 / ikev2.IKEv2_payload_Transform(
1284 transform_type="Integrity", transform_id=self.sa.ike_integ
1285 )
1286 / ikev2.IKEv2_payload_Transform(
1287 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1288 )
1289 / ikev2.IKEv2_payload_Transform(
1290 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1291 )
1292 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001293
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001294 props = ikev2.IKEv2_payload_Proposal(
1295 proposal=1, proto="IKEv2", trans_nb=4, trans=trans
1296 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001297
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001298 next_payload = None if self.ip6 else "Notify"
Filip Tehlar027d8132020-12-04 17:38:11 +00001299
Filip Tehlare7c83962020-09-23 11:20:12 +00001300 self.sa.init_req_packet = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001301 ikev2.IKEv2(
1302 init_SPI=self.sa.ispi, flags="Initiator", exch_type="IKE_SA_INIT"
1303 )
1304 / ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
1305 / ikev2.IKEv2_payload_KE(
1306 next_payload="Nonce", group=self.sa.ike_dh, load=self.sa.my_dh_pub_key
1307 )
1308 / ikev2.IKEv2_payload_Nonce(next_payload=next_payload, load=self.sa.i_nonce)
1309 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001310
Filip Tehlar027d8132020-12-04 17:38:11 +00001311 if not self.ip6:
1312 if self.sa.i_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001313 src_address = b"\x0a\x0a\x0a\x01"
Filip Tehlar027d8132020-12-04 17:38:11 +00001314 else:
1315 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
Filip Tehlare7c83962020-09-23 11:20:12 +00001316
Filip Tehlar027d8132020-12-04 17:38:11 +00001317 if self.sa.r_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001318 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar027d8132020-12-04 17:38:11 +00001319 else:
1320 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1321
1322 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1323 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1324 nat_src_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001325 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1326 )
Filip Tehlar027d8132020-12-04 17:38:11 +00001327 nat_dst_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001328 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1329 )
1330 self.sa.init_req_packet = (
1331 self.sa.init_req_packet / nat_src_detection / nat_dst_detection
1332 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001333
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001334 ike_msg = self.create_packet(
1335 self.pg0,
1336 self.sa.init_req_packet,
1337 self.sa.sport,
1338 self.sa.dport,
1339 self.sa.natt,
1340 self.ip6,
1341 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001342 self.pg0.add_stream(ike_msg)
1343 self.pg0.enable_capture()
1344 self.pg_start()
1345 capture = self.pg0.get_capture(1)
1346 self.verify_sa_init(capture[0])
1347
Filip Tehlar68ad6252020-10-30 05:28:11 +00001348 def generate_auth_payload(self, last_payload=None, is_rekey=False):
Filip Tehlare7c83962020-09-23 11:20:12 +00001349 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001350 last_payload = last_payload or "Notify"
1351 trans = (
1352 ikev2.IKEv2_payload_Transform(
1353 transform_type="Encryption",
1354 transform_id=self.sa.esp_crypto,
1355 length=tr_attr[1],
1356 key_length=tr_attr[0],
1357 )
1358 / ikev2.IKEv2_payload_Transform(
1359 transform_type="Integrity", transform_id=self.sa.esp_integ
1360 )
1361 / ikev2.IKEv2_payload_Transform(
1362 transform_type="Extended Sequence Number", transform_id="No ESN"
1363 )
1364 / ikev2.IKEv2_payload_Transform(
1365 transform_type="Extended Sequence Number", transform_id="ESN"
1366 )
1367 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001368
Filip Tehlar68ad6252020-10-30 05:28:11 +00001369 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001370 props = ikev2.IKEv2_payload_Proposal(
1371 proposal=1, proto="ESP", SPIsize=4, SPI=c.ispi, trans_nb=4, trans=trans
1372 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001373
1374 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001375 plain = (
1376 ikev2.IKEv2_payload_AUTH(
1377 next_payload="SA",
1378 auth_type=AuthMethod.value(self.sa.auth_method),
1379 load=self.sa.auth_data,
1380 )
1381 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1382 / ikev2.IKEv2_payload_TSi(
1383 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1384 )
1385 / ikev2.IKEv2_payload_TSr(
1386 next_payload=last_payload, number_of_TSs=len(tsr), traffic_selector=tsr
1387 )
1388 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001389
Filip Tehlar68ad6252020-10-30 05:28:11 +00001390 if is_rekey:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001391 first_payload = "Nonce"
1392 plain = (
1393 ikev2.IKEv2_payload_Nonce(load=self.sa.i_nonce, next_payload="SA")
1394 / plain
Atzm Watanabe03aae962022-08-08 15:45:36 +09001395 / ikev2.IKEv2_payload_Notify(
1396 type="REKEY_SA",
1397 proto="ESP",
1398 SPI=c.ispi,
1399 length=8 + len(c.ispi),
1400 next_payload="Notify",
1401 )
1402 / ikev2.IKEv2_payload_Notify(type="ESP_TFC_PADDING_NOT_SUPPORTED")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001403 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001404 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001405 first_payload = "IDi"
Benoît Gannec7cceee2021-09-28 11:19:37 +02001406 if self.no_idr_auth:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001407 ids = ikev2.IKEv2_payload_IDi(
1408 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.i_id
1409 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001410 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001411 ids = ikev2.IKEv2_payload_IDi(
1412 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1413 ) / ikev2.IKEv2_payload_IDr(
1414 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1415 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001416 plain = ids / plain
1417 return plain, first_payload
1418
1419 def send_sa_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001420 plain, first_payload = self.generate_auth_payload(last_payload="Notify")
1421 plain = plain / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
Filip Tehlare7c83962020-09-23 11:20:12 +00001422 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001423 init_SPI=self.sa.ispi,
1424 resp_SPI=self.sa.rspi,
1425 id=self.sa.new_msg_id(),
1426 flags="Initiator",
1427 exch_type="IKE_AUTH",
1428 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001429
Filip Tehlar68ad6252020-10-30 05:28:11 +00001430 ike_msg = self.encrypt_ike_msg(header, plain, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001431 packet = self.create_packet(
1432 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1433 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001434 self.pg0.add_stream(packet)
1435 self.pg0.enable_capture()
1436 self.pg_start()
1437 capture = self.pg0.get_capture(1)
1438 self.verify_sa_auth_resp(capture[0])
1439
1440 def verify_sa_init(self, packet):
1441 ih = self.get_ike_header(packet)
1442
1443 self.assertEqual(ih.id, self.sa.msg_id)
1444 self.assertEqual(ih.exch_type, 34)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001445 self.assertIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001446 self.assertEqual(ih.init_SPI, self.sa.ispi)
1447 self.assertNotEqual(ih.resp_SPI, 0)
1448 self.sa.rspi = ih.resp_SPI
1449 try:
1450 sa = ih[ikev2.IKEv2_payload_SA]
1451 self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1452 self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load
1453 except IndexError as e:
1454 self.logger.error("unexpected reply: SA/Nonce/KE payload found!")
1455 self.logger.error(ih.show())
1456 raise
1457 self.sa.complete_dh_data()
1458 self.sa.calc_keys()
1459 self.sa.auth_init()
1460
1461 def verify_sa_auth_resp(self, packet):
1462 ike = self.get_ike_header(packet)
1463 udp = packet[UDP]
1464 self.verify_udp(udp)
1465 self.assertEqual(ike.id, self.sa.msg_id)
1466 plain = self.sa.hmac_and_decrypt(ike)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001467 idr = ikev2.IKEv2_payload_IDr(plain)
1468 prop = idr[ikev2.IKEv2_payload_Proposal]
1469 self.assertEqual(prop.SPIsize, 4)
1470 self.sa.child_sas[0].rspi = prop.SPI
Filip Tehlare7c83962020-09-23 11:20:12 +00001471 self.sa.calc_child_keys()
1472
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001473 IKE_NODE_SUFFIX = "ip4"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001474
1475 def verify_counters(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001476 self.assert_counter(2, "processed", self.IKE_NODE_SUFFIX)
1477 self.assert_counter(1, "init_sa_req", self.IKE_NODE_SUFFIX)
1478 self.assert_counter(1, "ike_auth_req", self.IKE_NODE_SUFFIX)
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001479
Filip Tehlar68d27532021-01-25 10:09:27 +00001480 r = self.vapi.ikev2_sa_dump()
1481 s = r[0].sa.stats
1482 self.assertEqual(1, s.n_sa_auth_req)
1483 self.assertEqual(1, s.n_sa_init_req)
1484
Filip Tehlar12b517b2020-04-26 18:05:05 +00001485 def test_responder(self):
Filip Tehlar027d8132020-12-04 17:38:11 +00001486 self.send_sa_init_req()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001487 self.send_sa_auth()
jan_cavojskya340fe12020-07-08 09:24:12 +02001488 self.verify_ipsec_sas()
1489 self.verify_ike_sas()
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001490 self.verify_counters()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001491
1492
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001493class Ikev2Params(object):
1494 def config_params(self, params={}):
Filip Tehlar4f42a712020-07-01 08:56:59 +00001495 ec = VppEnum.vl_api_ipsec_crypto_alg_t
1496 ei = VppEnum.vl_api_ipsec_integ_alg_t
1497 self.vpp_enums = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001498 "AES-CBC-128": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_128,
1499 "AES-CBC-192": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_192,
1500 "AES-CBC-256": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_256,
1501 "AES-GCM-16ICV-128": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_128,
1502 "AES-GCM-16ICV-192": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_192,
1503 "AES-GCM-16ICV-256": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_256,
1504 "HMAC-SHA1-96": ei.IPSEC_API_INTEG_ALG_SHA1_96,
1505 "SHA2-256-128": ei.IPSEC_API_INTEG_ALG_SHA_256_128,
1506 "SHA2-384-192": ei.IPSEC_API_INTEG_ALG_SHA_384_192,
1507 "SHA2-512-256": ei.IPSEC_API_INTEG_ALG_SHA_512_256,
1508 }
Filip Tehlar4f42a712020-07-01 08:56:59 +00001509
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001510 dpd_disabled = True if "dpd_disabled" not in params else params["dpd_disabled"]
Filip Tehlar2008e312020-11-09 13:23:24 +00001511 if dpd_disabled:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001512 self.vapi.cli("ikev2 dpd disable")
1513 self.del_sa_from_responder = (
1514 False
1515 if "del_sa_from_responder" not in params
1516 else params["del_sa_from_responder"]
1517 )
1518 i_natt = False if "i_natt" not in params else params["i_natt"]
1519 r_natt = False if "r_natt" not in params else params["r_natt"]
1520 self.p = Profile(self, "pr1")
1521 self.ip6 = False if "ip6" not in params else params["ip6"]
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001522
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001523 if "auth" in params and params["auth"] == "rsa-sig":
1524 auth_method = "rsa-sig"
Klement Sekerab23ffd72021-05-31 16:08:53 +02001525 work_dir = f"{config.vpp_ws_dir}/src/plugins/ikev2/test/certs/"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001526 self.vapi.ikev2_set_local_key(key_file=work_dir + params["server-key"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001527
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001528 client_file = work_dir + params["client-cert"]
1529 server_pem = open(work_dir + params["server-cert"]).read()
1530 client_priv = open(work_dir + params["client-key"]).read()
1531 client_priv = load_pem_private_key(
1532 str.encode(client_priv), None, default_backend()
1533 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001534 self.peer_cert = x509.load_pem_x509_certificate(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001535 str.encode(server_pem), default_backend()
1536 )
1537 self.p.add_auth(method="rsa-sig", data=str.encode(client_file))
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001538 auth_data = None
1539 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001540 auth_data = b"$3cr3tpa$$w0rd"
1541 self.p.add_auth(method="shared-key", data=auth_data)
1542 auth_method = "shared-key"
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001543 client_priv = None
1544
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001545 is_init = True if "is_initiator" not in params else params["is_initiator"]
1546 self.no_idr_auth = params.get("no_idr_in_auth", False)
Filip Tehlare7c83962020-09-23 11:20:12 +00001547
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001548 idr = {"id_type": "fqdn", "data": b"vpp.home"}
1549 idi = {"id_type": "fqdn", "data": b"roadwarrior.example.com"}
1550 r_id = self.idr = idr["data"]
1551 i_id = self.idi = idi["data"]
Filip Tehlare7c83962020-09-23 11:20:12 +00001552 if is_init:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001553 # scapy is initiator, VPP is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001554 self.p.add_local_id(**idr)
1555 self.p.add_remote_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001556 if self.no_idr_auth:
1557 r_id = None
Filip Tehlare7c83962020-09-23 11:20:12 +00001558 else:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001559 # VPP is initiator, scapy is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001560 self.p.add_local_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001561 if not self.no_idr_auth:
1562 self.p.add_remote_id(**idr)
Filip Tehlare7c83962020-09-23 11:20:12 +00001563
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001564 loc_ts = (
1565 {"start_addr": "10.10.10.0", "end_addr": "10.10.10.255"}
1566 if "loc_ts" not in params
1567 else params["loc_ts"]
1568 )
1569 rem_ts = (
1570 {"start_addr": "10.0.0.0", "end_addr": "10.0.0.255"}
1571 if "rem_ts" not in params
1572 else params["rem_ts"]
1573 )
Filip Tehlar84962d12020-09-08 06:08:05 +00001574 self.p.add_local_ts(**loc_ts)
1575 self.p.add_remote_ts(**rem_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001576 if "responder" in params:
1577 self.p.add_responder(params["responder"])
1578 if "ike_transforms" in params:
1579 self.p.add_ike_transforms(params["ike_transforms"])
1580 if "esp_transforms" in params:
1581 self.p.add_esp_transforms(params["esp_transforms"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001582
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001583 udp_encap = False if "udp_encap" not in params else params["udp_encap"]
Filip Tehlar67b8a7f2020-11-06 11:00:42 +00001584 if udp_encap:
1585 self.p.set_udp_encap(True)
1586
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001587 if "responder_hostname" in params:
1588 hn = params["responder_hostname"]
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001589 self.p.add_responder_hostname(hn)
1590
1591 # configure static dns record
1592 self.vapi.dns_name_server_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001593 is_ip6=0, is_add=1, server_address=IPv4Address("8.8.8.8").packed
1594 )
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001595 self.vapi.dns_enable_disable(enable=1)
1596
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001597 cmd = "dns cache add {} {}".format(hn["hostname"], self.pg0.remote_ip4)
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001598 self.vapi.cli(cmd)
1599
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001600 self.sa = IKEv2SA(
1601 self,
1602 i_id=i_id,
1603 r_id=r_id,
1604 is_initiator=is_init,
1605 id_type=self.p.local_id["id_type"],
1606 i_natt=i_natt,
1607 r_natt=r_natt,
1608 priv_key=client_priv,
1609 auth_method=auth_method,
1610 nonce=params.get("nonce"),
1611 auth_data=auth_data,
1612 udp_encap=udp_encap,
1613 local_ts=self.p.remote_ts,
1614 remote_ts=self.p.local_ts,
1615 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001616
Filip Tehlar68ad6252020-10-30 05:28:11 +00001617 if is_init:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001618 ike_crypto = (
1619 ("AES-CBC", 32) if "ike-crypto" not in params else params["ike-crypto"]
1620 )
1621 ike_integ = (
1622 "HMAC-SHA1-96" if "ike-integ" not in params else params["ike-integ"]
1623 )
1624 ike_dh = "2048MODPgr" if "ike-dh" not in params else params["ike-dh"]
Filip Tehlar4f42a712020-07-01 08:56:59 +00001625
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001626 esp_crypto = (
1627 ("AES-CBC", 32) if "esp-crypto" not in params else params["esp-crypto"]
1628 )
1629 esp_integ = (
1630 "HMAC-SHA1-96" if "esp-integ" not in params else params["esp-integ"]
1631 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00001632
Filip Tehlar68ad6252020-10-30 05:28:11 +00001633 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001634 crypto=ike_crypto[0],
1635 crypto_key_len=ike_crypto[1],
1636 integ=ike_integ,
1637 prf="PRF_HMAC_SHA2_256",
1638 dh=ike_dh,
1639 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001640 self.sa.set_esp_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001641 crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], integ=esp_integ
1642 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001643
1644
Filip Tehlar459d17b2020-07-06 15:40:08 +00001645class TestApi(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001646 """Test IKEV2 API"""
1647
Filip Tehlar459d17b2020-07-06 15:40:08 +00001648 @classmethod
1649 def setUpClass(cls):
1650 super(TestApi, cls).setUpClass()
1651
1652 @classmethod
1653 def tearDownClass(cls):
1654 super(TestApi, cls).tearDownClass()
1655
1656 def tearDown(self):
1657 super(TestApi, self).tearDown()
1658 self.p1.remove_vpp_config()
1659 self.p2.remove_vpp_config()
1660 r = self.vapi.ikev2_profile_dump()
1661 self.assertEqual(len(r), 0)
1662
1663 def configure_profile(self, cfg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001664 p = Profile(self, cfg["name"])
1665 p.add_local_id(id_type=cfg["loc_id"][0], data=cfg["loc_id"][1])
1666 p.add_remote_id(id_type=cfg["rem_id"][0], data=cfg["rem_id"][1])
1667 p.add_local_ts(**cfg["loc_ts"])
1668 p.add_remote_ts(**cfg["rem_ts"])
1669 p.add_responder(cfg["responder"])
1670 p.add_ike_transforms(cfg["ike_ts"])
1671 p.add_esp_transforms(cfg["esp_ts"])
1672 p.add_auth(**cfg["auth"])
1673 p.set_udp_encap(cfg["udp_encap"])
1674 p.set_ipsec_over_udp_port(cfg["ipsec_over_udp_port"])
1675 if "lifetime_data" in cfg:
1676 p.set_lifetime_data(cfg["lifetime_data"])
1677 if "tun_itf" in cfg:
1678 p.set_tunnel_interface(cfg["tun_itf"])
1679 if "natt_disabled" in cfg and cfg["natt_disabled"]:
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001680 p.disable_natt()
Filip Tehlar459d17b2020-07-06 15:40:08 +00001681 p.add_vpp_config()
1682 return p
1683
1684 def test_profile_api(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001685 """test profile dump API"""
Filip Tehlar84962d12020-09-08 06:08:05 +00001686 loc_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001687 "proto": 8,
1688 "start_port": 1,
1689 "end_port": 19,
1690 "start_addr": "3.3.3.2",
1691 "end_addr": "3.3.3.3",
1692 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001693 rem_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001694 "proto": 9,
1695 "start_port": 10,
1696 "end_port": 119,
1697 "start_addr": "4.5.76.80",
1698 "end_addr": "2.3.4.6",
1699 }
Filip Tehlar459d17b2020-07-06 15:40:08 +00001700
Filip Tehlar84962d12020-09-08 06:08:05 +00001701 loc_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001702 "proto": 8,
1703 "start_port": 1,
1704 "end_port": 19,
1705 "start_addr": "ab::1",
1706 "end_addr": "ab::4",
1707 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001708 rem_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001709 "proto": 9,
1710 "start_port": 10,
1711 "end_port": 119,
1712 "start_addr": "cd::12",
1713 "end_addr": "cd::13",
1714 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001715
Filip Tehlar459d17b2020-07-06 15:40:08 +00001716 conf = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001717 "p1": {
1718 "name": "p1",
1719 "natt_disabled": True,
1720 "loc_id": ("fqdn", b"vpp.home"),
1721 "rem_id": ("fqdn", b"roadwarrior.example.com"),
1722 "loc_ts": loc_ts4,
1723 "rem_ts": rem_ts4,
1724 "responder": {"sw_if_index": 0, "addr": "5.6.7.8"},
1725 "ike_ts": {
1726 "crypto_alg": 20,
1727 "crypto_key_size": 32,
1728 "integ_alg": 0,
1729 "dh_group": 1,
1730 },
1731 "esp_ts": {"crypto_alg": 13, "crypto_key_size": 24, "integ_alg": 2},
1732 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1733 "udp_encap": True,
1734 "ipsec_over_udp_port": 4501,
1735 "lifetime_data": {
1736 "lifetime": 123,
1737 "lifetime_maxdata": 20192,
1738 "lifetime_jitter": 9,
1739 "handover": 132,
1740 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001741 },
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001742 "p2": {
1743 "name": "p2",
1744 "loc_id": ("ip4-addr", b"192.168.2.1"),
1745 "rem_id": ("ip6-addr", b"abcd::1"),
1746 "loc_ts": loc_ts6,
1747 "rem_ts": rem_ts6,
1748 "responder": {"sw_if_index": 4, "addr": "def::10"},
1749 "ike_ts": {
1750 "crypto_alg": 12,
1751 "crypto_key_size": 16,
1752 "integ_alg": 3,
1753 "dh_group": 3,
1754 },
1755 "esp_ts": {"crypto_alg": 9, "crypto_key_size": 24, "integ_alg": 4},
1756 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1757 "udp_encap": False,
1758 "ipsec_over_udp_port": 4600,
1759 "tun_itf": 0,
1760 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001761 }
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001762 self.p1 = self.configure_profile(conf["p1"])
1763 self.p2 = self.configure_profile(conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001764
1765 r = self.vapi.ikev2_profile_dump()
1766 self.assertEqual(len(r), 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001767 self.verify_profile(r[0].profile, conf["p1"])
1768 self.verify_profile(r[1].profile, conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001769
1770 def verify_id(self, api_id, cfg_id):
1771 self.assertEqual(api_id.type, IDType.value(cfg_id[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001772 self.assertEqual(bytes(api_id.data, "ascii"), cfg_id[1])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001773
1774 def verify_ts(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001775 self.assertEqual(api_ts.protocol_id, cfg_ts["proto"])
1776 self.assertEqual(api_ts.start_port, cfg_ts["start_port"])
1777 self.assertEqual(api_ts.end_port, cfg_ts["end_port"])
1778 self.assertEqual(api_ts.start_addr, ip_address(text_type(cfg_ts["start_addr"])))
1779 self.assertEqual(api_ts.end_addr, ip_address(text_type(cfg_ts["end_addr"])))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001780
1781 def verify_responder(self, api_r, cfg_r):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001782 self.assertEqual(api_r.sw_if_index, cfg_r["sw_if_index"])
1783 self.assertEqual(api_r.addr, ip_address(cfg_r["addr"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001784
1785 def verify_transforms(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001786 self.assertEqual(api_ts.crypto_alg, cfg_ts["crypto_alg"])
1787 self.assertEqual(api_ts.crypto_key_size, cfg_ts["crypto_key_size"])
1788 self.assertEqual(api_ts.integ_alg, cfg_ts["integ_alg"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001789
1790 def verify_ike_transforms(self, api_ts, cfg_ts):
1791 self.verify_transforms(api_ts, cfg_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001792 self.assertEqual(api_ts.dh_group, cfg_ts["dh_group"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001793
1794 def verify_esp_transforms(self, api_ts, cfg_ts):
1795 self.verify_transforms(api_ts, cfg_ts)
1796
1797 def verify_auth(self, api_auth, cfg_auth):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001798 self.assertEqual(api_auth.method, AuthMethod.value(cfg_auth["method"]))
1799 self.assertEqual(api_auth.data, cfg_auth["data"])
1800 self.assertEqual(api_auth.data_len, len(cfg_auth["data"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001801
1802 def verify_lifetime_data(self, p, ld):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001803 self.assertEqual(p.lifetime, ld["lifetime"])
1804 self.assertEqual(p.lifetime_maxdata, ld["lifetime_maxdata"])
1805 self.assertEqual(p.lifetime_jitter, ld["lifetime_jitter"])
1806 self.assertEqual(p.handover, ld["handover"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001807
1808 def verify_profile(self, ap, cp):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001809 self.assertEqual(ap.name, cp["name"])
1810 self.assertEqual(ap.udp_encap, cp["udp_encap"])
1811 self.verify_id(ap.loc_id, cp["loc_id"])
1812 self.verify_id(ap.rem_id, cp["rem_id"])
1813 self.verify_ts(ap.loc_ts, cp["loc_ts"])
1814 self.verify_ts(ap.rem_ts, cp["rem_ts"])
1815 self.verify_responder(ap.responder, cp["responder"])
1816 self.verify_ike_transforms(ap.ike_ts, cp["ike_ts"])
1817 self.verify_esp_transforms(ap.esp_ts, cp["esp_ts"])
1818 self.verify_auth(ap.auth, cp["auth"])
1819 natt_dis = False if "natt_disabled" not in cp else cp["natt_disabled"]
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001820 self.assertTrue(natt_dis == ap.natt_disabled)
1821
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001822 if "lifetime_data" in cp:
1823 self.verify_lifetime_data(ap, cp["lifetime_data"])
1824 self.assertEqual(ap.ipsec_over_udp_port, cp["ipsec_over_udp_port"])
1825 if "tun_itf" in cp:
1826 self.assertEqual(ap.tun_itf, cp["tun_itf"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001827 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001828 self.assertEqual(ap.tun_itf, 0xFFFFFFFF)
Filip Tehlar459d17b2020-07-06 15:40:08 +00001829
1830
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001831@tag_fixme_vpp_workers
Filip Tehlar027d8132020-12-04 17:38:11 +00001832class TestResponderBehindNAT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001833 """test responder - responder behind NAT"""
Filip Tehlar027d8132020-12-04 17:38:11 +00001834
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001835 IKE_NODE_SUFFIX = "ip4-natt"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001836
Filip Tehlar027d8132020-12-04 17:38:11 +00001837 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001838 self.config_params({"r_natt": True})
Filip Tehlar027d8132020-12-04 17:38:11 +00001839
1840
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001841@tag_fixme_vpp_workers
Filip Tehlar18107c92020-12-01 14:51:09 +00001842class TestInitiatorNATT(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001843 """test ikev2 initiator - NAT traversal (intitiator behind NAT)"""
Filip Tehlar18107c92020-12-01 14:51:09 +00001844
1845 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001846 self.config_params(
1847 {
1848 "i_natt": True,
1849 "is_initiator": False, # seen from test case perspective
1850 # thus vpp is initiator
1851 "responder": {
1852 "sw_if_index": self.pg0.sw_if_index,
1853 "addr": self.pg0.remote_ip4,
1854 },
1855 "ike-crypto": ("AES-GCM-16ICV", 32),
1856 "ike-integ": "NULL",
1857 "ike-dh": "3072MODPgr",
1858 "ike_transforms": {
1859 "crypto_alg": 20, # "aes-gcm-16"
1860 "crypto_key_size": 256,
1861 "dh_group": 15, # "modp-3072"
1862 },
1863 "esp_transforms": {
1864 "crypto_alg": 12, # "aes-cbc"
1865 "crypto_key_size": 256,
1866 # "hmac-sha2-256-128"
1867 "integ_alg": 12,
1868 },
1869 }
1870 )
Filip Tehlar18107c92020-12-01 14:51:09 +00001871
1872
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001873@tag_fixme_vpp_workers
Filip Tehlare7c83962020-09-23 11:20:12 +00001874class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001875 """test ikev2 initiator - pre shared key auth"""
Filip Tehlaredf29002020-10-10 04:39:11 +00001876
Filip Tehlare7c83962020-09-23 11:20:12 +00001877 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001878 self.config_params(
1879 {
1880 "is_initiator": False, # seen from test case perspective
1881 # thus vpp is initiator
1882 "ike-crypto": ("AES-GCM-16ICV", 32),
1883 "ike-integ": "NULL",
1884 "ike-dh": "3072MODPgr",
1885 "ike_transforms": {
1886 "crypto_alg": 20, # "aes-gcm-16"
1887 "crypto_key_size": 256,
1888 "dh_group": 15, # "modp-3072"
1889 },
1890 "esp_transforms": {
1891 "crypto_alg": 12, # "aes-cbc"
1892 "crypto_key_size": 256,
1893 # "hmac-sha2-256-128"
1894 "integ_alg": 12,
1895 },
1896 "responder_hostname": {
1897 "hostname": "vpp.responder.org",
1898 "sw_if_index": self.pg0.sw_if_index,
1899 },
1900 }
1901 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001902
1903
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001904@tag_fixme_vpp_workers
Filip Tehlar38340fa2020-11-19 21:34:48 +00001905class TestInitiatorRequestWindowSize(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001906 """test initiator - request window size (1)"""
Filip Tehlar38340fa2020-11-19 21:34:48 +00001907
1908 def rekey_respond(self, req, update_child_sa_data):
1909 ih = self.get_ike_header(req)
1910 plain = self.sa.hmac_and_decrypt(ih)
1911 sa = ikev2.IKEv2_payload_SA(plain)
1912 if update_child_sa_data:
1913 prop = sa[ikev2.IKEv2_payload_Proposal]
1914 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
1915 self.sa.r_nonce = self.sa.i_nonce
1916 self.sa.child_sas[0].ispi = prop.SPI
1917 self.sa.child_sas[0].rspi = prop.SPI
1918 self.sa.calc_child_keys()
1919
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001920 header = ikev2.IKEv2(
1921 init_SPI=self.sa.ispi,
1922 resp_SPI=self.sa.rspi,
1923 flags="Response",
1924 exch_type=36,
1925 id=ih.id,
1926 next_payload="Encrypted",
1927 )
1928 resp = self.encrypt_ike_msg(header, sa, "SA")
1929 packet = self.create_packet(
1930 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1931 )
Filip Tehlar38340fa2020-11-19 21:34:48 +00001932 self.send_and_assert_no_replies(self.pg0, packet)
1933
1934 def test_initiator(self):
1935 super(TestInitiatorRequestWindowSize, self).test_initiator()
1936 self.pg0.enable_capture()
1937 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001938 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar38340fa2020-11-19 21:34:48 +00001939 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1940 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1941 capture = self.pg0.get_capture(2)
1942
1943 # reply in reverse order
1944 self.rekey_respond(capture[1], True)
1945 self.rekey_respond(capture[0], False)
1946
1947 # verify that only the second request was accepted
1948 self.verify_ike_sas()
1949 self.verify_ipsec_sas(is_rekey=True)
1950
1951
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001952@tag_fixme_vpp_workers
Filip Tehlar68ad6252020-10-30 05:28:11 +00001953class TestInitiatorRekey(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001954 """test ikev2 initiator - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00001955
1956 def rekey_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001957 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar68ad6252020-10-30 05:28:11 +00001958 self.pg0.enable_capture()
1959 self.pg_start()
1960 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1961 capture = self.pg0.get_capture(1)
1962 ih = self.get_ike_header(capture[0])
1963 self.assertEqual(ih.exch_type, 36) # CHILD_SA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001964 self.assertNotIn("Response", ih.flags)
1965 self.assertIn("Initiator", ih.flags)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001966 plain = self.sa.hmac_and_decrypt(ih)
1967 sa = ikev2.IKEv2_payload_SA(plain)
1968 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00001969 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
1970 self.sa.r_nonce = self.sa.i_nonce
1971 # update new responder SPI
1972 self.sa.child_sas[0].ispi = prop.SPI
1973 self.sa.child_sas[0].rspi = prop.SPI
1974 self.sa.calc_child_keys()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001975 header = ikev2.IKEv2(
1976 init_SPI=self.sa.ispi,
1977 resp_SPI=self.sa.rspi,
1978 flags="Response",
1979 exch_type=36,
1980 id=ih.id,
1981 next_payload="Encrypted",
1982 )
1983 resp = self.encrypt_ike_msg(header, sa, "SA")
1984 packet = self.create_packet(
1985 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1986 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001987 self.send_and_assert_no_replies(self.pg0, packet)
1988
1989 def test_initiator(self):
1990 super(TestInitiatorRekey, self).test_initiator()
1991 self.rekey_from_initiator()
1992 self.verify_ike_sas()
1993 self.verify_ipsec_sas(is_rekey=True)
1994
1995
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001996@tag_fixme_vpp_workers
Filip Tehlaredf29002020-10-10 04:39:11 +00001997class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001998 """test ikev2 initiator - delete IKE SA from responder"""
Filip Tehlaredf29002020-10-10 04:39:11 +00001999
2000 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002001 self.config_params(
2002 {
2003 "del_sa_from_responder": True,
2004 "is_initiator": False, # seen from test case perspective
2005 # thus vpp is initiator
2006 "responder": {
2007 "sw_if_index": self.pg0.sw_if_index,
2008 "addr": self.pg0.remote_ip4,
2009 },
2010 "ike-crypto": ("AES-GCM-16ICV", 32),
2011 "ike-integ": "NULL",
2012 "ike-dh": "3072MODPgr",
2013 "ike_transforms": {
2014 "crypto_alg": 20, # "aes-gcm-16"
2015 "crypto_key_size": 256,
2016 "dh_group": 15, # "modp-3072"
2017 },
2018 "esp_transforms": {
2019 "crypto_alg": 12, # "aes-cbc"
2020 "crypto_key_size": 256,
2021 # "hmac-sha2-256-128"
2022 "integ_alg": 12,
2023 },
2024 "no_idr_in_auth": True,
2025 }
2026 )
Filip Tehlaredf29002020-10-10 04:39:11 +00002027
2028
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002029@tag_fixme_vpp_workers
Filip Tehlar027d8132020-12-04 17:38:11 +00002030class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002031 """test ikev2 responder - initiator behind NAT"""
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002032
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002033 IKE_NODE_SUFFIX = "ip4-natt"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002034
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002035 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002036 self.config_params({"i_natt": True})
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002037
2038
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002039@tag_fixme_vpp_workers
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002040class TestResponderPsk(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002041 """test ikev2 responder - pre shared key auth"""
2042
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002043 def config_tc(self):
2044 self.config_params()
2045
2046
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002047@tag_fixme_vpp_workers
Filip Tehlar2008e312020-11-09 13:23:24 +00002048class TestResponderDpd(TestResponderPsk):
2049 """
2050 Dead peer detection test
2051 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002052
Filip Tehlar2008e312020-11-09 13:23:24 +00002053 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002054 self.config_params({"dpd_disabled": False})
Filip Tehlar2008e312020-11-09 13:23:24 +00002055
2056 def tearDown(self):
2057 pass
2058
2059 def test_responder(self):
2060 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2061 super(TestResponderDpd, self).test_responder()
2062 self.pg0.enable_capture()
2063 self.pg_start()
2064 # capture empty request but don't reply
2065 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2066 ih = self.get_ike_header(capture[0])
2067 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2068 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002069 self.assertEqual(plain, b"")
Filip Tehlar2008e312020-11-09 13:23:24 +00002070 # wait for SA expiration
2071 time.sleep(3)
2072 ike_sas = self.vapi.ikev2_sa_dump()
2073 self.assertEqual(len(ike_sas), 0)
2074 ipsec_sas = self.vapi.ipsec_sa_dump()
2075 self.assertEqual(len(ipsec_sas), 0)
2076
2077
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002078@tag_fixme_vpp_workers
Filip Tehlar68ad6252020-10-30 05:28:11 +00002079class TestResponderRekey(TestResponderPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002080 """test ikev2 responder - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00002081
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002082 def send_rekey_from_initiator(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002083 packet = self.create_rekey_request()
Filip Tehlar68ad6252020-10-30 05:28:11 +00002084 self.pg0.add_stream(packet)
2085 self.pg0.enable_capture()
2086 self.pg_start()
2087 capture = self.pg0.get_capture(1)
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002088 return capture
2089
2090 def process_rekey_response(self, capture):
Filip Tehlar68ad6252020-10-30 05:28:11 +00002091 ih = self.get_ike_header(capture[0])
2092 plain = self.sa.hmac_and_decrypt(ih)
2093 sa = ikev2.IKEv2_payload_SA(plain)
2094 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00002095 self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2096 # update new responder SPI
2097 self.sa.child_sas[0].rspi = prop.SPI
2098
2099 def test_responder(self):
2100 super(TestResponderRekey, self).test_responder()
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002101 self.process_rekey_response(self.send_rekey_from_initiator())
Filip Tehlar68ad6252020-10-30 05:28:11 +00002102 self.sa.calc_child_keys()
2103 self.verify_ike_sas()
2104 self.verify_ipsec_sas(is_rekey=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002105 self.assert_counter(1, "rekey_req", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002106 r = self.vapi.ikev2_sa_dump()
2107 self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002108
2109
Atzm Watanabe7e6ffba2022-08-09 14:00:03 +09002110@tag_fixme_vpp_workers
2111class TestResponderRekeyRepeat(TestResponderRekey):
2112 """test ikev2 responder - rekey repeat"""
2113
2114 def test_responder(self):
2115 super(TestResponderRekeyRepeat, self).test_responder()
2116 # rekey request is not accepted until old IPsec SA is expired
2117 capture = self.send_rekey_from_initiator()
2118 ih = self.get_ike_header(capture[0])
2119 plain = self.sa.hmac_and_decrypt(ih)
2120 notify = ikev2.IKEv2_payload_Notify(plain)
2121 self.assertEqual(notify.type, 43)
2122 self.assertEqual(len(self.vapi.ipsec_sa_dump()), 3)
2123 # rekey request is accepted after old IPsec SA was expired
2124 for _ in range(50):
2125 if len(self.vapi.ipsec_sa_dump()) != 3:
2126 break
2127 time.sleep(0.2)
2128 else:
2129 self.fail("old IPsec SA not expired")
2130 self.process_rekey_response(self.send_rekey_from_initiator())
2131 self.sa.calc_child_keys()
2132 self.verify_ike_sas()
2133 self.verify_ipsec_sas(sa_count=3)
2134
2135
Filip Tehlard28196f2021-01-27 18:08:21 +00002136class TestResponderVrf(TestResponderPsk, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002137 """test ikev2 responder - non-default table id"""
Filip Tehlard28196f2021-01-27 18:08:21 +00002138
2139 @classmethod
2140 def setUpClass(cls):
2141 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002142
2143 globals()["ikev2"] = _ikev2
Filip Tehlard28196f2021-01-27 18:08:21 +00002144 super(IkePeer, cls).setUpClass()
2145 cls.create_pg_interfaces(range(1))
2146 cls.vapi.cli("ip table add 1")
2147 cls.vapi.cli("set interface ip table pg0 1")
2148 for i in cls.pg_interfaces:
2149 i.admin_up()
2150 i.config_ip4()
2151 i.resolve_arp()
2152 i.config_ip6()
2153 i.resolve_ndp()
2154
2155 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002156 self.config_params({"dpd_disabled": False})
Filip Tehlard28196f2021-01-27 18:08:21 +00002157
2158 def test_responder(self):
2159 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2160 super(TestResponderVrf, self).test_responder()
2161 self.pg0.enable_capture()
2162 self.pg_start()
2163 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2164 ih = self.get_ike_header(capture[0])
2165 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2166 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002167 self.assertEqual(plain, b"")
Filip Tehlard28196f2021-01-27 18:08:21 +00002168
2169
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002170@tag_fixme_vpp_workers
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002171class TestResponderRsaSign(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002172 """test ikev2 responder - cert based auth"""
2173
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002174 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002175 self.config_params(
2176 {
2177 "udp_encap": True,
2178 "auth": "rsa-sig",
2179 "server-key": "server-key.pem",
2180 "client-key": "client-key.pem",
2181 "client-cert": "client-cert.pem",
2182 "server-cert": "server-cert.pem",
2183 }
2184 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002185
Filip Tehlar4f42a712020-07-01 08:56:59 +00002186
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002187@tag_fixme_vpp_workers
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002188class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
2189 TemplateResponder, Ikev2Params
2190):
Filip Tehlar4f42a712020-07-01 08:56:59 +00002191 """
2192 IKE:AES_CBC_128_SHA256_128,DH=modp2048 ESP:AES_CBC_192_SHA_384_192
2193 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002194
Filip Tehlar4f42a712020-07-01 08:56:59 +00002195 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002196 self.config_params(
2197 {
2198 "ike-crypto": ("AES-CBC", 16),
2199 "ike-integ": "SHA2-256-128",
2200 "esp-crypto": ("AES-CBC", 24),
2201 "esp-integ": "SHA2-384-192",
2202 "ike-dh": "2048MODPgr",
2203 "nonce": os.urandom(256),
2204 "no_idr_in_auth": True,
2205 }
2206 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002207
2208
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002209@tag_fixme_vpp_workers
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002210class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
2211 TemplateResponder, Ikev2Params
2212):
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002213
Filip Tehlar4f42a712020-07-01 08:56:59 +00002214 """
2215 IKE:AES_CBC_128_SHA256_128,DH=modp3072 ESP:AES_GCM_16
2216 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002217
Filip Tehlar4f42a712020-07-01 08:56:59 +00002218 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002219 self.config_params(
2220 {
2221 "ike-crypto": ("AES-CBC", 32),
2222 "ike-integ": "SHA2-256-128",
2223 "esp-crypto": ("AES-GCM-16ICV", 32),
2224 "esp-integ": "NULL",
2225 "ike-dh": "3072MODPgr",
2226 }
2227 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002228
2229
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002230@tag_fixme_vpp_workers
Filip Tehlara7b963d2020-07-08 13:25:34 +00002231class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
2232 """
2233 IKE:AES_GCM_16_256
2234 """
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002235
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002236 IKE_NODE_SUFFIX = "ip6"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002237
Filip Tehlara7b963d2020-07-08 13:25:34 +00002238 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002239 self.config_params(
2240 {
2241 "del_sa_from_responder": True,
2242 "ip6": True,
2243 "natt": True,
2244 "ike-crypto": ("AES-GCM-16ICV", 32),
2245 "ike-integ": "NULL",
2246 "ike-dh": "2048MODPgr",
2247 "loc_ts": {"start_addr": "ab:cd::0", "end_addr": "ab:cd::10"},
2248 "rem_ts": {"start_addr": "11::0", "end_addr": "11::100"},
2249 }
2250 )
Filip Tehlara7b963d2020-07-08 13:25:34 +00002251
2252
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002253@tag_fixme_vpp_workers
Filip Tehlar2008e312020-11-09 13:23:24 +00002254class TestInitiatorKeepaliveMsg(TestInitiatorPsk):
2255 """
2256 Test for keep alive messages
2257 """
2258
2259 def send_empty_req_from_responder(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002260 packet = self.create_empty_request()
Filip Tehlar2008e312020-11-09 13:23:24 +00002261 self.pg0.add_stream(packet)
2262 self.pg0.enable_capture()
2263 self.pg_start()
2264 capture = self.pg0.get_capture(1)
2265 ih = self.get_ike_header(capture[0])
2266 self.assertEqual(ih.id, self.sa.msg_id)
2267 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002268 self.assertEqual(plain, b"")
2269 self.assert_counter(1, "keepalive", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002270 r = self.vapi.ikev2_sa_dump()
2271 self.assertEqual(1, r[0].sa.stats.n_keepalives)
Filip Tehlar2008e312020-11-09 13:23:24 +00002272
2273 def test_initiator(self):
2274 super(TestInitiatorKeepaliveMsg, self).test_initiator()
2275 self.send_empty_req_from_responder()
2276
2277
Filip Tehlar558607d2020-07-16 07:25:56 +00002278class TestMalformedMessages(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002279 """malformed packet test"""
Filip Tehlar558607d2020-07-16 07:25:56 +00002280
2281 def tearDown(self):
2282 pass
2283
2284 def config_tc(self):
2285 self.config_params()
2286
Filip Tehlar558607d2020-07-16 07:25:56 +00002287 def create_ike_init_msg(self, length=None, payload=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002288 msg = ikev2.IKEv2(
2289 length=length,
2290 init_SPI="\x11" * 8,
2291 flags="Initiator",
2292 exch_type="IKE_SA_INIT",
2293 )
Filip Tehlar558607d2020-07-16 07:25:56 +00002294 if payload is not None:
2295 msg /= payload
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002296 return self.create_packet(self.pg0, msg, self.sa.sport, self.sa.dport)
Filip Tehlar558607d2020-07-16 07:25:56 +00002297
2298 def verify_bad_packet_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002299 ike_msg = self.create_ike_init_msg(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002300 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002301 self.assert_counter(self.pkt_count, "bad_length")
Filip Tehlar558607d2020-07-16 07:25:56 +00002302
2303 def verify_bad_sa_payload_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002304 p = ikev2.IKEv2_payload_SA(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002305 ike_msg = self.create_ike_init_msg(payload=p)
2306 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002307 self.assert_counter(self.pkt_count, "malformed_packet")
Filip Tehlar558607d2020-07-16 07:25:56 +00002308
2309 def test_responder(self):
2310 self.pkt_count = 254
2311 self.verify_bad_packet_length()
2312 self.verify_bad_sa_payload_length()
2313
2314
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002315if __name__ == "__main__":
Filip Tehlar12b517b2020-04-26 18:05:05 +00002316 unittest.main(testRunner=VppTestRunner)