summaryrefslogtreecommitdiff
path: root/sys/net80211
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-08-01 15:40:41 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-08-01 15:40:41 +0000
commit5feceaaffe50ee74add8643b51d69638aa5d57ab (patch)
tree70a6a0b99a2fdf9be73c3b6e9652c37fbc760ad5 /sys/net80211
parent67fc7a22a0f86de2ffd6be3a953a14f7c6b6083b (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.c150
-rw-r--r--sys/net80211/ieee80211_crypto.h10
-rw-r--r--sys/net80211/ieee80211_input.c84
-rw-r--r--sys/net80211/ieee80211_node.h3
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, &gtk[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, &gtk[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, &gtk[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, &gtk[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;