aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/wpa.c
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2009-01-08 06:32:01 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:02 -0500
commit765cb46a3fc856245ea68a7c961ac87c77e4ae2d (patch)
tree210cb9cd260430221ddb3be9620ee8ae90ecee34 /net/mac80211/wpa.c
parentfb7333367632c67d8b6b06fb8d906cdabb11b02a (diff)
mac80211: 802.11w - Add BIP (AES-128-CMAC)
Implement Broadcast/Multicast Integrity Protocol for management frame protection. This patch adds the needed definitions for the new information element (MMIE) and implementation for the new "encryption" type (though, BIP is actually not encrypting data, it provides only integrity protection). These routines will be used by a follow-on patch that enables BIP for multicast/broadcast robust management frames. Signed-off-by: Jouni Malinen <j@w1.fi> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/wpa.c')
-rw-r--r--net/mac80211/wpa.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index aff46adde3f0..53e11e6ff66e 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright 2002-2004, Instant802 Networks, Inc. 2 * Copyright 2002-2004, Instant802 Networks, Inc.
3 * Copyright 2008, Jouni Malinen <j@w1.fi>
3 * 4 *
4 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 6 * it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,7 @@
19#include "michael.h" 20#include "michael.h"
20#include "tkip.h" 21#include "tkip.h"
21#include "aes_ccm.h" 22#include "aes_ccm.h"
23#include "aes_cmac.h"
22#include "wpa.h" 24#include "wpa.h"
23 25
24ieee80211_tx_result 26ieee80211_tx_result
@@ -491,3 +493,126 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
491 493
492 return RX_CONTINUE; 494 return RX_CONTINUE;
493} 495}
496
497
498static void bip_aad(struct sk_buff *skb, u8 *aad)
499{
500 /* BIP AAD: FC(masked) || A1 || A2 || A3 */
501
502 /* FC type/subtype */
503 aad[0] = skb->data[0];
504 /* Mask FC Retry, PwrMgt, MoreData flags to zero */
505 aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6));
506 /* A1 || A2 || A3 */
507 memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN);
508}
509
510
511static inline void bip_ipn_swap(u8 *d, const u8 *s)
512{
513 *d++ = s[5];
514 *d++ = s[4];
515 *d++ = s[3];
516 *d++ = s[2];
517 *d++ = s[1];
518 *d = s[0];
519}
520
521
522ieee80211_tx_result
523ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
524{
525 struct sk_buff *skb = tx->skb;
526 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
527 struct ieee80211_key *key = tx->key;
528 struct ieee80211_mmie *mmie;
529 u8 *pn, aad[20];
530 int i;
531
532 if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
533 /* hwaccel */
534 info->control.hw_key = &tx->key->conf;
535 return 0;
536 }
537
538 if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
539 return TX_DROP;
540
541 mmie = (struct ieee80211_mmie *) skb_put(skb, sizeof(*mmie));
542 mmie->element_id = WLAN_EID_MMIE;
543 mmie->length = sizeof(*mmie) - 2;
544 mmie->key_id = cpu_to_le16(key->conf.keyidx);
545
546 /* PN = PN + 1 */
547 pn = key->u.aes_cmac.tx_pn;
548
549 for (i = sizeof(key->u.aes_cmac.tx_pn) - 1; i >= 0; i--) {
550 pn[i]++;
551 if (pn[i])
552 break;
553 }
554 bip_ipn_swap(mmie->sequence_number, pn);
555
556 bip_aad(skb, aad);
557
558 /*
559 * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
560 */
561 ieee80211_aes_cmac(key->u.aes_cmac.tfm, key->u.aes_cmac.tx_crypto_buf,
562 aad, skb->data + 24, skb->len - 24, mmie->mic);
563
564 return TX_CONTINUE;
565}
566
567
568ieee80211_rx_result
569ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
570{
571 struct sk_buff *skb = rx->skb;
572 struct ieee80211_key *key = rx->key;
573 struct ieee80211_mmie *mmie;
574 u8 aad[20], mic[8], ipn[6];
575 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
576
577 if (!ieee80211_is_mgmt(hdr->frame_control))
578 return RX_CONTINUE;
579
580 if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
581 (rx->status->flag & RX_FLAG_IV_STRIPPED))
582 return RX_CONTINUE;
583
584 if (skb->len < 24 + sizeof(*mmie))
585 return RX_DROP_UNUSABLE;
586
587 mmie = (struct ieee80211_mmie *)
588 (skb->data + skb->len - sizeof(*mmie));
589 if (mmie->element_id != WLAN_EID_MMIE ||
590 mmie->length != sizeof(*mmie) - 2)
591 return RX_DROP_UNUSABLE; /* Invalid MMIE */
592
593 bip_ipn_swap(ipn, mmie->sequence_number);
594
595 if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
596 key->u.aes_cmac.replays++;
597 return RX_DROP_UNUSABLE;
598 }
599
600 if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
601 /* hardware didn't decrypt/verify MIC */
602 bip_aad(skb, aad);
603 ieee80211_aes_cmac(key->u.aes_cmac.tfm,
604 key->u.aes_cmac.rx_crypto_buf, aad,
605 skb->data + 24, skb->len - 24, mic);
606 if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
607 key->u.aes_cmac.icverrors++;
608 return RX_DROP_UNUSABLE;
609 }
610 }
611
612 memcpy(key->u.aes_cmac.rx_pn, ipn, 6);
613
614 /* Remove MMIE */
615 skb_trim(skb, skb->len - sizeof(*mmie));
616
617 return RX_CONTINUE;
618}