mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 10:46:33 +00:00
06b22ef295
Now when the new request socket is created from the listening socket, it's recorded what MKT was used by the peer. tcp_rsk_used_ao() is a new helper for checking if TCP-AO option was used to create the request socket. tcp_ao_copy_all_matching() will copy all keys that match the peer on the request socket, as well as preparing them for the usage (creating traffic keys). 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>
147 lines
3.8 KiB
C
147 lines
3.8 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_skb(struct tcp_ao_key *mkt, u8 *key,
|
|
const struct sk_buff *skb,
|
|
__be32 sisn, __be32 disn)
|
|
{
|
|
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
|
const struct tcphdr *th = tcp_hdr(skb);
|
|
|
|
return tcp_v6_ao_calc_key(mkt, key, &iph->saddr, &iph->daddr,
|
|
th->source, th->dest, sisn, disn);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
int tcp_v6_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key,
|
|
struct request_sock *req)
|
|
{
|
|
struct inet_request_sock *ireq = inet_rsk(req);
|
|
|
|
return tcp_v6_ao_calc_key(mkt, key,
|
|
&ireq->ir_v6_loc_addr, &ireq->ir_v6_rmt_addr,
|
|
htons(ireq->ir_num), ireq->ir_rmt_port,
|
|
htonl(tcp_rsk(req)->snt_isn),
|
|
htonl(tcp_rsk(req)->rcv_isn));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
struct tcp_ao_key *tcp_v6_ao_lookup_rsk(const struct sock *sk,
|
|
struct request_sock *req,
|
|
int sndid, int rcvid)
|
|
{
|
|
struct in6_addr *addr = &inet_rsk(req)->ir_v6_rmt_addr;
|
|
|
|
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);
|
|
}
|