1 /* 2 * SR-IPv6 implementation -- HMAC functions 3 * 4 * Author: 5 * David Lebrun <david.lebrun@uclouvain.be> 6 * 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 11 * 2 of the License, or (at your option) any later version. 12 */ 13 14 #include <linux/errno.h> 15 #include <linux/kernel.h> 16 #include <linux/types.h> 17 #include <linux/socket.h> 18 #include <linux/sockios.h> 19 #include <linux/net.h> 20 #include <linux/netdevice.h> 21 #include <linux/in6.h> 22 #include <linux/icmpv6.h> 23 #include <linux/mroute6.h> 24 #include <linux/slab.h> 25 26 #include <linux/netfilter.h> 27 #include <linux/netfilter_ipv6.h> 28 29 #include <net/sock.h> 30 #include <net/snmp.h> 31 32 #include <net/ipv6.h> 33 #include <net/protocol.h> 34 #include <net/transp_v6.h> 35 #include <net/rawv6.h> 36 #include <net/ndisc.h> 37 #include <net/ip6_route.h> 38 #include <net/addrconf.h> 39 #include <net/xfrm.h> 40 41 #include <linux/cryptohash.h> 42 #include <crypto/hash.h> 43 #include <crypto/sha.h> 44 #include <net/seg6.h> 45 #include <net/genetlink.h> 46 #include <net/seg6_hmac.h> 47 #include <linux/random.h> 48 49 static DEFINE_PER_CPU(char [SEG6_HMAC_RING_SIZE], hmac_ring); 50 51 static int seg6_hmac_cmpfn(struct rhashtable_compare_arg *arg, const void *obj) 52 { 53 const struct seg6_hmac_info *hinfo = obj; 54 55 return (hinfo->hmackeyid != *(__u32 *)arg->key); 56 } 57 58 static inline void seg6_hinfo_release(struct seg6_hmac_info *hinfo) 59 { 60 kfree_rcu(hinfo, rcu); 61 } 62 63 static void seg6_free_hi(void *ptr, void *arg) 64 { 65 struct seg6_hmac_info *hinfo = (struct seg6_hmac_info *)ptr; 66 67 if (hinfo) 68 seg6_hinfo_release(hinfo); 69 } 70 71 static const struct rhashtable_params rht_params = { 72 .head_offset = offsetof(struct seg6_hmac_info, node), 73 .key_offset = offsetof(struct seg6_hmac_info, hmackeyid), 74 .key_len = sizeof(u32), 75 .automatic_shrinking = true, 76 .obj_cmpfn = seg6_hmac_cmpfn, 77 }; 78 79 static struct seg6_hmac_algo hmac_algos[] = { 80 { 81 .alg_id = SEG6_HMAC_ALGO_SHA1, 82 .name = "hmac(sha1)", 83 }, 84 { 85 .alg_id = SEG6_HMAC_ALGO_SHA256, 86 .name = "hmac(sha256)", 87 }, 88 }; 89 90 static struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh) 91 { 92 struct sr6_tlv_hmac *tlv; 93 94 if (srh->hdrlen < (srh->first_segment + 1) * 2 + 5) 95 return NULL; 96 97 if (!sr_has_hmac(srh)) 98 return NULL; 99 100 tlv = (struct sr6_tlv_hmac *) 101 ((char *)srh + ((srh->hdrlen + 1) << 3) - 40); 102 103 if (tlv->tlvhdr.type != SR6_TLV_HMAC || tlv->tlvhdr.len != 38) 104 return NULL; 105 106 return tlv; 107 } 108 109 static struct seg6_hmac_algo *__hmac_get_algo(u8 alg_id) 110 { 111 struct seg6_hmac_algo *algo; 112 int i, alg_count; 113 114 alg_count = ARRAY_SIZE(hmac_algos); 115 for (i = 0; i < alg_count; i++) { 116 algo = &hmac_algos[i]; 117 if (algo->alg_id == alg_id) 118 return algo; 119 } 120 121 return NULL; 122 } 123 124 static int __do_hmac(struct seg6_hmac_info *hinfo, const char *text, u8 psize, 125 u8 *output, int outlen) 126 { 127 struct seg6_hmac_algo *algo; 128 struct crypto_shash *tfm; 129 struct shash_desc *shash; 130 int ret, dgsize; 131 132 algo = __hmac_get_algo(hinfo->alg_id); 133 if (!algo) 134 return -ENOENT; 135 136 tfm = *this_cpu_ptr(algo->tfms); 137 138 dgsize = crypto_shash_digestsize(tfm); 139 if (dgsize > outlen) { 140 pr_debug("sr-ipv6: __do_hmac: digest size too big (%d / %d)\n", 141 dgsize, outlen); 142 return -ENOMEM; 143 } 144 145 ret = crypto_shash_setkey(tfm, hinfo->secret, hinfo->slen); 146 if (ret < 0) { 147 pr_debug("sr-ipv6: crypto_shash_setkey failed: err %d\n", ret); 148 goto failed; 149 } 150 151 shash = *this_cpu_ptr(algo->shashs); 152 shash->tfm = tfm; 153 154 ret = crypto_shash_digest(shash, text, psize, output); 155 if (ret < 0) { 156 pr_debug("sr-ipv6: crypto_shash_digest failed: err %d\n", ret); 157 goto failed; 158 } 159 160 return dgsize; 161 162 failed: 163 return ret; 164 } 165 166 int seg6_hmac_compute(struct seg6_hmac_info *hinfo, struct ipv6_sr_hdr *hdr, 167 struct in6_addr *saddr, u8 *output) 168 { 169 __be32 hmackeyid = cpu_to_be32(hinfo->hmackeyid); 170 u8 tmp_out[SEG6_HMAC_MAX_DIGESTSIZE]; 171 int plen, i, dgsize, wrsize; 172 char *ring, *off; 173 174 /* a 160-byte buffer for digest output allows to store highest known 175 * hash function (RadioGatun) with up to 1216 bits 176 */ 177 178 /* saddr(16) + first_seg(1) + flags(1) + keyid(4) + seglist(16n) */ 179 plen = 16 + 1 + 1 + 4 + (hdr->first_segment + 1) * 16; 180 181 /* this limit allows for 14 segments */ 182 if (plen >= SEG6_HMAC_RING_SIZE) 183 return -EMSGSIZE; 184 185 /* Let's build the HMAC text on the ring buffer. The text is composed 186 * as follows, in order: 187 * 188 * 1. Source IPv6 address (128 bits) 189 * 2. first_segment value (8 bits) 190 * 3. Flags (8 bits) 191 * 4. HMAC Key ID (32 bits) 192 * 5. All segments in the segments list (n * 128 bits) 193 */ 194 195 local_bh_disable(); 196 ring = this_cpu_ptr(hmac_ring); 197 off = ring; 198 199 /* source address */ 200 memcpy(off, saddr, 16); 201 off += 16; 202 203 /* first_segment value */ 204 *off++ = hdr->first_segment; 205 206 /* flags */ 207 *off++ = hdr->flags; 208 209 /* HMAC Key ID */ 210 memcpy(off, &hmackeyid, 4); 211 off += 4; 212 213 /* all segments in the list */ 214 for (i = 0; i < hdr->first_segment + 1; i++) { 215 memcpy(off, hdr->segments + i, 16); 216 off += 16; 217 } 218 219 dgsize = __do_hmac(hinfo, ring, plen, tmp_out, 220 SEG6_HMAC_MAX_DIGESTSIZE); 221 local_bh_enable(); 222 223 if (dgsize < 0) 224 return dgsize; 225 226 wrsize = SEG6_HMAC_FIELD_LEN; 227 if (wrsize > dgsize) 228 wrsize = dgsize; 229 230 memset(output, 0, SEG6_HMAC_FIELD_LEN); 231 memcpy(output, tmp_out, wrsize); 232 233 return 0; 234 } 235 EXPORT_SYMBOL(seg6_hmac_compute); 236 237 /* checks if an incoming SR-enabled packet's HMAC status matches 238 * the incoming policy. 239 * 240 * called with rcu_read_lock() 241 */ 242 bool seg6_hmac_validate_skb(struct sk_buff *skb) 243 { 244 u8 hmac_output[SEG6_HMAC_FIELD_LEN]; 245 struct net *net = dev_net(skb->dev); 246 struct seg6_hmac_info *hinfo; 247 struct sr6_tlv_hmac *tlv; 248 struct ipv6_sr_hdr *srh; 249 struct inet6_dev *idev; 250 251 idev = __in6_dev_get(skb->dev); 252 253 srh = (struct ipv6_sr_hdr *)skb_transport_header(skb); 254 255 tlv = seg6_get_tlv_hmac(srh); 256 257 /* mandatory check but no tlv */ 258 if (idev->cnf.seg6_require_hmac > 0 && !tlv) 259 return false; 260 261 /* no check */ 262 if (idev->cnf.seg6_require_hmac < 0) 263 return true; 264 265 /* check only if present */ 266 if (idev->cnf.seg6_require_hmac == 0 && !tlv) 267 return true; 268 269 /* now, seg6_require_hmac >= 0 && tlv */ 270 271 hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid)); 272 if (!hinfo) 273 return false; 274 275 if (seg6_hmac_compute(hinfo, srh, &ipv6_hdr(skb)->saddr, hmac_output)) 276 return false; 277 278 if (memcmp(hmac_output, tlv->hmac, SEG6_HMAC_FIELD_LEN) != 0) 279 return false; 280 281 return true; 282 } 283 EXPORT_SYMBOL(seg6_hmac_validate_skb); 284 285 /* called with rcu_read_lock() */ 286 struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key) 287 { 288 struct seg6_pernet_data *sdata = seg6_pernet(net); 289 struct seg6_hmac_info *hinfo; 290 291 hinfo = rhashtable_lookup_fast(&sdata->hmac_infos, &key, rht_params); 292 293 return hinfo; 294 } 295 EXPORT_SYMBOL(seg6_hmac_info_lookup); 296 297 int seg6_hmac_info_add(struct net *net, u32 key, struct seg6_hmac_info *hinfo) 298 { 299 struct seg6_pernet_data *sdata = seg6_pernet(net); 300 int err; 301 302 err = rhashtable_lookup_insert_fast(&sdata->hmac_infos, &hinfo->node, 303 rht_params); 304 305 return err; 306 } 307 EXPORT_SYMBOL(seg6_hmac_info_add); 308 309 int seg6_hmac_info_del(struct net *net, u32 key) 310 { 311 struct seg6_pernet_data *sdata = seg6_pernet(net); 312 struct seg6_hmac_info *hinfo; 313 int err = -ENOENT; 314 315 hinfo = rhashtable_lookup_fast(&sdata->hmac_infos, &key, rht_params); 316 if (!hinfo) 317 goto out; 318 319 err = rhashtable_remove_fast(&sdata->hmac_infos, &hinfo->node, 320 rht_params); 321 if (err) 322 goto out; 323 324 seg6_hinfo_release(hinfo); 325 326 out: 327 return err; 328 } 329 EXPORT_SYMBOL(seg6_hmac_info_del); 330 331 int seg6_push_hmac(struct net *net, struct in6_addr *saddr, 332 struct ipv6_sr_hdr *srh) 333 { 334 struct seg6_hmac_info *hinfo; 335 struct sr6_tlv_hmac *tlv; 336 int err = -ENOENT; 337 338 tlv = seg6_get_tlv_hmac(srh); 339 if (!tlv) 340 return -EINVAL; 341 342 rcu_read_lock(); 343 344 hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid)); 345 if (!hinfo) 346 goto out; 347 348 memset(tlv->hmac, 0, SEG6_HMAC_FIELD_LEN); 349 err = seg6_hmac_compute(hinfo, srh, saddr, tlv->hmac); 350 351 out: 352 rcu_read_unlock(); 353 return err; 354 } 355 EXPORT_SYMBOL(seg6_push_hmac); 356 357 static int seg6_hmac_init_algo(void) 358 { 359 struct seg6_hmac_algo *algo; 360 struct crypto_shash *tfm; 361 struct shash_desc *shash; 362 int i, alg_count, cpu; 363 364 alg_count = ARRAY_SIZE(hmac_algos); 365 366 for (i = 0; i < alg_count; i++) { 367 struct crypto_shash **p_tfm; 368 int shsize; 369 370 algo = &hmac_algos[i]; 371 algo->tfms = alloc_percpu(struct crypto_shash *); 372 if (!algo->tfms) 373 return -ENOMEM; 374 375 for_each_possible_cpu(cpu) { 376 tfm = crypto_alloc_shash(algo->name, 0, GFP_KERNEL); 377 if (IS_ERR(tfm)) 378 return PTR_ERR(tfm); 379 p_tfm = per_cpu_ptr(algo->tfms, cpu); 380 *p_tfm = tfm; 381 } 382 383 p_tfm = raw_cpu_ptr(algo->tfms); 384 tfm = *p_tfm; 385 386 shsize = sizeof(*shash) + crypto_shash_descsize(tfm); 387 388 algo->shashs = alloc_percpu(struct shash_desc *); 389 if (!algo->shashs) 390 return -ENOMEM; 391 392 for_each_possible_cpu(cpu) { 393 shash = kzalloc_node(shsize, GFP_KERNEL, 394 cpu_to_node(cpu)); 395 if (!shash) 396 return -ENOMEM; 397 *per_cpu_ptr(algo->shashs, cpu) = shash; 398 } 399 } 400 401 return 0; 402 } 403 404 int __init seg6_hmac_init(void) 405 { 406 return seg6_hmac_init_algo(); 407 } 408 EXPORT_SYMBOL(seg6_hmac_init); 409 410 int __net_init seg6_hmac_net_init(struct net *net) 411 { 412 struct seg6_pernet_data *sdata = seg6_pernet(net); 413 414 rhashtable_init(&sdata->hmac_infos, &rht_params); 415 416 return 0; 417 } 418 EXPORT_SYMBOL(seg6_hmac_net_init); 419 420 void seg6_hmac_exit(void) 421 { 422 struct seg6_hmac_algo *algo = NULL; 423 int i, alg_count, cpu; 424 425 alg_count = ARRAY_SIZE(hmac_algos); 426 for (i = 0; i < alg_count; i++) { 427 algo = &hmac_algos[i]; 428 for_each_possible_cpu(cpu) { 429 struct crypto_shash *tfm; 430 struct shash_desc *shash; 431 432 shash = *per_cpu_ptr(algo->shashs, cpu); 433 kfree(shash); 434 tfm = *per_cpu_ptr(algo->tfms, cpu); 435 crypto_free_shash(tfm); 436 } 437 free_percpu(algo->tfms); 438 free_percpu(algo->shashs); 439 } 440 } 441 EXPORT_SYMBOL(seg6_hmac_exit); 442 443 void __net_exit seg6_hmac_net_exit(struct net *net) 444 { 445 struct seg6_pernet_data *sdata = seg6_pernet(net); 446 447 rhashtable_free_and_destroy(&sdata->hmac_infos, seg6_free_hi, NULL); 448 } 449 EXPORT_SYMBOL(seg6_hmac_net_exit); 450