From 4d95bf358eb276f0413d0a85c32691a9e9350520 Mon Sep 17 00:00:00 2001 From: damien Date: Tue, 12 Aug 2008 16:51:39 +0000 Subject: [PATCH] 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. --- sys/conf/files | 3 +- sys/net80211/ieee80211.h | 4 +- sys/net80211/ieee80211_crypto.h | 11 +- sys/net80211/ieee80211_crypto_bip.c | 223 ++++++++++++++++++++++++++++ sys/net80211/ieee80211_ioctl.h | 4 +- 5 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 sys/net80211/ieee80211_crypto_bip.c 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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#endif + +#include +#include +#include + +#include +#include + +/* 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) -- 2.20.1