Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'ipv6-sr-simplify-and-optimize-hmac-calculations'

Eric Biggers says:

====================
ipv6: sr: Simplify and optimize HMAC calculations

This series simplifies and optimizes the HMAC calculations in
IPv6 Segment Routing.
====================

Link: https://patch.msgid.link/20250824013644.71928-1-ebiggers@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+42 -203
+8 -12
include/net/seg6_hmac.h
··· 9 9 #ifndef _NET_SEG6_HMAC_H 10 10 #define _NET_SEG6_HMAC_H 11 11 12 + #include <crypto/sha1.h> 13 + #include <crypto/sha2.h> 12 14 #include <net/flow.h> 13 15 #include <net/ip6_fib.h> 14 16 #include <net/sock.h> ··· 21 19 #include <linux/seg6_hmac.h> 22 20 #include <linux/rhashtable-types.h> 23 21 24 - #define SEG6_HMAC_MAX_DIGESTSIZE 160 25 22 #define SEG6_HMAC_RING_SIZE 256 26 23 27 24 struct seg6_hmac_info { ··· 28 27 struct rcu_head rcu; 29 28 30 29 u32 hmackeyid; 30 + /* The raw key, kept only so it can be returned back to userspace */ 31 31 char secret[SEG6_HMAC_SECRET_LEN]; 32 32 u8 slen; 33 33 u8 alg_id; 34 - }; 35 - 36 - struct seg6_hmac_algo { 37 - u8 alg_id; 38 - char name[64]; 39 - struct crypto_shash * __percpu *tfms; 40 - struct shash_desc * __percpu *shashs; 34 + /* The prepared key, which the calculations actually use */ 35 + union { 36 + struct hmac_sha1_key sha1; 37 + struct hmac_sha256_key sha256; 38 + } key; 41 39 }; 42 40 43 41 extern int seg6_hmac_compute(struct seg6_hmac_info *hinfo, ··· 50 50 struct ipv6_sr_hdr *srh); 51 51 extern bool seg6_hmac_validate_skb(struct sk_buff *skb); 52 52 #ifdef CONFIG_IPV6_SEG6_HMAC 53 - extern int seg6_hmac_init(void); 54 - extern void seg6_hmac_exit(void); 55 53 extern int seg6_hmac_net_init(struct net *net); 56 54 extern void seg6_hmac_net_exit(struct net *net); 57 55 #else 58 - static inline int seg6_hmac_init(void) { return 0; } 59 - static inline void seg6_hmac_exit(void) {} 60 56 static inline int seg6_hmac_net_init(struct net *net) { return 0; } 61 57 static inline void seg6_hmac_net_exit(struct net *net) {} 62 58 #endif
+3 -4
net/ipv6/Kconfig
··· 304 304 config IPV6_SEG6_HMAC 305 305 bool "IPv6: Segment Routing HMAC support" 306 306 depends on IPV6 307 - select CRYPTO 308 - select CRYPTO_HMAC 309 - select CRYPTO_SHA1 310 - select CRYPTO_SHA256 307 + select CRYPTO_LIB_SHA1 308 + select CRYPTO_LIB_SHA256 309 + select CRYPTO_LIB_UTILS 311 310 help 312 311 Support for HMAC signature generation and verification 313 312 of SR-enabled packets.
-7
net/ipv6/seg6.c
··· 522 522 if (err) 523 523 goto out_unregister_iptun; 524 524 525 - err = seg6_hmac_init(); 526 - if (err) 527 - goto out_unregister_seg6; 528 - 529 525 pr_info("Segment Routing with IPv6\n"); 530 526 531 527 out: 532 528 return err; 533 - out_unregister_seg6: 534 - seg6_local_exit(); 535 529 out_unregister_iptun: 536 530 seg6_iptunnel_exit(); 537 531 out_unregister_genl: ··· 537 543 538 544 void seg6_exit(void) 539 545 { 540 - seg6_hmac_exit(); 541 546 seg6_local_exit(); 542 547 seg6_iptunnel_exit(); 543 548 genl_unregister_family(&seg6_genl_family);
+31 -180
net/ipv6/seg6_hmac.c
··· 16 16 #include <linux/in6.h> 17 17 #include <linux/icmpv6.h> 18 18 #include <linux/mroute6.h> 19 - #include <linux/slab.h> 20 19 #include <linux/rhashtable.h> 21 20 22 21 #include <linux/netfilter.h> ··· 33 34 #include <net/addrconf.h> 34 35 #include <net/xfrm.h> 35 36 36 - #include <crypto/hash.h> 37 + #include <crypto/sha1.h> 38 + #include <crypto/sha2.h> 37 39 #include <crypto/utils.h> 38 40 #include <net/seg6.h> 39 41 #include <net/genetlink.h> ··· 78 78 .obj_cmpfn = seg6_hmac_cmpfn, 79 79 }; 80 80 81 - static struct seg6_hmac_algo hmac_algos[] = { 82 - { 83 - .alg_id = SEG6_HMAC_ALGO_SHA1, 84 - .name = "hmac(sha1)", 85 - }, 86 - { 87 - .alg_id = SEG6_HMAC_ALGO_SHA256, 88 - .name = "hmac(sha256)", 89 - }, 90 - }; 91 - 92 81 static struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh) 93 82 { 94 83 struct sr6_tlv_hmac *tlv; ··· 97 108 return tlv; 98 109 } 99 110 100 - static struct seg6_hmac_algo *__hmac_get_algo(u8 alg_id) 101 - { 102 - struct seg6_hmac_algo *algo; 103 - int i, alg_count; 104 - 105 - alg_count = ARRAY_SIZE(hmac_algos); 106 - for (i = 0; i < alg_count; i++) { 107 - algo = &hmac_algos[i]; 108 - if (algo->alg_id == alg_id) 109 - return algo; 110 - } 111 - 112 - return NULL; 113 - } 114 - 115 - static int __do_hmac(struct seg6_hmac_info *hinfo, const char *text, u8 psize, 116 - u8 *output, int outlen) 117 - { 118 - struct seg6_hmac_algo *algo; 119 - struct crypto_shash *tfm; 120 - struct shash_desc *shash; 121 - int ret, dgsize; 122 - 123 - algo = __hmac_get_algo(hinfo->alg_id); 124 - if (!algo) 125 - return -ENOENT; 126 - 127 - tfm = *this_cpu_ptr(algo->tfms); 128 - 129 - dgsize = crypto_shash_digestsize(tfm); 130 - if (dgsize > outlen) { 131 - pr_debug("sr-ipv6: __do_hmac: digest size too big (%d / %d)\n", 132 - dgsize, outlen); 133 - return -ENOMEM; 134 - } 135 - 136 - ret = crypto_shash_setkey(tfm, hinfo->secret, hinfo->slen); 137 - if (ret < 0) { 138 - pr_debug("sr-ipv6: crypto_shash_setkey failed: err %d\n", ret); 139 - goto failed; 140 - } 141 - 142 - shash = *this_cpu_ptr(algo->shashs); 143 - shash->tfm = tfm; 144 - 145 - ret = crypto_shash_digest(shash, text, psize, output); 146 - if (ret < 0) { 147 - pr_debug("sr-ipv6: crypto_shash_digest failed: err %d\n", ret); 148 - goto failed; 149 - } 150 - 151 - return dgsize; 152 - 153 - failed: 154 - return ret; 155 - } 156 - 157 111 int seg6_hmac_compute(struct seg6_hmac_info *hinfo, struct ipv6_sr_hdr *hdr, 158 112 struct in6_addr *saddr, u8 *output) 159 113 { 160 114 __be32 hmackeyid = cpu_to_be32(hinfo->hmackeyid); 161 - u8 tmp_out[SEG6_HMAC_MAX_DIGESTSIZE]; 162 - int plen, i, dgsize, wrsize; 115 + int plen, i, ret = 0; 163 116 char *ring, *off; 164 - 165 - /* a 160-byte buffer for digest output allows to store highest known 166 - * hash function (RadioGatun) with up to 1216 bits 167 - */ 168 117 169 118 /* saddr(16) + first_seg(1) + flags(1) + keyid(4) + seglist(16n) */ 170 119 plen = 16 + 1 + 1 + 4 + (hdr->first_segment + 1) * 16; ··· 146 219 off += 16; 147 220 } 148 221 149 - dgsize = __do_hmac(hinfo, ring, plen, tmp_out, 150 - SEG6_HMAC_MAX_DIGESTSIZE); 222 + switch (hinfo->alg_id) { 223 + case SEG6_HMAC_ALGO_SHA1: 224 + hmac_sha1(&hinfo->key.sha1, ring, plen, output); 225 + static_assert(SEG6_HMAC_FIELD_LEN > SHA1_DIGEST_SIZE); 226 + memset(&output[SHA1_DIGEST_SIZE], 0, 227 + SEG6_HMAC_FIELD_LEN - SHA1_DIGEST_SIZE); 228 + break; 229 + case SEG6_HMAC_ALGO_SHA256: 230 + hmac_sha256(&hinfo->key.sha256, ring, plen, output); 231 + static_assert(SEG6_HMAC_FIELD_LEN == SHA256_DIGEST_SIZE); 232 + break; 233 + default: 234 + WARN_ON_ONCE(1); 235 + ret = -EINVAL; 236 + break; 237 + } 151 238 local_unlock_nested_bh(&hmac_storage.bh_lock); 152 239 local_bh_enable(); 153 - 154 - if (dgsize < 0) 155 - return dgsize; 156 - 157 - wrsize = SEG6_HMAC_FIELD_LEN; 158 - if (wrsize > dgsize) 159 - wrsize = dgsize; 160 - 161 - memset(output, 0, SEG6_HMAC_FIELD_LEN); 162 - memcpy(output, tmp_out, wrsize); 163 - 164 - return 0; 240 + return ret; 165 241 } 166 242 EXPORT_SYMBOL(seg6_hmac_compute); 167 243 ··· 235 305 struct seg6_pernet_data *sdata = seg6_pernet(net); 236 306 int err; 237 307 238 - if (!__hmac_get_algo(hinfo->alg_id)) 308 + switch (hinfo->alg_id) { 309 + case SEG6_HMAC_ALGO_SHA1: 310 + hmac_sha1_preparekey(&hinfo->key.sha1, 311 + hinfo->secret, hinfo->slen); 312 + break; 313 + case SEG6_HMAC_ALGO_SHA256: 314 + hmac_sha256_preparekey(&hinfo->key.sha256, 315 + hinfo->secret, hinfo->slen); 316 + break; 317 + default: 239 318 return -EINVAL; 319 + } 240 320 241 321 err = rhashtable_lookup_insert_fast(&sdata->hmac_infos, &hinfo->node, 242 322 rht_params); ··· 303 363 } 304 364 EXPORT_SYMBOL(seg6_push_hmac); 305 365 306 - static int seg6_hmac_init_algo(void) 307 - { 308 - struct seg6_hmac_algo *algo; 309 - struct crypto_shash *tfm; 310 - struct shash_desc *shash; 311 - int i, alg_count, cpu; 312 - int ret = -ENOMEM; 313 - 314 - alg_count = ARRAY_SIZE(hmac_algos); 315 - 316 - for (i = 0; i < alg_count; i++) { 317 - struct crypto_shash **p_tfm; 318 - int shsize; 319 - 320 - algo = &hmac_algos[i]; 321 - algo->tfms = alloc_percpu(struct crypto_shash *); 322 - if (!algo->tfms) 323 - goto error_out; 324 - 325 - for_each_possible_cpu(cpu) { 326 - tfm = crypto_alloc_shash(algo->name, 0, 0); 327 - if (IS_ERR(tfm)) { 328 - ret = PTR_ERR(tfm); 329 - goto error_out; 330 - } 331 - p_tfm = per_cpu_ptr(algo->tfms, cpu); 332 - *p_tfm = tfm; 333 - } 334 - 335 - p_tfm = raw_cpu_ptr(algo->tfms); 336 - tfm = *p_tfm; 337 - 338 - shsize = sizeof(*shash) + crypto_shash_descsize(tfm); 339 - 340 - algo->shashs = alloc_percpu(struct shash_desc *); 341 - if (!algo->shashs) 342 - goto error_out; 343 - 344 - for_each_possible_cpu(cpu) { 345 - shash = kzalloc_node(shsize, GFP_KERNEL, 346 - cpu_to_node(cpu)); 347 - if (!shash) 348 - goto error_out; 349 - *per_cpu_ptr(algo->shashs, cpu) = shash; 350 - } 351 - } 352 - 353 - return 0; 354 - 355 - error_out: 356 - seg6_hmac_exit(); 357 - return ret; 358 - } 359 - 360 - int __init seg6_hmac_init(void) 361 - { 362 - return seg6_hmac_init_algo(); 363 - } 364 - 365 366 int __net_init seg6_hmac_net_init(struct net *net) 366 367 { 367 368 struct seg6_pernet_data *sdata = seg6_pernet(net); 368 369 369 370 return rhashtable_init(&sdata->hmac_infos, &rht_params); 370 371 } 371 - 372 - void seg6_hmac_exit(void) 373 - { 374 - struct seg6_hmac_algo *algo = NULL; 375 - struct crypto_shash *tfm; 376 - struct shash_desc *shash; 377 - int i, alg_count, cpu; 378 - 379 - alg_count = ARRAY_SIZE(hmac_algos); 380 - for (i = 0; i < alg_count; i++) { 381 - algo = &hmac_algos[i]; 382 - 383 - if (algo->shashs) { 384 - for_each_possible_cpu(cpu) { 385 - shash = *per_cpu_ptr(algo->shashs, cpu); 386 - kfree(shash); 387 - } 388 - free_percpu(algo->shashs); 389 - } 390 - 391 - if (algo->tfms) { 392 - for_each_possible_cpu(cpu) { 393 - tfm = *per_cpu_ptr(algo->tfms, cpu); 394 - crypto_free_shash(tfm); 395 - } 396 - free_percpu(algo->tfms); 397 - } 398 - } 399 - } 400 - EXPORT_SYMBOL(seg6_hmac_exit); 401 372 402 373 void __net_exit seg6_hmac_net_exit(struct net *net) 403 374 {