add the code to encrypt/decrypt management frames, retrieve key id
authordamien <damien@openbsd.org>
Tue, 12 Aug 2008 19:56:59 +0000 (19:56 +0000)
committerdamien <damien@openbsd.org>
Tue, 12 Aug 2008 19:56:59 +0000 (19:56 +0000)
from MMIE etc...
this code can't be triggered as no drivers claim MFP capability yet.

sys/net80211/ieee80211_crypto.c
sys/net80211/ieee80211_input.c
sys/net80211/ieee80211_output.c

index 484660c..329af13 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_crypto.c,v 1.51 2008/08/12 19:34:54 damien Exp $    */
+/*     $OpenBSD: ieee80211_crypto.c,v 1.52 2008/08/12 19:56:59 damien Exp $    */
 
 /*-
  * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
@@ -188,11 +188,20 @@ struct ieee80211_key *
 ieee80211_get_txkey(struct ieee80211com *ic, const struct ieee80211_frame *wh,
     struct ieee80211_node *ni)
 {
-       if (!(ic->ic_flags & IEEE80211_F_RSNON) ||
-           IEEE80211_IS_MULTICAST(wh->i_addr1) ||
-           ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
-               return &ic->ic_nw_keys[ic->ic_wep_txkey];
-       return &ni->ni_pairwise_key;
+       int kid;
+
+       if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+           !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+           ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
+               return &ni->ni_pairwise_key;
+
+       if (!IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+           (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
+           IEEE80211_FC0_TYPE_MGT)
+               kid = ic->ic_def_txkey;
+       else
+               kid = ic->ic_igtk_kid;
+       return &ic->ic_nw_keys[kid];
 }
 
 struct mbuf *
@@ -210,6 +219,9 @@ ieee80211_encrypt(struct ieee80211com *ic, struct mbuf *m0,
        case IEEE80211_CIPHER_CCMP:
                m0 = ieee80211_ccmp_encrypt(ic, m0, k);
                break;
+       case IEEE80211_CIPHER_AES128_CMAC:
+               m0 = ieee80211_bip_encap(ic, m0, k);
+               break;
        default:
                /* should not get there */
                m_freem(m0);
@@ -224,21 +236,50 @@ ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0,
 {
        struct ieee80211_frame *wh;
        struct ieee80211_key *k;
+       u_int8_t *ivp, *mmie;
+       u_int16_t kid;
+       int hdrlen;
 
-       /* select the key for decryption */
+       /* find key for decryption */
        wh = mtod(m0, struct ieee80211_frame *);
-       if (!(ic->ic_flags & IEEE80211_F_RSNON) ||
-           IEEE80211_IS_MULTICAST(wh->i_addr1) ||
-           ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP) {
-               /* XXX check length! */
-               int hdrlen = ieee80211_get_hdrlen(wh);
-               const u_int8_t *ivp = (u_int8_t *)wh + hdrlen;
-               /* key identifier is always located at the same index */
-               int kid = ivp[IEEE80211_WEP_IVLEN] >> 6;
-               k = &ic->ic_nw_keys[kid];
-       } else
+       if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+           !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+           ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) {
                k = &ni->ni_pairwise_key;
 
+       } else if (!IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+           (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
+           IEEE80211_FC0_TYPE_MGT) {
+               /* retrieve group data key id from IV field */
+               hdrlen = ieee80211_get_hdrlen(wh);
+               /* check that IV field is present */
+               if (m0->m_len < hdrlen + 4) {
+                       m_freem(m0);
+                       return NULL;
+               }
+               ivp = (u_int8_t *)wh + hdrlen;
+               kid = ivp[3] >> 6;
+               k = &ic->ic_nw_keys[kid];
+       } else {
+               /* retrieve integrity group key id from MMIE */
+               if (m0->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
+                       m_freem(m0);
+                       return NULL;
+               }
+               /* it is assumed management frames are contiguous */
+               mmie = (u_int8_t *)wh + m0->m_len - IEEE80211_MMIE_LEN;
+               /* check that MMIE is valid */
+               if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) {
+                       m_freem(m0);
+                       return NULL;
+               }
+               kid = LE_READ_2(&mmie[2]);
+               if (kid != 4 && kid != 5) {
+                       m_freem(m0);
+                       return NULL;
+               }
+               k = &ic->ic_nw_keys[kid];
+       }
        switch (k->k_cipher) {
        case IEEE80211_CIPHER_WEP40:
        case IEEE80211_CIPHER_WEP104:
@@ -250,6 +291,9 @@ ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0,
        case IEEE80211_CIPHER_CCMP:
                m0 = ieee80211_ccmp_decrypt(ic, m0, k);
                break;
+       case IEEE80211_CIPHER_AES128_CMAC:
+               m0 = ieee80211_bip_decap(ic, m0, k);
+               break;
        default:
                /* key not defined */
                m_freem(m0);
index e9dd7df..99980cc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_input.c,v 1.95 2008/08/12 19:50:39 damien Exp $     */
+/*     $OpenBSD: ieee80211_input.c,v 1.96 2008/08/12 19:56:59 damien Exp $     */
 
 /*-
  * Copyright (c) 2001 Atsushi Onoe
@@ -453,6 +453,30 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
                        }
                }
 
+               if (ni->ni_flags & IEEE80211_NODE_RXMGMTPROT) {
+                       /* MMPDU protection is on for Rx */
+                       if (subtype == IEEE80211_FC0_SUBTYPE_DISASSOC ||
+                           subtype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
+                           subtype == IEEE80211_FC0_SUBTYPE_ACTION) {
+                               if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+                                   !(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
+                                       /* unicast mgmt not encrypted */
+                                       goto out;
+                               }
+                               /* do software decryption */
+                               m = ieee80211_decrypt(ic, m, ni);
+                               if (m == NULL) {
+                                       /* XXX stats */
+                                       goto out;
+                               }
+                               wh = mtod(m, struct ieee80211_frame *);
+                       }
+               } else if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+                   (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
+                       /* encrypted but MMPDU Rx protection off for TA */
+                       goto out;
+               }
+
                if (ifp->if_flags & IFF_DEBUG) {
                        /* avoid to print too many frames */
                        int doprint = 0;
index 8202ae6..60c2ed4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_output.c,v 1.69 2008/08/12 19:29:07 damien Exp $    */
+/*     $OpenBSD: ieee80211_output.c,v 1.70 2008/08/12 19:56:59 damien Exp $    */
 /*     $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $     */
 
 /*-
@@ -194,6 +194,24 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
        IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
        IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
 
+       /* check if protection is required for this mgmt frame */
+       if ((ic->ic_caps & IEEE80211_C_MFP) &&
+           (type == IEEE80211_FC0_SUBTYPE_DISASSOC ||
+            type == IEEE80211_FC0_SUBTYPE_DEAUTH ||
+            type == IEEE80211_FC0_SUBTYPE_ACTION)) {
+               /*
+                * Hack: we should not set the Protected bit in outgoing
+                * group management frames, however it is used as an
+                * indication to the drivers that they must encrypt the
+                * frame.  Drivers should clear this bit from group
+                * management frames (software crypto code will do it).
+                * XXX could use an mbuf flag..
+                */
+               if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+                   (ni->ni_flags & IEEE80211_NODE_TXMGMTPROT))
+                       wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
+       }
+
        if (ifp->if_flags & IFF_DEBUG) {
                /* avoid to print too many frames */
                if (ic->ic_opmode == IEEE80211_M_IBSS ||