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