diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2008-08-12 19:57:00 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2008-08-12 19:57:00 +0000 |
commit | a2407eb6ca89941166b13df3af2931416358e300 (patch) | |
tree | 5884321fc4e0d1d126ca88792653453ab6d466ed /sys/net80211 | |
parent | c62b4649d45dd791966395d51a81465d216be52f (diff) |
add the code to encrypt/decrypt management frames, retrieve key id
from MMIE etc...
this code can't be triggered as no drivers claim MFP capability yet.
Diffstat (limited to 'sys/net80211')
-rw-r--r-- | sys/net80211/ieee80211_crypto.c | 78 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 26 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 20 |
3 files changed, 105 insertions, 19 deletions
diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c index 484660cc9bb..329af139ef4 100644 --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -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); diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index e9dd7df6507..99980cc00a8 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -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; diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 8202ae6a7ad..60c2ed4de77 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -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 || |