1 /* $OpenBSD: ieee80211_crypto_bip.c,v 1.5 2014/07/12 18:44:22 tedu Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * This code implements the Broadcast/Multicast Integrity Protocol (BIP) 21 * defined in IEEE P802.11w/D7.0 section 8.3.4. 22 */ 23 24 #include <sys/param.h> 25 #include <sys/systm.h> 26 #include <sys/mbuf.h> 27 #include <sys/malloc.h> 28 #include <sys/kernel.h> 29 #include <sys/socket.h> 30 #include <sys/endian.h> 31 32 #include <net/if.h> 33 #include <net/if_dl.h> 34 #include <net/if_media.h> 35 #include <net/if_arp.h> 36 37 #ifdef INET 38 #include <netinet/in.h> 39 #include <netinet/if_ether.h> 40 #endif 41 42 #include <net80211/ieee80211_var.h> 43 #include <net80211/ieee80211_crypto.h> 44 #include <net80211/ieee80211_priv.h> 45 46 #include <crypto/rijndael.h> 47 #include <crypto/cmac.h> 48 49 /* BIP software crypto context */ 50 struct ieee80211_bip_ctx { 51 AES_CMAC_CTX cmac; 52 }; 53 54 /* 55 * Initialize software crypto context. This function can be overridden 56 * by drivers doing hardware crypto. 57 */ 58 int 59 ieee80211_bip_set_key(struct ieee80211com *ic, struct ieee80211_key *k) 60 { 61 struct ieee80211_bip_ctx *ctx; 62 63 ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO); 64 if (ctx == NULL) 65 return ENOMEM; 66 AES_CMAC_SetKey(&ctx->cmac, k->k_key); 67 k->k_priv = ctx; 68 return 0; 69 } 70 71 void 72 ieee80211_bip_delete_key(struct ieee80211com *ic, struct ieee80211_key *k) 73 { 74 if (k->k_priv != NULL) 75 free(k->k_priv, M_DEVBUF, 0); 76 k->k_priv = NULL; 77 } 78 79 /* pseudo-header used for BIP MIC computation */ 80 struct ieee80211_bip_frame { 81 u_int8_t i_fc[2]; 82 u_int8_t i_addr1[IEEE80211_ADDR_LEN]; 83 u_int8_t i_addr2[IEEE80211_ADDR_LEN]; 84 u_int8_t i_addr3[IEEE80211_ADDR_LEN]; 85 } __packed; 86 87 struct mbuf * 88 ieee80211_bip_encap(struct ieee80211com *ic, struct mbuf *m0, 89 struct ieee80211_key *k) 90 { 91 struct ieee80211_bip_ctx *ctx = k->k_priv; 92 struct ieee80211_bip_frame aad; 93 struct ieee80211_frame *wh; 94 u_int8_t *mmie, mic[AES_CMAC_DIGEST_LENGTH]; 95 struct mbuf *m; 96 97 wh = mtod(m0, struct ieee80211_frame *); 98 KASSERT((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 99 IEEE80211_FC0_TYPE_MGT); 100 /* clear Protected bit from group management frames */ 101 wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 102 103 /* construct AAD (additional authenticated data) */ 104 aad.i_fc[0] = wh->i_fc[0]; 105 aad.i_fc[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | 106 IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA); 107 /* XXX 11n may require clearing the Order bit too */ 108 IEEE80211_ADDR_COPY(aad.i_addr1, wh->i_addr1); 109 IEEE80211_ADDR_COPY(aad.i_addr2, wh->i_addr2); 110 IEEE80211_ADDR_COPY(aad.i_addr3, wh->i_addr3); 111 112 AES_CMAC_Init(&ctx->cmac); 113 AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&aad, sizeof aad); 114 AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&wh[1], 115 m0->m_len - sizeof(*wh)); 116 117 m = m0; 118 /* reserve trailing space for MMIE */ 119 if (M_TRAILINGSPACE(m) < IEEE80211_MMIE_LEN) { 120 MGET(m->m_next, M_DONTWAIT, m->m_type); 121 if (m->m_next == NULL) 122 goto nospace; 123 m = m->m_next; 124 m->m_len = 0; 125 } 126 127 /* construct Management MIC IE */ 128 mmie = mtod(m, u_int8_t *) + m->m_len; 129 mmie[0] = IEEE80211_ELEMID_MMIE; 130 mmie[1] = 16; 131 LE_WRITE_2(&mmie[2], k->k_id); 132 LE_WRITE_6(&mmie[4], k->k_tsc); 133 memset(&mmie[10], 0, 8); /* MMIE MIC field set to 0 */ 134 135 AES_CMAC_Update(&ctx->cmac, mmie, IEEE80211_MMIE_LEN); 136 AES_CMAC_Final(mic, &ctx->cmac); 137 /* truncate AES-128-CMAC to 64-bit */ 138 memcpy(&mmie[10], mic, 8); 139 140 m->m_len += IEEE80211_MMIE_LEN; 141 m0->m_pkthdr.len += IEEE80211_MMIE_LEN; 142 143 k->k_tsc++; 144 145 return m0; 146 nospace: 147 ic->ic_stats.is_tx_nombuf++; 148 m_freem(m0); 149 return NULL; 150 } 151 152 struct mbuf * 153 ieee80211_bip_decap(struct ieee80211com *ic, struct mbuf *m0, 154 struct ieee80211_key *k) 155 { 156 struct ieee80211_bip_ctx *ctx = k->k_priv; 157 struct ieee80211_frame *wh; 158 struct ieee80211_bip_frame aad; 159 u_int8_t *mmie, mic0[8], mic[AES_CMAC_DIGEST_LENGTH]; 160 u_int64_t ipn; 161 162 wh = mtod(m0, struct ieee80211_frame *); 163 KASSERT((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 164 IEEE80211_FC0_TYPE_MGT); 165 166 /* 167 * It is assumed that management frames are contiguous and that 168 * the mbuf length has already been checked to contain at least 169 * a header and a MMIE (checked in ieee80211_decrypt()). 170 */ 171 KASSERT(m0->m_len >= sizeof(*wh) + IEEE80211_MMIE_LEN); 172 mmie = mtod(m0, u_int8_t *) + m0->m_len - IEEE80211_MMIE_LEN; 173 174 ipn = LE_READ_6(&mmie[4]); 175 if (ipn <= k->k_mgmt_rsc) { 176 /* replayed frame, discard */ 177 ic->ic_stats.is_cmac_replays++; 178 m_freem(m0); 179 return NULL; 180 } 181 182 /* save and mask MMIE MIC field to 0 */ 183 memcpy(mic0, &mmie[10], 8); 184 memset(&mmie[10], 0, 8); 185 186 /* construct AAD (additional authenticated data) */ 187 aad.i_fc[0] = wh->i_fc[0]; 188 aad.i_fc[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | 189 IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA); 190 /* XXX 11n may require clearing the Order bit too */ 191 IEEE80211_ADDR_COPY(aad.i_addr1, wh->i_addr1); 192 IEEE80211_ADDR_COPY(aad.i_addr2, wh->i_addr2); 193 IEEE80211_ADDR_COPY(aad.i_addr3, wh->i_addr3); 194 195 /* compute MIC */ 196 AES_CMAC_Init(&ctx->cmac); 197 AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&aad, sizeof aad); 198 AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&wh[1], 199 m0->m_len - sizeof(*wh)); 200 AES_CMAC_Final(mic, &ctx->cmac); 201 202 /* check that MIC matches the one in MMIE */ 203 if (timingsafe_bcmp(mic, mic0, 8) != 0) { 204 ic->ic_stats.is_cmac_icv_errs++; 205 m_freem(m0); 206 return NULL; 207 } 208 /* 209 * There is no need to trim the MMIE from the mbuf since it is 210 * an information element and will be ignored by upper layers. 211 * We do it anyway as it is cheap to do it here and because it 212 * may be confused with fixed fields by upper layers. 213 */ 214 m_adj(m0, -IEEE80211_MMIE_LEN); 215 216 /* update last seen packet number (MIC is validated) */ 217 k->k_mgmt_rsc = ipn; 218 219 return m0; 220 } 221