aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac802154/llsec.c
diff options
context:
space:
mode:
authorPhoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>2014-05-16 11:46:38 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-16 17:23:40 -0400
commit03556e4d0dbbbf4af9df76f4a3839c86f6afb015 (patch)
treeb7a24d10f74faa0449cb1f11b30e88fbf67ad18e /net/mac802154/llsec.c
parent5d637d5aabd85132bd85779677d8acb708e0ed90 (diff)
mac802154: add llsec encryption method
Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac802154/llsec.c')
-rw-r--r--net/mac802154/llsec.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c
index a210d1eb65a9..2a4b68e2a934 100644
--- a/net/mac802154/llsec.c
+++ b/net/mac802154/llsec.c
@@ -527,3 +527,256 @@ int mac802154_llsec_seclevel_del(struct mac802154_llsec *sec,
527 527
528 return 0; 528 return 0;
529} 529}
530
531
532
533static 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
552static struct mac802154_llsec_key*
553llsec_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
600found:
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
608static 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
622static int
623llsec_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
640static struct crypto_aead*
641llsec_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
652static int
653llsec_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
702static 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
713int 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
777fail_read:
778 read_unlock(&sec->lock);
779fail:
780 rcu_read_unlock();
781 return rc;
782}