1 // SPDX-License-Identifier: GPL-2.0
2 /* Author: Dmitry Safonov <dima@arista.com> */
3 #include <inttypes.h>
4 #include "../../../../include/linux/kernel.h"
5 #include "aolib.h"
6
7 const size_t nr_packets = 20;
8 const size_t msg_len = 100;
9 const size_t quota = nr_packets * msg_len;
10 union tcp_addr wrong_addr;
11 #define SECOND_PASSWORD "at all times sincere friends of freedom have been rare"
12 #define fault(type) (inj == FAULT_ ## type)
13
14 static const int test_vrf_ifindex = 200;
15 static const uint8_t test_vrf_tabid = 42;
setup_vrfs(void)16 static void setup_vrfs(void)
17 {
18 int err;
19
20 if (!kernel_config_has(KCONFIG_NET_VRF))
21 return;
22
23 err = add_vrf("ksft-vrf", test_vrf_tabid, test_vrf_ifindex, -1);
24 if (err)
25 test_error("Failed to add a VRF: %d", err);
26
27 err = link_set_up("ksft-vrf");
28 if (err)
29 test_error("Failed to bring up a VRF");
30
31 err = ip_route_add_vrf(veth_name, TEST_FAMILY,
32 this_ip_addr, this_ip_dest, test_vrf_tabid);
33 if (err)
34 test_error("Failed to add a route to VRF");
35 }
36
37
prepare_sk(union tcp_addr * addr,uint8_t sndid,uint8_t rcvid)38 static int prepare_sk(union tcp_addr *addr, uint8_t sndid, uint8_t rcvid)
39 {
40 int sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
41
42 if (sk < 0)
43 test_error("socket()");
44
45 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest,
46 DEFAULT_TEST_PREFIX, 100, 100))
47 test_error("test_add_key()");
48
49 if (addr && test_add_key(sk, SECOND_PASSWORD, *addr,
50 DEFAULT_TEST_PREFIX, sndid, rcvid))
51 test_error("test_add_key()");
52
53 return sk;
54 }
55
prepare_lsk(union tcp_addr * addr,uint8_t sndid,uint8_t rcvid)56 static int prepare_lsk(union tcp_addr *addr, uint8_t sndid, uint8_t rcvid)
57 {
58 int sk = prepare_sk(addr, sndid, rcvid);
59
60 if (listen(sk, 10))
61 test_error("listen()");
62
63 return sk;
64 }
65
test_del_key(int sk,uint8_t sndid,uint8_t rcvid,int ifindex,bool async,int current_key,int rnext_key)66 static int test_del_key(int sk, uint8_t sndid, uint8_t rcvid, int ifindex,
67 bool async, int current_key, int rnext_key)
68 {
69 struct tcp_ao_info_opt ao_info = {};
70 struct tcp_ao_getsockopt key = {};
71 struct tcp_ao_del del = {};
72 sockaddr_af sockaddr;
73 int err;
74
75 tcp_addr_to_sockaddr_in(&del.addr, &this_ip_dest, 0);
76 del.prefix = DEFAULT_TEST_PREFIX;
77 del.sndid = sndid;
78 del.rcvid = rcvid;
79 if (ifindex) {
80 del.keyflags = TCP_AO_KEYF_IFINDEX;
81 del.ifindex = ifindex;
82 }
83
84 if (current_key >= 0) {
85 del.set_current = 1;
86 del.current_key = (uint8_t)current_key;
87 }
88 if (rnext_key >= 0) {
89 del.set_rnext = 1;
90 del.rnext = (uint8_t)rnext_key;
91 }
92
93 err = setsockopt(sk, IPPROTO_TCP, TCP_AO_DEL_KEY, &del, sizeof(del));
94 if (err < 0)
95 return -errno;
96
97 if (async)
98 return 0;
99
100 tcp_addr_to_sockaddr_in(&sockaddr, &this_ip_dest, 0);
101 err = test_get_one_ao(sk, &key, &sockaddr, sizeof(sockaddr),
102 DEFAULT_TEST_PREFIX, sndid, rcvid,
103 del.keyflags, del.ifindex);
104 if (!err)
105 return -EEXIST;
106 if (err != -E2BIG)
107 test_error("getsockopt()");
108 if (current_key < 0 && rnext_key < 0)
109 return 0;
110 if (test_get_ao_info(sk, &ao_info))
111 test_error("getsockopt(TCP_AO_INFO) failed");
112 if (current_key >= 0 && ao_info.current_key != (uint8_t)current_key)
113 return -ENOTRECOVERABLE;
114 if (rnext_key >= 0 && ao_info.rnext != (uint8_t)rnext_key)
115 return -ENOTRECOVERABLE;
116 return 0;
117 }
118
try_delete_key(char * tst_name,int sk,uint8_t sndid,uint8_t rcvid,int ifindex,bool async,int current_key,int rnext_key,fault_t inj)119 static void try_delete_key(char *tst_name, int sk, uint8_t sndid, uint8_t rcvid,
120 int ifindex, bool async, int current_key, int rnext_key,
121 fault_t inj)
122 {
123 int err;
124
125 err = test_del_key(sk, sndid, rcvid, ifindex, async, current_key, rnext_key);
126 if ((err == -EBUSY && fault(BUSY)) || (err == -EINVAL && fault(CURRNEXT))) {
127 test_ok("%s: key deletion was prevented", tst_name);
128 return;
129 }
130 if (err && fault(FIXME)) {
131 test_xfail("%s: failed to delete the key %u:%u %d",
132 tst_name, sndid, rcvid, err);
133 return;
134 }
135 if (!err) {
136 if (fault(BUSY) || fault(CURRNEXT)) {
137 test_fail("%s: the key was deleted %u:%u %d", tst_name,
138 sndid, rcvid, err);
139 } else {
140 test_ok("%s: the key was deleted", tst_name);
141 }
142 return;
143 }
144 test_fail("%s: can't delete the key %u:%u %d", tst_name, sndid, rcvid, err);
145 }
146
test_set_key(int sk,int current_keyid,int rnext_keyid)147 static int test_set_key(int sk, int current_keyid, int rnext_keyid)
148 {
149 struct tcp_ao_info_opt ao_info = {};
150 int err;
151
152 if (current_keyid >= 0) {
153 ao_info.set_current = 1;
154 ao_info.current_key = (uint8_t)current_keyid;
155 }
156 if (rnext_keyid >= 0) {
157 ao_info.set_rnext = 1;
158 ao_info.rnext = (uint8_t)rnext_keyid;
159 }
160
161 err = test_set_ao_info(sk, &ao_info);
162 if (err)
163 return err;
164 if (test_get_ao_info(sk, &ao_info))
165 test_error("getsockopt(TCP_AO_INFO) failed");
166 if (current_keyid >= 0 && ao_info.current_key != (uint8_t)current_keyid)
167 return -ENOTRECOVERABLE;
168 if (rnext_keyid >= 0 && ao_info.rnext != (uint8_t)rnext_keyid)
169 return -ENOTRECOVERABLE;
170 return 0;
171 }
172
test_add_current_rnext_key(int sk,const char * key,uint8_t keyflags,union tcp_addr in_addr,uint8_t prefix,bool set_current,bool set_rnext,uint8_t sndid,uint8_t rcvid)173 static int test_add_current_rnext_key(int sk, const char *key, uint8_t keyflags,
174 union tcp_addr in_addr, uint8_t prefix,
175 bool set_current, bool set_rnext,
176 uint8_t sndid, uint8_t rcvid)
177 {
178 struct tcp_ao_add tmp = {};
179 int err;
180
181 err = test_prepare_key(&tmp, DEFAULT_TEST_ALGO, in_addr,
182 set_current, set_rnext,
183 prefix, 0, sndid, rcvid, 0, keyflags,
184 strlen(key), key);
185 if (err)
186 return err;
187
188
189 err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp));
190 if (err < 0)
191 return -errno;
192
193 return test_verify_socket_key(sk, &tmp);
194 }
195
__try_add_current_rnext_key(int sk,const char * key,uint8_t keyflags,union tcp_addr in_addr,uint8_t prefix,bool set_current,bool set_rnext,uint8_t sndid,uint8_t rcvid)196 static int __try_add_current_rnext_key(int sk, const char *key, uint8_t keyflags,
197 union tcp_addr in_addr, uint8_t prefix,
198 bool set_current, bool set_rnext,
199 uint8_t sndid, uint8_t rcvid)
200 {
201 struct tcp_ao_info_opt ao_info = {};
202 int err;
203
204 err = test_add_current_rnext_key(sk, key, keyflags, in_addr, prefix,
205 set_current, set_rnext, sndid, rcvid);
206 if (err)
207 return err;
208
209 if (test_get_ao_info(sk, &ao_info))
210 test_error("getsockopt(TCP_AO_INFO) failed");
211 if (set_current && ao_info.current_key != sndid)
212 return -ENOTRECOVERABLE;
213 if (set_rnext && ao_info.rnext != rcvid)
214 return -ENOTRECOVERABLE;
215 return 0;
216 }
217
try_add_current_rnext_key(char * tst_name,int sk,const char * key,uint8_t keyflags,union tcp_addr in_addr,uint8_t prefix,bool set_current,bool set_rnext,uint8_t sndid,uint8_t rcvid,fault_t inj)218 static void try_add_current_rnext_key(char *tst_name, int sk, const char *key,
219 uint8_t keyflags,
220 union tcp_addr in_addr, uint8_t prefix,
221 bool set_current, bool set_rnext,
222 uint8_t sndid, uint8_t rcvid, fault_t inj)
223 {
224 int err;
225
226 err = __try_add_current_rnext_key(sk, key, keyflags, in_addr, prefix,
227 set_current, set_rnext, sndid, rcvid);
228 if (!err && !fault(CURRNEXT)) {
229 test_ok("%s", tst_name);
230 return;
231 }
232 if (err == -EINVAL && fault(CURRNEXT)) {
233 test_ok("%s", tst_name);
234 return;
235 }
236 test_fail("%s", tst_name);
237 }
238
check_closed_socket(void)239 static void check_closed_socket(void)
240 {
241 int sk;
242
243 sk = prepare_sk(&this_ip_dest, 200, 200);
244 try_delete_key("closed socket, delete a key", sk, 200, 200, 0, 0, -1, -1, 0);
245 try_delete_key("closed socket, delete all keys", sk, 100, 100, 0, 0, -1, -1, 0);
246 close(sk);
247
248 sk = prepare_sk(&this_ip_dest, 200, 200);
249 if (test_set_key(sk, 100, 200))
250 test_error("failed to set current/rnext keys");
251 try_delete_key("closed socket, delete current key", sk, 100, 100, 0, 0, -1, -1, FAULT_BUSY);
252 try_delete_key("closed socket, delete rnext key", sk, 200, 200, 0, 0, -1, -1, FAULT_BUSY);
253 close(sk);
254
255 sk = prepare_sk(&this_ip_dest, 200, 200);
256 if (test_add_key(sk, "Glory to heros!", this_ip_dest,
257 DEFAULT_TEST_PREFIX, 10, 11))
258 test_error("test_add_key()");
259 if (test_add_key(sk, "Glory to Ukraine!", this_ip_dest,
260 DEFAULT_TEST_PREFIX, 12, 13))
261 test_error("test_add_key()");
262 try_delete_key("closed socket, delete a key + set current/rnext", sk,
263 100, 100, 0, 0, 10, 13, 0);
264 try_delete_key("closed socket, force-delete current key", sk, 10, 11, 0, 0, 200, -1, 0);
265 try_delete_key("closed socket, force-delete rnext key", sk, 12, 13, 0, 0, -1, 200, 0);
266 try_delete_key("closed socket, delete current+rnext key", sk,
267 200, 200, 0, 0, -1, -1, FAULT_BUSY);
268 close(sk);
269
270 sk = prepare_sk(&this_ip_dest, 200, 200);
271 if (test_set_key(sk, 100, 200))
272 test_error("failed to set current/rnext keys");
273 try_add_current_rnext_key("closed socket, add + change current key",
274 sk, "Laaaa! Lalala-la-la-lalala...", 0,
275 this_ip_dest, DEFAULT_TEST_PREFIX,
276 true, false, 10, 20, 0);
277 try_add_current_rnext_key("closed socket, add + change rnext key",
278 sk, "Laaaa! Lalala-la-la-lalala...", 0,
279 this_ip_dest, DEFAULT_TEST_PREFIX,
280 false, true, 20, 10, 0);
281 close(sk);
282
283 if (!should_skip_test("closed socket, add + delete VRF-scoped key",
284 KCONFIG_NET_VRF)) {
285 sk = prepare_sk(&this_ip_dest, 200, 200);
286 if (test_add_key_vrf(sk, SECOND_PASSWORD, TCP_AO_KEYF_IFINDEX,
287 this_ip_dest, DEFAULT_TEST_PREFIX,
288 test_vrf_ifindex, 201, 201))
289 test_error("test_add_key_vrf()");
290 try_delete_key("closed socket, add + delete VRF-scoped key", sk, 201, 201,
291 test_vrf_ifindex, 0, -1, -1, 0);
292 close(sk);
293 }
294 }
295
assert_no_current_rnext(const char * tst_msg,int sk)296 static void assert_no_current_rnext(const char *tst_msg, int sk)
297 {
298 struct tcp_ao_info_opt ao_info = {};
299
300 if (test_get_ao_info(sk, &ao_info))
301 test_error("getsockopt(TCP_AO_INFO) failed");
302
303 errno = 0;
304 if (ao_info.set_current || ao_info.set_rnext) {
305 test_xfail("%s: the socket has current/rnext keys: %d:%d",
306 tst_msg,
307 (ao_info.set_current) ? ao_info.current_key : -1,
308 (ao_info.set_rnext) ? ao_info.rnext : -1);
309 } else {
310 test_ok("%s: the socket has no current/rnext keys", tst_msg);
311 }
312 }
313
assert_no_tcp_repair(void)314 static void assert_no_tcp_repair(void)
315 {
316 struct tcp_ao_repair ao_img = {};
317 socklen_t len = sizeof(ao_img);
318 int sk, err;
319
320 sk = prepare_sk(&this_ip_dest, 200, 200);
321 test_enable_repair(sk);
322 if (listen(sk, 10))
323 test_error("listen()");
324 errno = 0;
325 err = getsockopt(sk, SOL_TCP, TCP_AO_REPAIR, &ao_img, &len);
326 if (err && errno == EPERM)
327 test_ok("listen socket, getsockopt(TCP_AO_REPAIR) is restricted");
328 else
329 test_fail("listen socket, getsockopt(TCP_AO_REPAIR) works");
330 errno = 0;
331 err = setsockopt(sk, SOL_TCP, TCP_AO_REPAIR, &ao_img, sizeof(ao_img));
332 if (err && errno == EPERM)
333 test_ok("listen socket, setsockopt(TCP_AO_REPAIR) is restricted");
334 else
335 test_fail("listen socket, setsockopt(TCP_AO_REPAIR) works");
336 close(sk);
337 }
338
check_listen_socket(void)339 static void check_listen_socket(void)
340 {
341 int sk, err;
342
343 sk = prepare_lsk(&this_ip_dest, 200, 200);
344 try_delete_key("listen socket, delete a key", sk, 200, 200, 0, 0, -1, -1, 0);
345 try_delete_key("listen socket, delete all keys", sk, 100, 100, 0, 0, -1, -1, 0);
346 close(sk);
347
348 sk = prepare_lsk(&this_ip_dest, 200, 200);
349 err = test_set_key(sk, 100, -1);
350 if (err == -EINVAL)
351 test_ok("listen socket, setting current key not allowed");
352 else
353 test_fail("listen socket, set current key");
354 err = test_set_key(sk, -1, 200);
355 if (err == -EINVAL)
356 test_ok("listen socket, setting rnext key not allowed");
357 else
358 test_fail("listen socket, set rnext key");
359 close(sk);
360
361 sk = prepare_sk(&this_ip_dest, 200, 200);
362 if (test_set_key(sk, 100, 200))
363 test_error("failed to set current/rnext keys");
364 if (listen(sk, 10))
365 test_error("listen()");
366 assert_no_current_rnext("listen() after current/rnext keys set", sk);
367 try_delete_key("listen socket, delete current key from before listen()", sk,
368 100, 100, 0, 0, -1, -1, FAULT_FIXME);
369 try_delete_key("listen socket, delete rnext key from before listen()", sk,
370 200, 200, 0, 0, -1, -1, FAULT_FIXME);
371 close(sk);
372
373 assert_no_tcp_repair();
374
375 sk = prepare_lsk(&this_ip_dest, 200, 200);
376 if (test_add_key(sk, "Glory to heros!", this_ip_dest,
377 DEFAULT_TEST_PREFIX, 10, 11))
378 test_error("test_add_key()");
379 if (test_add_key(sk, "Glory to Ukraine!", this_ip_dest,
380 DEFAULT_TEST_PREFIX, 12, 13))
381 test_error("test_add_key()");
382 try_delete_key("listen socket, delete a key + set current/rnext", sk,
383 100, 100, 0, 0, 10, 13, FAULT_CURRNEXT);
384 try_delete_key("listen socket, force-delete current key", sk,
385 10, 11, 0, 0, 200, -1, FAULT_CURRNEXT);
386 try_delete_key("listen socket, force-delete rnext key", sk,
387 12, 13, 0, 0, -1, 200, FAULT_CURRNEXT);
388 try_delete_key("listen socket, delete a key", sk,
389 200, 200, 0, 0, -1, -1, 0);
390 close(sk);
391
392 sk = prepare_lsk(&this_ip_dest, 200, 200);
393 try_add_current_rnext_key("listen socket, add + change current key",
394 sk, "Laaaa! Lalala-la-la-lalala...", 0,
395 this_ip_dest, DEFAULT_TEST_PREFIX,
396 true, false, 10, 20, FAULT_CURRNEXT);
397 try_add_current_rnext_key("listen socket, add + change rnext key",
398 sk, "Laaaa! Lalala-la-la-lalala...", 0,
399 this_ip_dest, DEFAULT_TEST_PREFIX,
400 false, true, 20, 10, FAULT_CURRNEXT);
401 close(sk);
402 }
403
404 struct test_key {
405 char password[TCP_AO_MAXKEYLEN];
406 const char *alg;
407 unsigned int len;
408 uint8_t client_keyid;
409 uint8_t server_keyid;
410 uint8_t maclen;
411 uint8_t matches_client : 1,
412 matches_server : 1,
413 matches_vrf : 1,
414 is_current : 1,
415 is_rnext : 1,
416 used_on_server_tx : 1,
417 used_on_client_tx : 1,
418 skip_counters_checks : 1;
419 };
420
421 struct key_collection {
422 unsigned int nr_keys;
423 struct test_key *keys;
424 };
425
426 static struct key_collection collection;
427
428 #define TEST_MAX_MACLEN 16
429 const char *test_algos[] = { "cmac(aes128)", "hmac(sha1)", "hmac(sha256)" };
430 const unsigned int test_maclens[] = { 1, 4, 12, 16 };
431 #define MACLEN_SHIFT 2
432 #define ALGOS_SHIFT 4
433
make_mask(unsigned int shift,unsigned int prev_shift)434 static unsigned int make_mask(unsigned int shift, unsigned int prev_shift)
435 {
436 unsigned int ret = BIT(shift) - 1;
437
438 return ret << prev_shift;
439 }
440
init_key_in_collection(unsigned int index,bool randomized)441 static void init_key_in_collection(unsigned int index, bool randomized)
442 {
443 struct test_key *key = &collection.keys[index];
444 unsigned int algos_index;
445
446 /* Same for randomized and non-randomized test flows */
447 key->client_keyid = index;
448 key->server_keyid = 127 + index;
449 key->matches_client = 1;
450 key->matches_server = 1;
451 key->matches_vrf = 1;
452 /* not really even random, but good enough for a test */
453 key->len = rand() % (TCP_AO_MAXKEYLEN - TEST_TCP_AO_MINKEYLEN);
454 key->len += TEST_TCP_AO_MINKEYLEN;
455 randomize_buffer(key->password, key->len);
456
457 if (randomized) {
458 key->maclen = (rand() % TEST_MAX_MACLEN) + 1;
459 algos_index = rand();
460 } else {
461 unsigned int shift = MACLEN_SHIFT;
462
463 key->maclen = test_maclens[index & make_mask(shift, 0)];
464 algos_index = index & make_mask(ALGOS_SHIFT, shift);
465 }
466 key->alg = test_algos[algos_index % ARRAY_SIZE(test_algos)];
467 }
468
init_default_key_collection(unsigned int nr_keys,bool randomized)469 static int init_default_key_collection(unsigned int nr_keys, bool randomized)
470 {
471 size_t key_sz = sizeof(collection.keys[0]);
472
473 if (!nr_keys) {
474 free(collection.keys);
475 collection.keys = NULL;
476 return 0;
477 }
478
479 /*
480 * All keys have uniq sndid/rcvid and sndid != rcvid in order to
481 * check for any bugs/issues for different keyids, visible to both
482 * peers. Keyid == 254 is unused.
483 */
484 if (nr_keys > 127)
485 test_error("Test requires too many keys, correct the source");
486
487 collection.keys = reallocarray(collection.keys, nr_keys, key_sz);
488 if (!collection.keys)
489 return -ENOMEM;
490
491 memset(collection.keys, 0, nr_keys * key_sz);
492 collection.nr_keys = nr_keys;
493 while (nr_keys--)
494 init_key_in_collection(nr_keys, randomized);
495
496 return 0;
497 }
498
test_key_error(const char * msg,struct test_key * key)499 static void test_key_error(const char *msg, struct test_key *key)
500 {
501 test_error("%s: key: { %s, %u:%u, %u, %u:%u:%u:%u:%u (%u)}",
502 msg, key->alg, key->client_keyid, key->server_keyid,
503 key->maclen, key->matches_client, key->matches_server,
504 key->matches_vrf, key->is_current, key->is_rnext, key->len);
505 }
506
test_add_key_cr(int sk,const char * pwd,unsigned int pwd_len,union tcp_addr addr,uint8_t vrf,uint8_t sndid,uint8_t rcvid,uint8_t maclen,const char * alg,bool set_current,bool set_rnext)507 static int test_add_key_cr(int sk, const char *pwd, unsigned int pwd_len,
508 union tcp_addr addr, uint8_t vrf,
509 uint8_t sndid, uint8_t rcvid,
510 uint8_t maclen, const char *alg,
511 bool set_current, bool set_rnext)
512 {
513 struct tcp_ao_add tmp = {};
514 uint8_t keyflags = 0;
515 int err;
516
517 if (!alg)
518 alg = DEFAULT_TEST_ALGO;
519
520 if (vrf)
521 keyflags |= TCP_AO_KEYF_IFINDEX;
522 err = test_prepare_key(&tmp, alg, addr, set_current, set_rnext,
523 DEFAULT_TEST_PREFIX, vrf, sndid, rcvid, maclen,
524 keyflags, pwd_len, pwd);
525 if (err)
526 return err;
527
528 err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp));
529 if (err < 0)
530 return -errno;
531
532 return test_verify_socket_key(sk, &tmp);
533 }
534
verify_current_rnext(const char * tst,int sk,int current_keyid,int rnext_keyid)535 static void verify_current_rnext(const char *tst, int sk,
536 int current_keyid, int rnext_keyid)
537 {
538 struct tcp_ao_info_opt ao_info = {};
539
540 if (test_get_ao_info(sk, &ao_info))
541 test_error("getsockopt(TCP_AO_INFO) failed");
542
543 errno = 0;
544 if (current_keyid >= 0) {
545 if (!ao_info.set_current)
546 test_fail("%s: the socket doesn't have current key", tst);
547 else if (ao_info.current_key != current_keyid)
548 test_fail("%s: current key is not the expected one %d != %u",
549 tst, current_keyid, ao_info.current_key);
550 else
551 test_ok("%s: current key %u as expected",
552 tst, ao_info.current_key);
553 }
554 if (rnext_keyid >= 0) {
555 if (!ao_info.set_rnext)
556 test_fail("%s: the socket doesn't have rnext key", tst);
557 else if (ao_info.rnext != rnext_keyid)
558 test_fail("%s: rnext key is not the expected one %d != %u",
559 tst, rnext_keyid, ao_info.rnext);
560 else
561 test_ok("%s: rnext key %u as expected", tst, ao_info.rnext);
562 }
563 }
564
565
key_collection_socket(bool server,unsigned int port)566 static int key_collection_socket(bool server, unsigned int port)
567 {
568 unsigned int i;
569 int sk;
570
571 if (server)
572 sk = test_listen_socket(this_ip_addr, port, 1);
573 else
574 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
575 if (sk < 0)
576 test_error("socket()");
577
578 for (i = 0; i < collection.nr_keys; i++) {
579 struct test_key *key = &collection.keys[i];
580 union tcp_addr *addr = &wrong_addr;
581 uint8_t sndid, rcvid, vrf;
582 bool set_current = false, set_rnext = false;
583
584 if (key->matches_vrf)
585 vrf = 0;
586 else
587 vrf = test_vrf_ifindex;
588 if (server) {
589 if (key->matches_client)
590 addr = &this_ip_dest;
591 sndid = key->server_keyid;
592 rcvid = key->client_keyid;
593 } else {
594 if (key->matches_server)
595 addr = &this_ip_dest;
596 sndid = key->client_keyid;
597 rcvid = key->server_keyid;
598 key->used_on_client_tx = set_current = key->is_current;
599 key->used_on_server_tx = set_rnext = key->is_rnext;
600 }
601
602 if (test_add_key_cr(sk, key->password, key->len,
603 *addr, vrf, sndid, rcvid, key->maclen,
604 key->alg, set_current, set_rnext))
605 test_key_error("setsockopt(TCP_AO_ADD_KEY)", key);
606 #ifdef DEBUG
607 test_print("%s [%u/%u] key: { %s, %u:%u, %u, %u:%u:%u:%u (%u)}",
608 server ? "server" : "client", i, collection.nr_keys,
609 key->alg, rcvid, sndid, key->maclen,
610 key->matches_client, key->matches_server,
611 key->is_current, key->is_rnext, key->len);
612 #endif
613 }
614 return sk;
615 }
616
verify_counters(const char * tst_name,bool is_listen_sk,bool server,struct tcp_counters * a,struct tcp_counters * b)617 static void verify_counters(const char *tst_name, bool is_listen_sk, bool server,
618 struct tcp_counters *a, struct tcp_counters *b)
619 {
620 unsigned int i;
621
622 test_assert_counters_sk(tst_name, a, b, TEST_CNT_GOOD);
623
624 for (i = 0; i < collection.nr_keys; i++) {
625 struct test_key *key = &collection.keys[i];
626 uint8_t sndid, rcvid;
627 bool rx_cnt_expected;
628
629 if (key->skip_counters_checks)
630 continue;
631 if (server) {
632 sndid = key->server_keyid;
633 rcvid = key->client_keyid;
634 rx_cnt_expected = key->used_on_client_tx;
635 } else {
636 sndid = key->client_keyid;
637 rcvid = key->server_keyid;
638 rx_cnt_expected = key->used_on_server_tx;
639 }
640
641 test_assert_counters_key(tst_name, &a->ao, &b->ao,
642 rx_cnt_expected ? TEST_CNT_KEY_GOOD : 0,
643 sndid, rcvid);
644 }
645 test_tcp_counters_free(a);
646 test_tcp_counters_free(b);
647 test_ok("%s: passed counters checks", tst_name);
648 }
649
lookup_key(struct tcp_ao_getsockopt * buf,size_t len,int sndid,int rcvid)650 static struct tcp_ao_getsockopt *lookup_key(struct tcp_ao_getsockopt *buf,
651 size_t len, int sndid, int rcvid)
652 {
653 size_t i;
654
655 for (i = 0; i < len; i++) {
656 if (sndid >= 0 && buf[i].sndid != sndid)
657 continue;
658 if (rcvid >= 0 && buf[i].rcvid != rcvid)
659 continue;
660 return &buf[i];
661 }
662 return NULL;
663 }
664
verify_keys(const char * tst_name,int sk,bool is_listen_sk,bool server)665 static void verify_keys(const char *tst_name, int sk,
666 bool is_listen_sk, bool server)
667 {
668 socklen_t len = sizeof(struct tcp_ao_getsockopt);
669 struct tcp_ao_getsockopt *keys;
670 bool passed_test = true;
671 unsigned int i;
672
673 keys = calloc(collection.nr_keys, len);
674 if (!keys)
675 test_error("calloc()");
676
677 keys->nkeys = collection.nr_keys;
678 keys->get_all = 1;
679
680 if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, keys, &len)) {
681 free(keys);
682 test_error("getsockopt(TCP_AO_GET_KEYS)");
683 }
684
685 for (i = 0; i < collection.nr_keys; i++) {
686 struct test_key *key = &collection.keys[i];
687 struct tcp_ao_getsockopt *dump_key;
688 bool is_kdf_aes_128_cmac = false;
689 bool is_cmac_aes = false;
690 uint8_t sndid, rcvid;
691 bool matches = false;
692
693 if (server) {
694 if (key->matches_client)
695 matches = true;
696 sndid = key->server_keyid;
697 rcvid = key->client_keyid;
698 } else {
699 if (key->matches_server)
700 matches = true;
701 sndid = key->client_keyid;
702 rcvid = key->server_keyid;
703 }
704 if (!key->matches_vrf)
705 matches = false;
706 /* no keys get removed on the original listener socket */
707 if (is_listen_sk)
708 matches = true;
709
710 dump_key = lookup_key(keys, keys->nkeys, sndid, rcvid);
711 if (matches != !!dump_key) {
712 test_fail("%s: key %u:%u %s%s on the socket",
713 tst_name, sndid, rcvid,
714 key->matches_vrf ? "" : "[vrf] ",
715 matches ? "disappeared" : "yet present");
716 passed_test = false;
717 goto out;
718 }
719 if (!dump_key)
720 continue;
721
722 if (!strcmp("cmac(aes128)", key->alg)) {
723 is_kdf_aes_128_cmac = (key->len != 16);
724 is_cmac_aes = true;
725 }
726
727 if (is_cmac_aes) {
728 if (strcmp(dump_key->alg_name, "cmac(aes)")) {
729 test_fail("%s: key %u:%u cmac(aes) has unexpected alg %s",
730 tst_name, sndid, rcvid,
731 dump_key->alg_name);
732 passed_test = false;
733 continue;
734 }
735 } else if (strcmp(dump_key->alg_name, key->alg)) {
736 test_fail("%s: key %u:%u has unexpected alg %s != %s",
737 tst_name, sndid, rcvid,
738 dump_key->alg_name, key->alg);
739 passed_test = false;
740 continue;
741 }
742 if (is_kdf_aes_128_cmac) {
743 if (dump_key->keylen != 16) {
744 test_fail("%s: key %u:%u cmac(aes128) has unexpected len %u",
745 tst_name, sndid, rcvid,
746 dump_key->keylen);
747 continue;
748 }
749 } else if (dump_key->keylen != key->len) {
750 test_fail("%s: key %u:%u changed password len %u != %u",
751 tst_name, sndid, rcvid,
752 dump_key->keylen, key->len);
753 passed_test = false;
754 continue;
755 }
756 if (!is_kdf_aes_128_cmac &&
757 memcmp(dump_key->key, key->password, key->len)) {
758 test_fail("%s: key %u:%u has different password",
759 tst_name, sndid, rcvid);
760 passed_test = false;
761 continue;
762 }
763 if (dump_key->maclen != key->maclen) {
764 test_fail("%s: key %u:%u changed maclen %u != %u",
765 tst_name, sndid, rcvid,
766 dump_key->maclen, key->maclen);
767 passed_test = false;
768 continue;
769 }
770 }
771
772 if (passed_test)
773 test_ok("%s: The socket keys are consistent with the expectations",
774 tst_name);
775 out:
776 free(keys);
777 }
778
start_server(const char * tst_name,unsigned int port,size_t quota,struct tcp_counters * begin,unsigned int current_index,unsigned int rnext_index)779 static int start_server(const char *tst_name, unsigned int port, size_t quota,
780 struct tcp_counters *begin,
781 unsigned int current_index, unsigned int rnext_index)
782 {
783 struct tcp_counters lsk_c1, lsk_c2;
784 ssize_t bytes;
785 int sk, lsk;
786
787 synchronize_threads(); /* 1: key collection initialized */
788 lsk = key_collection_socket(true, port);
789 if (test_get_tcp_counters(lsk, &lsk_c1))
790 test_error("test_get_tcp_counters()");
791 synchronize_threads(); /* 2: MKTs added => connect() */
792 if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
793 test_error("test_wait_fd()");
794
795 sk = accept(lsk, NULL, NULL);
796 if (sk < 0)
797 test_error("accept()");
798 if (test_get_tcp_counters(sk, begin))
799 test_error("test_get_tcp_counters()");
800
801 synchronize_threads(); /* 3: accepted => send data */
802 if (test_get_tcp_counters(lsk, &lsk_c2))
803 test_error("test_get_tcp_counters()");
804 verify_keys(tst_name, lsk, true, true);
805 close(lsk);
806
807 bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
808 if (bytes != quota)
809 test_fail("%s: server served: %zd", tst_name, bytes);
810 else
811 test_ok("%s: server alive", tst_name);
812
813 verify_counters(tst_name, true, true, &lsk_c1, &lsk_c2);
814
815 return sk;
816 }
817
end_server(const char * tst_name,int sk,struct tcp_counters * begin)818 static void end_server(const char *tst_name, int sk,
819 struct tcp_counters *begin)
820 {
821 struct tcp_counters end;
822
823 if (test_get_tcp_counters(sk, &end))
824 test_error("test_get_tcp_counters()");
825 verify_keys(tst_name, sk, false, true);
826
827 synchronize_threads(); /* 4: verified => closed */
828 close(sk);
829
830 verify_counters(tst_name, false, true, begin, &end);
831 synchronize_threads(); /* 5: counters */
832 }
833
try_server_run(const char * tst_name,unsigned int port,size_t quota,unsigned int current_index,unsigned int rnext_index)834 static void try_server_run(const char *tst_name, unsigned int port, size_t quota,
835 unsigned int current_index, unsigned int rnext_index)
836 {
837 struct tcp_counters tmp;
838 int sk;
839
840 sk = start_server(tst_name, port, quota, &tmp,
841 current_index, rnext_index);
842 end_server(tst_name, sk, &tmp);
843 }
844
server_rotations(const char * tst_name,unsigned int port,size_t quota,unsigned int rotations,unsigned int current_index,unsigned int rnext_index)845 static void server_rotations(const char *tst_name, unsigned int port,
846 size_t quota, unsigned int rotations,
847 unsigned int current_index, unsigned int rnext_index)
848 {
849 struct tcp_counters tmp;
850 unsigned int i;
851 int sk;
852
853 sk = start_server(tst_name, port, quota, &tmp,
854 current_index, rnext_index);
855
856 for (i = current_index + 1; rotations > 0; i++, rotations--) {
857 ssize_t bytes;
858
859 if (i >= collection.nr_keys)
860 i = 0;
861 bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
862 if (bytes != quota) {
863 test_fail("%s: server served: %zd", tst_name, bytes);
864 return;
865 }
866 verify_current_rnext(tst_name, sk,
867 collection.keys[i].server_keyid, -1);
868 synchronize_threads(); /* verify current/rnext */
869 }
870 end_server(tst_name, sk, &tmp);
871 }
872
run_client(const char * tst_name,unsigned int port,unsigned int nr_keys,int current_index,int rnext_index,struct tcp_counters * before,const size_t msg_sz,const size_t msg_nr)873 static int run_client(const char *tst_name, unsigned int port,
874 unsigned int nr_keys, int current_index, int rnext_index,
875 struct tcp_counters *before,
876 const size_t msg_sz, const size_t msg_nr)
877 {
878 int sk;
879
880 synchronize_threads(); /* 1: key collection initialized */
881 sk = key_collection_socket(false, port);
882
883 if (current_index >= 0 || rnext_index >= 0) {
884 int sndid = -1, rcvid = -1;
885
886 if (current_index >= 0)
887 sndid = collection.keys[current_index].client_keyid;
888 if (rnext_index >= 0)
889 rcvid = collection.keys[rnext_index].server_keyid;
890 if (test_set_key(sk, sndid, rcvid))
891 test_error("failed to set current/rnext keys");
892 }
893 if (before && test_get_tcp_counters(sk, before))
894 test_error("test_get_tcp_counters()");
895
896 synchronize_threads(); /* 2: MKTs added => connect() */
897 if (test_connect_socket(sk, this_ip_dest, port++) <= 0)
898 test_error("failed to connect()");
899 if (current_index < 0)
900 current_index = nr_keys - 1;
901 if (rnext_index < 0)
902 rnext_index = nr_keys - 1;
903 collection.keys[current_index].used_on_client_tx = 1;
904 collection.keys[rnext_index].used_on_server_tx = 1;
905
906 synchronize_threads(); /* 3: accepted => send data */
907 if (test_client_verify(sk, msg_sz, msg_nr)) {
908 test_fail("verify failed");
909 close(sk);
910 if (before)
911 test_tcp_counters_free(before);
912 return -1;
913 }
914
915 return sk;
916 }
917
start_client(const char * tst_name,unsigned int port,unsigned int nr_keys,int current_index,int rnext_index,struct tcp_counters * before,const size_t msg_sz,const size_t msg_nr)918 static int start_client(const char *tst_name, unsigned int port,
919 unsigned int nr_keys, int current_index, int rnext_index,
920 struct tcp_counters *before,
921 const size_t msg_sz, const size_t msg_nr)
922 {
923 if (init_default_key_collection(nr_keys, true))
924 test_error("Failed to init the key collection");
925
926 return run_client(tst_name, port, nr_keys, current_index,
927 rnext_index, before, msg_sz, msg_nr);
928 }
929
end_client(const char * tst_name,int sk,unsigned int nr_keys,int current_index,int rnext_index,struct tcp_counters * start)930 static void end_client(const char *tst_name, int sk, unsigned int nr_keys,
931 int current_index, int rnext_index,
932 struct tcp_counters *start)
933 {
934 struct tcp_counters end;
935
936 /* Some application may become dependent on this kernel choice */
937 if (current_index < 0)
938 current_index = nr_keys - 1;
939 if (rnext_index < 0)
940 rnext_index = nr_keys - 1;
941 verify_current_rnext(tst_name, sk,
942 collection.keys[current_index].client_keyid,
943 collection.keys[rnext_index].server_keyid);
944 if (start && test_get_tcp_counters(sk, &end))
945 test_error("test_get_tcp_counters()");
946 verify_keys(tst_name, sk, false, false);
947 synchronize_threads(); /* 4: verify => closed */
948 close(sk);
949 if (start)
950 verify_counters(tst_name, false, false, start, &end);
951 synchronize_threads(); /* 5: counters */
952 }
953
try_unmatched_keys(int sk,int * rnext_index,unsigned int port)954 static void try_unmatched_keys(int sk, int *rnext_index, unsigned int port)
955 {
956 struct test_key *key;
957 unsigned int i = 0;
958 int err;
959
960 do {
961 key = &collection.keys[i];
962 if (!key->matches_server)
963 break;
964 } while (++i < collection.nr_keys);
965 if (key->matches_server)
966 test_error("all keys on client match the server");
967
968 err = test_add_key_cr(sk, key->password, key->len, wrong_addr,
969 0, key->client_keyid, key->server_keyid,
970 key->maclen, key->alg, 0, 0);
971 if (!err) {
972 test_fail("Added a key with non-matching ip-address for established sk");
973 return;
974 }
975 if (err == -EINVAL)
976 test_ok("Can't add a key with non-matching ip-address for established sk");
977 else
978 test_error("Failed to add a key");
979
980 err = test_add_key_cr(sk, key->password, key->len, this_ip_dest,
981 test_vrf_ifindex,
982 key->client_keyid, key->server_keyid,
983 key->maclen, key->alg, 0, 0);
984 if (!err) {
985 test_fail("Added a key with non-matching VRF for established sk");
986 return;
987 }
988 if (err == -EINVAL)
989 test_ok("Can't add a key with non-matching VRF for established sk");
990 else
991 test_error("Failed to add a key");
992
993 for (i = 0; i < collection.nr_keys; i++) {
994 key = &collection.keys[i];
995 if (!key->matches_client)
996 break;
997 }
998 if (key->matches_client)
999 test_error("all keys on server match the client");
1000 if (test_set_key(sk, -1, key->server_keyid))
1001 test_error("Can't change the current key");
1002 trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, this_ip_addr, this_ip_dest,
1003 -1, port, 0, -1, -1, -1, -1, -1,
1004 -1, key->server_keyid, -1);
1005 if (test_client_verify(sk, msg_len, nr_packets))
1006 test_fail("verify failed");
1007 *rnext_index = i;
1008 }
1009
client_non_matching(const char * tst_name,unsigned int port,unsigned int nr_keys,int current_index,int rnext_index,const size_t msg_sz,const size_t msg_nr)1010 static int client_non_matching(const char *tst_name, unsigned int port,
1011 unsigned int nr_keys,
1012 int current_index, int rnext_index,
1013 const size_t msg_sz, const size_t msg_nr)
1014 {
1015 unsigned int i;
1016
1017 if (init_default_key_collection(nr_keys, true))
1018 test_error("Failed to init the key collection");
1019
1020 for (i = 0; i < nr_keys; i++) {
1021 /* key (0, 0) matches */
1022 collection.keys[i].matches_client = !!((i + 3) % 4);
1023 collection.keys[i].matches_server = !!((i + 2) % 4);
1024 if (kernel_config_has(KCONFIG_NET_VRF))
1025 collection.keys[i].matches_vrf = !!((i + 1) % 4);
1026 }
1027
1028 return run_client(tst_name, port, nr_keys, current_index,
1029 rnext_index, NULL, msg_sz, msg_nr);
1030 }
1031
check_current_back(const char * tst_name,unsigned int port,unsigned int nr_keys,unsigned int current_index,unsigned int rnext_index,unsigned int rotate_to_index)1032 static void check_current_back(const char *tst_name, unsigned int port,
1033 unsigned int nr_keys,
1034 unsigned int current_index, unsigned int rnext_index,
1035 unsigned int rotate_to_index)
1036 {
1037 struct tcp_counters tmp;
1038 int sk;
1039
1040 sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
1041 &tmp, msg_len, nr_packets);
1042 if (sk < 0)
1043 return;
1044 if (test_set_key(sk, collection.keys[rotate_to_index].client_keyid, -1))
1045 test_error("Can't change the current key");
1046 trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, this_ip_dest, this_ip_addr,
1047 port, -1, 0, -1, -1, -1, -1, -1,
1048 collection.keys[rotate_to_index].client_keyid,
1049 collection.keys[current_index].client_keyid, -1);
1050 if (test_client_verify(sk, msg_len, nr_packets))
1051 test_fail("verify failed");
1052 /* There is a race here: between setting the current_key with
1053 * setsockopt(TCP_AO_INFO) and starting to send some data - there
1054 * might have been a segment received with the desired
1055 * RNext_key set. In turn that would mean that the first outgoing
1056 * segment will have the desired current_key (flipped back).
1057 * Which is what the user/test wants. As it's racy, skip checking
1058 * the counters, yet check what are the resulting current/rnext
1059 * keys on both sides.
1060 */
1061 collection.keys[rotate_to_index].skip_counters_checks = 1;
1062
1063 end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
1064 }
1065
roll_over_keys(const char * tst_name,unsigned int port,unsigned int nr_keys,unsigned int rotations,unsigned int current_index,unsigned int rnext_index)1066 static void roll_over_keys(const char *tst_name, unsigned int port,
1067 unsigned int nr_keys, unsigned int rotations,
1068 unsigned int current_index, unsigned int rnext_index)
1069 {
1070 struct tcp_counters tmp;
1071 unsigned int i;
1072 int sk;
1073
1074 sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
1075 &tmp, msg_len, nr_packets);
1076 if (sk < 0)
1077 return;
1078 for (i = rnext_index + 1; rotations > 0; i++, rotations--) {
1079 if (i >= collection.nr_keys)
1080 i = 0;
1081 trace_ao_event_expect(TCP_AO_RNEXT_REQUEST,
1082 this_ip_addr, this_ip_dest,
1083 -1, port, 0, -1, -1, -1, -1, -1,
1084 i == 0 ? -1 : collection.keys[i - 1].server_keyid,
1085 collection.keys[i].server_keyid, -1);
1086 if (test_set_key(sk, -1, collection.keys[i].server_keyid))
1087 test_error("Can't change the Rnext key");
1088 if (test_client_verify(sk, msg_len, nr_packets)) {
1089 test_fail("verify failed");
1090 close(sk);
1091 test_tcp_counters_free(&tmp);
1092 return;
1093 }
1094 verify_current_rnext(tst_name, sk, -1,
1095 collection.keys[i].server_keyid);
1096 collection.keys[i].used_on_server_tx = 1;
1097 synchronize_threads(); /* verify current/rnext */
1098 }
1099 end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
1100 }
1101
try_client_run(const char * tst_name,unsigned int port,unsigned int nr_keys,int current_index,int rnext_index)1102 static void try_client_run(const char *tst_name, unsigned int port,
1103 unsigned int nr_keys, int current_index, int rnext_index)
1104 {
1105 struct tcp_counters tmp;
1106 int sk;
1107
1108 sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
1109 &tmp, msg_len, nr_packets);
1110 if (sk < 0)
1111 return;
1112 end_client(tst_name, sk, nr_keys, current_index, rnext_index, &tmp);
1113 }
1114
try_client_match(const char * tst_name,unsigned int port,unsigned int nr_keys,int current_index,int rnext_index)1115 static void try_client_match(const char *tst_name, unsigned int port,
1116 unsigned int nr_keys,
1117 int current_index, int rnext_index)
1118 {
1119 int sk;
1120
1121 sk = client_non_matching(tst_name, port, nr_keys, current_index,
1122 rnext_index, msg_len, nr_packets);
1123 if (sk < 0)
1124 return;
1125 try_unmatched_keys(sk, &rnext_index, port);
1126 end_client(tst_name, sk, nr_keys, current_index, rnext_index, NULL);
1127 }
1128
server_fn(void * arg)1129 static void *server_fn(void *arg)
1130 {
1131 unsigned int port = test_server_port;
1132
1133 setup_vrfs();
1134 try_server_run("server: Check current/rnext keys unset before connect()",
1135 port++, quota, 19, 19);
1136 try_server_run("server: Check current/rnext keys set before connect()",
1137 port++, quota, 10, 10);
1138 try_server_run("server: Check current != rnext keys set before connect()",
1139 port++, quota, 5, 10);
1140 try_server_run("server: Check current flapping back on peer's RnextKey request",
1141 port++, quota * 2, 5, 10);
1142 server_rotations("server: Rotate over all different keys", port++,
1143 quota, 20, 0, 0);
1144 try_server_run("server: Check accept() => established key matching",
1145 port++, quota * 2, 0, 0);
1146
1147 synchronize_threads(); /* don't race to exit: client exits */
1148 return NULL;
1149 }
1150
check_established_socket(void)1151 static void check_established_socket(void)
1152 {
1153 unsigned int port = test_server_port;
1154
1155 try_client_run("client: Check current/rnext keys unset before connect()",
1156 port++, 20, -1, -1);
1157 try_client_run("client: Check current/rnext keys set before connect()",
1158 port++, 20, 10, 10);
1159 try_client_run("client: Check current != rnext keys set before connect()",
1160 port++, 20, 10, 5);
1161 check_current_back("client: Check current flapping back on peer's RnextKey request",
1162 port++, 20, 10, 5, 2);
1163 roll_over_keys("client: Rotate over all different keys", port++,
1164 20, 20, 0, 0);
1165 try_client_match("client: Check connect() => established key matching",
1166 port++, 20, 0, 0);
1167 }
1168
client_fn(void * arg)1169 static void *client_fn(void *arg)
1170 {
1171 if (inet_pton(TEST_FAMILY, TEST_WRONG_IP, &wrong_addr) != 1)
1172 test_error("Can't convert ip address %s", TEST_WRONG_IP);
1173 setup_vrfs();
1174 check_closed_socket();
1175 check_listen_socket();
1176 check_established_socket();
1177 return NULL;
1178 }
1179
main(int argc,char * argv[])1180 int main(int argc, char *argv[])
1181 {
1182 test_init(122, server_fn, client_fn);
1183 return 0;
1184 }
1185