1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * INET An implementation of the TCP Authentication Option (TCP-AO).
6 * Authors: Dmitry Safonov <dima@arista.com>
7 * Francesco Ruggeri <fruggeri@arista.com>
8 * Salam Noureddine <noureddine@arista.com>
10 #include <crypto/hash.h>
11 #include <linux/tcp.h>
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
)
22 struct kdf_input_block
{
25 struct tcp6_ao_context ctx
;
28 struct tcp_sigpool hp
;
31 err
= tcp_sigpool_start(mkt
->tcp_sigpool_id
, &hp
);
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
;
44 tmp
->outlen
= htons(tcp_ao_digest_size(mkt
) * 8); /* in bits */
46 err
= tcp_ao_calc_traffic_key(mkt
, key
, tmp
, sizeof(*tmp
), &hp
);
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
)
56 const struct ipv6hdr
*iph
= ipv6_hdr(skb
);
57 const struct tcphdr
*th
= tcp_hdr(skb
);
59 return tcp_v6_ao_calc_key(mkt
, key
, &iph
->saddr
,
60 &iph
->daddr
, th
->source
,
61 th
->dest
, sisn
, disn
);
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
)
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
);
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
);
78 int tcp_v6_ao_calc_key_rsk(struct tcp_ao_key
*mkt
, u8
*key
,
79 struct request_sock
*req
)
81 struct inet_request_sock
*ireq
= inet_rsk(req
);
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
));
90 struct tcp_ao_key
*tcp_v6_ao_lookup(const struct sock
*sk
,
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
;
98 return tcp_ao_do_lookup(sk
, l3index
, (union tcp_ao_addr
*)addr
,
99 AF_INET6
, sndid
, rcvid
);
102 struct tcp_ao_key
*tcp_v6_ao_lookup_rsk(const struct sock
*sk
,
103 struct request_sock
*req
,
104 int sndid
, int rcvid
)
106 struct inet_request_sock
*ireq
= inet_rsk(req
);
107 struct in6_addr
*addr
= &ireq
->ir_v6_rmt_addr
;
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
);
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
)
119 struct tcp6_pseudohdr
*bp
;
120 struct scatterlist sg
;
123 /* 1. TCP pseudo-header (RFC2460) */
126 bp
->len
= cpu_to_be32(nbytes
);
127 bp
->protocol
= cpu_to_be32(IPPROTO_TCP
);
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
);
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
)
138 return tcp_ao_hash_skb(AF_INET6
, ao_hash
, key
, sk
, skb
, tkey
,
142 int tcp_v6_parse_ao(struct sock
*sk
, int cmd
,
143 sockptr_t optval
, int optlen
)
145 return tcp_parse_ao(sk
, cmd
, AF_INET6
, optval
, optlen
);
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
)
152 void *hash_buf
= NULL
;
155 hash_buf
= kmalloc(tcp_ao_digest_size(ao_key
), GFP_ATOMIC
);
159 err
= tcp_v6_ao_calc_key_rsk(ao_key
, hash_buf
, req
);
163 err
= tcp_ao_hash_skb(AF_INET6
, ao_hash
, ao_key
, req_to_sk(req
), skb
,
164 hash_buf
, hash_offset
, sne
);