Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net/tcp: Add TCP-AO sign to outgoing packets

Using precalculated traffic keys, sign TCP segments as prescribed by
RFC5925. Per RFC, TCP header options are included in sign calculation:
"The TCP header, by default including options, and where the TCP
checksum and TCP-AO MAC fields are set to zero, all in network-
byte order." (5.1.3)

tcp_ao_hash_header() has exclude_options parameter to optionally exclude
TCP header from hash calculation, as described in RFC5925 (9.1), this is
needed for interaction with middleboxes that may change "some TCP
options". This is wired up to AO key flags and setsockopt() later.

Similarly to TCP-MD5 hash TCP segment fragments.

From this moment a user can start sending TCP-AO signed segments with
one of crypto ahash algorithms from supported by Linux kernel. It can
have a user-specified MAC length, to either save TCP option header space
or provide higher protection using a longer signature.
The inbound segments are not yet verified, TCP-AO option is ignored and
they are accepted.

Co-developed-by: Francesco Ruggeri <fruggeri@arista.com>
Signed-off-by: Francesco Ruggeri <fruggeri@arista.com>
Co-developed-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Acked-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Dmitry Safonov and committed by
David S. Miller
1e03d32b 7c2ffaf2

+391 -38
+64
include/net/tcp.h
··· 195 195 #define TCPOPT_SACK 5 /* SACK Block */ 196 196 #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ 197 197 #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ 198 + #define TCPOPT_AO 29 /* Authentication Option (RFC5925) */ 198 199 #define TCPOPT_MPTCP 30 /* Multipath TCP (RFC6824) */ 199 200 #define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ 200 201 #define TCPOPT_EXP 254 /* Experimental */ ··· 2201 2200 int (*ao_calc_key_sk)(struct tcp_ao_key *mkt, u8 *key, 2202 2201 const struct sock *sk, 2203 2202 __be32 sisn, __be32 disn, bool send); 2203 + int (*calc_ao_hash)(char *location, struct tcp_ao_key *ao, 2204 + const struct sock *sk, const struct sk_buff *skb, 2205 + const u8 *tkey, int hash_offset, u32 sne); 2204 2206 #endif 2205 2207 }; 2206 2208 ··· 2256 2252 return 0; 2257 2253 } 2258 2254 #endif 2255 + 2256 + struct tcp_key { 2257 + union { 2258 + struct tcp_ao_key *ao_key; 2259 + struct tcp_md5sig_key *md5_key; 2260 + }; 2261 + enum { 2262 + TCP_KEY_NONE = 0, 2263 + TCP_KEY_MD5, 2264 + TCP_KEY_AO, 2265 + } type; 2266 + }; 2267 + 2268 + static inline void tcp_get_current_key(const struct sock *sk, 2269 + struct tcp_key *out) 2270 + { 2271 + #if defined(CONFIG_TCP_AO) || defined(CONFIG_TCP_MD5SIG) 2272 + const struct tcp_sock *tp = tcp_sk(sk); 2273 + #endif 2274 + #ifdef CONFIG_TCP_AO 2275 + struct tcp_ao_info *ao; 2276 + 2277 + ao = rcu_dereference_protected(tp->ao_info, lockdep_sock_is_held(sk)); 2278 + if (ao) { 2279 + out->ao_key = READ_ONCE(ao->current_key); 2280 + out->type = TCP_KEY_AO; 2281 + return; 2282 + } 2283 + #endif 2284 + #ifdef CONFIG_TCP_MD5SIG 2285 + if (static_branch_unlikely(&tcp_md5_needed.key) && 2286 + rcu_access_pointer(tp->md5sig_info)) { 2287 + out->md5_key = tp->af_specific->md5_lookup(sk, sk); 2288 + if (out->md5_key) { 2289 + out->type = TCP_KEY_MD5; 2290 + return; 2291 + } 2292 + } 2293 + #endif 2294 + out->type = TCP_KEY_NONE; 2295 + } 2296 + 2297 + static inline bool tcp_key_is_md5(const struct tcp_key *key) 2298 + { 2299 + #ifdef CONFIG_TCP_MD5SIG 2300 + if (static_branch_unlikely(&tcp_md5_needed.key) && 2301 + key->type == TCP_KEY_MD5) 2302 + return true; 2303 + #endif 2304 + return false; 2305 + } 2306 + 2307 + static inline bool tcp_key_is_ao(const struct tcp_key *key) 2308 + { 2309 + #ifdef CONFIG_TCP_AO 2310 + if (key->type == TCP_KEY_AO) 2311 + return true; 2312 + #endif 2313 + return false; 2314 + } 2259 2315 2260 2316 int tcpv4_offload_init(void); 2261 2317
+23
include/net/tcp_ao.h
··· 111 111 112 112 struct tcp_sigpool; 113 113 114 + int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb, 115 + struct tcp_ao_key *key, struct tcphdr *th, 116 + __u8 *hash_location); 117 + int tcp_ao_hash_skb(unsigned short int family, 118 + char *ao_hash, struct tcp_ao_key *key, 119 + const struct sock *sk, const struct sk_buff *skb, 120 + const u8 *tkey, int hash_offset, u32 sne); 114 121 int tcp_parse_ao(struct sock *sk, int cmd, unsigned short int family, 115 122 sockptr_t optval, int optlen); 116 123 int tcp_ao_calc_traffic_key(struct tcp_ao_key *mkt, u8 *key, void *ctx, ··· 133 126 int tcp_v4_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key, 134 127 const struct sock *sk, 135 128 __be32 sisn, __be32 disn, bool send); 129 + int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key, 130 + const struct sock *sk, const struct sk_buff *skb, 131 + const u8 *tkey, int hash_offset, u32 sne); 136 132 /* ipv6 specific functions */ 133 + int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp, 134 + const struct in6_addr *daddr, 135 + const struct in6_addr *saddr, int nbytes); 137 136 int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key, 138 137 const struct sock *sk, __be32 sisn, 139 138 __be32 disn, bool send); 140 139 struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk, 141 140 struct sock *addr_sk, int sndid, int rcvid); 141 + int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key, 142 + const struct sock *sk, const struct sk_buff *skb, 143 + const u8 *tkey, int hash_offset, u32 sne); 142 144 int tcp_v6_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen); 143 145 void tcp_ao_established(struct sock *sk); 144 146 void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb); 145 147 void tcp_ao_connect_init(struct sock *sk); 146 148 147 149 #else /* CONFIG_TCP_AO */ 150 + 151 + static inline int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb, 152 + struct tcp_ao_key *key, struct tcphdr *th, 153 + __u8 *hash_location) 154 + { 155 + return 0; 156 + } 148 157 149 158 static inline struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk, 150 159 const union tcp_ao_addr *addr, int family, int sndid, int rcvid)
+199
net/ipv4/tcp_ao.c
··· 262 262 return -EOPNOTSUPP; 263 263 } 264 264 265 + static int tcp_v4_ao_hash_pseudoheader(struct tcp_sigpool *hp, 266 + __be32 daddr, __be32 saddr, 267 + int nbytes) 268 + { 269 + struct tcp4_pseudohdr *bp; 270 + struct scatterlist sg; 271 + 272 + bp = hp->scratch; 273 + bp->saddr = saddr; 274 + bp->daddr = daddr; 275 + bp->pad = 0; 276 + bp->protocol = IPPROTO_TCP; 277 + bp->len = cpu_to_be16(nbytes); 278 + 279 + sg_init_one(&sg, bp, sizeof(*bp)); 280 + ahash_request_set_crypt(hp->req, &sg, NULL, sizeof(*bp)); 281 + return crypto_ahash_update(hp->req); 282 + } 283 + 284 + static int tcp_ao_hash_pseudoheader(unsigned short int family, 285 + const struct sock *sk, 286 + const struct sk_buff *skb, 287 + struct tcp_sigpool *hp, int nbytes) 288 + { 289 + const struct tcphdr *th = tcp_hdr(skb); 290 + 291 + /* TODO: Can we rely on checksum being zero to mean outbound pkt? */ 292 + if (!th->check) { 293 + if (family == AF_INET) 294 + return tcp_v4_ao_hash_pseudoheader(hp, sk->sk_daddr, 295 + sk->sk_rcv_saddr, skb->len); 296 + #if IS_ENABLED(CONFIG_IPV6) 297 + else if (family == AF_INET6) 298 + return tcp_v6_ao_hash_pseudoheader(hp, &sk->sk_v6_daddr, 299 + &sk->sk_v6_rcv_saddr, skb->len); 300 + #endif 301 + else 302 + return -EAFNOSUPPORT; 303 + } 304 + 305 + if (family == AF_INET) { 306 + const struct iphdr *iph = ip_hdr(skb); 307 + 308 + return tcp_v4_ao_hash_pseudoheader(hp, iph->daddr, 309 + iph->saddr, skb->len); 310 + #if IS_ENABLED(CONFIG_IPV6) 311 + } else if (family == AF_INET6) { 312 + const struct ipv6hdr *iph = ipv6_hdr(skb); 313 + 314 + return tcp_v6_ao_hash_pseudoheader(hp, &iph->daddr, 315 + &iph->saddr, skb->len); 316 + #endif 317 + } 318 + return -EAFNOSUPPORT; 319 + } 320 + 321 + /* tcp_ao_hash_sne(struct tcp_sigpool *hp) 322 + * @hp - used for hashing 323 + * @sne - sne value 324 + */ 325 + static int tcp_ao_hash_sne(struct tcp_sigpool *hp, u32 sne) 326 + { 327 + struct scatterlist sg; 328 + __be32 *bp; 329 + 330 + bp = (__be32 *)hp->scratch; 331 + *bp = htonl(sne); 332 + 333 + sg_init_one(&sg, bp, sizeof(*bp)); 334 + ahash_request_set_crypt(hp->req, &sg, NULL, sizeof(*bp)); 335 + return crypto_ahash_update(hp->req); 336 + } 337 + 338 + static int tcp_ao_hash_header(struct tcp_sigpool *hp, 339 + const struct tcphdr *th, 340 + bool exclude_options, u8 *hash, 341 + int hash_offset, int hash_len) 342 + { 343 + int err, len = th->doff << 2; 344 + struct scatterlist sg; 345 + u8 *hdr = hp->scratch; 346 + 347 + /* We are not allowed to change tcphdr, make a local copy */ 348 + if (exclude_options) { 349 + len = sizeof(*th) + sizeof(struct tcp_ao_hdr) + hash_len; 350 + memcpy(hdr, th, sizeof(*th)); 351 + memcpy(hdr + sizeof(*th), 352 + (u8 *)th + hash_offset - sizeof(struct tcp_ao_hdr), 353 + sizeof(struct tcp_ao_hdr)); 354 + memset(hdr + sizeof(*th) + sizeof(struct tcp_ao_hdr), 355 + 0, hash_len); 356 + ((struct tcphdr *)hdr)->check = 0; 357 + } else { 358 + len = th->doff << 2; 359 + memcpy(hdr, th, len); 360 + /* zero out tcp-ao hash */ 361 + ((struct tcphdr *)hdr)->check = 0; 362 + memset(hdr + hash_offset, 0, hash_len); 363 + } 364 + 365 + sg_init_one(&sg, hdr, len); 366 + ahash_request_set_crypt(hp->req, &sg, NULL, len); 367 + err = crypto_ahash_update(hp->req); 368 + WARN_ON_ONCE(err != 0); 369 + return err; 370 + } 371 + 372 + int tcp_ao_hash_skb(unsigned short int family, 373 + char *ao_hash, struct tcp_ao_key *key, 374 + const struct sock *sk, const struct sk_buff *skb, 375 + const u8 *tkey, int hash_offset, u32 sne) 376 + { 377 + const struct tcphdr *th = tcp_hdr(skb); 378 + int tkey_len = tcp_ao_digest_size(key); 379 + struct tcp_sigpool hp; 380 + void *hash_buf = NULL; 381 + 382 + hash_buf = kmalloc(tkey_len, GFP_ATOMIC); 383 + if (!hash_buf) 384 + goto clear_hash_noput; 385 + 386 + if (tcp_sigpool_start(key->tcp_sigpool_id, &hp)) 387 + goto clear_hash_noput; 388 + 389 + if (crypto_ahash_setkey(crypto_ahash_reqtfm(hp.req), tkey, tkey_len)) 390 + goto clear_hash; 391 + 392 + /* For now use sha1 by default. Depends on alg in tcp_ao_key */ 393 + if (crypto_ahash_init(hp.req)) 394 + goto clear_hash; 395 + 396 + if (tcp_ao_hash_sne(&hp, sne)) 397 + goto clear_hash; 398 + if (tcp_ao_hash_pseudoheader(family, sk, skb, &hp, skb->len)) 399 + goto clear_hash; 400 + if (tcp_ao_hash_header(&hp, th, false, 401 + ao_hash, hash_offset, tcp_ao_maclen(key))) 402 + goto clear_hash; 403 + if (tcp_sigpool_hash_skb_data(&hp, skb, th->doff << 2)) 404 + goto clear_hash; 405 + ahash_request_set_crypt(hp.req, NULL, hash_buf, 0); 406 + if (crypto_ahash_final(hp.req)) 407 + goto clear_hash; 408 + 409 + memcpy(ao_hash, hash_buf, tcp_ao_maclen(key)); 410 + tcp_sigpool_end(&hp); 411 + kfree(hash_buf); 412 + return 0; 413 + 414 + clear_hash: 415 + tcp_sigpool_end(&hp); 416 + clear_hash_noput: 417 + memset(ao_hash, 0, tcp_ao_maclen(key)); 418 + kfree(hash_buf); 419 + return 1; 420 + } 421 + 422 + int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key, 423 + const struct sock *sk, const struct sk_buff *skb, 424 + const u8 *tkey, int hash_offset, u32 sne) 425 + { 426 + return tcp_ao_hash_skb(AF_INET, ao_hash, key, sk, skb, 427 + tkey, hash_offset, sne); 428 + } 429 + 265 430 struct tcp_ao_key *tcp_v4_ao_lookup(const struct sock *sk, struct sock *addr_sk, 266 431 int sndid, int rcvid) 267 432 { 268 433 union tcp_ao_addr *addr = (union tcp_ao_addr *)&addr_sk->sk_daddr; 269 434 270 435 return tcp_ao_do_lookup(sk, addr, AF_INET, sndid, rcvid); 436 + } 437 + 438 + int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb, 439 + struct tcp_ao_key *key, struct tcphdr *th, 440 + __u8 *hash_location) 441 + { 442 + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); 443 + struct tcp_sock *tp = tcp_sk(sk); 444 + struct tcp_ao_info *ao; 445 + void *tkey_buf = NULL; 446 + u8 *traffic_key; 447 + 448 + ao = rcu_dereference_protected(tcp_sk(sk)->ao_info, 449 + lockdep_sock_is_held(sk)); 450 + traffic_key = snd_other_key(key); 451 + if (unlikely(tcb->tcp_flags & TCPHDR_SYN)) { 452 + __be32 disn; 453 + 454 + if (!(tcb->tcp_flags & TCPHDR_ACK)) { 455 + disn = 0; 456 + tkey_buf = kmalloc(tcp_ao_digest_size(key), GFP_ATOMIC); 457 + if (!tkey_buf) 458 + return -ENOMEM; 459 + traffic_key = tkey_buf; 460 + } else { 461 + disn = ao->risn; 462 + } 463 + tp->af_specific->ao_calc_key_sk(key, traffic_key, 464 + sk, ao->lisn, disn, true); 465 + } 466 + tp->af_specific->calc_ao_hash(hash_location, key, sk, skb, traffic_key, 467 + hash_location - (u8 *)th, 0); 468 + kfree(tkey_buf); 469 + return 0; 271 470 } 272 471 273 472 static int tcp_ao_cache_traffic_keys(const struct sock *sk,
+1
net/ipv4/tcp_ipv4.c
··· 2287 2287 #endif 2288 2288 #ifdef CONFIG_TCP_AO 2289 2289 .ao_lookup = tcp_v4_ao_lookup, 2290 + .calc_ao_hash = tcp_v4_ao_hash_skb, 2290 2291 .ao_parse = tcp_v4_parse_ao, 2291 2292 .ao_calc_key_sk = tcp_v4_ao_calc_key_sk, 2292 2293 #endif
+74 -38
net/ipv4/tcp_output.c
··· 422 422 #define OPTION_FAST_OPEN_COOKIE BIT(8) 423 423 #define OPTION_SMC BIT(9) 424 424 #define OPTION_MPTCP BIT(10) 425 + #define OPTION_AO BIT(11) 425 426 426 427 static void smc_options_write(__be32 *ptr, u16 *options) 427 428 { ··· 615 614 * (but it may well be that other scenarios fail similarly). 616 615 */ 617 616 static void tcp_options_write(struct tcphdr *th, struct tcp_sock *tp, 618 - struct tcp_out_options *opts) 617 + struct tcp_out_options *opts, 618 + struct tcp_key *key) 619 619 { 620 620 __be32 *ptr = (__be32 *)(th + 1); 621 621 u16 options = opts->options; /* mungable copy */ 622 622 623 - if (unlikely(OPTION_MD5 & options)) { 623 + if (tcp_key_is_md5(key)) { 624 624 *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | 625 625 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); 626 626 /* overload cookie hash location */ 627 627 opts->hash_location = (__u8 *)ptr; 628 628 ptr += 4; 629 - } 629 + } else if (tcp_key_is_ao(key)) { 630 + #ifdef CONFIG_TCP_AO 631 + struct tcp_ao_key *rnext_key; 632 + struct tcp_ao_info *ao_info; 633 + u8 maclen; 630 634 635 + ao_info = rcu_dereference_check(tp->ao_info, 636 + lockdep_sock_is_held(&tp->inet_conn.icsk_inet.sk)); 637 + rnext_key = READ_ONCE(ao_info->rnext_key); 638 + if (WARN_ON_ONCE(!rnext_key)) 639 + goto out_ao; 640 + maclen = tcp_ao_maclen(key->ao_key); 641 + *ptr++ = htonl((TCPOPT_AO << 24) | 642 + (tcp_ao_len(key->ao_key) << 16) | 643 + (key->ao_key->sndid << 8) | 644 + (rnext_key->rcvid)); 645 + opts->hash_location = (__u8 *)ptr; 646 + ptr += maclen / sizeof(*ptr); 647 + if (unlikely(maclen % sizeof(*ptr))) { 648 + memset(ptr, TCPOPT_NOP, sizeof(*ptr)); 649 + ptr++; 650 + } 651 + out_ao: 652 + #endif 653 + } 631 654 if (unlikely(opts->mss)) { 632 655 *ptr++ = htonl((TCPOPT_MSS << 24) | 633 656 (TCPOLEN_MSS << 16) | ··· 792 767 */ 793 768 static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, 794 769 struct tcp_out_options *opts, 795 - struct tcp_md5sig_key **md5) 770 + struct tcp_key *key) 796 771 { 797 772 struct tcp_sock *tp = tcp_sk(sk); 798 773 unsigned int remaining = MAX_TCP_OPTION_SPACE; 799 774 struct tcp_fastopen_request *fastopen = tp->fastopen_req; 775 + bool timestamps; 800 776 801 - *md5 = NULL; 802 - #ifdef CONFIG_TCP_MD5SIG 803 - if (static_branch_unlikely(&tcp_md5_needed.key) && 804 - rcu_access_pointer(tp->md5sig_info)) { 805 - *md5 = tp->af_specific->md5_lookup(sk, sk); 806 - if (*md5) { 807 - opts->options |= OPTION_MD5; 808 - remaining -= TCPOLEN_MD5SIG_ALIGNED; 777 + /* Better than switch (key.type) as it has static branches */ 778 + if (tcp_key_is_md5(key)) { 779 + timestamps = false; 780 + opts->options |= OPTION_MD5; 781 + remaining -= TCPOLEN_MD5SIG_ALIGNED; 782 + } else { 783 + timestamps = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps); 784 + if (tcp_key_is_ao(key)) { 785 + opts->options |= OPTION_AO; 786 + remaining -= tcp_ao_len(key->ao_key); 809 787 } 810 788 } 811 - #endif 812 789 813 790 /* We always get an MSS option. The option bytes which will be seen in 814 791 * normal data packets should timestamps be used, must be in the MSS ··· 824 797 opts->mss = tcp_advertise_mss(sk); 825 798 remaining -= TCPOLEN_MSS_ALIGNED; 826 799 827 - if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps) && !*md5)) { 800 + if (likely(timestamps)) { 828 801 opts->options |= OPTION_TS; 829 802 opts->tsval = tcp_skb_timestamp_ts(tp->tcp_usec_ts, skb) + tp->tsoffset; 830 803 opts->tsecr = tp->rx_opt.ts_recent; ··· 949 922 */ 950 923 static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb, 951 924 struct tcp_out_options *opts, 952 - struct tcp_md5sig_key **md5) 925 + struct tcp_key *key) 953 926 { 954 927 struct tcp_sock *tp = tcp_sk(sk); 955 928 unsigned int size = 0; ··· 957 930 958 931 opts->options = 0; 959 932 960 - *md5 = NULL; 961 - #ifdef CONFIG_TCP_MD5SIG 962 - if (static_branch_unlikely(&tcp_md5_needed.key) && 963 - rcu_access_pointer(tp->md5sig_info)) { 964 - *md5 = tp->af_specific->md5_lookup(sk, sk); 965 - if (*md5) { 966 - opts->options |= OPTION_MD5; 967 - size += TCPOLEN_MD5SIG_ALIGNED; 968 - } 933 + /* Better than switch (key.type) as it has static branches */ 934 + if (tcp_key_is_md5(key)) { 935 + opts->options |= OPTION_MD5; 936 + size += TCPOLEN_MD5SIG_ALIGNED; 937 + } else if (tcp_key_is_ao(key)) { 938 + opts->options |= OPTION_AO; 939 + size += tcp_ao_len(key->ao_key); 969 940 } 970 - #endif 971 941 972 942 if (likely(tp->rx_opt.tstamp_ok)) { 973 943 opts->options |= OPTION_TS; ··· 1269 1245 struct tcp_out_options opts; 1270 1246 unsigned int tcp_options_size, tcp_header_size; 1271 1247 struct sk_buff *oskb = NULL; 1272 - struct tcp_md5sig_key *md5; 1248 + struct tcp_key key; 1273 1249 struct tcphdr *th; 1274 1250 u64 prior_wstamp; 1275 1251 int err; ··· 1301 1277 tcb = TCP_SKB_CB(skb); 1302 1278 memset(&opts, 0, sizeof(opts)); 1303 1279 1280 + tcp_get_current_key(sk, &key); 1304 1281 if (unlikely(tcb->tcp_flags & TCPHDR_SYN)) { 1305 - tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5); 1282 + tcp_options_size = tcp_syn_options(sk, skb, &opts, &key); 1306 1283 } else { 1307 - tcp_options_size = tcp_established_options(sk, skb, &opts, 1308 - &md5); 1284 + tcp_options_size = tcp_established_options(sk, skb, &opts, &key); 1309 1285 /* Force a PSH flag on all (GSO) packets to expedite GRO flush 1310 1286 * at receiver : This slightly improve GRO performance. 1311 1287 * Note that we do not force the PSH flag for non GSO packets, ··· 1386 1362 th->window = htons(min(tp->rcv_wnd, 65535U)); 1387 1363 } 1388 1364 1389 - tcp_options_write(th, tp, &opts); 1365 + tcp_options_write(th, tp, &opts, &key); 1390 1366 1367 + if (tcp_key_is_md5(&key)) { 1391 1368 #ifdef CONFIG_TCP_MD5SIG 1392 - /* Calculate the MD5 hash, as we have all we need now */ 1393 - if (md5) { 1369 + /* Calculate the MD5 hash, as we have all we need now */ 1394 1370 sk_gso_disable(sk); 1395 1371 tp->af_specific->calc_md5_hash(opts.hash_location, 1396 - md5, sk, skb); 1397 - } 1372 + key.md5_key, sk, skb); 1398 1373 #endif 1374 + } else if (tcp_key_is_ao(&key)) { 1375 + int err; 1376 + 1377 + err = tcp_ao_transmit_skb(sk, skb, key.ao_key, th, 1378 + opts.hash_location); 1379 + if (err) { 1380 + kfree_skb_reason(skb, SKB_DROP_REASON_NOT_SPECIFIED); 1381 + return -ENOMEM; 1382 + } 1383 + } 1399 1384 1400 1385 /* BPF prog is the last one writing header option */ 1401 1386 bpf_skops_write_hdr_opt(sk, skb, NULL, NULL, 0, &opts); ··· 1837 1804 u32 mss_now; 1838 1805 unsigned int header_len; 1839 1806 struct tcp_out_options opts; 1840 - struct tcp_md5sig_key *md5; 1807 + struct tcp_key key; 1841 1808 1842 1809 mss_now = tp->mss_cache; 1843 1810 ··· 1846 1813 if (mtu != inet_csk(sk)->icsk_pmtu_cookie) 1847 1814 mss_now = tcp_sync_mss(sk, mtu); 1848 1815 } 1849 - 1850 - header_len = tcp_established_options(sk, NULL, &opts, &md5) + 1816 + tcp_get_current_key(sk, &key); 1817 + header_len = tcp_established_options(sk, NULL, &opts, &key) + 1851 1818 sizeof(struct tcphdr); 1852 1819 /* The mss_cache is sized based on tp->tcp_header_len, which assumes 1853 1820 * some common options. If this is an odd packet (because we have SACK ··· 3646 3613 const struct tcp_sock *tp = tcp_sk(sk); 3647 3614 struct tcp_md5sig_key *md5 = NULL; 3648 3615 struct tcp_out_options opts; 3616 + struct tcp_key key = {}; 3649 3617 struct sk_buff *skb; 3650 3618 int tcp_header_size; 3651 3619 struct tcphdr *th; ··· 3701 3667 #ifdef CONFIG_TCP_MD5SIG 3702 3668 rcu_read_lock(); 3703 3669 md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req)); 3670 + if (md5) 3671 + key.type = TCP_KEY_MD5; 3704 3672 #endif 3705 3673 skb_set_hash(skb, READ_ONCE(tcp_rsk(req)->txhash), PKT_HASH_TYPE_L4); 3706 3674 /* bpf program will be interested in the tcp_flags */ ··· 3729 3693 3730 3694 /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ 3731 3695 th->window = htons(min(req->rsk_rcv_wnd, 65535U)); 3732 - tcp_options_write(th, NULL, &opts); 3696 + tcp_options_write(th, NULL, &opts, &key); 3733 3697 th->doff = (tcp_header_size >> 2); 3734 3698 TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); 3735 3699
+28
net/ipv6/tcp_ao.c
··· 7 7 * Francesco Ruggeri <fruggeri@arista.com> 8 8 * Salam Noureddine <noureddine@arista.com> 9 9 */ 10 + #include <crypto/hash.h> 10 11 #include <linux/tcp.h> 11 12 12 13 #include <net/tcp.h> ··· 78 77 struct in6_addr *addr = &addr_sk->sk_v6_daddr; 79 78 80 79 return tcp_v6_ao_do_lookup(sk, addr, sndid, rcvid); 80 + } 81 + 82 + int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp, 83 + const struct in6_addr *daddr, 84 + const struct in6_addr *saddr, int nbytes) 85 + { 86 + struct tcp6_pseudohdr *bp; 87 + struct scatterlist sg; 88 + 89 + bp = hp->scratch; 90 + /* 1. TCP pseudo-header (RFC2460) */ 91 + bp->saddr = *saddr; 92 + bp->daddr = *daddr; 93 + bp->len = cpu_to_be32(nbytes); 94 + bp->protocol = cpu_to_be32(IPPROTO_TCP); 95 + 96 + sg_init_one(&sg, bp, sizeof(*bp)); 97 + ahash_request_set_crypt(hp->req, &sg, NULL, sizeof(*bp)); 98 + return crypto_ahash_update(hp->req); 99 + } 100 + 101 + int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key, 102 + const struct sock *sk, const struct sk_buff *skb, 103 + const u8 *tkey, int hash_offset, u32 sne) 104 + { 105 + return tcp_ao_hash_skb(AF_INET6, ao_hash, key, sk, skb, tkey, 106 + hash_offset, sne); 81 107 } 82 108 83 109 int tcp_v6_parse_ao(struct sock *sk, int cmd,
+2
net/ipv6/tcp_ipv6.c
··· 1920 1920 #endif 1921 1921 #ifdef CONFIG_TCP_AO 1922 1922 .ao_lookup = tcp_v6_ao_lookup, 1923 + .calc_ao_hash = tcp_v6_ao_hash_skb, 1923 1924 .ao_parse = tcp_v6_parse_ao, 1924 1925 .ao_calc_key_sk = tcp_v6_ao_calc_key_sk, 1925 1926 #endif ··· 1954 1953 #endif 1955 1954 #ifdef CONFIG_TCP_AO 1956 1955 .ao_lookup = tcp_v6_ao_lookup, 1956 + .calc_ao_hash = tcp_v4_ao_hash_skb, 1957 1957 .ao_parse = tcp_v6_parse_ao, 1958 1958 #endif 1959 1959 };