Welcome BIP: the Broadcast/Multicast Integrity Protocol defined
authordamien <damien@openbsd.org>
Tue, 12 Aug 2008 16:51:39 +0000 (16:51 +0000)
committerdamien <damien@openbsd.org>
Tue, 12 Aug 2008 16:51:39 +0000 (16:51 +0000)
in Draft IEEE P802.11w.
It provides data integrity and replay protection for broadcast/
multicast robust management frames (not used yet) using AES-128
in CMAC mode.

sys/conf/files
sys/net80211/ieee80211.h
sys/net80211/ieee80211_crypto.h
sys/net80211/ieee80211_crypto_bip.c [new file with mode: 0644]
sys/net80211/ieee80211_ioctl.h

index c6c54db..9ea3b43 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.439 2008/08/12 15:43:00 damien Exp $
+#      $OpenBSD: files,v 1.440 2008/08/12 16:51:39 damien Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -786,6 +786,7 @@ file net/if_mpe.c                   mpe                     needs-count
 file net80211/ieee80211.c              wlan
 file net80211/ieee80211_amrr.c         wlan
 file net80211/ieee80211_crypto.c       wlan
+file net80211/ieee80211_crypto_bip.c   wlan
 file net80211/ieee80211_crypto_ccmp.c  wlan
 file net80211/ieee80211_crypto_tkip.c  wlan
 file net80211/ieee80211_crypto_wep.c   wlan
index ae9bea0..d50766e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211.h,v 1.38 2008/08/12 16:24:24 damien Exp $   */
+/*     $OpenBSD: ieee80211.h,v 1.39 2008/08/12 16:51:39 damien Exp $   */
 /*     $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $     */
 
 /*-
@@ -169,6 +169,7 @@ struct ieee80211_htframe_addr4 {    /* 11n */
 #define        IEEE80211_SEQ_SEQ_SHIFT                 4
 
 #define        IEEE80211_NWID_LEN                      32
+#define IEEE80211_MMIE_LEN                     18      /* 11w */
 
 /*
  * QoS Control field (see 7.1.3.5).
@@ -273,6 +274,7 @@ enum {
        IEEE80211_ELEMID_QOS_CAP                = 46,
        IEEE80211_ELEMID_RSN                    = 48,
        IEEE80211_ELEMID_XRATES                 = 50,
+       IEEE80211_ELEMID_MMIE                   = 76,   /* 11w */
        IEEE80211_ELEMID_TPC                    = 150,
        IEEE80211_ELEMID_CCKM                   = 156,
        IEEE80211_ELEMID_VENDOR                 = 221   /* vendor private */
index 6540e4d..b5161d9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_crypto.h,v 1.16 2008/08/12 16:33:38 damien Exp $    */
+/*     $OpenBSD: ieee80211_crypto.h,v 1.17 2008/08/12 16:51:39 damien Exp $    */
 /*     $NetBSD: ieee80211_crypto.h,v 1.2 2003/09/14 01:14:55 dyoung Exp $      */
 
 /*-
@@ -146,4 +146,13 @@ extern     void ieee80211_derive_ptk(enum ieee80211_akm, const u_int8_t *,
            const u_int8_t *, struct ieee80211_ptk *);
 extern int ieee80211_cipher_keylen(enum ieee80211_cipher);
 
+extern int ieee80211_bip_set_key(struct ieee80211com *,
+           struct ieee80211_key *);
+extern void ieee80211_bip_delete_key(struct ieee80211com *,
+           struct ieee80211_key *);
+extern struct  mbuf *ieee80211_bip_encap(struct ieee80211com *, struct mbuf *,
+           struct ieee80211_key *);
+extern struct  mbuf *ieee80211_bip_decap(struct ieee80211com *, struct mbuf *,
+           struct ieee80211_key *);
+
 #endif /* _NET80211_IEEE80211_CRYPTO_H_ */
diff --git a/sys/net80211/ieee80211_crypto_bip.c b/sys/net80211/ieee80211_crypto_bip.c
new file mode 100644 (file)
index 0000000..f40e71c
--- /dev/null
@@ -0,0 +1,223 @@
+/*     $OpenBSD: ieee80211_crypto_bip.c,v 1.1 2008/08/12 16:51:39 damien Exp $ */
+
+/*-
+ * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This code implements the Broadcast/Multicast Integrity Protocol (BIP)
+ * defined in IEEE P802.11w/D6.0 section 8.3.4.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/if_llc.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_priv.h>
+
+#include <crypto/rijndael.h>
+#include <crypto/cmac.h>
+
+/* BIP software crypto context */
+struct ieee80211_bip_ctx {
+       AES_CMAC_CTX    cmac;
+};
+
+/*
+ * Initialize software crypto context.  This function can be overridden
+ * by drivers doing hardware crypto.
+ */
+int
+ieee80211_bip_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+       struct ieee80211_bip_ctx *ctx;
+
+       ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (ctx == NULL)
+               return ENOMEM;
+       AES_CMAC_SetKey(&ctx->cmac, k->k_key);
+       k->k_priv = ctx;
+       return 0;
+}
+
+void
+ieee80211_bip_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
+{
+       if (k->k_priv != NULL)
+               free(k->k_priv, M_DEVBUF);
+       k->k_priv = NULL;
+}
+
+/* pseudo-header used for BIP MIC computation */
+struct ieee80211_bip_frame {
+       u_int8_t        i_fc[2];
+       u_int8_t        i_addr1[IEEE80211_ADDR_LEN];
+       u_int8_t        i_addr2[IEEE80211_ADDR_LEN];
+       u_int8_t        i_addr3[IEEE80211_ADDR_LEN];
+} __packed;
+
+struct mbuf *
+ieee80211_bip_encap(struct ieee80211com *ic, struct mbuf *m0,
+    struct ieee80211_key *k)
+{
+       struct ieee80211_bip_ctx *ctx = k->k_priv;
+       struct ieee80211_bip_frame aad;
+       struct ieee80211_frame *wh;
+       u_int8_t *mmie, mic[AES_CMAC_DIGEST_LENGTH];
+       struct mbuf *m;
+
+       wh = mtod(m0, struct ieee80211_frame *);
+       KASSERT((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
+           IEEE80211_FC0_TYPE_MGT);
+       /* clear Protected bit from group management frames */
+       wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
+
+       /* construct AAD (additional authenticated data) */
+       aad.i_fc[0] = wh->i_fc[0];
+       aad.i_fc[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY |
+           IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA);
+       /* XXX 11n may require clearing the Order bit too */
+       IEEE80211_ADDR_COPY(aad.i_addr1, wh->i_addr1);
+       IEEE80211_ADDR_COPY(aad.i_addr2, wh->i_addr2);
+       IEEE80211_ADDR_COPY(aad.i_addr3, wh->i_addr3);
+
+       AES_CMAC_Init(&ctx->cmac);
+       AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&aad, sizeof aad);
+       AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&wh[1],
+           m0->m_len - sizeof(*wh));
+
+       m = m0;
+       /* reserve trailing space for MMIE */
+       if (M_TRAILINGSPACE(m) < IEEE80211_MMIE_LEN) {
+               MGET(m->m_next, M_DONTWAIT, m->m_type);
+               if (m->m_next == NULL)
+                       goto nospace;
+               m = m->m_next;
+               m->m_len = 0;
+       }
+
+       /* construct Management MIC IE */
+       mmie = mtod(m, u_int8_t *) + m->m_len;
+       mmie[0] = IEEE80211_ELEMID_MMIE;
+       mmie[1] = 16;
+       LE_WRITE_2(&mmie[2], k->k_id);
+       LE_WRITE_6(&mmie[4], k->k_tsc);
+       memset(&mmie[10], 0, 8);        /* MMIE MIC field set to 0 */
+
+       AES_CMAC_Update(&ctx->cmac, mmie, IEEE80211_MMIE_LEN);
+       AES_CMAC_Final(mic, &ctx->cmac);
+       /* truncate AES-128-CMAC to 64-bit */
+       memcpy(&mmie[10], mic, 8);
+
+       m->m_len += IEEE80211_MMIE_LEN;
+       m0->m_pkthdr.len += IEEE80211_MMIE_LEN;
+
+       k->k_tsc++;
+
+       return m0;
+ nospace:
+       ic->ic_stats.is_tx_nombuf++;
+       m_freem(m0);
+       return NULL;
+}
+
+struct mbuf *
+ieee80211_bip_decap(struct ieee80211com *ic, struct mbuf *m0,
+    struct ieee80211_key *k)
+{
+       struct ieee80211_bip_ctx *ctx = k->k_priv;
+       struct ieee80211_frame *wh;
+       struct ieee80211_bip_frame aad;
+       u_int8_t *mmie, mic0[8], mic[AES_CMAC_DIGEST_LENGTH];
+       u_int64_t ipn;
+
+       wh = mtod(m0, struct ieee80211_frame *);
+       KASSERT((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
+           IEEE80211_FC0_TYPE_MGT);
+
+       /*
+        * It is assumed that management frames are contiguous and that
+        * the mbuf length has already been checked to contain at least
+        * a header and a MMIE (checked in ieee80211_decrypt()).
+        */
+       KASSERT(m0->m_len >= sizeof(*wh) + IEEE80211_MMIE_LEN);
+       mmie = mtod(m0, u_int8_t *) + m0->m_len - IEEE80211_MMIE_LEN;
+
+       ipn = LE_READ_6(&mmie[4]);
+       if (ipn <= k->k_mgmt_rsc) {
+               /* replayed frame, discard */
+               ic->ic_stats.is_cmac_replays++;
+               m_freem(m0);
+               return NULL;
+       }
+
+       /* save and mask MMIE MIC field to 0 */
+       memcpy(mic0, &mmie[10], 8);
+       memset(&mmie[10], 0, 8);
+
+       /* construct AAD (additional authenticated data) */
+       aad.i_fc[0] = wh->i_fc[0];
+       aad.i_fc[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY |
+           IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA);
+       /* XXX 11n may require clearing the Order bit too */
+       IEEE80211_ADDR_COPY(aad.i_addr1, wh->i_addr1);
+       IEEE80211_ADDR_COPY(aad.i_addr2, wh->i_addr2);
+       IEEE80211_ADDR_COPY(aad.i_addr3, wh->i_addr3);
+
+       /* compute MIC */
+       AES_CMAC_Init(&ctx->cmac);
+       AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&aad, sizeof aad);
+       AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&wh[1],
+           m0->m_len - sizeof(*wh));
+       AES_CMAC_Final(mic, &ctx->cmac);
+       /* truncate AES-128-CMAC to 64-bit */
+       memcpy(&mmie[10], mic, 8);
+
+       /* check that MIC matches the one in MMIE */
+       if (memcmp(&mmie[10], mic0, 8) != 0) {
+               ic->ic_stats.is_cmac_icv_errs++;
+               m_freem(m0);
+               return NULL;
+       }
+       /*
+        * There is no need to trim the MMIE from the mbuf since it is
+        * an information element and will be ignored by upper layers.
+        * We do it anyway as it is cheap to do it here and because we
+        * did not check for the presence of fixed fields yet.
+        */
+       m_adj(m0, -IEEE80211_MMIE_LEN);
+
+       /* update last seen packet number (MIC is validated) */
+       k->k_mgmt_rsc = ipn;
+
+       return m0;
+}
index b9e1672..9f15c0f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_ioctl.h,v 1.12 2008/08/12 16:45:44 damien Exp $     */
+/*     $OpenBSD: ieee80211_ioctl.h,v 1.13 2008/08/12 16:51:39 damien Exp $     */
 /*     $NetBSD: ieee80211_ioctl.h,v 1.7 2004/04/30 22:51:04 dyoung Exp $       */
 
 /*-
@@ -93,6 +93,8 @@ struct ieee80211_stats {
        u_int32_t       is_tkip_icv_errs;
        u_int32_t       is_ccmp_replays;
        u_int32_t       is_ccmp_dec_errs;
+       u_int32_t       is_cmac_replays;
+       u_int32_t       is_cmac_icv_errs;
 };
 
 #define        SIOCG80211STATS         _IOWR('i', 242, struct ifreq)