Add testcases for rekeying psp connections. Some simple tx or rx only scenarios, and also a more complicated mix of tx/rx rekeys and device key rotations. Note: the data echo handler does not appear here because it was added in commit 2aeb71b2f9e8 ("selftests: drv-net: add PSP responder") Signed-off-by: Daniel Zahka --- tools/testing/selftests/drivers/net/psp.py | 120 +++++++++++++++++++ .../testing/selftests/drivers/net/psp_responder.c | 131 +++++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py index 63dc8757ba37..f6bce462f28a 100755 --- a/tools/testing/selftests/drivers/net/psp.py +++ b/tools/testing/selftests/drivers/net/psp.py @@ -19,6 +19,19 @@ from lib.py import NetDrvEpEnv, PSPFamily, NlError from lib.py import bkg, rand_port, wait_port_listen +class PSPExceptShortIO(Exception): + pass + + +def psp_ver_keylen(version): + """Key length for given PSP version""" + if version == 0 or version == 2: + return 16 + elif version == 1 or version == 3: + return 32 + raise Exception(f"psp_ver_keylen(): bad version: {version}") + + def _get_outq(s): one = b'\0' * 4 outq = fcntl.ioctl(s.fileno(), termios.TIOCOUTQ, one) @@ -60,6 +73,19 @@ def _close_psp_conn(cfg, s): _close_conn(cfg, s) +def _provide_spi(cfg, version): + _send_with_ack(cfg, b'provide spi\0') + tx = cfg.comm_sock.recv(4 + psp_ver_keylen(version)) + return { + 'spi': struct.unpack('I', tx[:4])[0], + 'key': tx[4:] + } + + +def _use_spi(cfg, rx): + _send_with_ack(cfg, b'use spi\0' + struct.pack('I', rx['spi']) + rx['key']) + + def _spi_xchg(s, rx): s.send(struct.pack('I', rx['spi']) + rx['key']) tx = s.recv(4 + len(rx['key'])) @@ -110,6 +136,29 @@ def _check_data_outq(s, exp_len, force_wait=False): ksft_eq(outq, exp_len) +def _recv_careful(s, target, rounds=100): + data = b'' + for _ in range(rounds): + try: + data += s.recv(target - len(data), socket.MSG_DONTWAIT) + if len(data) == target: + return data + except BlockingIOError: + time.sleep(0.001) + raise PSPExceptShortIO(target, len(data), data) + + +def _req_echo(cfg, s, expect_fail=False): + _send_with_ack(cfg, b'data echo\0') + try: + _recv_careful(s, 5) + if expect_fail: + raise Exception("Received unexpected echo reply") + except PSPExceptShortIO: + if not expect_fail: + raise + + def _get_stat(cfg, key): return cfg.pspnl.get_stats({'dev-id': cfg.psp_dev_id})[key] @@ -399,6 +448,77 @@ def _data_basic_send(cfg, version, ipver): _close_psp_conn(cfg, s) +def data_basic_rx_rekey(cfg, version=0): + """ Test basic rx rekey """ + _init_psp_dev(cfg) + + s = _establish_psp_conn(cfg, version, None) + data_len = _send_careful(cfg, s, 10) + _check_data_rx(cfg, data_len) + + for _ in range(10): + rx_assoc = cfg.pspnl.rx_assoc({"version": version, + "dev-id": cfg.psp_dev_id, + "sock-fd": s.fileno()}) + rx = rx_assoc['rx-key'] + _use_spi(cfg, rx) + _req_echo(cfg, s) + + +def data_basic_tx_rekey(cfg, version=0): + """Test basic tx rekey""" + _init_psp_dev(cfg) + + s = _establish_psp_conn(cfg, version) + data_len = _send_careful(cfg, s, 10) + _check_data_rx(cfg, data_len) + + for _ in range(10): + tx = _provide_spi(cfg, version) + cfg.pspnl.tx_assoc({"dev-id": cfg.psp_dev_id, + "version": version, + "tx-key": tx, + "sock-fd": s.fileno()}) + data_len += _send_careful(cfg, s, 10) + _check_data_rx(cfg, data_len) + + +def data_rekey_and_rotate(cfg, version=0): + """Test a mix of key rotations and rekey operations""" + _init_psp_dev(cfg) + + s = _establish_psp_conn(cfg, version) + data_len = _send_careful(cfg, s, 10) + _check_data_rx(cfg, data_len) + + rounds = 3 + tx_rekeys_per_round = 2 + + for _ in range(rounds): + cfg.pspnl.key_rotate({"id": cfg.psp_dev_id}) + + # receive data on rotated key + _req_echo(cfg, s) + + # rekey and receive data on active key + rx_assoc = cfg.pspnl.rx_assoc({"version": version, + "dev-id": cfg.psp_dev_id, + "sock-fd": s.fileno()}) + rx = rx_assoc['rx-key'] + _use_spi(cfg, rx) + _req_echo(cfg, s) + + # perform an arbitrary number of tx rekeys + for _ in range(tx_rekeys_per_round): + tx = _provide_spi(cfg, version) + cfg.pspnl.tx_assoc({"dev-id": cfg.psp_dev_id, + "version": version, + "tx-key": tx, + "sock-fd": s.fileno()}) + data_len += _send_careful(cfg, s, 1) + _check_data_rx(cfg, data_len) + + def __bad_xfer_do(cfg, s, tx, version='hdr0-aes-gcm-128'): # Make sure we accept the ACK for the SPI before we seal with the bad assoc _check_data_outq(s, 0) diff --git a/tools/testing/selftests/drivers/net/psp_responder.c b/tools/testing/selftests/drivers/net/psp_responder.c index a26e7628bbb1..d62982e3bc68 100644 --- a/tools/testing/selftests/drivers/net/psp_responder.c +++ b/tools/testing/selftests/drivers/net/psp_responder.c @@ -37,6 +37,77 @@ static struct { unsigned char rx; } psp_vers; +static int psp_ver_key_len(unsigned char version) +{ + switch (version) { + case PSP_VERSION_HDR0_AES_GCM_128: + case PSP_VERSION_HDR0_AES_GMAC_128: + return 16; + case PSP_VERSION_HDR0_AES_GCM_256: + case PSP_VERSION_HDR0_AES_GMAC_256: + return 32; + default: + fprintf(stderr, "ERROR: %s: bad version %d\n", + __func__, version); + } + + return 0; +} + +static int +set_tx_spi(struct ynl_sock *ys, struct opts *opts, __u32 spi, char *key, + int data_sock) +{ + struct psp_tx_assoc_rsp *tsp; + struct psp_tx_assoc_req *teq; + ssize_t sz; + + teq = psp_tx_assoc_req_alloc(); + + psp_tx_assoc_req_set_sock_fd(teq, data_sock); + psp_tx_assoc_req_set_version(teq, psp_vers.tx); + psp_tx_assoc_req_set_tx_key_spi(teq, spi); + psp_tx_assoc_req_set_tx_key_key(teq, key, psp_ver_key_len(psp_vers.tx)); + + tsp = psp_tx_assoc(ys, teq); + psp_tx_assoc_req_free(teq); + if (!tsp) { + perror("ERROR: failed to Tx assoc"); + return -1; + } + psp_tx_assoc_rsp_free(tsp); + + return 0; +} + +static int +get_rx_spi(struct ynl_sock *ys, struct opts *opts, __u32 *spi, char *key, + int data_sock) +{ + struct psp_rx_assoc_rsp *rsp; + struct psp_rx_assoc_req *req; + + req = psp_rx_assoc_req_alloc(); + + psp_rx_assoc_req_set_sock_fd(req, data_sock); + psp_rx_assoc_req_set_version(req, psp_vers.rx); + + rsp = psp_rx_assoc(ys, req); + psp_rx_assoc_req_free(req); + + if (!rsp) { + perror("ERROR: failed to Rx assoc"); + return -1; + } + + memcpy(spi, &rsp->rx_key.spi, sizeof(*spi)); + memcpy(key, rsp->rx_key.key, rsp->rx_key._len.key); + + psp_rx_assoc_rsp_free(rsp); + + return 0; +} + static int conn_setup_psp(struct ynl_sock *ys, struct opts *opts, int data_sock) { struct psp_rx_assoc_rsp *rsp; @@ -118,6 +189,52 @@ static void send_str(int sock, int value) send(sock, buf, ret + 1, MSG_WAITALL); } +static void +handle_provide_spi(struct ynl_sock *ys, struct opts *opts, int data_sock, + int comm_sock) +{ + char msg[sizeof(__u32) + psp_ver_key_len(psp_vers.tx)]; + __u32 spi; + + if (data_sock < 0) { + fprintf(stderr, "WARN: provide tx spi but no data sock\n"); + send_err(comm_sock); + return; + } + + if (get_rx_spi(ys, opts, &spi, &msg[sizeof(spi)], data_sock)) { + fprintf(stderr, "ERROR: get_rx_spi() failed\n"); + send_err(comm_sock); + return; + } + + send_ack(comm_sock); + memcpy(msg, &spi, sizeof(spi)); + send(comm_sock, msg, sizeof(msg), MSG_WAITALL); +} + +static void +handle_use_spi(struct ynl_sock *ys, struct opts *opts, char *msg, int data_sock, + int comm_sock) +{ + __u32 spi; + + if (data_sock < 0) { + fprintf(stderr, "WARN: use tx spi but no data sock\n"); + send_err(comm_sock); + return; + } + + memcpy(&spi, msg, sizeof(spi)); + if (set_tx_spi(ys, opts, spi, &msg[sizeof(spi)], data_sock)) { + fprintf(stderr, "ERROR: set_tx_spi() failed!\n"); + send_err(comm_sock); + return; + } + + send_ack(comm_sock); +} + static void run_session(struct ynl_sock *ys, struct opts *opts, int server_sock, int comm_sock) @@ -224,6 +341,20 @@ run_session(struct ynl_sock *ys, struct opts *opts, fprintf(stderr, "WARN: echo but no data sock\n"); send_ack(comm_sock); } + if (cmd("provide spi")) + handle_provide_spi(ys, opts, data_sock, comm_sock); + if (cmd("use spi")) { + char msg[sizeof(__u32) + psp_ver_key_len(psp_vers.tx)]; + + if (off >= sizeof(msg)) { + memcpy(msg, buf, sizeof(msg)); + __consume(sizeof(msg)); + handle_use_spi(ys, opts, msg, data_sock, comm_sock); + } else { + fprintf(stderr, "WARN: short use spi command!\n"); + send_err(comm_sock); + } + } if (cmd("data close")) { if (data_sock >= 0) { close(data_sock); -- 2.47.3