mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 14:50:19 +00:00
1e03d32bea
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>
115 lines
2.9 KiB
C
115 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* INET An implementation of the TCP Authentication Option (TCP-AO).
|
|
* See RFC5925.
|
|
*
|
|
* Authors: Dmitry Safonov <dima@arista.com>
|
|
* Francesco Ruggeri <fruggeri@arista.com>
|
|
* Salam Noureddine <noureddine@arista.com>
|
|
*/
|
|
#include <crypto/hash.h>
|
|
#include <linux/tcp.h>
|
|
|
|
#include <net/tcp.h>
|
|
#include <net/ipv6.h>
|
|
|
|
static int tcp_v6_ao_calc_key(struct tcp_ao_key *mkt, u8 *key,
|
|
const struct in6_addr *saddr,
|
|
const struct in6_addr *daddr,
|
|
__be16 sport, __be16 dport,
|
|
__be32 sisn, __be32 disn)
|
|
{
|
|
struct kdf_input_block {
|
|
u8 counter;
|
|
u8 label[6];
|
|
struct tcp6_ao_context ctx;
|
|
__be16 outlen;
|
|
} __packed * tmp;
|
|
struct tcp_sigpool hp;
|
|
int err;
|
|
|
|
err = tcp_sigpool_start(mkt->tcp_sigpool_id, &hp);
|
|
if (err)
|
|
return err;
|
|
|
|
tmp = hp.scratch;
|
|
tmp->counter = 1;
|
|
memcpy(tmp->label, "TCP-AO", 6);
|
|
tmp->ctx.saddr = *saddr;
|
|
tmp->ctx.daddr = *daddr;
|
|
tmp->ctx.sport = sport;
|
|
tmp->ctx.dport = dport;
|
|
tmp->ctx.sisn = sisn;
|
|
tmp->ctx.disn = disn;
|
|
tmp->outlen = htons(tcp_ao_digest_size(mkt) * 8); /* in bits */
|
|
|
|
err = tcp_ao_calc_traffic_key(mkt, key, tmp, sizeof(*tmp), &hp);
|
|
tcp_sigpool_end(&hp);
|
|
|
|
return err;
|
|
}
|
|
|
|
int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
|
|
const struct sock *sk, __be32 sisn,
|
|
__be32 disn, bool send)
|
|
{
|
|
if (send)
|
|
return tcp_v6_ao_calc_key(mkt, key, &sk->sk_v6_rcv_saddr,
|
|
&sk->sk_v6_daddr, htons(sk->sk_num),
|
|
sk->sk_dport, sisn, disn);
|
|
else
|
|
return tcp_v6_ao_calc_key(mkt, key, &sk->sk_v6_daddr,
|
|
&sk->sk_v6_rcv_saddr, sk->sk_dport,
|
|
htons(sk->sk_num), disn, sisn);
|
|
}
|
|
|
|
static struct tcp_ao_key *tcp_v6_ao_do_lookup(const struct sock *sk,
|
|
const struct in6_addr *addr,
|
|
int sndid, int rcvid)
|
|
{
|
|
return tcp_ao_do_lookup(sk, (union tcp_ao_addr *)addr, AF_INET6,
|
|
sndid, rcvid);
|
|
}
|
|
|
|
struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk,
|
|
struct sock *addr_sk,
|
|
int sndid, int rcvid)
|
|
{
|
|
struct in6_addr *addr = &addr_sk->sk_v6_daddr;
|
|
|
|
return tcp_v6_ao_do_lookup(sk, addr, sndid, rcvid);
|
|
}
|
|
|
|
int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp,
|
|
const struct in6_addr *daddr,
|
|
const struct in6_addr *saddr, int nbytes)
|
|
{
|
|
struct tcp6_pseudohdr *bp;
|
|
struct scatterlist sg;
|
|
|
|
bp = hp->scratch;
|
|
/* 1. TCP pseudo-header (RFC2460) */
|
|
bp->saddr = *saddr;
|
|
bp->daddr = *daddr;
|
|
bp->len = cpu_to_be32(nbytes);
|
|
bp->protocol = cpu_to_be32(IPPROTO_TCP);
|
|
|
|
sg_init_one(&sg, bp, sizeof(*bp));
|
|
ahash_request_set_crypt(hp->req, &sg, NULL, sizeof(*bp));
|
|
return crypto_ahash_update(hp->req);
|
|
}
|
|
|
|
int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
|
|
const struct sock *sk, const struct sk_buff *skb,
|
|
const u8 *tkey, int hash_offset, u32 sne)
|
|
{
|
|
return tcp_ao_hash_skb(AF_INET6, ao_hash, key, sk, skb, tkey,
|
|
hash_offset, sne);
|
|
}
|
|
|
|
int tcp_v6_parse_ao(struct sock *sk, int cmd,
|
|
sockptr_t optval, int optlen)
|
|
{
|
|
return tcp_parse_ao(sk, cmd, AF_INET6, optval, optlen);
|
|
}
|