blob: 5b699dd0d8d3479b0f4fba6d8a566ef29722e1e0 [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
1394 / ikev2.IKEv2_payload_Notify(type="REKEY_SA", proto="ESP", SPI=c.ispi)
1395 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001396 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001397 first_payload = "IDi"
Benoît Gannec7cceee2021-09-28 11:19:37 +02001398 if self.no_idr_auth:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001399 ids = ikev2.IKEv2_payload_IDi(
1400 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.i_id
1401 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001402 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001403 ids = ikev2.IKEv2_payload_IDi(
1404 next_payload="IDr", IDtype=self.sa.id_type, load=self.sa.i_id
1405 ) / ikev2.IKEv2_payload_IDr(
1406 next_payload="AUTH", IDtype=self.sa.id_type, load=self.sa.r_id
1407 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001408 plain = ids / plain
1409 return plain, first_payload
1410
1411 def send_sa_auth(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001412 plain, first_payload = self.generate_auth_payload(last_payload="Notify")
1413 plain = plain / ikev2.IKEv2_payload_Notify(type="INITIAL_CONTACT")
Filip Tehlare7c83962020-09-23 11:20:12 +00001414 header = ikev2.IKEv2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001415 init_SPI=self.sa.ispi,
1416 resp_SPI=self.sa.rspi,
1417 id=self.sa.new_msg_id(),
1418 flags="Initiator",
1419 exch_type="IKE_AUTH",
1420 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001421
Filip Tehlar68ad6252020-10-30 05:28:11 +00001422 ike_msg = self.encrypt_ike_msg(header, plain, first_payload)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001423 packet = self.create_packet(
1424 self.pg0, ike_msg, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1425 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001426 self.pg0.add_stream(packet)
1427 self.pg0.enable_capture()
1428 self.pg_start()
1429 capture = self.pg0.get_capture(1)
1430 self.verify_sa_auth_resp(capture[0])
1431
1432 def verify_sa_init(self, packet):
1433 ih = self.get_ike_header(packet)
1434
1435 self.assertEqual(ih.id, self.sa.msg_id)
1436 self.assertEqual(ih.exch_type, 34)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001437 self.assertIn("Response", ih.flags)
Filip Tehlare7c83962020-09-23 11:20:12 +00001438 self.assertEqual(ih.init_SPI, self.sa.ispi)
1439 self.assertNotEqual(ih.resp_SPI, 0)
1440 self.sa.rspi = ih.resp_SPI
1441 try:
1442 sa = ih[ikev2.IKEv2_payload_SA]
1443 self.sa.r_nonce = ih[ikev2.IKEv2_payload_Nonce].load
1444 self.sa.r_dh_data = ih[ikev2.IKEv2_payload_KE].load
1445 except IndexError as e:
1446 self.logger.error("unexpected reply: SA/Nonce/KE payload found!")
1447 self.logger.error(ih.show())
1448 raise
1449 self.sa.complete_dh_data()
1450 self.sa.calc_keys()
1451 self.sa.auth_init()
1452
1453 def verify_sa_auth_resp(self, packet):
1454 ike = self.get_ike_header(packet)
1455 udp = packet[UDP]
1456 self.verify_udp(udp)
1457 self.assertEqual(ike.id, self.sa.msg_id)
1458 plain = self.sa.hmac_and_decrypt(ike)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001459 idr = ikev2.IKEv2_payload_IDr(plain)
1460 prop = idr[ikev2.IKEv2_payload_Proposal]
1461 self.assertEqual(prop.SPIsize, 4)
1462 self.sa.child_sas[0].rspi = prop.SPI
Filip Tehlare7c83962020-09-23 11:20:12 +00001463 self.sa.calc_child_keys()
1464
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001465 IKE_NODE_SUFFIX = "ip4"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001466
1467 def verify_counters(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001468 self.assert_counter(2, "processed", self.IKE_NODE_SUFFIX)
1469 self.assert_counter(1, "init_sa_req", self.IKE_NODE_SUFFIX)
1470 self.assert_counter(1, "ike_auth_req", self.IKE_NODE_SUFFIX)
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001471
Filip Tehlar68d27532021-01-25 10:09:27 +00001472 r = self.vapi.ikev2_sa_dump()
1473 s = r[0].sa.stats
1474 self.assertEqual(1, s.n_sa_auth_req)
1475 self.assertEqual(1, s.n_sa_init_req)
1476
Filip Tehlar12b517b2020-04-26 18:05:05 +00001477 def test_responder(self):
Filip Tehlar027d8132020-12-04 17:38:11 +00001478 self.send_sa_init_req()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001479 self.send_sa_auth()
jan_cavojskya340fe12020-07-08 09:24:12 +02001480 self.verify_ipsec_sas()
1481 self.verify_ike_sas()
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001482 self.verify_counters()
Filip Tehlar12b517b2020-04-26 18:05:05 +00001483
1484
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001485class Ikev2Params(object):
1486 def config_params(self, params={}):
Filip Tehlar4f42a712020-07-01 08:56:59 +00001487 ec = VppEnum.vl_api_ipsec_crypto_alg_t
1488 ei = VppEnum.vl_api_ipsec_integ_alg_t
1489 self.vpp_enums = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001490 "AES-CBC-128": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_128,
1491 "AES-CBC-192": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_192,
1492 "AES-CBC-256": ec.IPSEC_API_CRYPTO_ALG_AES_CBC_256,
1493 "AES-GCM-16ICV-128": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_128,
1494 "AES-GCM-16ICV-192": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_192,
1495 "AES-GCM-16ICV-256": ec.IPSEC_API_CRYPTO_ALG_AES_GCM_256,
1496 "HMAC-SHA1-96": ei.IPSEC_API_INTEG_ALG_SHA1_96,
1497 "SHA2-256-128": ei.IPSEC_API_INTEG_ALG_SHA_256_128,
1498 "SHA2-384-192": ei.IPSEC_API_INTEG_ALG_SHA_384_192,
1499 "SHA2-512-256": ei.IPSEC_API_INTEG_ALG_SHA_512_256,
1500 }
Filip Tehlar4f42a712020-07-01 08:56:59 +00001501
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001502 dpd_disabled = True if "dpd_disabled" not in params else params["dpd_disabled"]
Filip Tehlar2008e312020-11-09 13:23:24 +00001503 if dpd_disabled:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001504 self.vapi.cli("ikev2 dpd disable")
1505 self.del_sa_from_responder = (
1506 False
1507 if "del_sa_from_responder" not in params
1508 else params["del_sa_from_responder"]
1509 )
1510 i_natt = False if "i_natt" not in params else params["i_natt"]
1511 r_natt = False if "r_natt" not in params else params["r_natt"]
1512 self.p = Profile(self, "pr1")
1513 self.ip6 = False if "ip6" not in params else params["ip6"]
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001514
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001515 if "auth" in params and params["auth"] == "rsa-sig":
1516 auth_method = "rsa-sig"
Klement Sekerab23ffd72021-05-31 16:08:53 +02001517 work_dir = f"{config.vpp_ws_dir}/src/plugins/ikev2/test/certs/"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001518 self.vapi.ikev2_set_local_key(key_file=work_dir + params["server-key"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001519
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001520 client_file = work_dir + params["client-cert"]
1521 server_pem = open(work_dir + params["server-cert"]).read()
1522 client_priv = open(work_dir + params["client-key"]).read()
1523 client_priv = load_pem_private_key(
1524 str.encode(client_priv), None, default_backend()
1525 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001526 self.peer_cert = x509.load_pem_x509_certificate(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001527 str.encode(server_pem), default_backend()
1528 )
1529 self.p.add_auth(method="rsa-sig", data=str.encode(client_file))
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001530 auth_data = None
1531 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001532 auth_data = b"$3cr3tpa$$w0rd"
1533 self.p.add_auth(method="shared-key", data=auth_data)
1534 auth_method = "shared-key"
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001535 client_priv = None
1536
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001537 is_init = True if "is_initiator" not in params else params["is_initiator"]
1538 self.no_idr_auth = params.get("no_idr_in_auth", False)
Filip Tehlare7c83962020-09-23 11:20:12 +00001539
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001540 idr = {"id_type": "fqdn", "data": b"vpp.home"}
1541 idi = {"id_type": "fqdn", "data": b"roadwarrior.example.com"}
1542 r_id = self.idr = idr["data"]
1543 i_id = self.idi = idi["data"]
Filip Tehlare7c83962020-09-23 11:20:12 +00001544 if is_init:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001545 # scapy is initiator, VPP is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001546 self.p.add_local_id(**idr)
1547 self.p.add_remote_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001548 if self.no_idr_auth:
1549 r_id = None
Filip Tehlare7c83962020-09-23 11:20:12 +00001550 else:
Benoît Gannec7cceee2021-09-28 11:19:37 +02001551 # VPP is initiator, scapy is responder
Filip Tehlare7c83962020-09-23 11:20:12 +00001552 self.p.add_local_id(**idi)
Benoît Gannec7cceee2021-09-28 11:19:37 +02001553 if not self.no_idr_auth:
1554 self.p.add_remote_id(**idr)
Filip Tehlare7c83962020-09-23 11:20:12 +00001555
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001556 loc_ts = (
1557 {"start_addr": "10.10.10.0", "end_addr": "10.10.10.255"}
1558 if "loc_ts" not in params
1559 else params["loc_ts"]
1560 )
1561 rem_ts = (
1562 {"start_addr": "10.0.0.0", "end_addr": "10.0.0.255"}
1563 if "rem_ts" not in params
1564 else params["rem_ts"]
1565 )
Filip Tehlar84962d12020-09-08 06:08:05 +00001566 self.p.add_local_ts(**loc_ts)
1567 self.p.add_remote_ts(**rem_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001568 if "responder" in params:
1569 self.p.add_responder(params["responder"])
1570 if "ike_transforms" in params:
1571 self.p.add_ike_transforms(params["ike_transforms"])
1572 if "esp_transforms" in params:
1573 self.p.add_esp_transforms(params["esp_transforms"])
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001574
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001575 udp_encap = False if "udp_encap" not in params else params["udp_encap"]
Filip Tehlar67b8a7f2020-11-06 11:00:42 +00001576 if udp_encap:
1577 self.p.set_udp_encap(True)
1578
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001579 if "responder_hostname" in params:
1580 hn = params["responder_hostname"]
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001581 self.p.add_responder_hostname(hn)
1582
1583 # configure static dns record
1584 self.vapi.dns_name_server_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001585 is_ip6=0, is_add=1, server_address=IPv4Address("8.8.8.8").packed
1586 )
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001587 self.vapi.dns_enable_disable(enable=1)
1588
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001589 cmd = "dns cache add {} {}".format(hn["hostname"], self.pg0.remote_ip4)
Filip Tehlaraf2cc642021-02-22 16:15:51 +00001590 self.vapi.cli(cmd)
1591
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001592 self.sa = IKEv2SA(
1593 self,
1594 i_id=i_id,
1595 r_id=r_id,
1596 is_initiator=is_init,
1597 id_type=self.p.local_id["id_type"],
1598 i_natt=i_natt,
1599 r_natt=r_natt,
1600 priv_key=client_priv,
1601 auth_method=auth_method,
1602 nonce=params.get("nonce"),
1603 auth_data=auth_data,
1604 udp_encap=udp_encap,
1605 local_ts=self.p.remote_ts,
1606 remote_ts=self.p.local_ts,
1607 )
Benoît Gannec7cceee2021-09-28 11:19:37 +02001608
Filip Tehlar68ad6252020-10-30 05:28:11 +00001609 if is_init:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001610 ike_crypto = (
1611 ("AES-CBC", 32) if "ike-crypto" not in params else params["ike-crypto"]
1612 )
1613 ike_integ = (
1614 "HMAC-SHA1-96" if "ike-integ" not in params else params["ike-integ"]
1615 )
1616 ike_dh = "2048MODPgr" if "ike-dh" not in params else params["ike-dh"]
Filip Tehlar4f42a712020-07-01 08:56:59 +00001617
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001618 esp_crypto = (
1619 ("AES-CBC", 32) if "esp-crypto" not in params else params["esp-crypto"]
1620 )
1621 esp_integ = (
1622 "HMAC-SHA1-96" if "esp-integ" not in params else params["esp-integ"]
1623 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00001624
Filip Tehlar68ad6252020-10-30 05:28:11 +00001625 self.sa.set_ike_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001626 crypto=ike_crypto[0],
1627 crypto_key_len=ike_crypto[1],
1628 integ=ike_integ,
1629 prf="PRF_HMAC_SHA2_256",
1630 dh=ike_dh,
1631 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001632 self.sa.set_esp_props(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001633 crypto=esp_crypto[0], crypto_key_len=esp_crypto[1], integ=esp_integ
1634 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00001635
1636
Filip Tehlar459d17b2020-07-06 15:40:08 +00001637class TestApi(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001638 """Test IKEV2 API"""
1639
Filip Tehlar459d17b2020-07-06 15:40:08 +00001640 @classmethod
1641 def setUpClass(cls):
1642 super(TestApi, cls).setUpClass()
1643
1644 @classmethod
1645 def tearDownClass(cls):
1646 super(TestApi, cls).tearDownClass()
1647
1648 def tearDown(self):
1649 super(TestApi, self).tearDown()
1650 self.p1.remove_vpp_config()
1651 self.p2.remove_vpp_config()
1652 r = self.vapi.ikev2_profile_dump()
1653 self.assertEqual(len(r), 0)
1654
1655 def configure_profile(self, cfg):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001656 p = Profile(self, cfg["name"])
1657 p.add_local_id(id_type=cfg["loc_id"][0], data=cfg["loc_id"][1])
1658 p.add_remote_id(id_type=cfg["rem_id"][0], data=cfg["rem_id"][1])
1659 p.add_local_ts(**cfg["loc_ts"])
1660 p.add_remote_ts(**cfg["rem_ts"])
1661 p.add_responder(cfg["responder"])
1662 p.add_ike_transforms(cfg["ike_ts"])
1663 p.add_esp_transforms(cfg["esp_ts"])
1664 p.add_auth(**cfg["auth"])
1665 p.set_udp_encap(cfg["udp_encap"])
1666 p.set_ipsec_over_udp_port(cfg["ipsec_over_udp_port"])
1667 if "lifetime_data" in cfg:
1668 p.set_lifetime_data(cfg["lifetime_data"])
1669 if "tun_itf" in cfg:
1670 p.set_tunnel_interface(cfg["tun_itf"])
1671 if "natt_disabled" in cfg and cfg["natt_disabled"]:
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001672 p.disable_natt()
Filip Tehlar459d17b2020-07-06 15:40:08 +00001673 p.add_vpp_config()
1674 return p
1675
1676 def test_profile_api(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001677 """test profile dump API"""
Filip Tehlar84962d12020-09-08 06:08:05 +00001678 loc_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001679 "proto": 8,
1680 "start_port": 1,
1681 "end_port": 19,
1682 "start_addr": "3.3.3.2",
1683 "end_addr": "3.3.3.3",
1684 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001685 rem_ts4 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001686 "proto": 9,
1687 "start_port": 10,
1688 "end_port": 119,
1689 "start_addr": "4.5.76.80",
1690 "end_addr": "2.3.4.6",
1691 }
Filip Tehlar459d17b2020-07-06 15:40:08 +00001692
Filip Tehlar84962d12020-09-08 06:08:05 +00001693 loc_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001694 "proto": 8,
1695 "start_port": 1,
1696 "end_port": 19,
1697 "start_addr": "ab::1",
1698 "end_addr": "ab::4",
1699 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001700 rem_ts6 = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001701 "proto": 9,
1702 "start_port": 10,
1703 "end_port": 119,
1704 "start_addr": "cd::12",
1705 "end_addr": "cd::13",
1706 }
Filip Tehlar84962d12020-09-08 06:08:05 +00001707
Filip Tehlar459d17b2020-07-06 15:40:08 +00001708 conf = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001709 "p1": {
1710 "name": "p1",
1711 "natt_disabled": True,
1712 "loc_id": ("fqdn", b"vpp.home"),
1713 "rem_id": ("fqdn", b"roadwarrior.example.com"),
1714 "loc_ts": loc_ts4,
1715 "rem_ts": rem_ts4,
1716 "responder": {"sw_if_index": 0, "addr": "5.6.7.8"},
1717 "ike_ts": {
1718 "crypto_alg": 20,
1719 "crypto_key_size": 32,
1720 "integ_alg": 0,
1721 "dh_group": 1,
1722 },
1723 "esp_ts": {"crypto_alg": 13, "crypto_key_size": 24, "integ_alg": 2},
1724 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1725 "udp_encap": True,
1726 "ipsec_over_udp_port": 4501,
1727 "lifetime_data": {
1728 "lifetime": 123,
1729 "lifetime_maxdata": 20192,
1730 "lifetime_jitter": 9,
1731 "handover": 132,
1732 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001733 },
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001734 "p2": {
1735 "name": "p2",
1736 "loc_id": ("ip4-addr", b"192.168.2.1"),
1737 "rem_id": ("ip6-addr", b"abcd::1"),
1738 "loc_ts": loc_ts6,
1739 "rem_ts": rem_ts6,
1740 "responder": {"sw_if_index": 4, "addr": "def::10"},
1741 "ike_ts": {
1742 "crypto_alg": 12,
1743 "crypto_key_size": 16,
1744 "integ_alg": 3,
1745 "dh_group": 3,
1746 },
1747 "esp_ts": {"crypto_alg": 9, "crypto_key_size": 24, "integ_alg": 4},
1748 "auth": {"method": "shared-key", "data": b"sharedkeydata"},
1749 "udp_encap": False,
1750 "ipsec_over_udp_port": 4600,
1751 "tun_itf": 0,
1752 },
Filip Tehlar459d17b2020-07-06 15:40:08 +00001753 }
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001754 self.p1 = self.configure_profile(conf["p1"])
1755 self.p2 = self.configure_profile(conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001756
1757 r = self.vapi.ikev2_profile_dump()
1758 self.assertEqual(len(r), 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001759 self.verify_profile(r[0].profile, conf["p1"])
1760 self.verify_profile(r[1].profile, conf["p2"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001761
1762 def verify_id(self, api_id, cfg_id):
1763 self.assertEqual(api_id.type, IDType.value(cfg_id[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001764 self.assertEqual(bytes(api_id.data, "ascii"), cfg_id[1])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001765
1766 def verify_ts(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001767 self.assertEqual(api_ts.protocol_id, cfg_ts["proto"])
1768 self.assertEqual(api_ts.start_port, cfg_ts["start_port"])
1769 self.assertEqual(api_ts.end_port, cfg_ts["end_port"])
1770 self.assertEqual(api_ts.start_addr, ip_address(text_type(cfg_ts["start_addr"])))
1771 self.assertEqual(api_ts.end_addr, ip_address(text_type(cfg_ts["end_addr"])))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001772
1773 def verify_responder(self, api_r, cfg_r):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001774 self.assertEqual(api_r.sw_if_index, cfg_r["sw_if_index"])
1775 self.assertEqual(api_r.addr, ip_address(cfg_r["addr"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001776
1777 def verify_transforms(self, api_ts, cfg_ts):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001778 self.assertEqual(api_ts.crypto_alg, cfg_ts["crypto_alg"])
1779 self.assertEqual(api_ts.crypto_key_size, cfg_ts["crypto_key_size"])
1780 self.assertEqual(api_ts.integ_alg, cfg_ts["integ_alg"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001781
1782 def verify_ike_transforms(self, api_ts, cfg_ts):
1783 self.verify_transforms(api_ts, cfg_ts)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001784 self.assertEqual(api_ts.dh_group, cfg_ts["dh_group"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001785
1786 def verify_esp_transforms(self, api_ts, cfg_ts):
1787 self.verify_transforms(api_ts, cfg_ts)
1788
1789 def verify_auth(self, api_auth, cfg_auth):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001790 self.assertEqual(api_auth.method, AuthMethod.value(cfg_auth["method"]))
1791 self.assertEqual(api_auth.data, cfg_auth["data"])
1792 self.assertEqual(api_auth.data_len, len(cfg_auth["data"]))
Filip Tehlar459d17b2020-07-06 15:40:08 +00001793
1794 def verify_lifetime_data(self, p, ld):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001795 self.assertEqual(p.lifetime, ld["lifetime"])
1796 self.assertEqual(p.lifetime_maxdata, ld["lifetime_maxdata"])
1797 self.assertEqual(p.lifetime_jitter, ld["lifetime_jitter"])
1798 self.assertEqual(p.handover, ld["handover"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001799
1800 def verify_profile(self, ap, cp):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001801 self.assertEqual(ap.name, cp["name"])
1802 self.assertEqual(ap.udp_encap, cp["udp_encap"])
1803 self.verify_id(ap.loc_id, cp["loc_id"])
1804 self.verify_id(ap.rem_id, cp["rem_id"])
1805 self.verify_ts(ap.loc_ts, cp["loc_ts"])
1806 self.verify_ts(ap.rem_ts, cp["rem_ts"])
1807 self.verify_responder(ap.responder, cp["responder"])
1808 self.verify_ike_transforms(ap.ike_ts, cp["ike_ts"])
1809 self.verify_esp_transforms(ap.esp_ts, cp["esp_ts"])
1810 self.verify_auth(ap.auth, cp["auth"])
1811 natt_dis = False if "natt_disabled" not in cp else cp["natt_disabled"]
Filip Tehlard7fc12f2020-10-30 04:47:44 +00001812 self.assertTrue(natt_dis == ap.natt_disabled)
1813
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001814 if "lifetime_data" in cp:
1815 self.verify_lifetime_data(ap, cp["lifetime_data"])
1816 self.assertEqual(ap.ipsec_over_udp_port, cp["ipsec_over_udp_port"])
1817 if "tun_itf" in cp:
1818 self.assertEqual(ap.tun_itf, cp["tun_itf"])
Filip Tehlar459d17b2020-07-06 15:40:08 +00001819 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001820 self.assertEqual(ap.tun_itf, 0xFFFFFFFF)
Filip Tehlar459d17b2020-07-06 15:40:08 +00001821
1822
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001823@tag_fixme_vpp_workers
Filip Tehlar027d8132020-12-04 17:38:11 +00001824class TestResponderBehindNAT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001825 """test responder - responder behind NAT"""
Filip Tehlar027d8132020-12-04 17:38:11 +00001826
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001827 IKE_NODE_SUFFIX = "ip4-natt"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00001828
Filip Tehlar027d8132020-12-04 17:38:11 +00001829 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001830 self.config_params({"r_natt": True})
Filip Tehlar027d8132020-12-04 17:38:11 +00001831
1832
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001833@tag_fixme_vpp_workers
Filip Tehlar18107c92020-12-01 14:51:09 +00001834class TestInitiatorNATT(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001835 """test ikev2 initiator - NAT traversal (intitiator behind NAT)"""
Filip Tehlar18107c92020-12-01 14:51:09 +00001836
1837 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001838 self.config_params(
1839 {
1840 "i_natt": True,
1841 "is_initiator": False, # seen from test case perspective
1842 # thus vpp is initiator
1843 "responder": {
1844 "sw_if_index": self.pg0.sw_if_index,
1845 "addr": self.pg0.remote_ip4,
1846 },
1847 "ike-crypto": ("AES-GCM-16ICV", 32),
1848 "ike-integ": "NULL",
1849 "ike-dh": "3072MODPgr",
1850 "ike_transforms": {
1851 "crypto_alg": 20, # "aes-gcm-16"
1852 "crypto_key_size": 256,
1853 "dh_group": 15, # "modp-3072"
1854 },
1855 "esp_transforms": {
1856 "crypto_alg": 12, # "aes-cbc"
1857 "crypto_key_size": 256,
1858 # "hmac-sha2-256-128"
1859 "integ_alg": 12,
1860 },
1861 }
1862 )
Filip Tehlar18107c92020-12-01 14:51:09 +00001863
1864
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001865@tag_fixme_vpp_workers
Filip Tehlare7c83962020-09-23 11:20:12 +00001866class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001867 """test ikev2 initiator - pre shared key auth"""
Filip Tehlaredf29002020-10-10 04:39:11 +00001868
Filip Tehlare7c83962020-09-23 11:20:12 +00001869 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001870 self.config_params(
1871 {
1872 "is_initiator": False, # seen from test case perspective
1873 # thus vpp is initiator
1874 "ike-crypto": ("AES-GCM-16ICV", 32),
1875 "ike-integ": "NULL",
1876 "ike-dh": "3072MODPgr",
1877 "ike_transforms": {
1878 "crypto_alg": 20, # "aes-gcm-16"
1879 "crypto_key_size": 256,
1880 "dh_group": 15, # "modp-3072"
1881 },
1882 "esp_transforms": {
1883 "crypto_alg": 12, # "aes-cbc"
1884 "crypto_key_size": 256,
1885 # "hmac-sha2-256-128"
1886 "integ_alg": 12,
1887 },
1888 "responder_hostname": {
1889 "hostname": "vpp.responder.org",
1890 "sw_if_index": self.pg0.sw_if_index,
1891 },
1892 }
1893 )
Filip Tehlare7c83962020-09-23 11:20:12 +00001894
1895
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001896@tag_fixme_vpp_workers
Filip Tehlar38340fa2020-11-19 21:34:48 +00001897class TestInitiatorRequestWindowSize(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001898 """test initiator - request window size (1)"""
Filip Tehlar38340fa2020-11-19 21:34:48 +00001899
1900 def rekey_respond(self, req, update_child_sa_data):
1901 ih = self.get_ike_header(req)
1902 plain = self.sa.hmac_and_decrypt(ih)
1903 sa = ikev2.IKEv2_payload_SA(plain)
1904 if update_child_sa_data:
1905 prop = sa[ikev2.IKEv2_payload_Proposal]
1906 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
1907 self.sa.r_nonce = self.sa.i_nonce
1908 self.sa.child_sas[0].ispi = prop.SPI
1909 self.sa.child_sas[0].rspi = prop.SPI
1910 self.sa.calc_child_keys()
1911
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001912 header = ikev2.IKEv2(
1913 init_SPI=self.sa.ispi,
1914 resp_SPI=self.sa.rspi,
1915 flags="Response",
1916 exch_type=36,
1917 id=ih.id,
1918 next_payload="Encrypted",
1919 )
1920 resp = self.encrypt_ike_msg(header, sa, "SA")
1921 packet = self.create_packet(
1922 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1923 )
Filip Tehlar38340fa2020-11-19 21:34:48 +00001924 self.send_and_assert_no_replies(self.pg0, packet)
1925
1926 def test_initiator(self):
1927 super(TestInitiatorRequestWindowSize, self).test_initiator()
1928 self.pg0.enable_capture()
1929 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001930 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar38340fa2020-11-19 21:34:48 +00001931 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1932 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1933 capture = self.pg0.get_capture(2)
1934
1935 # reply in reverse order
1936 self.rekey_respond(capture[1], True)
1937 self.rekey_respond(capture[0], False)
1938
1939 # verify that only the second request was accepted
1940 self.verify_ike_sas()
1941 self.verify_ipsec_sas(is_rekey=True)
1942
1943
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001944@tag_fixme_vpp_workers
Filip Tehlar68ad6252020-10-30 05:28:11 +00001945class TestInitiatorRekey(TestInitiatorPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001946 """test ikev2 initiator - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00001947
1948 def rekey_from_initiator(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001949 ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
Filip Tehlar68ad6252020-10-30 05:28:11 +00001950 self.pg0.enable_capture()
1951 self.pg_start()
1952 self.vapi.ikev2_initiate_rekey_child_sa(ispi=ispi)
1953 capture = self.pg0.get_capture(1)
1954 ih = self.get_ike_header(capture[0])
1955 self.assertEqual(ih.exch_type, 36) # CHILD_SA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001956 self.assertNotIn("Response", ih.flags)
1957 self.assertIn("Initiator", ih.flags)
Filip Tehlar68ad6252020-10-30 05:28:11 +00001958 plain = self.sa.hmac_and_decrypt(ih)
1959 sa = ikev2.IKEv2_payload_SA(plain)
1960 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00001961 self.sa.i_nonce = sa[ikev2.IKEv2_payload_Nonce].load
1962 self.sa.r_nonce = self.sa.i_nonce
1963 # update new responder SPI
1964 self.sa.child_sas[0].ispi = prop.SPI
1965 self.sa.child_sas[0].rspi = prop.SPI
1966 self.sa.calc_child_keys()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001967 header = ikev2.IKEv2(
1968 init_SPI=self.sa.ispi,
1969 resp_SPI=self.sa.rspi,
1970 flags="Response",
1971 exch_type=36,
1972 id=ih.id,
1973 next_payload="Encrypted",
1974 )
1975 resp = self.encrypt_ike_msg(header, sa, "SA")
1976 packet = self.create_packet(
1977 self.pg0, resp, self.sa.sport, self.sa.dport, self.sa.natt, self.ip6
1978 )
Filip Tehlar68ad6252020-10-30 05:28:11 +00001979 self.send_and_assert_no_replies(self.pg0, packet)
1980
1981 def test_initiator(self):
1982 super(TestInitiatorRekey, self).test_initiator()
1983 self.rekey_from_initiator()
1984 self.verify_ike_sas()
1985 self.verify_ipsec_sas(is_rekey=True)
1986
1987
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00001988@tag_fixme_vpp_workers
Filip Tehlaredf29002020-10-10 04:39:11 +00001989class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001990 """test ikev2 initiator - delete IKE SA from responder"""
Filip Tehlaredf29002020-10-10 04:39:11 +00001991
1992 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001993 self.config_params(
1994 {
1995 "del_sa_from_responder": True,
1996 "is_initiator": False, # seen from test case perspective
1997 # thus vpp is initiator
1998 "responder": {
1999 "sw_if_index": self.pg0.sw_if_index,
2000 "addr": self.pg0.remote_ip4,
2001 },
2002 "ike-crypto": ("AES-GCM-16ICV", 32),
2003 "ike-integ": "NULL",
2004 "ike-dh": "3072MODPgr",
2005 "ike_transforms": {
2006 "crypto_alg": 20, # "aes-gcm-16"
2007 "crypto_key_size": 256,
2008 "dh_group": 15, # "modp-3072"
2009 },
2010 "esp_transforms": {
2011 "crypto_alg": 12, # "aes-cbc"
2012 "crypto_key_size": 256,
2013 # "hmac-sha2-256-128"
2014 "integ_alg": 12,
2015 },
2016 "no_idr_in_auth": True,
2017 }
2018 )
Filip Tehlaredf29002020-10-10 04:39:11 +00002019
2020
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002021@tag_fixme_vpp_workers
Filip Tehlar027d8132020-12-04 17:38:11 +00002022class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002023 """test ikev2 responder - initiator behind NAT"""
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002024
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002025 IKE_NODE_SUFFIX = "ip4-natt"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002026
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002027 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002028 self.config_params({"i_natt": True})
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002029
2030
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002031@tag_fixme_vpp_workers
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002032class TestResponderPsk(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002033 """test ikev2 responder - pre shared key auth"""
2034
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002035 def config_tc(self):
2036 self.config_params()
2037
2038
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002039@tag_fixme_vpp_workers
Filip Tehlar2008e312020-11-09 13:23:24 +00002040class TestResponderDpd(TestResponderPsk):
2041 """
2042 Dead peer detection test
2043 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002044
Filip Tehlar2008e312020-11-09 13:23:24 +00002045 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002046 self.config_params({"dpd_disabled": False})
Filip Tehlar2008e312020-11-09 13:23:24 +00002047
2048 def tearDown(self):
2049 pass
2050
2051 def test_responder(self):
2052 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2053 super(TestResponderDpd, self).test_responder()
2054 self.pg0.enable_capture()
2055 self.pg_start()
2056 # capture empty request but don't reply
2057 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2058 ih = self.get_ike_header(capture[0])
2059 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2060 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002061 self.assertEqual(plain, b"")
Filip Tehlar2008e312020-11-09 13:23:24 +00002062 # wait for SA expiration
2063 time.sleep(3)
2064 ike_sas = self.vapi.ikev2_sa_dump()
2065 self.assertEqual(len(ike_sas), 0)
2066 ipsec_sas = self.vapi.ipsec_sa_dump()
2067 self.assertEqual(len(ipsec_sas), 0)
2068
2069
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002070@tag_fixme_vpp_workers
Filip Tehlar68ad6252020-10-30 05:28:11 +00002071class TestResponderRekey(TestResponderPsk):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002072 """test ikev2 responder - rekey"""
Filip Tehlar68ad6252020-10-30 05:28:11 +00002073
2074 def rekey_from_initiator(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002075 packet = self.create_rekey_request()
Filip Tehlar68ad6252020-10-30 05:28:11 +00002076 self.pg0.add_stream(packet)
2077 self.pg0.enable_capture()
2078 self.pg_start()
2079 capture = self.pg0.get_capture(1)
2080 ih = self.get_ike_header(capture[0])
2081 plain = self.sa.hmac_and_decrypt(ih)
2082 sa = ikev2.IKEv2_payload_SA(plain)
2083 prop = sa[ikev2.IKEv2_payload_Proposal]
Filip Tehlar68ad6252020-10-30 05:28:11 +00002084 self.sa.r_nonce = sa[ikev2.IKEv2_payload_Nonce].load
2085 # update new responder SPI
2086 self.sa.child_sas[0].rspi = prop.SPI
2087
2088 def test_responder(self):
2089 super(TestResponderRekey, self).test_responder()
2090 self.rekey_from_initiator()
2091 self.sa.calc_child_keys()
2092 self.verify_ike_sas()
2093 self.verify_ipsec_sas(is_rekey=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002094 self.assert_counter(1, "rekey_req", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002095 r = self.vapi.ikev2_sa_dump()
2096 self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
Filip Tehlar68ad6252020-10-30 05:28:11 +00002097
2098
Filip Tehlard28196f2021-01-27 18:08:21 +00002099class TestResponderVrf(TestResponderPsk, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002100 """test ikev2 responder - non-default table id"""
Filip Tehlard28196f2021-01-27 18:08:21 +00002101
2102 @classmethod
2103 def setUpClass(cls):
2104 import scapy.contrib.ikev2 as _ikev2
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002105
2106 globals()["ikev2"] = _ikev2
Filip Tehlard28196f2021-01-27 18:08:21 +00002107 super(IkePeer, cls).setUpClass()
2108 cls.create_pg_interfaces(range(1))
2109 cls.vapi.cli("ip table add 1")
2110 cls.vapi.cli("set interface ip table pg0 1")
2111 for i in cls.pg_interfaces:
2112 i.admin_up()
2113 i.config_ip4()
2114 i.resolve_arp()
2115 i.config_ip6()
2116 i.resolve_ndp()
2117
2118 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002119 self.config_params({"dpd_disabled": False})
Filip Tehlard28196f2021-01-27 18:08:21 +00002120
2121 def test_responder(self):
2122 self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
2123 super(TestResponderVrf, self).test_responder()
2124 self.pg0.enable_capture()
2125 self.pg_start()
2126 capture = self.pg0.get_capture(expected_count=1, timeout=5)
2127 ih = self.get_ike_header(capture[0])
2128 self.assertEqual(ih.exch_type, 37) # INFORMATIONAL
2129 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002130 self.assertEqual(plain, b"")
Filip Tehlard28196f2021-01-27 18:08:21 +00002131
2132
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002133@tag_fixme_vpp_workers
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002134class TestResponderRsaSign(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002135 """test ikev2 responder - cert based auth"""
2136
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002137 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002138 self.config_params(
2139 {
2140 "udp_encap": True,
2141 "auth": "rsa-sig",
2142 "server-key": "server-key.pem",
2143 "client-key": "client-key.pem",
2144 "client-cert": "client-cert.pem",
2145 "server-cert": "server-cert.pem",
2146 }
2147 )
Filip Tehlarbfeae8c2020-06-23 20:35:58 +00002148
Filip Tehlar4f42a712020-07-01 08:56:59 +00002149
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002150@tag_fixme_vpp_workers
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002151class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
2152 TemplateResponder, Ikev2Params
2153):
Filip Tehlar4f42a712020-07-01 08:56:59 +00002154 """
2155 IKE:AES_CBC_128_SHA256_128,DH=modp2048 ESP:AES_CBC_192_SHA_384_192
2156 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002157
Filip Tehlar4f42a712020-07-01 08:56:59 +00002158 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002159 self.config_params(
2160 {
2161 "ike-crypto": ("AES-CBC", 16),
2162 "ike-integ": "SHA2-256-128",
2163 "esp-crypto": ("AES-CBC", 24),
2164 "esp-integ": "SHA2-384-192",
2165 "ike-dh": "2048MODPgr",
2166 "nonce": os.urandom(256),
2167 "no_idr_in_auth": True,
2168 }
2169 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002170
2171
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002172@tag_fixme_vpp_workers
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002173class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
2174 TemplateResponder, Ikev2Params
2175):
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002176
Filip Tehlar4f42a712020-07-01 08:56:59 +00002177 """
2178 IKE:AES_CBC_128_SHA256_128,DH=modp3072 ESP:AES_GCM_16
2179 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002180
Filip Tehlar4f42a712020-07-01 08:56:59 +00002181 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002182 self.config_params(
2183 {
2184 "ike-crypto": ("AES-CBC", 32),
2185 "ike-integ": "SHA2-256-128",
2186 "esp-crypto": ("AES-GCM-16ICV", 32),
2187 "esp-integ": "NULL",
2188 "ike-dh": "3072MODPgr",
2189 }
2190 )
Filip Tehlar4f42a712020-07-01 08:56:59 +00002191
2192
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002193@tag_fixme_vpp_workers
Filip Tehlara7b963d2020-07-08 13:25:34 +00002194class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
2195 """
2196 IKE:AES_GCM_16_256
2197 """
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002198
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002199 IKE_NODE_SUFFIX = "ip6"
Filip Tehlarfab5e7f2021-01-14 13:32:01 +00002200
Filip Tehlara7b963d2020-07-08 13:25:34 +00002201 def config_tc(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002202 self.config_params(
2203 {
2204 "del_sa_from_responder": True,
2205 "ip6": True,
2206 "natt": True,
2207 "ike-crypto": ("AES-GCM-16ICV", 32),
2208 "ike-integ": "NULL",
2209 "ike-dh": "2048MODPgr",
2210 "loc_ts": {"start_addr": "ab:cd::0", "end_addr": "ab:cd::10"},
2211 "rem_ts": {"start_addr": "11::0", "end_addr": "11::100"},
2212 }
2213 )
Filip Tehlara7b963d2020-07-08 13:25:34 +00002214
2215
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +00002216@tag_fixme_vpp_workers
Filip Tehlar2008e312020-11-09 13:23:24 +00002217class TestInitiatorKeepaliveMsg(TestInitiatorPsk):
2218 """
2219 Test for keep alive messages
2220 """
2221
2222 def send_empty_req_from_responder(self):
Filip Tehlar38340fa2020-11-19 21:34:48 +00002223 packet = self.create_empty_request()
Filip Tehlar2008e312020-11-09 13:23:24 +00002224 self.pg0.add_stream(packet)
2225 self.pg0.enable_capture()
2226 self.pg_start()
2227 capture = self.pg0.get_capture(1)
2228 ih = self.get_ike_header(capture[0])
2229 self.assertEqual(ih.id, self.sa.msg_id)
2230 plain = self.sa.hmac_and_decrypt(ih)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002231 self.assertEqual(plain, b"")
2232 self.assert_counter(1, "keepalive", "ip4")
Filip Tehlar68d27532021-01-25 10:09:27 +00002233 r = self.vapi.ikev2_sa_dump()
2234 self.assertEqual(1, r[0].sa.stats.n_keepalives)
Filip Tehlar2008e312020-11-09 13:23:24 +00002235
2236 def test_initiator(self):
2237 super(TestInitiatorKeepaliveMsg, self).test_initiator()
2238 self.send_empty_req_from_responder()
2239
2240
Filip Tehlar558607d2020-07-16 07:25:56 +00002241class TestMalformedMessages(TemplateResponder, Ikev2Params):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002242 """malformed packet test"""
Filip Tehlar558607d2020-07-16 07:25:56 +00002243
2244 def tearDown(self):
2245 pass
2246
2247 def config_tc(self):
2248 self.config_params()
2249
Filip Tehlar558607d2020-07-16 07:25:56 +00002250 def create_ike_init_msg(self, length=None, payload=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002251 msg = ikev2.IKEv2(
2252 length=length,
2253 init_SPI="\x11" * 8,
2254 flags="Initiator",
2255 exch_type="IKE_SA_INIT",
2256 )
Filip Tehlar558607d2020-07-16 07:25:56 +00002257 if payload is not None:
2258 msg /= payload
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002259 return self.create_packet(self.pg0, msg, self.sa.sport, self.sa.dport)
Filip Tehlar558607d2020-07-16 07:25:56 +00002260
2261 def verify_bad_packet_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002262 ike_msg = self.create_ike_init_msg(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002263 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002264 self.assert_counter(self.pkt_count, "bad_length")
Filip Tehlar558607d2020-07-16 07:25:56 +00002265
2266 def verify_bad_sa_payload_length(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002267 p = ikev2.IKEv2_payload_SA(length=0xDEAD)
Filip Tehlar558607d2020-07-16 07:25:56 +00002268 ike_msg = self.create_ike_init_msg(payload=p)
2269 self.send_and_assert_no_replies(self.pg0, ike_msg * self.pkt_count)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002270 self.assert_counter(self.pkt_count, "malformed_packet")
Filip Tehlar558607d2020-07-16 07:25:56 +00002271
2272 def test_responder(self):
2273 self.pkt_count = 254
2274 self.verify_bad_packet_length()
2275 self.verify_bad_sa_payload_length()
2276
2277
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002278if __name__ == "__main__":
Filip Tehlar12b517b2020-04-26 18:05:05 +00002279 unittest.main(testRunner=VppTestRunner)