aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/wpa.c
diff options
context:
space:
mode:
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 aff46adde3f..53e11e6ff66 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}