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 } 169