Mention branches and keyring.
[releases.git] / ipv6 / tcp_ao.c
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
16 static 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
52 int 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
64 int 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
78 int 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
90 struct 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
102 struct 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
115 int 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
134 int 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
142 int 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
148 int 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);
165 out:
166         kfree(hash_buf);
167         return err;
168 }