1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * SR-IPv6 implementation -- HMAC functions
6 * David Lebrun <david.lebrun@uclouvain.be>
9 #include <linux/errno.h>
10 #include <linux/kernel.h>
11 #include <linux/types.h>
12 #include <linux/socket.h>
13 #include <linux/sockios.h>
14 #include <linux/net.h>
15 #include <linux/netdevice.h>
16 #include <linux/in6.h>
17 #include <linux/icmpv6.h>
18 #include <linux/mroute6.h>
19 #include <linux/slab.h>
20 #include <linux/rhashtable.h>
22 #include <linux/netfilter.h>
23 #include <linux/netfilter_ipv6.h>
29 #include <net/protocol.h>
30 #include <net/transp_v6.h>
31 #include <net/rawv6.h>
32 #include <net/ndisc.h>
33 #include <net/ip6_route.h>
34 #include <net/addrconf.h>
37 #include <crypto/hash.h>
39 #include <net/genetlink.h>
40 #include <net/seg6_hmac.h>
41 #include <linux/random.h>
43 static DEFINE_PER_CPU(char [SEG6_HMAC_RING_SIZE
], hmac_ring
);
45 static int seg6_hmac_cmpfn(struct rhashtable_compare_arg
*arg
, const void *obj
)
47 const struct seg6_hmac_info
*hinfo
= obj
;
49 return (hinfo
->hmackeyid
!= *(__u32
*)arg
->key
);
52 static inline void seg6_hinfo_release(struct seg6_hmac_info
*hinfo
)
54 kfree_rcu(hinfo
, rcu
);
57 static void seg6_free_hi(void *ptr
, void *arg
)
59 struct seg6_hmac_info
*hinfo
= (struct seg6_hmac_info
*)ptr
;
62 seg6_hinfo_release(hinfo
);
65 static const struct rhashtable_params rht_params
= {
66 .head_offset
= offsetof(struct seg6_hmac_info
, node
),
67 .key_offset
= offsetof(struct seg6_hmac_info
, hmackeyid
),
68 .key_len
= sizeof(u32
),
69 .automatic_shrinking
= true,
70 .obj_cmpfn
= seg6_hmac_cmpfn
,
73 static struct seg6_hmac_algo hmac_algos
[] = {
75 .alg_id
= SEG6_HMAC_ALGO_SHA1
,
79 .alg_id
= SEG6_HMAC_ALGO_SHA256
,
80 .name
= "hmac(sha256)",
84 static struct sr6_tlv_hmac
*seg6_get_tlv_hmac(struct ipv6_sr_hdr
*srh
)
86 struct sr6_tlv_hmac
*tlv
;
88 if (srh
->hdrlen
< (srh
->first_segment
+ 1) * 2 + 5)
91 if (!sr_has_hmac(srh
))
94 tlv
= (struct sr6_tlv_hmac
*)
95 ((char *)srh
+ ((srh
->hdrlen
+ 1) << 3) - 40);
97 if (tlv
->tlvhdr
.type
!= SR6_TLV_HMAC
|| tlv
->tlvhdr
.len
!= 38)
103 static struct seg6_hmac_algo
*__hmac_get_algo(u8 alg_id
)
105 struct seg6_hmac_algo
*algo
;
108 alg_count
= ARRAY_SIZE(hmac_algos
);
109 for (i
= 0; i
< alg_count
; i
++) {
110 algo
= &hmac_algos
[i
];
111 if (algo
->alg_id
== alg_id
)
118 static int __do_hmac(struct seg6_hmac_info
*hinfo
, const char *text
, u8 psize
,
119 u8
*output
, int outlen
)
121 struct seg6_hmac_algo
*algo
;
122 struct crypto_shash
*tfm
;
123 struct shash_desc
*shash
;
126 algo
= __hmac_get_algo(hinfo
->alg_id
);
130 tfm
= *this_cpu_ptr(algo
->tfms
);
132 dgsize
= crypto_shash_digestsize(tfm
);
133 if (dgsize
> outlen
) {
134 pr_debug("sr-ipv6: __do_hmac: digest size too big (%d / %d)\n",
139 ret
= crypto_shash_setkey(tfm
, hinfo
->secret
, hinfo
->slen
);
141 pr_debug("sr-ipv6: crypto_shash_setkey failed: err %d\n", ret
);
145 shash
= *this_cpu_ptr(algo
->shashs
);
148 ret
= crypto_shash_digest(shash
, text
, psize
, output
);
150 pr_debug("sr-ipv6: crypto_shash_digest failed: err %d\n", ret
);
160 int seg6_hmac_compute(struct seg6_hmac_info
*hinfo
, struct ipv6_sr_hdr
*hdr
,
161 struct in6_addr
*saddr
, u8
*output
)
163 __be32 hmackeyid
= cpu_to_be32(hinfo
->hmackeyid
);
164 u8 tmp_out
[SEG6_HMAC_MAX_DIGESTSIZE
];
165 int plen
, i
, dgsize
, wrsize
;
168 /* a 160-byte buffer for digest output allows to store highest known
169 * hash function (RadioGatun) with up to 1216 bits
172 /* saddr(16) + first_seg(1) + flags(1) + keyid(4) + seglist(16n) */
173 plen
= 16 + 1 + 1 + 4 + (hdr
->first_segment
+ 1) * 16;
175 /* this limit allows for 14 segments */
176 if (plen
>= SEG6_HMAC_RING_SIZE
)
179 /* Let's build the HMAC text on the ring buffer. The text is composed
180 * as follows, in order:
182 * 1. Source IPv6 address (128 bits)
183 * 2. first_segment value (8 bits)
185 * 4. HMAC Key ID (32 bits)
186 * 5. All segments in the segments list (n * 128 bits)
190 ring
= this_cpu_ptr(hmac_ring
);
194 memcpy(off
, saddr
, 16);
197 /* first_segment value */
198 *off
++ = hdr
->first_segment
;
204 memcpy(off
, &hmackeyid
, 4);
207 /* all segments in the list */
208 for (i
= 0; i
< hdr
->first_segment
+ 1; i
++) {
209 memcpy(off
, hdr
->segments
+ i
, 16);
213 dgsize
= __do_hmac(hinfo
, ring
, plen
, tmp_out
,
214 SEG6_HMAC_MAX_DIGESTSIZE
);
220 wrsize
= SEG6_HMAC_FIELD_LEN
;
224 memset(output
, 0, SEG6_HMAC_FIELD_LEN
);
225 memcpy(output
, tmp_out
, wrsize
);
229 EXPORT_SYMBOL(seg6_hmac_compute
);
231 /* checks if an incoming SR-enabled packet's HMAC status matches
232 * the incoming policy.
234 * called with rcu_read_lock()
236 bool seg6_hmac_validate_skb(struct sk_buff
*skb
)
238 u8 hmac_output
[SEG6_HMAC_FIELD_LEN
];
239 struct net
*net
= dev_net(skb
->dev
);
240 struct seg6_hmac_info
*hinfo
;
241 struct sr6_tlv_hmac
*tlv
;
242 struct ipv6_sr_hdr
*srh
;
243 struct inet6_dev
*idev
;
245 idev
= __in6_dev_get(skb
->dev
);
247 srh
= (struct ipv6_sr_hdr
*)skb_transport_header(skb
);
249 tlv
= seg6_get_tlv_hmac(srh
);
251 /* mandatory check but no tlv */
252 if (idev
->cnf
.seg6_require_hmac
> 0 && !tlv
)
256 if (idev
->cnf
.seg6_require_hmac
< 0)
259 /* check only if present */
260 if (idev
->cnf
.seg6_require_hmac
== 0 && !tlv
)
263 /* now, seg6_require_hmac >= 0 && tlv */
265 hinfo
= seg6_hmac_info_lookup(net
, be32_to_cpu(tlv
->hmackeyid
));
269 if (seg6_hmac_compute(hinfo
, srh
, &ipv6_hdr(skb
)->saddr
, hmac_output
))
272 if (memcmp(hmac_output
, tlv
->hmac
, SEG6_HMAC_FIELD_LEN
) != 0)
277 EXPORT_SYMBOL(seg6_hmac_validate_skb
);
279 /* called with rcu_read_lock() */
280 struct seg6_hmac_info
*seg6_hmac_info_lookup(struct net
*net
, u32 key
)
282 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
283 struct seg6_hmac_info
*hinfo
;
285 hinfo
= rhashtable_lookup_fast(&sdata
->hmac_infos
, &key
, rht_params
);
289 EXPORT_SYMBOL(seg6_hmac_info_lookup
);
291 int seg6_hmac_info_add(struct net
*net
, u32 key
, struct seg6_hmac_info
*hinfo
)
293 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
296 err
= rhashtable_lookup_insert_fast(&sdata
->hmac_infos
, &hinfo
->node
,
301 EXPORT_SYMBOL(seg6_hmac_info_add
);
303 int seg6_hmac_info_del(struct net
*net
, u32 key
)
305 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
306 struct seg6_hmac_info
*hinfo
;
309 hinfo
= rhashtable_lookup_fast(&sdata
->hmac_infos
, &key
, rht_params
);
313 err
= rhashtable_remove_fast(&sdata
->hmac_infos
, &hinfo
->node
,
318 seg6_hinfo_release(hinfo
);
323 EXPORT_SYMBOL(seg6_hmac_info_del
);
325 int seg6_push_hmac(struct net
*net
, struct in6_addr
*saddr
,
326 struct ipv6_sr_hdr
*srh
)
328 struct seg6_hmac_info
*hinfo
;
329 struct sr6_tlv_hmac
*tlv
;
332 tlv
= seg6_get_tlv_hmac(srh
);
338 hinfo
= seg6_hmac_info_lookup(net
, be32_to_cpu(tlv
->hmackeyid
));
342 memset(tlv
->hmac
, 0, SEG6_HMAC_FIELD_LEN
);
343 err
= seg6_hmac_compute(hinfo
, srh
, saddr
, tlv
->hmac
);
349 EXPORT_SYMBOL(seg6_push_hmac
);
351 static int seg6_hmac_init_algo(void)
353 struct seg6_hmac_algo
*algo
;
354 struct crypto_shash
*tfm
;
355 struct shash_desc
*shash
;
356 int i
, alg_count
, cpu
;
358 alg_count
= ARRAY_SIZE(hmac_algos
);
360 for (i
= 0; i
< alg_count
; i
++) {
361 struct crypto_shash
**p_tfm
;
364 algo
= &hmac_algos
[i
];
365 algo
->tfms
= alloc_percpu(struct crypto_shash
*);
369 for_each_possible_cpu(cpu
) {
370 tfm
= crypto_alloc_shash(algo
->name
, 0, 0);
373 p_tfm
= per_cpu_ptr(algo
->tfms
, cpu
);
377 p_tfm
= raw_cpu_ptr(algo
->tfms
);
380 shsize
= sizeof(*shash
) + crypto_shash_descsize(tfm
);
382 algo
->shashs
= alloc_percpu(struct shash_desc
*);
386 for_each_possible_cpu(cpu
) {
387 shash
= kzalloc_node(shsize
, GFP_KERNEL
,
391 *per_cpu_ptr(algo
->shashs
, cpu
) = shash
;
398 int __init
seg6_hmac_init(void)
400 return seg6_hmac_init_algo();
402 EXPORT_SYMBOL(seg6_hmac_init
);
404 int __net_init
seg6_hmac_net_init(struct net
*net
)
406 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
408 rhashtable_init(&sdata
->hmac_infos
, &rht_params
);
412 EXPORT_SYMBOL(seg6_hmac_net_init
);
414 void seg6_hmac_exit(void)
416 struct seg6_hmac_algo
*algo
= NULL
;
417 int i
, alg_count
, cpu
;
419 alg_count
= ARRAY_SIZE(hmac_algos
);
420 for (i
= 0; i
< alg_count
; i
++) {
421 algo
= &hmac_algos
[i
];
422 for_each_possible_cpu(cpu
) {
423 struct crypto_shash
*tfm
;
424 struct shash_desc
*shash
;
426 shash
= *per_cpu_ptr(algo
->shashs
, cpu
);
428 tfm
= *per_cpu_ptr(algo
->tfms
, cpu
);
429 crypto_free_shash(tfm
);
431 free_percpu(algo
->tfms
);
432 free_percpu(algo
->shashs
);
435 EXPORT_SYMBOL(seg6_hmac_exit
);
437 void __net_exit
seg6_hmac_net_exit(struct net
*net
)
439 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
441 rhashtable_free_and_destroy(&sdata
->hmac_infos
, seg6_free_hi
, NULL
);
443 EXPORT_SYMBOL(seg6_hmac_net_exit
);