From patchwork Thu Oct 27 20:43:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Safonov X-Patchwork-Id: 619302 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5350FECAAA1 for ; Thu, 27 Oct 2022 20:53:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236527AbiJ0Uxz (ORCPT ); Thu, 27 Oct 2022 16:53:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58318 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237153AbiJ0Uwa (ORCPT ); Thu, 27 Oct 2022 16:52:30 -0400 Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D84F75CD0 for ; Thu, 27 Oct 2022 13:45:34 -0700 (PDT) Received: by mail-wm1-x333.google.com with SMTP id c7-20020a05600c0ac700b003c6cad86f38so5042309wmr.2 for ; Thu, 27 Oct 2022 13:45:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=arista.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=dwtJ3yUpPWJmmUE5F3LoS4PKdhnx1qXfUagzNvltjAg=; b=MJppJJocAVD1udLbf7Ml91Z1RvMgYtufEIobXxw8y+LEFIt5MUz2X61gtPUXpgjQY9 LKxeQkW6kawSB/rHZ11ZZ8tRLTtpyB+D6cT+JzWFT6KysDtaQePNKVNTcPLq3dygeqxb ePRCSkhCuNiCs3VkFew2WNIKeEHRNgFOoVbreGxzznEm7305W9w3ikfmXaDzLTjhWDXD Rb9nmmhrlsTKrzcTpPGSaLaOhqnGagmm1FUbRjHQiTBPR9ZosgzSDA+7B+m5tC7qwNs1 1+UgoYW+eBDLDBLQWdcaIV5CyWIAjlGseu3BibcNfAKBXppDyg1Bd9yddIB32yBymG4m 0IkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dwtJ3yUpPWJmmUE5F3LoS4PKdhnx1qXfUagzNvltjAg=; b=TQne8V7uVWe9x61gfNJtcTo5Ctiua67XRJ6uNpedNXT8x2ZnLD3aDlXPrv41JgyEOA ElbOtMQEOk0EmK0a1zqtb68lLZlIR4JQwbdZonuov8Ki2gOCB4lJM0kpN8l02RjJry7t rjyAbYtzmReDesbq37qNYKr/7630/MdV6ZJYDuPnrgm7Q9bQx/VzBJPX7gnwkC907wT6 Xf07SyjUSH2MAdQf6tdlF4l69FAmKM5TROMXheYYi9yTP5cwSNdmIEdJGdrNdVHftyn3 atPfknTXY3WHAoI04LnVg06V+hv8fP8RucRFMDS0Xv7DEptuhEpcMN1n29pgs/8lEGv6 LMGw== X-Gm-Message-State: ACrzQf1eab3yUC+uzkCF/8YaFu7ebFp/YINJmz8E5nN4IqwI+uzFBLtO WaQ8Of0vt+Yq+W7H6qVcd+lWTw== X-Google-Smtp-Source: AMsMyM4fnejBkCU0f691xbz7CzjpBLMN+lXSIezDH+0/8XINsCm+6EGJGTAS8aqCd0g0ebKEjE8jEQ== X-Received: by 2002:a1c:7c14:0:b0:3b5:1133:d2ed with SMTP id x20-20020a1c7c14000000b003b51133d2edmr7182857wmc.133.1666903488225; Thu, 27 Oct 2022 13:44:48 -0700 (PDT) Received: from Mindolluin.ire.aristanetworks.com ([217.173.96.166]) by smtp.gmail.com with ESMTPSA id n3-20020a5d6b83000000b00236644228besm1968739wrx.40.2022.10.27.13.44.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Oct 2022 13:44:47 -0700 (PDT) From: Dmitry Safonov To: linux-kernel@vger.kernel.org, David Ahern , Eric Dumazet Cc: Dmitry Safonov , Andy Lutomirski , Ard Biesheuvel , Bob Gilligan , Dan Carpenter , "David S. Miller" , Dmitry Safonov <0x7f454c46@gmail.com>, Eric Biggers , "Eric W. Biederman" , Francesco Ruggeri , Herbert Xu , Hideaki YOSHIFUJI , Ivan Delalande , Jakub Kicinski , Leonard Crestez , Paolo Abeni , Salam Noureddine , Shuah Khan , netdev@vger.kernel.org, linux-crypto@vger.kernel.org Subject: [PATCH v3 35/36] selftests/nettest: Add TCP-AO support Date: Thu, 27 Oct 2022 21:43:46 +0100 Message-Id: <20221027204347.529913-36-dima@arista.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221027204347.529913-1-dima@arista.com> References: <20221027204347.529913-1-dima@arista.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Roughly, the same as TCP-MD5 support. Signed-off-by: Dmitry Safonov --- tools/testing/selftests/net/nettest.c | 179 +++++++++++++++++++++++--- 1 file changed, 160 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/net/nettest.c b/tools/testing/selftests/net/nettest.c index 3499d6aff9e4..c81d3e2ceae1 100644 --- a/tools/testing/selftests/net/nettest.c +++ b/tools/testing/selftests/net/nettest.c @@ -77,7 +77,9 @@ struct sock_args { has_expected_laddr:1, has_expected_raddr:1, bind_test_only:1, - use_md5:1; + use_md5:1, + use_tcpao:1, + tcp_ao_excopts:1; unsigned short port; @@ -96,7 +98,7 @@ struct sock_args { const char *serverns; const char *password; - /* prefix for MD5 password */ + /* prefix for MD5/TCP-AO password */ const char *auth_prefix_str; union { struct sockaddr_in v4; @@ -105,6 +107,8 @@ struct sock_args { unsigned int prefix_len; /* 0: default, -1: force off, +1: force on */ int bind_key_ifindex; + unsigned int tcp_ao_sndid, tcp_ao_rcvid, tcp_ao_maclen; + char *tcp_ao_algo; /* expected addresses and device index for connection */ const char *expected_dev; @@ -300,7 +304,67 @@ static int tcp_md5sig(int sd, void *addr, socklen_t alen, struct sock_args *args return rc; } -static int tcp_md5_remote(int sd, struct sock_args *args) +static int tcp_ao(int sd, void *addr, socklen_t alen, struct sock_args *args) +{ + int keylen = strlen(args->password); + struct tcp_ao ao = {}; + int opt = TCP_AO; + int rc; + + if (keylen > TCP_AO_MAXKEYLEN) { + log_error("key length is too big"); + return -1; + } + ao.tcpa_keylen = keylen; + memcpy(ao.tcpa_key, args->password, keylen); + if (args->tcp_ao_algo) + strcpy(ao.tcpa_alg_name, args->tcp_ao_algo); + else + strcpy(ao.tcpa_alg_name, "cmac(aes128)"); + if (args->tcp_ao_maclen) + ao.tcpa_maclen = args->tcp_ao_maclen; + + ao.tcpa_sndid = args->tcp_ao_sndid; + ao.tcpa_rcvid = args->tcp_ao_rcvid; + if (args->tcp_ao_excopts) + ao.tcpa_keyflags |= TCP_AO_KEYF_EXCLUDE_OPT; + + if (args->prefix_len) { + ao.tcpa_prefix = args->prefix_len; + } else { + switch (args->version) { + case AF_INET: + ao.tcpa_prefix = 32; + break; + case AF_INET6: + ao.tcpa_prefix = 128; + break; + default: + log_error("unknown address family\n"); + exit(1); + } + } + memcpy(&ao.tcpa_addr, addr, alen); + + /* FIXME: Remove once matching by port is supported */ + if (args->version == AF_INET) { + struct sockaddr_in *sin = (void *)&ao.tcpa_addr; + + sin->sin_port = htons(0); + } else if (args->version == AF_INET6) { + struct sockaddr_in6 *sin6 = (void *)&ao.tcpa_addr; + + sin6->sin6_port = htons(0); + } + + rc = setsockopt(sd, IPPROTO_TCP, opt, &ao, sizeof(ao)); + if (rc < 0) + log_err_errno("setsockopt(TCP_AO)"); + + return rc; +} + +static int tcp_auth_remote(int sd, struct sock_args *args) { struct sockaddr_in sin = { .sin_family = AF_INET, @@ -329,7 +393,10 @@ static int tcp_md5_remote(int sd, struct sock_args *args) exit(1); } - if (tcp_md5sig(sd, addr, alen, args)) + if (args->use_md5 && tcp_md5sig(sd, addr, alen, args)) + return -1; + + if (args->use_tcpao && tcp_ao(sd, addr, alen, args)) return -1; return 0; @@ -1546,10 +1613,8 @@ static int do_server(struct sock_args *args, int ipc_fd) return rc; } - if (args->use_md5 && tcp_md5_remote(lsd, args)) { - close(lsd); - goto err_exit; - } + if (tcp_auth_remote(lsd, args)) + goto err_close; ipc_write(ipc_fd, 1); while (1) { @@ -1598,6 +1663,8 @@ static int do_server(struct sock_args *args, int ipc_fd) close(lsd); return rc; +err_close: + close(lsd); err_exit: ipc_write(ipc_fd, 0); return 1; @@ -1673,6 +1740,9 @@ static int connectsock(void *addr, socklen_t alen, struct sock_args *args) if (args->use_md5 && tcp_md5sig(sd, addr, alen, args)) goto err; + if (args->use_tcpao && tcp_ao(sd, addr, alen, args)) + goto err; + if (args->bind_test_only) goto out; @@ -1799,6 +1869,44 @@ static char *random_msg(int len) return m; } +static void strip_newlines(char *str) +{ + size_t i = strlen(str); + + for (; i > 0; i--) { + if (str[i - 1] != '\n') + return; + str[i - 1] = '\0'; + } +} + +static int set_tcp_ao_param(struct sock_args *args, const char *opt) +{ + char *end, *sep = strstr(opt, ":"); + unsigned long tmp; + + errno = 0; + if (sep == NULL) + goto err_fail; + + tmp = strtoul(opt, &end, 0); + if (errno || tmp > 255 || end != sep) + goto err_fail; + args->tcp_ao_sndid = (unsigned int) tmp; + + tmp = strtoul(++sep, &end, 0); + if (errno || tmp > 255 || (*end != '\n' && *end != '\0')) + goto err_fail; + args->tcp_ao_rcvid = (unsigned int) tmp; + + return 0; + +err_fail: + fprintf(stderr, "TCP-AO argument format is sndid:rcvid where ids in [0,255]\n" + "Example: -T 100:200\n"); + return -1; +} + static int ipc_child(int fd, struct sock_args *args) { char *outbuf, *errbuf; @@ -1860,13 +1968,19 @@ static int ipc_parent(int cpid, int fd, struct sock_args *args) return client_status; } -#define GETOPT_STR "sr:l:c:p:t:g:P:DRn:MX:m:d:I:BN:O:SUCi6xL:0:1:2:3:Fbqf" -#define OPT_FORCE_BIND_KEY_IFINDEX 1001 -#define OPT_NO_BIND_KEY_IFINDEX 1002 +#define GETOPT_STR "sr:l:c:p:t:g:P:DRn:MT:X:m:d:I:BN:O:SUCi6xL:0:1:2:3:Fbqf" +#define OPT_FORCE_BIND_KEY_IFINDEX 1001 +#define OPT_NO_BIND_KEY_IFINDEX 1002 +#define OPT_TCPAO_ALGO 1003 +#define OPT_TCPAO_MACLEN 1004 +#define OPT_TCPAO_EXCOPTS 1005 static struct option long_opts[] = { - {"force-bind-key-ifindex", 0, 0, OPT_FORCE_BIND_KEY_IFINDEX}, - {"no-bind-key-ifindex", 0, 0, OPT_NO_BIND_KEY_IFINDEX}, + {"force-bind-key-ifindex", 0, 0, OPT_FORCE_BIND_KEY_IFINDEX}, + {"no-bind-key-ifindex", 0, 0, OPT_NO_BIND_KEY_IFINDEX}, + {"tcpao_algo", 1, 0, OPT_TCPAO_ALGO }, + {"tcpao_maclen", 1, 0, OPT_TCPAO_MACLEN }, + {"tcpao_excopts", 0, 0, OPT_TCPAO_EXCOPTS }, {0, 0, 0, 0} }; @@ -1905,8 +2019,12 @@ static void print_usage(char *prog) " -n num number of times to send message\n" "\n" " -M use MD5 sum protection\n" - " -X password MD5 password\n" - " -m prefix/len prefix and length to use for MD5 key\n" + " -T snd:rcvid use TCP authopt (RFC5925) with snd/rcv ids\n" + " --tcpao_algo=algo TCP-AO hashing algorithm [valid with -T]\n" + " --tcpao_maclen=maclen TCP-AO MAC length [valid with -T]\n" + " --tcpao_excopts Exclude TCP options [valid with -T]\n" + " -X password MD5/TCP-AO password\n" + " -m prefix/len prefix and length to use for MD5/TCP-AO key\n" " --no-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX off\n" " --force-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX on\n" " (default: only if -I is passed)\n" @@ -2025,6 +2143,29 @@ int main(int argc, char *argv[]) case OPT_NO_BIND_KEY_IFINDEX: args.bind_key_ifindex = -1; break; + case OPT_TCPAO_ALGO: + args.tcp_ao_algo = strdup(optarg); + strip_newlines(args.tcp_ao_algo); + if (strlen(args.tcp_ao_algo) == 0) { + fprintf(stderr, "Invalid argument --tcpao_algo=%s\n", optarg); + return 1; + } + break; + case OPT_TCPAO_MACLEN: + if (str_to_uint(optarg, 1, 255, &tmp) != 0) { + fprintf(stderr, "Invalid --tcpao_maclen=%s\n", optarg); + return 1; + } + args.tcp_ao_maclen = tmp; + break; + case OPT_TCPAO_EXCOPTS: + args.tcp_ao_excopts = 1; + break; + case 'T': + args.use_tcpao = 1; + if (set_tcp_ao_param(&args, optarg)) + return 1; + break; case 'X': args.password = optarg; break; @@ -2090,15 +2231,15 @@ int main(int argc, char *argv[]) } } - if (args.password && (!args.use_md5 || + if (args.password && ((!args.use_md5 && !args.use_tcpao) || (!args.has_remote_ip && !args.auth_prefix_str) || args.type != SOCK_STREAM)) { - log_error("MD5 passwords apply to TCP only and require a remote ip for the password\n"); + log_error("TCP-MD5/TCP-AO passwords apply to TCP only and require a remote ip for the password\n"); return 1; } - if ((args.auth_prefix_str || args.use_md5) && !args.password) { - log_error("Prefix range for MD5 protection specified without a password\n"); + if ((args.auth_prefix_str || args.use_md5 || args.use_tcpao) && !args.password) { + log_error("Prefix range for TCP-MD5/TCP-AO protection specified without a password\n"); return 1; }