diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-01 15:40:41 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-01 15:40:41 +0000 |
commit | 5feceaaffe50ee74add8643b51d69638aa5d57ab (patch) | |
tree | 70a6a0b99a2fdf9be73c3b6e9652c37fbc760ad5 /sys/net80211 | |
parent | 67fc7a22a0f86de2ffd6be3a953a14f7c6b6083b (diff) |
add generic ieee80211_encrypt() and ieee80211_decrypt() functions that
can handle multiple ciphers (the key to use is determined automatically
by these functions based on the frame's destination address).
add ieee80211_ccmp_encrypt() and ieee80211_ccmp_decrypt().
those two functions only do encapsulation/decapsulation of CCMP frames
for now (they don't do SW crypto). they will help to test things with
drivers that can do HW crypto.
add a ni_pairwise_key field to struct ieee80211_node to actually install
the pairwise transient key.
install the GTK in ic_nw_keys[].
Diffstat (limited to 'sys/net80211')
-rw-r--r-- | sys/net80211/ieee80211_crypto.c | 150 | ||||
-rw-r--r-- | sys/net80211/ieee80211_crypto.h | 10 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 84 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 3 |
4 files changed, 207 insertions, 40 deletions
diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c index da7419022af..e40fb03b3bd 100644 --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_crypto.c,v 1.29 2007/08/01 12:59:33 damien Exp $ */ +/* $OpenBSD: ieee80211_crypto.c,v 1.30 2007/08/01 15:40:40 damien Exp $ */ /* $NetBSD: ieee80211_crypto.c,v 1.5 2003/12/14 09:56:53 dyoung Exp $ */ /*- @@ -74,6 +74,10 @@ struct vector { void ieee80211_crc_init(void); u_int32_t ieee80211_crc_update(u_int32_t, const u_int8_t *, int); +struct mbuf *ieee80211_ccmp_encrypt(struct ieee80211com *, struct mbuf *, + struct ieee80211_key *); +struct mbuf *ieee80211_ccmp_decrypt(struct ieee80211com *, struct mbuf *, + struct ieee80211_key *); void ieee80211_aes_key_wrap(const u_int8_t *, size_t, const u_int8_t *, size_t, u_int8_t *); int ieee80211_aes_key_unwrap(const u_int8_t *, size_t, const u_int8_t *, @@ -115,6 +119,150 @@ ieee80211_crypto_detach(struct ifnet *ifp) } } +struct mbuf * +ieee80211_encrypt(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_node *ni) +{ + struct ieee80211_frame *wh; + struct ieee80211_key *k; + + /* select the key for encryption */ + wh = mtod(m0, struct ieee80211_frame *); + if (IEEE80211_IS_MULTICAST(wh->i_addr1) || + ni->ni_pairwise_cipher == IEEE80211_CIPHER_USEGROUP) + k = &ic->ic_nw_keys[ic->ic_wep_txkey]; + else + k = &ni->ni_pairwise_key; + + switch (k->k_cipher) { + case IEEE80211_CIPHER_CCMP: + m0 = ieee80211_ccmp_encrypt(ic, m0, k); + break; + case IEEE80211_CIPHER_WEP40: + case IEEE80211_CIPHER_WEP104: + m0 = ieee80211_wep_crypt(&ic->ic_if, m0, 1); + break; + default: + /* should not get there */ + m_freem(m0); + m0 = NULL; + } + return m0; +} + +struct mbuf * +ieee80211_decrypt(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_node *ni) +{ + struct ieee80211_frame *wh; + struct ieee80211_key *k; + + /* select the key for decryption */ + wh = mtod(m0, struct ieee80211_frame *); + if (IEEE80211_IS_MULTICAST(wh->i_addr1) || + ni->ni_pairwise_cipher == IEEE80211_CIPHER_USEGROUP) { + size_t hdrlen = sizeof(*wh); /* XXX QoS */ + 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 + k = &ni->ni_pairwise_key; + + switch (k->k_cipher) { + case IEEE80211_CIPHER_CCMP: + m0 = ieee80211_ccmp_decrypt(ic, m0, k); + break; + case IEEE80211_CIPHER_WEP40: + case IEEE80211_CIPHER_WEP104: + m0 = ieee80211_wep_crypt(&ic->ic_if, m0, 0); + break; + default: + /* should not get there */ + m_freem(m0); + m0 = NULL; + } + return m0; +} + +#define IEEE80211_CCMP_HDRLEN 8 +#define IEEE80211_CCMP_MICLEN 8 + +struct mbuf * +ieee80211_ccmp_encrypt(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_key *k) +{ + struct ieee80211_frame *wh; + size_t hdrlen = sizeof(*wh); /* XXX QoS */ + u_int8_t *ivp; + + M_PREPEND(m0, IEEE80211_CCMP_HDRLEN, M_NOWAIT); + if (m0 == NULL) + return m0; + wh = mtod(m0, struct ieee80211_frame *); + ovbcopy(mtod(m0, u_int8_t *) + IEEE80211_CCMP_HDRLEN, wh, hdrlen); + ivp = (u_int8_t *)wh + hdrlen; + + k->k_tsc++; /* increment the 48-bit PN */ + ivp[0] = k->k_tsc; /* PN0 */ + ivp[1] = k->k_tsc >> 8; /* PN1 */ + ivp[2] = 0; /* Rsvd */ + ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */ + ivp[4] = k->k_tsc >> 16; /* PN2 */ + ivp[5] = k->k_tsc >> 24; /* PN3 */ + ivp[6] = k->k_tsc >> 32; /* PN4 */ + ivp[7] = k->k_tsc >> 40; /* PN5 */ + + /* XXX encrypt payload if HW encryption not supported */ + + return m0; +} + +struct mbuf * +ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_key *k) +{ + struct ieee80211_frame *wh; + size_t hdrlen = sizeof(*wh); /* XXX QoS */ + u_int64_t pn; + u_int8_t *ivp; + + wh = mtod(m0, struct ieee80211_frame *); + ivp = (u_int8_t *)wh + hdrlen; + + /* check that ExtIV bit is be set */ + if (!(ivp[3] & IEEE80211_WEP_EXTIV)) { + m_freem(m0); + return NULL; + } + /* extract the 48-bit PN from the CCMP header */ + pn = (u_int64_t)ivp[0] | + (u_int64_t)ivp[1] << 8 | + (u_int64_t)ivp[4] << 16 | + (u_int64_t)ivp[5] << 24 | + (u_int64_t)ivp[6] << 32 | + (u_int64_t)ivp[7] << 40; + /* NB: the keys are refreshed, we'll never overflow the 48 bits */ + if (pn <= k->k_rsc) { + /* replayed frame, discard */ + /* XXX statistics */ + m_freem(m0); + return NULL; + } + + /* XXX decrypt payload if HW encryption not supported */ + + ovbcopy(mtod(m0, u_int8_t *), + mtod(m0, u_int8_t *) + IEEE80211_CCMP_HDRLEN, hdrlen); + m_adj(m0, IEEE80211_CCMP_HDRLEN); + m_adj(m0, -IEEE80211_CCMP_MICLEN); + + /* update last seen packet number */ + k->k_rsc = pn; + + return m0; +} + /* Round up to a multiple of IEEE80211_WEP_KEYLEN + IEEE80211_WEP_IVLEN */ #define klen_round(x) \ (((x) + (IEEE80211_WEP_KEYLEN + IEEE80211_WEP_IVLEN - 1)) & \ diff --git a/sys/net80211/ieee80211_crypto.h b/sys/net80211/ieee80211_crypto.h index 2a15425c0f7..0ac915fbd35 100644 --- a/sys/net80211/ieee80211_crypto.h +++ b/sys/net80211/ieee80211_crypto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_crypto.h,v 1.5 2007/08/01 12:37:46 damien Exp $ */ +/* $OpenBSD: ieee80211_crypto.h,v 1.6 2007/08/01 15:40:40 damien Exp $ */ /* $NetBSD: ieee80211_crypto.h,v 1.2 2003/09/14 01:14:55 dyoung Exp $ */ /*- @@ -73,8 +73,16 @@ struct ieee80211_key { u_int8_t k_key[IEEE80211_KEYBUF_SIZE]; }; +/* forward references */ +struct ieee80211com; +struct ieee80211_node; + extern void ieee80211_crypto_attach(struct ifnet *); extern void ieee80211_crypto_detach(struct ifnet *); +extern struct mbuf *ieee80211_encrypt(struct ieee80211com *, struct mbuf *, + struct ieee80211_node *); +extern struct mbuf *ieee80211_decrypt(struct ieee80211com *, struct mbuf *, + struct ieee80211_node *); extern struct mbuf *ieee80211_wep_crypt(struct ifnet *, struct mbuf *, int); extern void ieee80211_derive_ptk(const u_int8_t *, size_t, const u_int8_t *, const u_int8_t *, const u_int8_t *, const u_int8_t *, u_int8_t *, diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 8fd50e56f41..31128e87015 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -1,5 +1,5 @@ /* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */ -/* $OpenBSD: ieee80211_input.c,v 1.55 2007/08/01 15:22:12 damien Exp $ */ +/* $OpenBSD: ieee80211_input.c,v 1.56 2007/08/01 15:40:40 damien Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting @@ -2041,7 +2041,7 @@ void ieee80211_recv_4way_msg3(struct ieee80211com *ic, const struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { - struct ieee80211_key k; + struct ieee80211_key *k; const u_int8_t *frm, *efrm; const u_int8_t *rsn1, *rsn2, *gtk; @@ -2120,35 +2120,41 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, } /* install the PTK */ - memset(&k, 0, sizeof k); - k.k_cipher = ni->ni_pairwise_cipher; - k.k_flags = IEEE80211_KEY_TX; - k.k_len = BE_READ_2(key->keylen); + k = &ni->ni_pairwise_key; + memset(k, 0, sizeof(*k)); + k->k_cipher = ni->ni_pairwise_cipher; + k->k_flags = IEEE80211_KEY_TX; + k->k_len = BE_READ_2(key->keylen); /* check that key length matches pairwise cipher */ - if (k.k_len != ieee80211_cipher_keylen(k.k_cipher)) + if (k->k_len != ieee80211_cipher_keylen(k->k_cipher)) return; - memcpy(k.k_key, ni->ni_ptk.tk, k.k_len); - if ((*ic->ic_set_key)(ic, ni, &k) != 0) + memcpy(k->k_key, ni->ni_ptk.tk, k->k_len); + if ((*ic->ic_set_key)(ic, ni, k) != 0) return; if (gtk != NULL) { + u_int8_t kid; + /* check that the GTK KDE is valid */ if (gtk[1] - 4 < 2) return; + /* install the GTK */ - memset(&k, 0, sizeof k); - k.k_id = gtk[6] & 3; - k.k_cipher = ni->ni_group_cipher; - k.k_flags = IEEE80211_KEY_GROUP; + kid = gtk[6] & 3; + k = &ic->ic_nw_keys[kid]; + memset(k, 0, sizeof(*k)); + k->k_id = kid; + k->k_cipher = ni->ni_group_cipher; + k->k_flags = IEEE80211_KEY_GROUP; if (gtk[6] & (1 << 2)) /* Tx bit */ - k.k_flags |= IEEE80211_KEY_TX; - k.k_len = gtk[1] - 6; + k->k_flags |= IEEE80211_KEY_TX; + k->k_len = gtk[1] - 6; /* check that key length matches group cipher */ - if (k.k_len != ieee80211_cipher_keylen(k.k_cipher)) + if (k->k_len != ieee80211_cipher_keylen(k->k_cipher)) return; /* XXX PTK already installed! */ - memcpy(k.k_key, >k[7], k.k_len); - k.k_rsc = LE_READ_8(key->rsc); - if ((*ic->ic_set_key)(ic, ni, &k) != 0) + memcpy(k->k_key, >k[7], k->k_len); + k->k_rsc = LE_READ_8(key->rsc); + if ((*ic->ic_set_key)(ic, ni, k) != 0) return; } @@ -2172,7 +2178,7 @@ void ieee80211_recv_4way_msg4(struct ieee80211com *ic, const struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { - struct ieee80211_key k; + struct ieee80211_key *k; if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) @@ -2184,12 +2190,13 @@ ieee80211_recv_4way_msg4(struct ieee80211com *ic, /* empty key data field */ /* install the PTK */ - memset(&k, 0, sizeof k); - k.k_cipher = ni->ni_pairwise_cipher; - k.k_flags = IEEE80211_KEY_TX; - k.k_len = ieee80211_cipher_keylen(k.k_cipher); - memcpy(k.k_key, ni->ni_ptk.tk, k.k_len); - if ((*ic->ic_set_key)(ic, ni, &k) != 0) + k = &ni->ni_pairwise_key; + memset(k, 0, sizeof(*k)); + k->k_cipher = ni->ni_pairwise_cipher; + k->k_flags = IEEE80211_KEY_TX; + k->k_len = ieee80211_cipher_keylen(k->k_cipher); + memcpy(k->k_key, ni->ni_ptk.tk, k->k_len); + if ((*ic->ic_set_key)(ic, ni, k) != 0) return; if (ic->ic_opmode == IEEE80211_M_IBSS) { @@ -2215,9 +2222,10 @@ void ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, const struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { - struct ieee80211_key k; + struct ieee80211_key *k; const u_int8_t *frm, *efrm; const u_int8_t *gtk; + u_int8_t kid; if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) @@ -2256,19 +2264,21 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, if (gtk[1] - 4 < 2) return; /* install the GTK */ - memset(&k, 0, sizeof k); - k.k_id = gtk[6] & 3; - k.k_cipher = ni->ni_group_cipher; - k.k_flags = IEEE80211_KEY_GROUP; + kid = gtk[6] & 3; + k = &ic->ic_nw_keys[kid]; + memset(k, 0, sizeof(*k)); + k->k_id = kid; + k->k_cipher = ni->ni_group_cipher; + k->k_flags = IEEE80211_KEY_GROUP; if (gtk[6] & (1 << 2)) /* Tx bit */ - k.k_flags |= IEEE80211_KEY_TX; - k.k_len = gtk[1] - 6; + k->k_flags |= IEEE80211_KEY_TX; + k->k_len = gtk[1] - 6; /* check that key length matches group cipher */ - if (k.k_len != ieee80211_cipher_keylen(k.k_cipher)) + if (k->k_len != ieee80211_cipher_keylen(k->k_cipher)) return; - memcpy(k.k_key, >k[7], k.k_len); - k.k_rsc = LE_READ_8(key->rsc); - if ((*ic->ic_set_key)(ic, ni, &k) != 0) + memcpy(k->k_key, >k[7], k->k_len); + k->k_rsc = LE_READ_8(key->rsc); + if ((*ic->ic_set_key)(ic, ni, k) != 0) return; /* update the last seen value of the key replay counter field */ diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 11db49d4c2a..72919b64588 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.h,v 1.19 2007/08/01 12:32:26 damien Exp $ */ +/* $OpenBSD: ieee80211_node.h,v 1.20 2007/08/01 15:40:40 damien Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- @@ -124,6 +124,7 @@ struct ieee80211_node { u_int64_t ni_replaycnt; u_int8_t ni_replaycnt_ok; u_int8_t *ni_rsnie; + struct ieee80211_key ni_pairwise_key; struct ieee80211_ptk ni_ptk; u_int8_t ni_ptk_ok; u_int8_t ni_key_count; |