summaryrefslogtreecommitdiff
path: root/sys/net80211
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2008-08-12 19:57:00 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2008-08-12 19:57:00 +0000
commita2407eb6ca89941166b13df3af2931416358e300 (patch)
tree5884321fc4e0d1d126ca88792653453ab6d466ed /sys/net80211
parentc62b4649d45dd791966395d51a81465d216be52f (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.c78
-rw-r--r--sys/net80211/ieee80211_input.c26
-rw-r--r--sys/net80211/ieee80211_output.c20
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 ||