summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2008-08-12 16:51:40 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2008-08-12 16:51:40 +0000
commit4f73ded4f3379a942f591a68fe5c8ded39e72914 (patch)
tree3746e36b1e23c0e955967759aa8b7c05c1a6819f /sys
parentb50ed8931445f809a6b42e4e8ab7a788e447f76d (diff)
Welcome BIP: the Broadcast/Multicast Integrity Protocol defined
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files3
-rw-r--r--sys/net80211/ieee80211.h4
-rw-r--r--sys/net80211/ieee80211_crypto.h11
-rw-r--r--sys/net80211/ieee80211_crypto_bip.c223
-rw-r--r--sys/net80211/ieee80211_ioctl.h4
5 files changed, 241 insertions, 4 deletions
diff --git a/sys/conf/files b/sys/conf/files
index c6c54dbd983..9ea3b43e7a0 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -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
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index ae9bea0ad67..d50766ef7b6 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -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 */
diff --git a/sys/net80211/ieee80211_crypto.h b/sys/net80211/ieee80211_crypto.h
index 6540e4df5cb..b5161d919d0 100644
--- a/sys/net80211/ieee80211_crypto.h
+++ b/sys/net80211/ieee80211_crypto.h
@@ -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
index 00000000000..f40e71ce9bb
--- /dev/null
+++ b/sys/net80211/ieee80211_crypto_bip.c
@@ -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;
+}
diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
index b9e16728e49..9f15c0fa7e6 100644
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -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)