Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * INET		An implementation of the TCP Authentication Option (TCP-AO).
  4 *		See RFC5925.
  5 *
  6 * Authors:	Dmitry Safonov <dima@arista.com>
  7 *		Francesco Ruggeri <fruggeri@arista.com>
  8 *		Salam Noureddine <noureddine@arista.com>
  9 */
 10#include <crypto/hash.h>
 11#include <linux/tcp.h>
 12
 13#include <net/tcp.h>
 14#include <net/ipv6.h>
 15
 16static int tcp_v6_ao_calc_key(struct tcp_ao_key *mkt, u8 *key,
 17			      const struct in6_addr *saddr,
 18			      const struct in6_addr *daddr,
 19			      __be16 sport, __be16 dport,
 20			      __be32 sisn, __be32 disn)
 21{
 22	struct kdf_input_block {
 23		u8			counter;
 24		u8			label[6];
 25		struct tcp6_ao_context	ctx;
 26		__be16			outlen;
 27	} __packed * tmp;
 28	struct tcp_sigpool hp;
 29	int err;
 30
 31	err = tcp_sigpool_start(mkt->tcp_sigpool_id, &hp);
 32	if (err)
 33		return err;
 34
 35	tmp = hp.scratch;
 36	tmp->counter	= 1;
 37	memcpy(tmp->label, "TCP-AO", 6);
 38	tmp->ctx.saddr	= *saddr;
 39	tmp->ctx.daddr	= *daddr;
 40	tmp->ctx.sport	= sport;
 41	tmp->ctx.dport	= dport;
 42	tmp->ctx.sisn	= sisn;
 43	tmp->ctx.disn	= disn;
 44	tmp->outlen	= htons(tcp_ao_digest_size(mkt) * 8); /* in bits */
 45
 46	err = tcp_ao_calc_traffic_key(mkt, key, tmp, sizeof(*tmp), &hp);
 47	tcp_sigpool_end(&hp);
 48
 49	return err;
 50}
 51
 52int tcp_v6_ao_calc_key_skb(struct tcp_ao_key *mkt, u8 *key,
 53			   const struct sk_buff *skb,
 54			   __be32 sisn, __be32 disn)
 55{
 56	const struct ipv6hdr *iph = ipv6_hdr(skb);
 57	const struct tcphdr *th = tcp_hdr(skb);
 58
 59	return tcp_v6_ao_calc_key(mkt, key, &iph->saddr,
 60				  &iph->daddr, th->source,
 61				  th->dest, sisn, disn);
 62}
 63
 64int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 65			  const struct sock *sk, __be32 sisn,
 66			  __be32 disn, bool send)
 67{
 68	if (send)
 69		return tcp_v6_ao_calc_key(mkt, key, &sk->sk_v6_rcv_saddr,
 70					  &sk->sk_v6_daddr, htons(sk->sk_num),
 71					  sk->sk_dport, sisn, disn);
 72	else
 73		return tcp_v6_ao_calc_key(mkt, key, &sk->sk_v6_daddr,
 74					  &sk->sk_v6_rcv_saddr, sk->sk_dport,
 75					  htons(sk->sk_num), disn, sisn);
 76}
 77
 78int tcp_v6_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key,
 79			   struct request_sock *req)
 80{
 81	struct inet_request_sock *ireq = inet_rsk(req);
 82
 83	return tcp_v6_ao_calc_key(mkt, key,
 84			&ireq->ir_v6_loc_addr, &ireq->ir_v6_rmt_addr,
 85			htons(ireq->ir_num), ireq->ir_rmt_port,
 86			htonl(tcp_rsk(req)->snt_isn),
 87			htonl(tcp_rsk(req)->rcv_isn));
 88}
 89
 90struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk,
 91				    struct sock *addr_sk,
 92				    int sndid, int rcvid)
 93{
 94	int l3index = l3mdev_master_ifindex_by_index(sock_net(sk),
 95						     addr_sk->sk_bound_dev_if);
 96	struct in6_addr *addr = &addr_sk->sk_v6_daddr;
 97
 98	return tcp_ao_do_lookup(sk, l3index, (union tcp_ao_addr *)addr,
 99				AF_INET6, sndid, rcvid);
100}
101
102struct tcp_ao_key *tcp_v6_ao_lookup_rsk(const struct sock *sk,
103					struct request_sock *req,
104					int sndid, int rcvid)
105{
106	struct inet_request_sock *ireq = inet_rsk(req);
107	struct in6_addr *addr = &ireq->ir_v6_rmt_addr;
108	int l3index;
109
110	l3index = l3mdev_master_ifindex_by_index(sock_net(sk), ireq->ir_iif);
111	return tcp_ao_do_lookup(sk, l3index, (union tcp_ao_addr *)addr,
112				AF_INET6, sndid, rcvid);
113}
114
115int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp,
116				const struct in6_addr *daddr,
117				const struct in6_addr *saddr, int nbytes)
118{
119	struct tcp6_pseudohdr *bp;
120	struct scatterlist sg;
121
122	bp = hp->scratch;
123	/* 1. TCP pseudo-header (RFC2460) */
124	bp->saddr = *saddr;
125	bp->daddr = *daddr;
126	bp->len = cpu_to_be32(nbytes);
127	bp->protocol = cpu_to_be32(IPPROTO_TCP);
128
129	sg_init_one(&sg, bp, sizeof(*bp));
130	ahash_request_set_crypt(hp->req, &sg, NULL, sizeof(*bp));
131	return crypto_ahash_update(hp->req);
132}
133
134int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
135		       const struct sock *sk, const struct sk_buff *skb,
136		       const u8 *tkey, int hash_offset, u32 sne)
137{
138	return tcp_ao_hash_skb(AF_INET6, ao_hash, key, sk, skb, tkey,
139			hash_offset, sne);
140}
141
142int tcp_v6_parse_ao(struct sock *sk, int cmd,
143		    sockptr_t optval, int optlen)
144{
145	return tcp_parse_ao(sk, cmd, AF_INET6, optval, optlen);
146}
147
148int tcp_v6_ao_synack_hash(char *ao_hash, struct tcp_ao_key *ao_key,
149			  struct request_sock *req, const struct sk_buff *skb,
150			  int hash_offset, u32 sne)
151{
152	void *hash_buf = NULL;
153	int err;
154
155	hash_buf = kmalloc(tcp_ao_digest_size(ao_key), GFP_ATOMIC);
156	if (!hash_buf)
157		return -ENOMEM;
158
159	err = tcp_v6_ao_calc_key_rsk(ao_key, hash_buf, req);
160	if (err)
161		goto out;
162
163	err = tcp_ao_hash_skb(AF_INET6, ao_hash, ao_key, req_to_sk(req), skb,
164			      hash_buf, hash_offset, sne);
165out:
166	kfree(hash_buf);
167	return err;
168}