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

mac802154: add llsec encryption method

Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Phoebe Buckheister and committed by
David S. Miller
03556e4d 5d637d5a

+255
+253
net/mac802154/llsec.c
··· 527 527 528 528 return 0; 529 529 } 530 + 531 + 532 + 533 + static int llsec_recover_addr(struct mac802154_llsec *sec, 534 + struct ieee802154_addr *addr) 535 + { 536 + __le16 caddr = sec->params.coord_shortaddr; 537 + addr->pan_id = sec->params.pan_id; 538 + 539 + if (caddr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) { 540 + return -EINVAL; 541 + } else if (caddr == cpu_to_le16(IEEE802154_ADDR_UNDEF)) { 542 + addr->extended_addr = sec->params.coord_hwaddr; 543 + addr->mode = IEEE802154_ADDR_LONG; 544 + } else { 545 + addr->short_addr = sec->params.coord_shortaddr; 546 + addr->mode = IEEE802154_ADDR_SHORT; 547 + } 548 + 549 + return 0; 550 + } 551 + 552 + static struct mac802154_llsec_key* 553 + llsec_lookup_key(struct mac802154_llsec *sec, 554 + const struct ieee802154_hdr *hdr, 555 + const struct ieee802154_addr *addr, 556 + struct ieee802154_llsec_key_id *key_id) 557 + { 558 + struct ieee802154_addr devaddr = *addr; 559 + u8 key_id_mode = hdr->sec.key_id_mode; 560 + struct ieee802154_llsec_key_entry *key_entry; 561 + struct mac802154_llsec_key *key; 562 + 563 + if (key_id_mode == IEEE802154_SCF_KEY_IMPLICIT && 564 + devaddr.mode == IEEE802154_ADDR_NONE) { 565 + if (hdr->fc.type == IEEE802154_FC_TYPE_BEACON) { 566 + devaddr.extended_addr = sec->params.coord_hwaddr; 567 + devaddr.mode = IEEE802154_ADDR_LONG; 568 + } else if (llsec_recover_addr(sec, &devaddr) < 0) { 569 + return NULL; 570 + } 571 + } 572 + 573 + list_for_each_entry_rcu(key_entry, &sec->table.keys, list) { 574 + const struct ieee802154_llsec_key_id *id = &key_entry->id; 575 + 576 + if (!(key_entry->key->frame_types & BIT(hdr->fc.type))) 577 + continue; 578 + 579 + if (id->mode != key_id_mode) 580 + continue; 581 + 582 + if (key_id_mode == IEEE802154_SCF_KEY_IMPLICIT) { 583 + if (ieee802154_addr_equal(&devaddr, &id->device_addr)) 584 + goto found; 585 + } else { 586 + if (id->id != hdr->sec.key_id) 587 + continue; 588 + 589 + if ((key_id_mode == IEEE802154_SCF_KEY_INDEX) || 590 + (key_id_mode == IEEE802154_SCF_KEY_SHORT_INDEX && 591 + id->short_source == hdr->sec.short_src) || 592 + (key_id_mode == IEEE802154_SCF_KEY_HW_INDEX && 593 + id->extended_source == hdr->sec.extended_src)) 594 + goto found; 595 + } 596 + } 597 + 598 + return NULL; 599 + 600 + found: 601 + key = container_of(key_entry->key, struct mac802154_llsec_key, key); 602 + if (key_id) 603 + *key_id = key_entry->id; 604 + return llsec_key_get(key); 605 + } 606 + 607 + 608 + static void llsec_geniv(u8 iv[16], __le64 addr, 609 + const struct ieee802154_sechdr *sec) 610 + { 611 + __be64 addr_bytes = (__force __be64) swab64((__force u64) addr); 612 + __be32 frame_counter = (__force __be32) swab32((__force u32) sec->frame_counter); 613 + 614 + iv[0] = 1; /* L' = L - 1 = 1 */ 615 + memcpy(iv + 1, &addr_bytes, sizeof(addr_bytes)); 616 + memcpy(iv + 9, &frame_counter, sizeof(frame_counter)); 617 + iv[13] = sec->level; 618 + iv[14] = 0; 619 + iv[15] = 1; 620 + } 621 + 622 + static int 623 + llsec_do_encrypt_unauth(struct sk_buff *skb, const struct mac802154_llsec *sec, 624 + const struct ieee802154_hdr *hdr, 625 + struct mac802154_llsec_key *key) 626 + { 627 + u8 iv[16]; 628 + struct scatterlist src; 629 + struct blkcipher_desc req = { 630 + .tfm = key->tfm0, 631 + .info = iv, 632 + .flags = 0, 633 + }; 634 + 635 + llsec_geniv(iv, sec->params.hwaddr, &hdr->sec); 636 + sg_init_one(&src, skb->data, skb->len); 637 + return crypto_blkcipher_encrypt_iv(&req, &src, &src, skb->len); 638 + } 639 + 640 + static struct crypto_aead* 641 + llsec_tfm_by_len(struct mac802154_llsec_key *key, int authlen) 642 + { 643 + int i; 644 + 645 + for (i = 0; i < ARRAY_SIZE(key->tfm); i++) 646 + if (crypto_aead_authsize(key->tfm[i]) == authlen) 647 + return key->tfm[i]; 648 + 649 + BUG(); 650 + } 651 + 652 + static int 653 + llsec_do_encrypt_auth(struct sk_buff *skb, const struct mac802154_llsec *sec, 654 + const struct ieee802154_hdr *hdr, 655 + struct mac802154_llsec_key *key) 656 + { 657 + u8 iv[16]; 658 + unsigned char *data; 659 + int authlen, assoclen, datalen, rc; 660 + struct scatterlist src, assoc[2], dst[2]; 661 + struct aead_request *req; 662 + 663 + authlen = ieee802154_sechdr_authtag_len(&hdr->sec); 664 + llsec_geniv(iv, sec->params.hwaddr, &hdr->sec); 665 + 666 + req = aead_request_alloc(llsec_tfm_by_len(key, authlen), GFP_ATOMIC); 667 + if (!req) 668 + return -ENOMEM; 669 + 670 + sg_init_table(assoc, 2); 671 + sg_set_buf(&assoc[0], skb_mac_header(skb), skb->mac_len); 672 + assoclen = skb->mac_len; 673 + 674 + data = skb_mac_header(skb) + skb->mac_len; 675 + datalen = skb_tail_pointer(skb) - data; 676 + 677 + if (hdr->sec.level & IEEE802154_SCF_SECLEVEL_ENC) { 678 + sg_set_buf(&assoc[1], data, 0); 679 + } else { 680 + sg_set_buf(&assoc[1], data, datalen); 681 + assoclen += datalen; 682 + datalen = 0; 683 + } 684 + 685 + sg_init_one(&src, data, datalen); 686 + 687 + sg_init_table(dst, 2); 688 + sg_set_buf(&dst[0], data, datalen); 689 + sg_set_buf(&dst[1], skb_put(skb, authlen), authlen); 690 + 691 + aead_request_set_callback(req, 0, NULL, NULL); 692 + aead_request_set_assoc(req, assoc, assoclen); 693 + aead_request_set_crypt(req, &src, dst, datalen, iv); 694 + 695 + rc = crypto_aead_encrypt(req); 696 + 697 + kfree(req); 698 + 699 + return rc; 700 + } 701 + 702 + static int llsec_do_encrypt(struct sk_buff *skb, 703 + const struct mac802154_llsec *sec, 704 + const struct ieee802154_hdr *hdr, 705 + struct mac802154_llsec_key *key) 706 + { 707 + if (hdr->sec.level == IEEE802154_SCF_SECLEVEL_ENC) 708 + return llsec_do_encrypt_unauth(skb, sec, hdr, key); 709 + else 710 + return llsec_do_encrypt_auth(skb, sec, hdr, key); 711 + } 712 + 713 + int mac802154_llsec_encrypt(struct mac802154_llsec *sec, struct sk_buff *skb) 714 + { 715 + struct ieee802154_hdr hdr; 716 + int rc, authlen, hlen; 717 + struct mac802154_llsec_key *key; 718 + u32 frame_ctr; 719 + 720 + hlen = ieee802154_hdr_pull(skb, &hdr); 721 + 722 + if (hlen < 0 || hdr.fc.type != IEEE802154_FC_TYPE_DATA) 723 + return -EINVAL; 724 + 725 + if (!hdr.fc.security_enabled || hdr.sec.level == 0) { 726 + skb_push(skb, hlen); 727 + return 0; 728 + } 729 + 730 + authlen = ieee802154_sechdr_authtag_len(&hdr.sec); 731 + 732 + if (skb->len + hlen + authlen + IEEE802154_MFR_SIZE > IEEE802154_MTU) 733 + return -EMSGSIZE; 734 + 735 + rcu_read_lock(); 736 + 737 + read_lock_bh(&sec->lock); 738 + 739 + if (!sec->params.enabled) { 740 + rc = -EINVAL; 741 + goto fail_read; 742 + } 743 + 744 + key = llsec_lookup_key(sec, &hdr, &hdr.dest, NULL); 745 + if (!key) { 746 + rc = -ENOKEY; 747 + goto fail_read; 748 + } 749 + 750 + read_unlock_bh(&sec->lock); 751 + 752 + write_lock_bh(&sec->lock); 753 + 754 + frame_ctr = be32_to_cpu(sec->params.frame_counter); 755 + hdr.sec.frame_counter = cpu_to_le32(frame_ctr); 756 + if (frame_ctr == 0xFFFFFFFF) { 757 + write_unlock_bh(&sec->lock); 758 + llsec_key_put(key); 759 + rc = -EOVERFLOW; 760 + goto fail; 761 + } 762 + 763 + sec->params.frame_counter = cpu_to_be32(frame_ctr + 1); 764 + 765 + write_unlock_bh(&sec->lock); 766 + 767 + rcu_read_unlock(); 768 + 769 + skb->mac_len = ieee802154_hdr_push(skb, &hdr); 770 + skb_reset_mac_header(skb); 771 + 772 + rc = llsec_do_encrypt(skb, sec, &hdr, key); 773 + llsec_key_put(key); 774 + 775 + return rc < 0 ? rc : 0; 776 + 777 + fail_read: 778 + read_unlock(&sec->lock); 779 + fail: 780 + rcu_read_unlock(); 781 + return rc; 782 + }
+2
net/mac802154/llsec.h
··· 102 102 int mac802154_llsec_seclevel_del(struct mac802154_llsec *sec, 103 103 const struct ieee802154_llsec_seclevel *sl); 104 104 105 + int mac802154_llsec_encrypt(struct mac802154_llsec *sec, struct sk_buff *skb); 106 + 105 107 #endif /* MAC802154_LLSEC_H */