blob: ac77a4163a1199178b171209336d4534c53ed6a6 [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
Filip Tehlar68ad6252020-10-30 05:28:11 +0000755 def verify_ipsec_sas(self, is_rekey=False):
Filip Tehlar12b517b2020-04-26 18:05:05 +0000756 sas = self.vapi.ipsec_sa_dump()
Filip Tehlar68ad6252020-10-30 05:28:11 +0000757 if is_rekey:
758 # after rekey there is a short period of time in which old
759 # inbound SA is still present
760 sa_count = 3
761 else:
762 sa_count = 2
763 self.assertEqual(len(sas), sa_count)
Filip Tehlare7c83962020-09-23 11:20:12 +0000764 if self.sa.is_initiator:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000765 if is_rekey:
766 sa0 = sas[0].entry
767 sa1 = sas[2].entry
768 else:
769 sa0 = sas[0].entry
770 sa1 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000771 else:
Filip Tehlar68ad6252020-10-30 05:28:11 +0000772 if is_rekey:
773 sa0 = sas[2].entry
774 sa1 = sas[0].entry
775 else:
776 sa1 = sas[0].entry
777 sa0 = sas[1].entry
Filip Tehlare7c83962020-09-23 11:20:12 +0000778
Filip Tehlar12b517b2020-04-26 18:05:05 +0000779 c = self.sa.child_sas[0]
780
Filip Tehlar67b8a7f2020-11-06 11:00:42 +0000781 self.verify_udp_encap(sa0)
782 self.verify_udp_encap(sa1)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000783 vpp_crypto_alg = self.vpp_enums[self.sa.vpp_esp_cypto_alg]
784 self.assertEqual(sa0.crypto_algorithm, vpp_crypto_alg)
785 self.assertEqual(sa1.crypto_algorithm, vpp_crypto_alg)
786
787 if self.sa.esp_integ is None:
788 vpp_integ_alg = 0
789 else:
790 vpp_integ_alg = self.vpp_enums[self.sa.esp_integ]
791 self.assertEqual(sa0.integrity_algorithm, vpp_integ_alg)
792 self.assertEqual(sa1.integrity_algorithm, vpp_integ_alg)
793
Filip Tehlar12b517b2020-04-26 18:05:05 +0000794 # verify crypto keys
795 self.assertEqual(sa0.crypto_key.length, len(c.sk_er))
796 self.assertEqual(sa1.crypto_key.length, len(c.sk_ei))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200797 self.assertEqual(sa0.crypto_key.data[: len(c.sk_er)], c.sk_er)
798 self.assertEqual(sa1.crypto_key.data[: len(c.sk_ei)], c.sk_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000799
800 # verify integ keys
Filip Tehlar4f42a712020-07-01 08:56:59 +0000801 if vpp_integ_alg:
802 self.assertEqual(sa0.integrity_key.length, len(c.sk_ar))
803 self.assertEqual(sa1.integrity_key.length, len(c.sk_ai))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200804 self.assertEqual(sa0.integrity_key.data[: len(c.sk_ar)], c.sk_ar)
805 self.assertEqual(sa1.integrity_key.data[: len(c.sk_ai)], c.sk_ai)
Filip Tehlar4f42a712020-07-01 08:56:59 +0000806 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200807 self.assertEqual(sa0.salt.to_bytes(4, "little"), c.salt_er)
808 self.assertEqual(sa1.salt.to_bytes(4, "little"), c.salt_ei)
Filip Tehlar12b517b2020-04-26 18:05:05 +0000809
jan_cavojskya340fe12020-07-08 09:24:12 +0200810 def verify_keymat(self, api_keys, keys, name):
811 km = getattr(keys, name)
812 api_km = getattr(api_keys, name)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200813 api_km_len = getattr(api_keys, name + "_len")
jan_cavojskya340fe12020-07-08 09:24:12 +0200814 self.assertEqual(len(km), api_km_len)
815 self.assertEqual(km, api_km[:api_km_len])
816
817 def verify_id(self, api_id, exp_id):
818 self.assertEqual(api_id.type, IDType.value(exp_id.type))
819 self.assertEqual(api_id.data_len, exp_id.data_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200820 self.assertEqual(bytes(api_id.data, "ascii"), exp_id.type)
jan_cavojskya340fe12020-07-08 09:24:12 +0200821
822 def verify_ike_sas(self):
823 r = self.vapi.ikev2_sa_dump()
824 self.assertEqual(len(r), 1)
825 sa = r[0].sa
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200826 self.assertEqual(self.sa.ispi, (sa.ispi).to_bytes(8, "big"))
827 self.assertEqual(self.sa.rspi, (sa.rspi).to_bytes(8, "big"))
Filip Tehlar84962d12020-09-08 06:08:05 +0000828 if self.ip6:
Filip Tehlare7c83962020-09-23 11:20:12 +0000829 if self.sa.is_initiator:
830 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.remote_ip6))
831 self.assertEqual(sa.raddr, IPv6Address(self.pg0.local_ip6))
832 else:
833 self.assertEqual(sa.iaddr, IPv6Address(self.pg0.local_ip6))
834 self.assertEqual(sa.raddr, IPv6Address(self.pg0.remote_ip6))
Filip Tehlar84962d12020-09-08 06:08:05 +0000835 else:
Filip Tehlare7c83962020-09-23 11:20:12 +0000836 if self.sa.is_initiator:
837 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.remote_ip4))
838 self.assertEqual(sa.raddr, IPv4Address(self.pg0.local_ip4))
839 else:
840 self.assertEqual(sa.iaddr, IPv4Address(self.pg0.local_ip4))
841 self.assertEqual(sa.raddr, IPv4Address(self.pg0.remote_ip4))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200842 self.verify_keymat(sa.keys, self.sa, "sk_d")
843 self.verify_keymat(sa.keys, self.sa, "sk_ai")
844 self.verify_keymat(sa.keys, self.sa, "sk_ar")
845 self.verify_keymat(sa.keys, self.sa, "sk_ei")
846 self.verify_keymat(sa.keys, self.sa, "sk_er")
847 self.verify_keymat(sa.keys, self.sa, "sk_pi")
848 self.verify_keymat(sa.keys, self.sa, "sk_pr")
jan_cavojskya340fe12020-07-08 09:24:12 +0200849
850 self.assertEqual(sa.i_id.type, self.sa.id_type)
851 self.assertEqual(sa.r_id.type, self.sa.id_type)
852 self.assertEqual(sa.i_id.data_len, len(self.sa.i_id))
Benoît Gannec7cceee2021-09-28 11:19:37 +0200853 self.assertEqual(sa.r_id.data_len, len(self.idr))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200854 self.assertEqual(bytes(sa.i_id.data, "ascii"), self.sa.i_id)
855 self.assertEqual(bytes(sa.r_id.data, "ascii"), self.idr)
jan_cavojskya340fe12020-07-08 09:24:12 +0200856
857 r = self.vapi.ikev2_child_sa_dump(sa_index=sa.sa_index)
858 self.assertEqual(len(r), 1)
859 csa = r[0].child_sa
860 self.assertEqual(csa.sa_index, sa.sa_index)
861 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200862 if hasattr(c, "sk_ai"):
863 self.verify_keymat(csa.keys, c, "sk_ai")
864 self.verify_keymat(csa.keys, c, "sk_ar")
865 self.verify_keymat(csa.keys, c, "sk_ei")
866 self.verify_keymat(csa.keys, c, "sk_er")
867 self.assertEqual(csa.i_spi.to_bytes(4, "big"), c.ispi)
868 self.assertEqual(csa.r_spi.to_bytes(4, "big"), c.rspi)
jan_cavojskya340fe12020-07-08 09:24:12 +0200869
Filip Tehlar84962d12020-09-08 06:08:05 +0000870 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
jan_cavojskya340fe12020-07-08 09:24:12 +0200871 tsi = tsi[0]
872 tsr = tsr[0]
873 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200874 is_initiator=True, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
875 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200876 self.assertEqual(len(r), 1)
877 ts = r[0].ts
878 self.verify_ts(r[0].ts, tsi[0], True)
879
880 r = self.vapi.ikev2_traffic_selector_dump(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200881 is_initiator=False, sa_index=sa.sa_index, child_sa_index=csa.child_sa_index
882 )
jan_cavojskya340fe12020-07-08 09:24:12 +0200883 self.assertEqual(len(r), 1)
884 self.verify_ts(r[0].ts, tsr[0], False)
885
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200886 n = self.vapi.ikev2_nonce_get(is_initiator=True, sa_index=sa.sa_index)
jan_cavojskya340fe12020-07-08 09:24:12 +0200887 self.verify_nonce(n, self.sa.i_nonce)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200888 n = self.vapi.ikev2_nonce_get(is_initiator=False, sa_index=sa.sa_index)
jan_cavojskya340fe12020-07-08 09:24:12 +0200889 self.verify_nonce(n, self.sa.r_nonce)
890
891 def verify_nonce(self, api_nonce, nonce):
892 self.assertEqual(api_nonce.data_len, len(nonce))
893 self.assertEqual(api_nonce.nonce, nonce)
894
895 def verify_ts(self, api_ts, ts, is_initiator):
896 if is_initiator:
897 self.assertTrue(api_ts.is_local)
898 else:
899 self.assertFalse(api_ts.is_local)
Filip Tehlar84962d12020-09-08 06:08:05 +0000900
901 if self.p.ts_is_ip4:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200902 self.assertEqual(api_ts.start_addr, IPv4Address(ts.starting_address_v4))
903 self.assertEqual(api_ts.end_addr, IPv4Address(ts.ending_address_v4))
Filip Tehlar84962d12020-09-08 06:08:05 +0000904 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200905 self.assertEqual(api_ts.start_addr, IPv6Address(ts.starting_address_v6))
906 self.assertEqual(api_ts.end_addr, IPv6Address(ts.ending_address_v6))
jan_cavojskya340fe12020-07-08 09:24:12 +0200907 self.assertEqual(api_ts.start_port, ts.start_port)
908 self.assertEqual(api_ts.end_port, ts.end_port)
909 self.assertEqual(api_ts.protocol_id, ts.IP_protocol_ID)
910
Filip Tehlare7c83962020-09-23 11:20:12 +0000911
912class TemplateInitiator(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200913 """initiator test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +0000914
Filip Tehlaredf29002020-10-10 04:39:11 +0000915 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200916 ispi = int.from_bytes(self.sa.ispi, "little")
Filip Tehlaredf29002020-10-10 04:39:11 +0000917 self.pg0.enable_capture()
918 self.pg_start()
919 self.vapi.ikev2_initiate_del_ike_sa(ispi=ispi)
920 capture = self.pg0.get_capture(1)
921 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200922 self.assertNotIn("Response", ih.flags)
923 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +0000924 self.assertEqual(ih.init_SPI, self.sa.ispi)
925 self.assertEqual(ih.resp_SPI, self.sa.rspi)
926 plain = self.sa.hmac_and_decrypt(ih)
927 d = ikev2.IKEv2_payload_Delete(plain)
928 self.assertEqual(d.proto, 1) # proto=IKEv2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200929 header = ikev2.IKEv2(
930 init_SPI=self.sa.ispi,
931 resp_SPI=self.sa.rspi,
932 flags="Response",
933 exch_type="INFORMATIONAL",
934 id=ih.id,
935 next_payload="Encrypted",
936 )
937 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +0000938 self.send_and_assert_no_replies(self.pg0, resp)
939
940 def verify_del_sa(self, packet):
941 ih = self.get_ike_header(packet)
942 self.assertEqual(ih.id, self.sa.msg_id)
943 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200944 self.assertIn("Response", ih.flags)
945 self.assertIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +0000946 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200947 self.assertEqual(plain, b"")
Filip Tehlaredf29002020-10-10 04:39:11 +0000948
949 def initiate_del_sa_from_responder(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200950 header = ikev2.IKEv2(
951 init_SPI=self.sa.ispi,
952 resp_SPI=self.sa.rspi,
953 exch_type="INFORMATIONAL",
954 id=self.sa.new_msg_id(),
955 )
956 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
957 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
958 packet = self.create_packet(
959 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
960 )
Filip Tehlaredf29002020-10-10 04:39:11 +0000961 self.pg0.add_stream(packet)
962 self.pg0.enable_capture()
963 self.pg_start()
964 capture = self.pg0.get_capture(1)
965 self.verify_del_sa(capture[0])
Filip Tehlare7c83962020-09-23 11:20:12 +0000966
Filip Tehlarec112e52020-10-07 23:52:37 +0000967 @staticmethod
968 def find_notify_payload(packet, notify_type):
969 n = packet[ikev2.IKEv2_payload_Notify]
970 while n is not None:
971 if n.type == notify_type:
972 return n
973 n = n.payload
974 return None
975
976 def verify_nat_detection(self, packet):
977 if self.ip6:
978 iph = packet[IPv6]
979 else:
980 iph = packet[IP]
981 udp = packet[UDP]
982
983 # NAT_DETECTION_SOURCE_IP
984 s = self.find_notify_payload(packet, 16388)
985 self.assertIsNotNone(s)
986 src_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200987 inet_pton(socket.AF_INET, iph.src), udp.sport, b"\x00" * 8
988 )
Filip Tehlarec112e52020-10-07 23:52:37 +0000989 self.assertEqual(s.load, src_sha)
990
991 # NAT_DETECTION_DESTINATION_IP
992 s = self.find_notify_payload(packet, 16389)
993 self.assertIsNotNone(s)
994 dst_sha = self.sa.compute_nat_sha1(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200995 inet_pton(socket.AF_INET, iph.dst), udp.dport, b"\x00" * 8
996 )
Filip Tehlarec112e52020-10-07 23:52:37 +0000997 self.assertEqual(s.load, dst_sha)
998
Filip Tehlare7c83962020-09-23 11:20:12 +0000999 def verify_sa_init_request(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001000 udp = packet[UDP]
1001 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001002 ih = packet[ikev2.IKEv2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001003 self.assertNotEqual(ih.init_SPI, 8 * b"\x00")
Filip Tehlare7c83962020-09-23 11:20:12 +00001004 self.assertEqual(ih.exch_type, 34) # SA_INIT
1005 self.sa.ispi = ih.init_SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001006 self.assertEqual(ih.resp_SPI, 8 * b"\x00")
1007 self.assertIn("Initiator", ih.flags)
1008 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001009 self.sa.i_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1010 self.sa.i_dh_data = ih[ikev2.IKEv2_payload_KE].load
1011
1012 prop = packet[ikev2.IKEv2_payload_Proposal]
1013 self.assertEqual(prop.proto, 1) # proto = ikev2
1014 self.assertEqual(prop.proposal, 1)
1015 self.assertEqual(prop.trans[0].transform_type, 1) # encryption
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001016 self.assertEqual(
1017 prop.trans[0].transform_id, self.p.ike_transforms["crypto_alg"]
1018 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001019 self.assertEqual(prop.trans[1].transform_type, 2) # prf
1020 self.assertEqual(prop.trans[1].transform_id, 5) # "hmac-sha2-256"
1021 self.assertEqual(prop.trans[2].transform_type, 4) # dh
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001022 self.assertEqual(prop.trans[2].transform_id, self.p.ike_transforms["dh_group"])
Filip Tehlare7c83962020-09-23 11:20:12 +00001023
Filip Tehlarec112e52020-10-07 23:52:37 +00001024 self.verify_nat_detection(packet)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001025 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001026 crypto="AES-GCM-16ICV",
1027 crypto_key_len=32,
1028 integ="NULL",
1029 prf="PRF_HMAC_SHA2_256",
1030 dh="3072MODPgr",
1031 )
1032 self.sa.set_esp_props(crypto="AES-CBC", crypto_key_len=32, integ="SHA2-256-128")
Filip Tehlar68ad6252020-10-30 05:28:11 +00001033 self.sa.generate_dh_data()
Filip Tehlare7c83962020-09-23 11:20:12 +00001034 self.sa.complete_dh_data()
1035 self.sa.calc_keys()
1036
Filip Tehlar68ad6252020-10-30 05:28:11 +00001037 def update_esp_transforms(self, trans, sa):
1038 while trans:
1039 if trans.transform_type == 1: # ecryption
1040 sa.esp_crypto = CRYPTO_IDS[trans.transform_id]
1041 elif trans.transform_type == 3: # integrity
1042 sa.esp_integ = INTEG_IDS[trans.transform_id]
1043 trans = trans.payload
1044
Filip Tehlare7c83962020-09-23 11:20:12 +00001045 def verify_sa_auth_req(self, packet):
Filip Tehlar18107c92020-12-01 14:51:09 +00001046 udp = packet[UDP]
1047 self.sa.dport = udp.sport
Filip Tehlare7c83962020-09-23 11:20:12 +00001048 ih = self.get_ike_header(packet)
1049 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1050 self.assertEqual(ih.init_SPI, self.sa.ispi)
1051 self.assertEqual(ih.exch_type, 35) # IKE_AUTH
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001052 self.assertIn("Initiator", ih.flags)
1053 self.assertNotIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001054
1055 udp = packet[UDP]
1056 self.verify_udp(udp)
1057 self.assertEqual(ih.id, self.sa.msg_id + 1)
1058 self.sa.msg_id += 1
1059 plain = self.sa.hmac_and_decrypt(ih)
1060 idi = ikev2.IKEv2_payload_IDi(plain)
Filip Tehlare7c83962020-09-23 11:20:12 +00001061 self.assertEqual(idi.load, self.sa.i_id)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001062 if self.no_idr_auth:
1063 self.assertEqual(idi.next_payload, 39) # AUTH
1064 else:
1065 idr = ikev2.IKEv2_payload_IDr(idi.payload)
1066 self.assertEqual(idr.load, self.sa.r_id)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001067 prop = idi[ikev2.IKEv2_payload_Proposal]
1068 c = self.sa.child_sas[0]
1069 c.ispi = prop.SPI
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001070 self.update_esp_transforms(prop[ikev2.IKEv2_payload_Transform], self.sa)
Filip Tehlare7c83962020-09-23 11:20:12 +00001071
1072 def send_init_response(self):
1073 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001074 trans = (
1075 ikev2.IKEv2_payload_Transform(
1076 transform_type="Encryption",
1077 transform_id=self.sa.ike_crypto,
1078 length=tr_attr[1],
1079 key_length=tr_attr[0],
1080 )
1081 / ikev2.IKEv2_payload_Transform(
1082 transform_type="Integrity", transform_id=self.sa.ike_integ
1083 )
1084 / ikev2.IKEv2_payload_Transform(
1085 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1086 )
1087 / ikev2.IKEv2_payload_Transform(
1088 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1089 )
1090 )
1091 props = ikev2.IKEv2_payload_Proposal(
1092 proposal=1, proto="IKEv2", trans_nb=4, trans=trans
1093 )
Filip Tehlar18107c92020-12-01 14:51:09 +00001094
1095 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
1096 if self.sa.natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001097 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar18107c92020-12-01 14:51:09 +00001098 else:
1099 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1100 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1101 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1102
Filip Tehlare7c83962020-09-23 11:20:12 +00001103 self.sa.init_resp_packet = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001104 ikev2.IKEv2(
1105 init_SPI=self.sa.ispi,
1106 resp_SPI=self.sa.rspi,
1107 exch_type="IKE_SA_INIT",
1108 flags="Response",
1109 )
1110 / ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
1111 / ikev2.IKEv2_payload_KE(
1112 next_payload="Nonce", group=self.sa.ike_dh, load=self.sa.my_dh_pub_key
1113 )
1114 / ikev2.IKEv2_payload_Nonce(load=self.sa.r_nonce, next_payload="Notify")
1115 / ikev2.IKEv2_payload_Notify(
1116 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1117 )
1118 / ikev2.IKEv2_payload_Notify(
1119 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1120 )
1121 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001122
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001123 ike_msg = self.create_packet(
1124 self.pg0,
1125 self.sa.init_resp_packet,
1126 self.sa.sport,
1127 self.sa.dport,
1128 False,
1129 self.ip6,
1130 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001131 self.pg_send(self.pg0, ike_msg)
1132 capture = self.pg0.get_capture(1)
1133 self.verify_sa_auth_req(capture[0])
1134
1135 def initiate_sa_init(self):
1136 self.pg0.enable_capture()
1137 self.pg_start()
1138 self.vapi.ikev2_initiate_sa_init(name=self.p.profile_name)
1139
1140 capture = self.pg0.get_capture(1)
1141 self.verify_sa_init_request(capture[0])
1142 self.send_init_response()
1143
1144 def send_auth_response(self):
1145 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001146 trans = (
1147 ikev2.IKEv2_payload_Transform(
1148 transform_type="Encryption",
1149 transform_id=self.sa.esp_crypto,
1150 length=tr_attr[1],
1151 key_length=tr_attr[0],
1152 )
1153 / ikev2.IKEv2_payload_Transform(
1154 transform_type="Integrity", transform_id=self.sa.esp_integ
1155 )
1156 / ikev2.IKEv2_payload_Transform(
1157 transform_type="Extended Sequence Number", transform_id="No ESN"
1158 )
1159 / ikev2.IKEv2_payload_Transform(
1160 transform_type="Extended Sequence Number", transform_id="ESN"
1161 )
1162 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001163
Filip Tehlar68ad6252020-10-30 05:28:11 +00001164 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001165 props = ikev2.IKEv2_payload_Proposal(
1166 proposal=1, proto="ESP", SPIsize=4, SPI=c.rspi, trans_nb=4, trans=trans
1167 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001168
1169 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001170 plain = (
1171 ikev2.IKEv2_payload_IDi(
1172 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1173 )
1174 / ikev2.IKEv2_payload_IDr(
1175 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1176 )
1177 / ikev2.IKEv2_payload_AUTH(
1178 next_payload="SA",
1179 auth_type=AuthMethod.value(self.sa.auth_method),
1180 load=self.sa.auth_data,
1181 )
1182 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1183 / ikev2.IKEv2_payload_TSi(
1184 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1185 )
1186 / ikev2.IKEv2_payload_TSr(
1187 next_payload="Notify", number_of_TSs=len(tsr), traffic_selector=tsr
1188 )
1189 / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
1190 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001191
1192 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001193 init_SPI=self.sa.ispi,
1194 resp_SPI=self.sa.rspi,
1195 id=self.sa.new_msg_id(),
1196 flags="Response",
1197 exch_type="IKE_AUTH",
1198 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001199
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001200 ike_msg = self.encrypt_ike_msg(header, plain, "IDi")
1201 packet = self.create_packet(
1202 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1203 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001204 self.pg_send(self.pg0, packet)
1205
1206 def test_initiator(self):
1207 self.initiate_sa_init()
1208 self.sa.auth_init()
1209 self.sa.calc_child_keys()
1210 self.send_auth_response()
1211 self.verify_ike_sas()
1212
1213
1214class TemplateResponder(IkePeer):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001215 """responder test template"""
Filip Tehlare7c83962020-09-23 11:20:12 +00001216
Filip Tehlaredf29002020-10-10 04:39:11 +00001217 def initiate_del_sa_from_responder(self):
1218 self.pg0.enable_capture()
1219 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001220 self.vapi.ikev2_initiate_del_ike_sa(ispi=int.from_bytes(self.sa.ispi, "little"))
Filip Tehlaredf29002020-10-10 04:39:11 +00001221 capture = self.pg0.get_capture(1)
1222 ih = self.get_ike_header(capture[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001223 self.assertNotIn("Response", ih.flags)
1224 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001225 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
1226 plain = self.sa.hmac_and_decrypt(ih)
1227 d = ikev2.IKEv2_payload_Delete(plain)
1228 self.assertEqual(d.proto, 1) # proto=IKEv2
1229 self.assertEqual(ih.init_SPI, self.sa.ispi)
1230 self.assertEqual(ih.resp_SPI, self.sa.rspi)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001231 header = ikev2.IKEv2(
1232 init_SPI=self.sa.ispi,
1233 resp_SPI=self.sa.rspi,
1234 flags="Initiator+Response",
1235 exch_type="INFORMATIONAL",
1236 id=ih.id,
1237 next_payload="Encrypted",
1238 )
1239 resp = self.encrypt_ike_msg(header, b"", None)
Filip Tehlaredf29002020-10-10 04:39:11 +00001240 self.send_and_assert_no_replies(self.pg0, resp)
Filip Tehlare7c83962020-09-23 11:20:12 +00001241
1242 def verify_del_sa(self, packet):
1243 ih = self.get_ike_header(packet)
1244 self.assertEqual(ih.id, self.sa.msg_id)
1245 self.assertEqual(ih.exch_type, 37) # exchange informational
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001246 self.assertIn("Response", ih.flags)
1247 self.assertNotIn("Initiator", ih.flags)
Filip Tehlaredf29002020-10-10 04:39:11 +00001248 self.assertEqual(ih.next_payload, 46) # Encrypted
1249 self.assertEqual(ih.init_SPI, self.sa.ispi)
1250 self.assertEqual(ih.resp_SPI, self.sa.rspi)
1251 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001252 self.assertEqual(plain, b"")
Filip Tehlare7c83962020-09-23 11:20:12 +00001253
Filip Tehlaredf29002020-10-10 04:39:11 +00001254 def initiate_del_sa_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001255 header = ikev2.IKEv2(
1256 init_SPI=self.sa.ispi,
1257 resp_SPI=self.sa.rspi,
1258 flags="Initiator",
1259 exch_type="INFORMATIONAL",
1260 id=self.sa.new_msg_id(),
1261 )
1262 del_sa = ikev2.IKEv2_payload_Delete(proto="IKEv2")
1263 ike_msg = self.encrypt_ike_msg(header, del_sa, "Delete")
1264 packet = self.create_packet(
1265 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1266 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001267 self.pg0.add_stream(packet)
1268 self.pg0.enable_capture()
1269 self.pg_start()
1270 capture = self.pg0.get_capture(1)
1271 self.verify_del_sa(capture[0])
1272
Filip Tehlar027d8132020-12-04 17:38:11 +00001273 def send_sa_init_req(self):
Filip Tehlare7c83962020-09-23 11:20:12 +00001274 tr_attr = self.sa.ike_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001275 trans = (
1276 ikev2.IKEv2_payload_Transform(
1277 transform_type="Encryption",
1278 transform_id=self.sa.ike_crypto,
1279 length=tr_attr[1],
1280 key_length=tr_attr[0],
1281 )
1282 / ikev2.IKEv2_payload_Transform(
1283 transform_type="Integrity", transform_id=self.sa.ike_integ
1284 )
1285 / ikev2.IKEv2_payload_Transform(
1286 transform_type="PRF", transform_id=self.sa.ike_prf_alg.name
1287 )
1288 / ikev2.IKEv2_payload_Transform(
1289 transform_type="GroupDesc", transform_id=self.sa.ike_dh
1290 )
1291 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001292
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001293 props = ikev2.IKEv2_payload_Proposal(
1294 proposal=1, proto="IKEv2", trans_nb=4, trans=trans
1295 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001296
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001297 next_payload = None if self.ip6 else "Notify"
Filip Tehlar027d8132020-12-04 17:38:11 +00001298
Filip Tehlare7c83962020-09-23 11:20:12 +00001299 self.sa.init_req_packet = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001300 ikev2.IKEv2(
1301 init_SPI=self.sa.ispi, flags="Initiator", exch_type="IKE_SA_INIT"
1302 )
1303 / ikev2.IKEv2_payload_SA(next_payload="KE", prop=props)
1304 / ikev2.IKEv2_payload_KE(
1305 next_payload="Nonce", group=self.sa.ike_dh, load=self.sa.my_dh_pub_key
1306 )
1307 / ikev2.IKEv2_payload_Nonce(next_payload=next_payload, load=self.sa.i_nonce)
1308 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001309
Filip Tehlar027d8132020-12-04 17:38:11 +00001310 if not self.ip6:
1311 if self.sa.i_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001312 src_address = b"\x0a\x0a\x0a\x01"
Filip Tehlar027d8132020-12-04 17:38:11 +00001313 else:
1314 src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
Filip Tehlare7c83962020-09-23 11:20:12 +00001315
Filip Tehlar027d8132020-12-04 17:38:11 +00001316 if self.sa.r_natt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001317 dst_address = b"\x0a\x0a\x0a\x0a"
Filip Tehlar027d8132020-12-04 17:38:11 +00001318 else:
1319 dst_address = inet_pton(socket.AF_INET, self.pg0.local_ip4)
1320
1321 src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
1322 dst_nat = self.sa.compute_nat_sha1(dst_address, self.sa.dport)
1323 nat_src_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001324 type="NAT_DETECTION_SOURCE_IP", load=src_nat, next_payload="Notify"
1325 )
Filip Tehlar027d8132020-12-04 17:38:11 +00001326 nat_dst_detection = ikev2.IKEv2_payload_Notify(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001327 type="NAT_DETECTION_DESTINATION_IP", load=dst_nat
1328 )
1329 self.sa.init_req_packet = (
1330 self.sa.init_req_packet / nat_src_detection / nat_dst_detection
1331 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001332
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001333 ike_msg = self.create_packet(
1334 self.pg0,
1335 self.sa.init_req_packet,
1336 self.sa.sport,
1337 self.sa.dport,
1338 self.sa.natt,
1339 self.ip6,
1340 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001341 self.pg0.add_stream(ike_msg)
1342 self.pg0.enable_capture()
1343 self.pg_start()
1344 capture = self.pg0.get_capture(1)
1345 self.verify_sa_init(capture[0])
1346
Filip Tehlar68ad6252020-10-30 05:28:11 +00001347 def generate_auth_payload(self, last_payload=None, is_rekey=False):
Filip Tehlare7c83962020-09-23 11:20:12 +00001348 tr_attr = self.sa.esp_crypto_attr()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001349 last_payload = last_payload or "Notify"
1350 trans = (
1351 ikev2.IKEv2_payload_Transform(
1352 transform_type="Encryption",
1353 transform_id=self.sa.esp_crypto,
1354 length=tr_attr[1],
1355 key_length=tr_attr[0],
1356 )
1357 / ikev2.IKEv2_payload_Transform(
1358 transform_type="Integrity", transform_id=self.sa.esp_integ
1359 )
1360 / ikev2.IKEv2_payload_Transform(
1361 transform_type="Extended Sequence Number", transform_id="No ESN"
1362 )
1363 / ikev2.IKEv2_payload_Transform(
1364 transform_type="Extended Sequence Number", transform_id="ESN"
1365 )
1366 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001367
Filip Tehlar68ad6252020-10-30 05:28:11 +00001368 c = self.sa.child_sas[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001369 props = ikev2.IKEv2_payload_Proposal(
1370 proposal=1, proto="ESP", SPIsize=4, SPI=c.ispi, trans_nb=4, trans=trans
1371 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001372
1373 tsi, tsr = self.sa.generate_ts(self.p.ts_is_ip4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001374 plain = (
1375 ikev2.IKEv2_payload_AUTH(
1376 next_payload="SA",
1377 auth_type=AuthMethod.value(self.sa.auth_method),
1378 load=self.sa.auth_data,
1379 )
1380 / ikev2.IKEv2_payload_SA(next_payload="TSi", prop=props)
1381 / ikev2.IKEv2_payload_TSi(
1382 next_payload="TSr", number_of_TSs=len(tsi), traffic_selector=tsi
1383 )
1384 / ikev2.IKEv2_payload_TSr(
1385 next_payload=last_payload, number_of_TSs=len(tsr), traffic_selector=tsr
1386 )
1387 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001388
Filip Tehlar68ad6252020-10-30 05:28:11 +00001389 if is_rekey:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001390 first_payload = "Nonce"
1391 plain = (
1392 ikev2.IKEv2_payload_Nonce(load=self.sa.i_nonce, next_payload="SA")
1393 / plain
Atzm Watanabe03aae962022-08-08 15:45:36 +09001394 / ikev2.IKEv2_payload_Notify(
1395 type="REKEY_SA",
1396 proto="ESP",
1397 SPI=c.ispi,
1398 length=8 + len(c.ispi),
1399 next_payload="Notify",
1400 )
1401 / ikev2.IKEv2_payload_Notify(type="ESP_TFC_PADDING_NOT_SUPPORTED")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001402 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001403 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001404 first_payload = "IDi"
Benoît Gannec7cceee2021-09-28 11:19:37 +02001405 if self.no_idr_auth:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001406 ids = ikev2.IKEv2_payload_IDi(
1407 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.i_id
1408 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001409 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001410 ids = ikev2.IKEv2_payload_IDi(
1411 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1412 ) / ikev2.IKEv2_payload_IDr(
1413 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1414 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001415 plain = ids / plain
1416 return plain, first_payload
1417
1418 def send_sa_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001419 plain, first_payload = self.generate_auth_payload(last_payload="Notify")
1420 plain = plain / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
Filip Tehlare7c83962020-09-23 11:20:12 +00001421 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001422 init_SPI=self.sa.ispi,
1423 resp_SPI=self.sa.rspi,
1424 id=self.sa.new_msg_id(),
1425 flags="Initiator",
1426 exch_type="IKE_AUTH",
1427 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001428
Filip Tehlar68ad6252020-10-30 05:28:11 +00001429 ike_msg = self.encrypt_ike_msg(header, plain, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001430 packet = self.create_packet(
1431 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1432 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001433 self.pg0.add_stream(packet)
1434 self.pg0.enable_capture()
1435 self.pg_start()
1436 capture = self.pg0.get_capture(1)
1437 self.verify_sa_auth_resp(capture[0])
1438
1439 def verify_sa_init(self, packet):
1440 ih = self.get_ike_header(packet)
1441
1442 self.assertEqual(ih.id, self.sa.msg_id)
1443 self.assertEqual(ih.exch_type, 34)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001444 self.assertIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001445 self.assertEqual(ih.init_SPI, self.sa.ispi)
1446 self.assertNotEqual(ih.resp_SPI, 0)
1447 self.sa.rspi = ih.resp_SPI
1448 try:
1449 sa = ih[ikev2.IKEv2_payload_SA]
1450 self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1451 self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load
1452 except IndexError as e:
1453 self.logger.error("unexpected reply: SA/Nonce/KE payload found!")
1454 self.logger.error(ih.show())
1455 raise
1456 self.sa.complete_dh_data()
1457 self.sa.calc_keys()
1458 self.sa.auth_init()
1459
1460 def verify_sa_auth_resp(self, packet):
1461 ike = self.get_ike_header(packet)
1462 udp = packet[UDP]
1463 self.verify_udp(udp)
1464 self.assertEqual(ike.id, self.sa.msg_id)
1465 plain = self.sa.hmac_and_decrypt(ike)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001466 idr = ikev2.IKEv2_payload_IDr(plain)
1467 prop = idr[ikev2.IKEv2_payload_Proposal]
1468 self.assertEqual(prop.SPIsize, 4)
1469 self.sa.child_sas[0].rspi = prop.SPI
Filip Tehlare7c83962020-09-23 11:20:12 +00001470 self.sa.calc_child_keys()
1471
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001472 IKE_NODE_SUFFIX = "ip4"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001473
1474 def verify_counters(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001475 self.assert_counter(2, "processed", self.IKE_NODE_SUFFIX)
1476 self.assert_counter(1, "init_sa_req", self.IKE_NODE_SUFFIX)
1477 self.assert_counter(1, "ike_auth_req", self.IKE_NODE_SUFFIX)
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001478
Filip Tehlar68d27532021-01-25 10:09:27 +00001479 r = self.vapi.ikev2_sa_dump()
1480 s = r[0].sa.stats
1481 self.assertEqual(1, s.n_sa_auth_req)
1482 self.assertEqual(1, s.n_sa_init_req)
1483
Filip Tehlar12b517b2020-04-26 18:05:05 +00001484 def test_responder(self):
Filip Tehlar027d8132020-12-04 17:38:11 +00001485 self.send_sa_init_req()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001486 self.send_sa_auth()
jan_cavojskya340fe12020-07-08 09:24:12 +02001487 self.verify_ipsec_sas()
1488 self.verify_ike_sas()
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001489 self.verify_counters()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001490
1491
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001492class Ikev2Params(object):
1493 def config_params(self, params={}):
Filip Tehlar4f42a712020-07-01 08:56:59 +00001494 ec = VppEnum.vl_api_ipsec_crypto_alg_t
1495 ei = VppEnum.vl_api_ipsec_integ_alg_t
1496 self.vpp_enums = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001497 "AES-CBC-128": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_128,
1498 "AES-CBC-192": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_192,
1499 "AES-CBC-256": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_256,
1500 "AES-GCM-16ICV-128": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_128,
1501 "AES-GCM-16ICV-192": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_192,
1502 "AES-GCM-16ICV-256": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_256,
1503 "HMAC-SHA1-96": ei.IPSEC_API_INTEG_ALG_SHA1_96,
1504 "SHA2-256-128": ei.IPSEC_API_INTEG_ALG_SHA_256_128,
1505 "SHA2-384-192": ei.IPSEC_API_INTEG_ALG_SHA_384_192,
1506 "SHA2-512-256": ei.IPSEC_API_INTEG_ALG_SHA_512_256,
1507 }
Filip Tehlar4f42a712020-07-01 08:56:59 +00001508
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001509 dpd_disabled = True if "dpd_disabled" not in params else params["dpd_disabled"]
Filip Tehlar2008e312020-11-09 13:23:24 +00001510 if dpd_disabled:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001511 self.vapi.cli("ikev2 dpd disable")
1512 self.del_sa_from_responder = (
1513 False
1514 if "del_sa_from_responder" not in params
1515 else params["del_sa_from_responder"]
1516 )
1517 i_natt = False if "i_natt" not in params else params["i_natt"]
1518 r_natt = False if "r_natt" not in params else params["r_natt"]
1519 self.p = Profile(self, "pr1")
1520 self.ip6 = False if "ip6" not in params else params["ip6"]
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001521
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001522 if "auth" in params and params["auth"] == "rsa-sig":
1523 auth_method = "rsa-sig"
Klement Sekerab23ffd72021-05-31 16:08:53 +02001524 work_dir = f"{config.vpp_ws_dir}/src/plugins/ikev2/test/certs/"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001525 self.vapi.ikev2_set_local_key(key_file=work_dir + params["server-key"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001526
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001527 client_file = work_dir + params["client-cert"]
1528 server_pem = open(work_dir + params["server-cert"]).read()
1529 client_priv = open(work_dir + params["client-key"]).read()
1530 client_priv = load_pem_private_key(
1531 str.encode(client_priv), None, default_backend()
1532 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001533 self.peer_cert = x509.load_pem_x509_certificate(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001534 str.encode(server_pem), default_backend()
1535 )
1536 self.p.add_auth(method="rsa-sig", data=str.encode(client_file))
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001537 auth_data = None
1538 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001539 auth_data = b"$3cr3tpa$$w0rd"
1540 self.p.add_auth(method="shared-key", data=auth_data)
1541 auth_method = "shared-key"
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001542 client_priv = None
1543
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001544 is_init = True if "is_initiator" not in params else params["is_initiator"]
1545 self.no_idr_auth = params.get("no_idr_in_auth", False)
Filip Tehlare7c83962020-09-23 11:20:12 +00001546
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001547 idr = {"id_type": "fqdn", "data": b"vpp.home"}
1548 idi = {"id_type": "fqdn", "data": b"roadwarrior.example.com"}
1549 r_id = self.idr = idr["data"]
1550 i_id = self.idi = idi["data"]
Filip Tehlare7c83962020-09-23 11:20:12 +00001551 if is_init:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001552 # scapy is initiator, VPP is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001553 self.p.add_local_id(**idr)
1554 self.p.add_remote_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001555 if self.no_idr_auth:
1556 r_id = None
Filip Tehlare7c83962020-09-23 11:20:12 +00001557 else:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001558 # VPP is initiator, scapy is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001559 self.p.add_local_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001560 if not self.no_idr_auth:
1561 self.p.add_remote_id(**idr)
Filip Tehlare7c83962020-09-23 11:20:12 +00001562
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001563 loc_ts = (
1564 {"start_addr": "10.10.10.0", "end_addr": "10.10.10.255"}
1565 if "loc_ts" not in params
1566 else params["loc_ts"]
1567 )
1568 rem_ts = (
1569 {"start_addr": "10.0.0.0", "end_addr": "10.0.0.255"}
1570 if "rem_ts" not in params
1571 else params["rem_ts"]
1572 )
Filip Tehlar84962d12020-09-08 06:08:05 +00001573 self.p.add_local_ts(**loc_ts)
1574 self.p.add_remote_ts(**rem_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001575 if "responder" in params:
1576 self.p.add_responder(params["responder"])
1577 if "ike_transforms" in params:
1578 self.p.add_ike_transforms(params["ike_transforms"])
1579 if "esp_transforms" in params:
1580 self.p.add_esp_transforms(params["esp_transforms"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001581
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001582 udp_encap = False if "udp_encap" not in params else params["udp_encap"]
Filip Tehlar67b8a7f2020-11-06 11:00:42 +00001583 if udp_encap:
1584 self.p.set_udp_encap(True)
1585
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001586 if "responder_hostname" in params:
1587 hn = params["responder_hostname"]
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001588 self.p.add_responder_hostname(hn)
1589
1590 # configure static dns record
1591 self.vapi.dns_name_server_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001592 is_ip6=0, is_add=1, server_address=IPv4Address("8.8.8.8").packed
1593 )
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001594 self.vapi.dns_enable_disable(enable=1)
1595
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001596 cmd = "dns cache add {} {}".format(hn["hostname"], self.pg0.remote_ip4)
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001597 self.vapi.cli(cmd)
1598
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001599 self.sa = IKEv2SA(
1600 self,
1601 i_id=i_id,
1602 r_id=r_id,
1603 is_initiator=is_init,
1604 id_type=self.p.local_id["id_type"],
1605 i_natt=i_natt,
1606 r_natt=r_natt,
1607 priv_key=client_priv,
1608 auth_method=auth_method,
1609 nonce=params.get("nonce"),
1610 auth_data=auth_data,
1611 udp_encap=udp_encap,
1612 local_ts=self.p.remote_ts,
1613 remote_ts=self.p.local_ts,
1614 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001615
Filip Tehlar68ad6252020-10-30 05:28:11 +00001616 if is_init:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001617 ike_crypto = (
1618 ("AES-CBC", 32) if "ike-crypto" not in params else params["ike-crypto"]
1619 )
1620 ike_integ = (
1621 "HMAC-SHA1-96" if "ike-integ" not in params else params["ike-integ"]
1622 )
1623 ike_dh = "2048MODPgr" if "ike-dh" not in params else params["ike-dh"]
Filip Tehlar4f42a712020-07-01 08:56:59 +00001624
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001625 esp_crypto = (
1626 ("AES-CBC", 32) if "esp-crypto" not in params else params["esp-crypto"]
1627 )
1628 esp_integ = (
1629 "HMAC-SHA1-96" if "esp-integ" not in params else params["esp-integ"]
1630 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00001631
Filip Tehlar68ad6252020-10-30 05:28:11 +00001632 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001633 crypto=ike_crypto[0],
1634 crypto_key_len=ike_crypto[1],
1635 integ=ike_integ,
1636 prf="PRF_HMAC_SHA2_256",
1637 dh=ike_dh,
1638 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001639 self.sa.set_esp_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001640 crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], integ=esp_integ
1641 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001642
1643
Filip Tehlar459d17b2020-07-06 15:40:08 +00001644class TestApi(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001645 """Test IKEV2 API"""
1646
Filip Tehlar459d17b2020-07-06 15:40:08 +00001647 @classmethod
1648 def setUpClass(cls):
1649 super(TestApi, cls).setUpClass()
1650
1651 @classmethod
1652 def tearDownClass(cls):
1653 super(TestApi, cls).tearDownClass()
1654
1655 def tearDown(self):
1656 super(TestApi, self).tearDown()
1657 self.p1.remove_vpp_config()
1658 self.p2.remove_vpp_config()
1659 r = self.vapi.ikev2_profile_dump()
1660 self.assertEqual(len(r), 0)
1661
1662 def configure_profile(self, cfg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001663 p = Profile(self, cfg["name"])
1664 p.add_local_id(id_type=cfg["loc_id"][0], data=cfg["loc_id"][1])
1665 p.add_remote_id(id_type=cfg["rem_id"][0], data=cfg["rem_id"][1])
1666 p.add_local_ts(**cfg["loc_ts"])
1667 p.add_remote_ts(**cfg["rem_ts"])
1668 p.add_responder(cfg["responder"])
1669 p.add_ike_transforms(cfg["ike_ts"])
1670 p.add_esp_transforms(cfg["esp_ts"])
1671 p.add_auth(**cfg["auth"])
1672 p.set_udp_encap(cfg["udp_encap"])
1673 p.set_ipsec_over_udp_port(cfg["ipsec_over_udp_port"])
1674 if "lifetime_data" in cfg:
1675 p.set_lifetime_data(cfg["lifetime_data"])
1676 if "tun_itf" in cfg:
1677 p.set_tunnel_interface(cfg["tun_itf"])
1678 if "natt_disabled" in cfg and cfg["natt_disabled"]:
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001679 p.disable_natt()
Filip Tehlar459d17b2020-07-06 15:40:08 +00001680 p.add_vpp_config()
1681 return p
1682
1683 def test_profile_api(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001684 """test profile dump API"""
Filip Tehlar84962d12020-09-08 06:08:05 +00001685 loc_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001686 "proto": 8,
1687 "start_port": 1,
1688 "end_port": 19,
1689 "start_addr": "3.3.3.2",
1690 "end_addr": "3.3.3.3",
1691 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001692 rem_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001693 "proto": 9,
1694 "start_port": 10,
1695 "end_port": 119,
1696 "start_addr": "4.5.76.80",
1697 "end_addr": "2.3.4.6",
1698 }
Filip Tehlar459d17b2020-07-06 15:40:08 +00001699
Filip Tehlar84962d12020-09-08 06:08:05 +00001700 loc_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001701 "proto": 8,
1702 "start_port": 1,
1703 "end_port": 19,
1704 "start_addr": "ab::1",
1705 "end_addr": "ab::4",
1706 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001707 rem_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001708 "proto": 9,
1709 "start_port": 10,
1710 "end_port": 119,
1711 "start_addr": "cd::12",
1712 "end_addr": "cd::13",
1713 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001714
Filip Tehlar459d17b2020-07-06 15:40:08 +00001715 conf = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001716 "p1": {
1717 "name": "p1",
1718 "natt_disabled": True,
1719 "loc_id": ("fqdn", b"vpp.home"),
1720 "rem_id": ("fqdn", b"roadwarrior.example.com"),
1721 "loc_ts": loc_ts4,
1722 "rem_ts": rem_ts4,
1723 "responder": {"sw_if_index": 0, "addr": "5.6.7.8"},
1724 "ike_ts": {
1725 "crypto_alg": 20,
1726 "crypto_key_size": 32,
1727 "integ_alg": 0,
1728 "dh_group": 1,
1729 },
1730 "esp_ts": {"crypto_alg": 13, "crypto_key_size": 24, "integ_alg": 2},
1731 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1732 "udp_encap": True,
1733 "ipsec_over_udp_port": 4501,
1734 "lifetime_data": {
1735 "lifetime": 123,
1736 "lifetime_maxdata": 20192,
1737 "lifetime_jitter": 9,
1738 "handover": 132,
1739 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001740 },
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001741 "p2": {
1742 "name": "p2",
1743 "loc_id": ("ip4-addr", b"192.168.2.1"),
1744 "rem_id": ("ip6-addr", b"abcd::1"),
1745 "loc_ts": loc_ts6,
1746 "rem_ts": rem_ts6,
1747 "responder": {"sw_if_index": 4, "addr": "def::10"},
1748 "ike_ts": {
1749 "crypto_alg": 12,
1750 "crypto_key_size": 16,
1751 "integ_alg": 3,
1752 "dh_group": 3,
1753 },
1754 "esp_ts": {"crypto_alg": 9, "crypto_key_size": 24, "integ_alg": 4},
1755 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1756 "udp_encap": False,
1757 "ipsec_over_udp_port": 4600,
1758 "tun_itf": 0,
1759 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001760 }
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001761 self.p1 = self.configure_profile(conf["p1"])
1762 self.p2 = self.configure_profile(conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001763
1764 r = self.vapi.ikev2_profile_dump()
1765 self.assertEqual(len(r), 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001766 self.verify_profile(r[0].profile, conf["p1"])
1767 self.verify_profile(r[1].profile, conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001768
1769 def verify_id(self, api_id, cfg_id):
1770 self.assertEqual(api_id.type, IDType.value(cfg_id[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001771 self.assertEqual(bytes(api_id.data, "ascii"), cfg_id[1])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001772
1773 def verify_ts(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001774 self.assertEqual(api_ts.protocol_id, cfg_ts["proto"])
1775 self.assertEqual(api_ts.start_port, cfg_ts["start_port"])
1776 self.assertEqual(api_ts.end_port, cfg_ts["end_port"])
1777 self.assertEqual(api_ts.start_addr, ip_address(text_type(cfg_ts["start_addr"])))
1778 self.assertEqual(api_ts.end_addr, ip_address(text_type(cfg_ts["end_addr"])))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001779
1780 def verify_responder(self, api_r, cfg_r):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001781 self.assertEqual(api_r.sw_if_index, cfg_r["sw_if_index"])
1782 self.assertEqual(api_r.addr, ip_address(cfg_r["addr"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001783
1784 def verify_transforms(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001785 self.assertEqual(api_ts.crypto_alg, cfg_ts["crypto_alg"])
1786 self.assertEqual(api_ts.crypto_key_size, cfg_ts["crypto_key_size"])
1787 self.assertEqual(api_ts.integ_alg, cfg_ts["integ_alg"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001788
1789 def verify_ike_transforms(self, api_ts, cfg_ts):
1790 self.verify_transforms(api_ts, cfg_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001791 self.assertEqual(api_ts.dh_group, cfg_ts["dh_group"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001792
1793 def verify_esp_transforms(self, api_ts, cfg_ts):
1794 self.verify_transforms(api_ts, cfg_ts)
1795
1796 def verify_auth(self, api_auth, cfg_auth):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001797 self.assertEqual(api_auth.method, AuthMethod.value(cfg_auth["method"]))
1798 self.assertEqual(api_auth.data, cfg_auth["data"])
1799 self.assertEqual(api_auth.data_len, len(cfg_auth["data"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001800
1801 def verify_lifetime_data(self, p, ld):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001802 self.assertEqual(p.lifetime, ld["lifetime"])
1803 self.assertEqual(p.lifetime_maxdata, ld["lifetime_maxdata"])
1804 self.assertEqual(p.lifetime_jitter, ld["lifetime_jitter"])
1805 self.assertEqual(p.handover, ld["handover"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001806
1807 def verify_profile(self, ap, cp):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001808 self.assertEqual(ap.name, cp["name"])
1809 self.assertEqual(ap.udp_encap, cp["udp_encap"])
1810 self.verify_id(ap.loc_id, cp["loc_id"])
1811 self.verify_id(ap.rem_id, cp["rem_id"])
1812 self.verify_ts(ap.loc_ts, cp["loc_ts"])
1813 self.verify_ts(ap.rem_ts, cp["rem_ts"])
1814 self.verify_responder(ap.responder, cp["responder"])
1815 self.verify_ike_transforms(ap.ike_ts, cp["ike_ts"])
1816 self.verify_esp_transforms(ap.esp_ts, cp["esp_ts"])
1817 self.verify_auth(ap.auth, cp["auth"])
1818 natt_dis = False if "natt_disabled" not in cp else cp["natt_disabled"]
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001819 self.assertTrue(natt_dis == ap.natt_disabled)
1820
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001821 if "lifetime_data" in cp:
1822 self.verify_lifetime_data(ap, cp["lifetime_data"])
1823 self.assertEqual(ap.ipsec_over_udp_port, cp["ipsec_over_udp_port"])
1824 if "tun_itf" in cp:
1825 self.assertEqual(ap.tun_itf, cp["tun_itf"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001826 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001827 self.assertEqual(ap.tun_itf, 0xFFFFFFFF)
Filip Tehlar459d17b2020-07-06 15:40:08 +00001828
1829
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001830@tag_fixme_vpp_workers
Filip Tehlar027d8132020-12-04 17:38:11 +00001831class TestResponderBehindNAT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001832 """test responder - responder behind NAT"""
Filip Tehlar027d8132020-12-04 17:38:11 +00001833
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001834 IKE_NODE_SUFFIX = "ip4-natt"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001835
Filip Tehlar027d8132020-12-04 17:38:11 +00001836 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001837 self.config_params({"r_natt": True})
Filip Tehlar027d8132020-12-04 17:38:11 +00001838
1839
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001840@tag_fixme_vpp_workers
Filip Tehlar18107c92020-12-01 14:51:09 +00001841class TestInitiatorNATT(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001842 """test ikev2 initiator - NAT traversal (intitiator behind NAT)"""
Filip Tehlar18107c92020-12-01 14:51:09 +00001843
1844 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001845 self.config_params(
1846 {
1847 "i_natt": True,
1848 "is_initiator": False, # seen from test case perspective
1849 # thus vpp is initiator
1850 "responder": {
1851 "sw_if_index": self.pg0.sw_if_index,
1852 "addr": self.pg0.remote_ip4,
1853 },
1854 "ike-crypto": ("AES-GCM-16ICV", 32),
1855 "ike-integ": "NULL",
1856 "ike-dh": "3072MODPgr",
1857 "ike_transforms": {
1858 "crypto_alg": 20, # "aes-gcm-16"
1859 "crypto_key_size": 256,
1860 "dh_group": 15, # "modp-3072"
1861 },
1862 "esp_transforms": {
1863 "crypto_alg": 12, # "aes-cbc"
1864 "crypto_key_size": 256,
1865 # "hmac-sha2-256-128"
1866 "integ_alg": 12,
1867 },
1868 }
1869 )
Filip Tehlar18107c92020-12-01 14:51:09 +00001870
1871
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001872@tag_fixme_vpp_workers
Filip Tehlare7c83962020-09-23 11:20:12 +00001873class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001874 """test ikev2 initiator - pre shared key auth"""
Filip Tehlaredf29002020-10-10 04:39:11 +00001875
Filip Tehlare7c83962020-09-23 11:20:12 +00001876 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001877 self.config_params(
1878 {
1879 "is_initiator": False, # seen from test case perspective
1880 # thus vpp is initiator
1881 "ike-crypto": ("AES-GCM-16ICV", 32),
1882 "ike-integ": "NULL",
1883 "ike-dh": "3072MODPgr",
1884 "ike_transforms": {
1885 "crypto_alg": 20, # "aes-gcm-16"
1886 "crypto_key_size": 256,
1887 "dh_group": 15, # "modp-3072"
1888 },
1889 "esp_transforms": {
1890 "crypto_alg": 12, # "aes-cbc"
1891 "crypto_key_size": 256,
1892 # "hmac-sha2-256-128"
1893 "integ_alg": 12,
1894 },
1895 "responder_hostname": {
1896 "hostname": "vpp.responder.org",
1897 "sw_if_index": self.pg0.sw_if_index,
1898 },
1899 }
1900 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001901
1902
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001903@tag_fixme_vpp_workers
Filip Tehlar38340fa2020-11-19 21:34:48 +00001904class TestInitiatorRequestWindowSize(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001905 """test initiator - request window size (1)"""
Filip Tehlar38340fa2020-11-19 21:34:48 +00001906
1907 def rekey_respond(self, req, update_child_sa_data):
1908 ih = self.get_ike_header(req)
1909 plain = self.sa.hmac_and_decrypt(ih)
1910 sa = ikev2.IKEv2_payload_SA(plain)
1911 if update_child_sa_data:
1912 prop = sa[ikev2.IKEv2_payload_Proposal]
1913 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
1914 self.sa.r_nonce = self.sa.i_nonce
1915 self.sa.child_sas[0].ispi = prop.SPI
1916 self.sa.child_sas[0].rspi = prop.SPI
1917 self.sa.calc_child_keys()
1918
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001919 header = ikev2.IKEv2(
1920 init_SPI=self.sa.ispi,
1921 resp_SPI=self.sa.rspi,
1922 flags="Response",
1923 exch_type=36,
1924 id=ih.id,
1925 next_payload="Encrypted",
1926 )
1927 resp = self.encrypt_ike_msg(header, sa, "SA")
1928 packet = self.create_packet(
1929 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1930 )
Filip Tehlar38340fa2020-11-19 21:34:48 +00001931 self.send_and_assert_no_replies(self.pg0, packet)
1932
1933 def test_initiator(self):
1934 super(TestInitiatorRequestWindowSize, self).test_initiator()
1935 self.pg0.enable_capture()
1936 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001937 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar38340fa2020-11-19 21:34:48 +00001938 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1939 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1940 capture = self.pg0.get_capture(2)
1941
1942 # reply in reverse order
1943 self.rekey_respond(capture[1], True)
1944 self.rekey_respond(capture[0], False)
1945
1946 # verify that only the second request was accepted
1947 self.verify_ike_sas()
1948 self.verify_ipsec_sas(is_rekey=True)
1949
1950
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001951@tag_fixme_vpp_workers
Filip Tehlar68ad6252020-10-30 05:28:11 +00001952class TestInitiatorRekey(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001953 """test ikev2 initiator - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00001954
1955 def rekey_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001956 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar68ad6252020-10-30 05:28:11 +00001957 self.pg0.enable_capture()
1958 self.pg_start()
1959 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1960 capture = self.pg0.get_capture(1)
1961 ih = self.get_ike_header(capture[0])
1962 self.assertEqual(ih.exch_type, 36) # CHILD_SA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001963 self.assertNotIn("Response", ih.flags)
1964 self.assertIn("Initiator", ih.flags)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001965 plain = self.sa.hmac_and_decrypt(ih)
1966 sa = ikev2.IKEv2_payload_SA(plain)
1967 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00001968 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
1969 self.sa.r_nonce = self.sa.i_nonce
1970 # update new responder SPI
1971 self.sa.child_sas[0].ispi = prop.SPI
1972 self.sa.child_sas[0].rspi = prop.SPI
1973 self.sa.calc_child_keys()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001974 header = ikev2.IKEv2(
1975 init_SPI=self.sa.ispi,
1976 resp_SPI=self.sa.rspi,
1977 flags="Response",
1978 exch_type=36,
1979 id=ih.id,
1980 next_payload="Encrypted",
1981 )
1982 resp = self.encrypt_ike_msg(header, sa, "SA")
1983 packet = self.create_packet(
1984 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1985 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001986 self.send_and_assert_no_replies(self.pg0, packet)
1987
1988 def test_initiator(self):
1989 super(TestInitiatorRekey, self).test_initiator()
1990 self.rekey_from_initiator()
1991 self.verify_ike_sas()
1992 self.verify_ipsec_sas(is_rekey=True)
1993
1994
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001995@tag_fixme_vpp_workers
Filip Tehlaredf29002020-10-10 04:39:11 +00001996class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001997 """test ikev2 initiator - delete IKE SA from responder"""
Filip Tehlaredf29002020-10-10 04:39:11 +00001998
1999 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002000 self.config_params(
2001 {
2002 "del_sa_from_responder": True,
2003 "is_initiator": False, # seen from test case perspective
2004 # thus vpp is initiator
2005 "responder": {
2006 "sw_if_index": self.pg0.sw_if_index,
2007 "addr": self.pg0.remote_ip4,
2008 },
2009 "ike-crypto": ("AES-GCM-16ICV", 32),
2010 "ike-integ": "NULL",
2011 "ike-dh": "3072MODPgr",
2012 "ike_transforms": {
2013 "crypto_alg": 20, # "aes-gcm-16"
2014 "crypto_key_size": 256,
2015 "dh_group": 15, # "modp-3072"
2016 },
2017 "esp_transforms": {
2018 "crypto_alg": 12, # "aes-cbc"
2019 "crypto_key_size": 256,
2020 # "hmac-sha2-256-128"
2021 "integ_alg": 12,
2022 },
2023 "no_idr_in_auth": True,
2024 }
2025 )
Filip Tehlaredf29002020-10-10 04:39:11 +00002026
2027
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002028@tag_fixme_vpp_workers
Filip Tehlar027d8132020-12-04 17:38:11 +00002029class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002030 """test ikev2 responder - initiator behind NAT"""
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002031
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002032 IKE_NODE_SUFFIX = "ip4-natt"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002033
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002034 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002035 self.config_params({"i_natt": True})
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002036
2037
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002038@tag_fixme_vpp_workers
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002039class TestResponderPsk(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002040 """test ikev2 responder - pre shared key auth"""
2041
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002042 def config_tc(self):
2043 self.config_params()
2044
2045
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002046@tag_fixme_vpp_workers
Filip Tehlar2008e312020-11-09 13:23:24 +00002047class TestResponderDpd(TestResponderPsk):
2048 """
2049 Dead peer detection test
2050 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002051
Filip Tehlar2008e312020-11-09 13:23:24 +00002052 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002053 self.config_params({"dpd_disabled": False})
Filip Tehlar2008e312020-11-09 13:23:24 +00002054
2055 def tearDown(self):
2056 pass
2057
2058 def test_responder(self):
2059 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2060 super(TestResponderDpd, self).test_responder()
2061 self.pg0.enable_capture()
2062 self.pg_start()
2063 # capture empty request but don't reply
2064 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2065 ih = self.get_ike_header(capture[0])
2066 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2067 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002068 self.assertEqual(plain, b"")
Filip Tehlar2008e312020-11-09 13:23:24 +00002069 # wait for SA expiration
2070 time.sleep(3)
2071 ike_sas = self.vapi.ikev2_sa_dump()
2072 self.assertEqual(len(ike_sas), 0)
2073 ipsec_sas = self.vapi.ipsec_sa_dump()
2074 self.assertEqual(len(ipsec_sas), 0)
2075
2076
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002077@tag_fixme_vpp_workers
Filip Tehlar68ad6252020-10-30 05:28:11 +00002078class TestResponderRekey(TestResponderPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002079 """test ikev2 responder - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00002080
2081 def rekey_from_initiator(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002082 packet = self.create_rekey_request()
Filip Tehlar68ad6252020-10-30 05:28:11 +00002083 self.pg0.add_stream(packet)
2084 self.pg0.enable_capture()
2085 self.pg_start()
2086 capture = self.pg0.get_capture(1)
2087 ih = self.get_ike_header(capture[0])
2088 plain = self.sa.hmac_and_decrypt(ih)
2089 sa = ikev2.IKEv2_payload_SA(plain)
2090 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00002091 self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2092 # update new responder SPI
2093 self.sa.child_sas[0].rspi = prop.SPI
2094
2095 def test_responder(self):
2096 super(TestResponderRekey, self).test_responder()
2097 self.rekey_from_initiator()
2098 self.sa.calc_child_keys()
2099 self.verify_ike_sas()
2100 self.verify_ipsec_sas(is_rekey=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002101 self.assert_counter(1, "rekey_req", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002102 r = self.vapi.ikev2_sa_dump()
2103 self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002104
2105
Filip Tehlard28196f2021-01-27 18:08:21 +00002106class TestResponderVrf(TestResponderPsk, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002107 """test ikev2 responder - non-default table id"""
Filip Tehlard28196f2021-01-27 18:08:21 +00002108
2109 @classmethod
2110 def setUpClass(cls):
2111 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002112
2113 globals()["ikev2"] = _ikev2
Filip Tehlard28196f2021-01-27 18:08:21 +00002114 super(IkePeer, cls).setUpClass()
2115 cls.create_pg_interfaces(range(1))
2116 cls.vapi.cli("ip table add 1")
2117 cls.vapi.cli("set interface ip table pg0 1")
2118 for i in cls.pg_interfaces:
2119 i.admin_up()
2120 i.config_ip4()
2121 i.resolve_arp()
2122 i.config_ip6()
2123 i.resolve_ndp()
2124
2125 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002126 self.config_params({"dpd_disabled": False})
Filip Tehlard28196f2021-01-27 18:08:21 +00002127
2128 def test_responder(self):
2129 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2130 super(TestResponderVrf, self).test_responder()
2131 self.pg0.enable_capture()
2132 self.pg_start()
2133 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2134 ih = self.get_ike_header(capture[0])
2135 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2136 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002137 self.assertEqual(plain, b"")
Filip Tehlard28196f2021-01-27 18:08:21 +00002138
2139
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002140@tag_fixme_vpp_workers
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002141class TestResponderRsaSign(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002142 """test ikev2 responder - cert based auth"""
2143
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002144 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002145 self.config_params(
2146 {
2147 "udp_encap": True,
2148 "auth": "rsa-sig",
2149 "server-key": "server-key.pem",
2150 "client-key": "client-key.pem",
2151 "client-cert": "client-cert.pem",
2152 "server-cert": "server-cert.pem",
2153 }
2154 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002155
Filip Tehlar4f42a712020-07-01 08:56:59 +00002156
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002157@tag_fixme_vpp_workers
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002158class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
2159 TemplateResponder, Ikev2Params
2160):
Filip Tehlar4f42a712020-07-01 08:56:59 +00002161 """
2162 IKE:AES_CBC_128_SHA256_128,DH=modp2048 ESP:AES_CBC_192_SHA_384_192
2163 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002164
Filip Tehlar4f42a712020-07-01 08:56:59 +00002165 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002166 self.config_params(
2167 {
2168 "ike-crypto": ("AES-CBC", 16),
2169 "ike-integ": "SHA2-256-128",
2170 "esp-crypto": ("AES-CBC", 24),
2171 "esp-integ": "SHA2-384-192",
2172 "ike-dh": "2048MODPgr",
2173 "nonce": os.urandom(256),
2174 "no_idr_in_auth": True,
2175 }
2176 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002177
2178
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002179@tag_fixme_vpp_workers
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002180class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
2181 TemplateResponder, Ikev2Params
2182):
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002183
Filip Tehlar4f42a712020-07-01 08:56:59 +00002184 """
2185 IKE:AES_CBC_128_SHA256_128,DH=modp3072 ESP:AES_GCM_16
2186 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002187
Filip Tehlar4f42a712020-07-01 08:56:59 +00002188 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002189 self.config_params(
2190 {
2191 "ike-crypto": ("AES-CBC", 32),
2192 "ike-integ": "SHA2-256-128",
2193 "esp-crypto": ("AES-GCM-16ICV", 32),
2194 "esp-integ": "NULL",
2195 "ike-dh": "3072MODPgr",
2196 }
2197 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002198
2199
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002200@tag_fixme_vpp_workers
Filip Tehlara7b963d2020-07-08 13:25:34 +00002201class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
2202 """
2203 IKE:AES_GCM_16_256
2204 """
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002205
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002206 IKE_NODE_SUFFIX = "ip6"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002207
Filip Tehlara7b963d2020-07-08 13:25:34 +00002208 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002209 self.config_params(
2210 {
2211 "del_sa_from_responder": True,
2212 "ip6": True,
2213 "natt": True,
2214 "ike-crypto": ("AES-GCM-16ICV", 32),
2215 "ike-integ": "NULL",
2216 "ike-dh": "2048MODPgr",
2217 "loc_ts": {"start_addr": "ab:cd::0", "end_addr": "ab:cd::10"},
2218 "rem_ts": {"start_addr": "11::0", "end_addr": "11::100"},
2219 }
2220 )
Filip Tehlara7b963d2020-07-08 13:25:34 +00002221
2222
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002223@tag_fixme_vpp_workers
Filip Tehlar2008e312020-11-09 13:23:24 +00002224class TestInitiatorKeepaliveMsg(TestInitiatorPsk):
2225 """
2226 Test for keep alive messages
2227 """
2228
2229 def send_empty_req_from_responder(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002230 packet = self.create_empty_request()
Filip Tehlar2008e312020-11-09 13:23:24 +00002231 self.pg0.add_stream(packet)
2232 self.pg0.enable_capture()
2233 self.pg_start()
2234 capture = self.pg0.get_capture(1)
2235 ih = self.get_ike_header(capture[0])
2236 self.assertEqual(ih.id, self.sa.msg_id)
2237 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002238 self.assertEqual(plain, b"")
2239 self.assert_counter(1, "keepalive", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002240 r = self.vapi.ikev2_sa_dump()
2241 self.assertEqual(1, r[0].sa.stats.n_keepalives)
Filip Tehlar2008e312020-11-09 13:23:24 +00002242
2243 def test_initiator(self):
2244 super(TestInitiatorKeepaliveMsg, self).test_initiator()
2245 self.send_empty_req_from_responder()
2246
2247
Filip Tehlar558607d2020-07-16 07:25:56 +00002248class TestMalformedMessages(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002249 """malformed packet test"""
Filip Tehlar558607d2020-07-16 07:25:56 +00002250
2251 def tearDown(self):
2252 pass
2253
2254 def config_tc(self):
2255 self.config_params()
2256
Filip Tehlar558607d2020-07-16 07:25:56 +00002257 def create_ike_init_msg(self, length=None, payload=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002258 msg = ikev2.IKEv2(
2259 length=length,
2260 init_SPI="\x11" * 8,
2261 flags="Initiator",
2262 exch_type="IKE_SA_INIT",
2263 )
Filip Tehlar558607d2020-07-16 07:25:56 +00002264 if payload is not None:
2265 msg /= payload
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002266 return self.create_packet(self.pg0, msg, self.sa.sport, self.sa.dport)
Filip Tehlar558607d2020-07-16 07:25:56 +00002267
2268 def verify_bad_packet_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002269 ike_msg = self.create_ike_init_msg(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002270 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002271 self.assert_counter(self.pkt_count, "bad_length")
Filip Tehlar558607d2020-07-16 07:25:56 +00002272
2273 def verify_bad_sa_payload_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002274 p = ikev2.IKEv2_payload_SA(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002275 ike_msg = self.create_ike_init_msg(payload=p)
2276 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002277 self.assert_counter(self.pkt_count, "malformed_packet")
Filip Tehlar558607d2020-07-16 07:25:56 +00002278
2279 def test_responder(self):
2280 self.pkt_count = 254
2281 self.verify_bad_packet_length()
2282 self.verify_bad_sa_payload_length()
2283
2284
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002285if __name__ == "__main__":
Filip Tehlar12b517b2020-04-26 18:05:05 +00002286 unittest.main(testRunner=VppTestRunner)