Browse Source

[802.11] Add support for WEP-protected networks

WEP is a highly flawed cryptosystem, barely better than no encryption at all,
but many people still use it. It does have the advantage of being very simple
and small in code size.

Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Joshua Oreman 15 years ago
parent
commit
01b4f52089
4 changed files with 317 additions and 0 deletions
  1. 7
    0
      src/config/config_net80211.c
  2. 6
    0
      src/config/general.h
  3. 1
    0
      src/include/gpxe/errfile.h
  4. 303
    0
      src/net/80211/wep.c

+ 7
- 0
src/config/config_net80211.c View File

@@ -31,3 +31,10 @@ REQUIRE_OBJECT ( iwmgmt_cmd );
31 31
 REQUIRE_OBJECT ( wireless_errors );
32 32
 #endif
33 33
 
34
+/*
35
+ * Drag in 802.11 cryptosystems and handshaking protocols
36
+ *
37
+ */
38
+#ifdef CRYPTO_80211_WEP
39
+REQUIRE_OBJECT ( wep );
40
+#endif

+ 6
- 0
src/config/general.h View File

@@ -64,6 +64,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
64 64
 //#undef	SANBOOT_PROTO_AOE	/* AoE protocol */
65 65
 //#undef	SANBOOT_PROTO_IB_SRP	/* Infiniband SCSI RDMA protocol */
66 66
 
67
+/*
68
+ * 802.11 cryptosystems and handshaking protocols
69
+ *
70
+ */
71
+#define	CRYPTO_80211_WEP	/* WEP encryption (deprecated and insecure!) */
72
+
67 73
 /*
68 74
  * Name resolution modules
69 75
  *

+ 1
- 0
src/include/gpxe/errfile.h View File

@@ -159,6 +159,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
159 159
 #define ERRFILE_ib_cmrc			( ERRFILE_NET | 0x00210000 )
160 160
 #define ERRFILE_ib_srp			( ERRFILE_NET | 0x00220000 )
161 161
 #define ERRFILE_sec80211		( ERRFILE_NET | 0x00230000 )
162
+#define ERRFILE_wep			( ERRFILE_NET | 0x00240000 )
162 163
 
163 164
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
164 165
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 303
- 0
src/net/80211/wep.c View File

@@ -0,0 +1,303 @@
1
+/*
2
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <gpxe/net80211.h>
22
+#include <gpxe/sec80211.h>
23
+#include <gpxe/crypto.h>
24
+#include <gpxe/arc4.h>
25
+#include <gpxe/crc32.h>
26
+#include <stdlib.h>
27
+#include <string.h>
28
+#include <errno.h>
29
+
30
+/** @file
31
+ *
32
+ * The WEP wireless encryption method (insecure!)
33
+ *
34
+ * The data field in a WEP-encrypted packet contains a 3-byte
35
+ * initialisation vector, one-byte Key ID field (only the bottom two
36
+ * bits are ever used), encrypted data, and a 4-byte encrypted CRC of
37
+ * the plaintext data, called the ICV. To decrypt it, the IV is
38
+ * prepended to the shared key and the data stream (including ICV) is
39
+ * run through the ARC4 stream cipher; if the ICV matches a CRC32
40
+ * calculated on the plaintext, the packet is valid.
41
+ *
42
+ * For efficiency and code-size reasons, this file assumes it is
43
+ * running on a little-endian machine.
44
+ */
45
+
46
+/** Length of WEP initialisation vector */
47
+#define WEP_IV_LEN	3
48
+
49
+/** Length of WEP key ID byte */
50
+#define WEP_KID_LEN	1
51
+
52
+/** Length of WEP ICV checksum */
53
+#define WEP_ICV_LEN	4
54
+
55
+/** Maximum length of WEP key */
56
+#define WEP_MAX_KEY	16
57
+
58
+/** Amount of data placed before the encrypted bytes */
59
+#define WEP_HEADER_LEN	4
60
+
61
+/** Amount of data placed after the encrypted bytes */
62
+#define WEP_TRAILER_LEN	4
63
+
64
+/** Total WEP overhead bytes */
65
+#define WEP_OVERHEAD	8
66
+
67
+/** Context for WEP encryption and decryption */
68
+struct wep_ctx
69
+{
70
+	/** Encoded WEP key
71
+	 *
72
+	 * The actual key bytes are stored beginning at offset 3, to
73
+	 * leave room for easily inserting the IV before a particular
74
+	 * operation.
75
+	 */
76
+	u8 key[WEP_IV_LEN + WEP_MAX_KEY];
77
+
78
+	/** Length of WEP key (not including IV bytes) */
79
+	int keylen;
80
+
81
+	/** ARC4 context */
82
+	struct arc4_ctx arc4;
83
+};
84
+
85
+/**
86
+ * Initialize WEP algorithm
87
+ *
88
+ * @v crypto	802.11 cryptographic algorithm
89
+ * @v key	WEP key to use
90
+ * @v keylen	Length of WEP key
91
+ * @v rsc	Initial receive sequence counter (unused)
92
+ * @ret rc	Return status code
93
+ *
94
+ * Standard key lengths are 5 and 13 bytes; 16-byte keys are
95
+ * occasionally supported as an extension to the standard.
96
+ */
97
+static int wep_init ( struct net80211_crypto *crypto, const void *key,
98
+		      int keylen, const void *rsc __unused )
99
+{
100
+	struct wep_ctx *ctx = crypto->priv;
101
+
102
+	ctx->keylen = ( keylen > WEP_MAX_KEY ? WEP_MAX_KEY : keylen );
103
+	memcpy ( ctx->key + WEP_IV_LEN, key, ctx->keylen );
104
+
105
+	return 0;
106
+}
107
+
108
+/**
109
+ * Encrypt packet using WEP
110
+ *
111
+ * @v crypto	802.11 cryptographic algorithm
112
+ * @v iob	I/O buffer of plaintext packet
113
+ * @ret eiob	Newly allocated I/O buffer for encrypted packet, or NULL
114
+ *
115
+ * If memory allocation fails, @c NULL is returned.
116
+ */
117
+static struct io_buffer * wep_encrypt ( struct net80211_crypto *crypto,
118
+					struct io_buffer *iob )
119
+{
120
+	struct wep_ctx *ctx = crypto->priv;
121
+	struct io_buffer *eiob;
122
+	struct ieee80211_frame *hdr;
123
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
124
+	int datalen = iob_len ( iob ) - hdrlen;
125
+	int newlen = hdrlen + datalen + WEP_OVERHEAD;
126
+	u32 iv, icv;
127
+
128
+	eiob = alloc_iob ( newlen );
129
+	if ( ! eiob )
130
+		return NULL;
131
+
132
+	memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen );
133
+	hdr = eiob->data;
134
+	hdr->fc |= IEEE80211_FC_PROTECTED;
135
+
136
+	/* Calculate IV, put it in the header (with key ID byte = 0), and
137
+	   set it up at the start of the encryption key. */
138
+	iv = random() & 0xffffff; /* IV in bottom 3 bytes, top byte = KID = 0 */
139
+	memcpy ( iob_put ( eiob, WEP_HEADER_LEN ), &iv, WEP_HEADER_LEN );
140
+	memcpy ( ctx->key, &iv, WEP_IV_LEN );
141
+
142
+	/* Encrypt the data using RC4 */
143
+	cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key,
144
+			ctx->keylen + WEP_IV_LEN );
145
+	cipher_encrypt ( &arc4_algorithm, &ctx->arc4, iob->data + hdrlen,
146
+			 iob_put ( eiob, datalen ), datalen );
147
+
148
+	/* Add ICV */
149
+	icv = ~crc32_le ( ~0, iob->data + hdrlen, datalen );
150
+	cipher_encrypt ( &arc4_algorithm, &ctx->arc4, &icv,
151
+			 iob_put ( eiob, WEP_ICV_LEN ), WEP_ICV_LEN );
152
+
153
+	return eiob;
154
+}
155
+
156
+/**
157
+ * Decrypt packet using WEP
158
+ *
159
+ * @v crypto	802.11 cryptographic algorithm
160
+ * @v eiob	I/O buffer of encrypted packet
161
+ * @ret iob	Newly allocated I/O buffer for plaintext packet, or NULL
162
+ *
163
+ * If a consistency check for the decryption fails (usually indicating
164
+ * an invalid key), @c NULL is returned.
165
+ */
166
+static struct io_buffer * wep_decrypt ( struct net80211_crypto *crypto,
167
+					struct io_buffer *eiob )
168
+{
169
+	struct wep_ctx *ctx = crypto->priv;
170
+	struct io_buffer *iob;
171
+	struct ieee80211_frame *hdr;
172
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
173
+	int datalen = iob_len ( eiob ) - hdrlen - WEP_OVERHEAD;
174
+	int newlen = hdrlen + datalen;
175
+	u32 iv, icv, crc;
176
+
177
+	iob = alloc_iob ( newlen );
178
+	if ( ! iob )
179
+		return NULL;
180
+
181
+	memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen );
182
+	hdr = iob->data;
183
+	hdr->fc &= ~IEEE80211_FC_PROTECTED;
184
+
185
+	/* Strip off IV and use it to initialize cryptosystem */
186
+	memcpy ( &iv, eiob->data + hdrlen, 4 );
187
+	iv &= 0xffffff;		/* ignore key ID byte */
188
+	memcpy ( ctx->key, &iv, WEP_IV_LEN );
189
+
190
+	/* Decrypt the data using RC4 */
191
+	cipher_setkey ( &arc4_algorithm, &ctx->arc4, ctx->key,
192
+			ctx->keylen + WEP_IV_LEN );
193
+	cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen +
194
+			 WEP_HEADER_LEN, iob_put ( iob, datalen ), datalen );
195
+
196
+	/* Strip off ICV and verify it */
197
+	cipher_decrypt ( &arc4_algorithm, &ctx->arc4, eiob->data + hdrlen +
198
+			 WEP_HEADER_LEN + datalen, &icv, WEP_ICV_LEN );
199
+	crc = ~crc32_le ( ~0, iob->data + hdrlen, datalen );
200
+	if ( crc != icv ) {
201
+		DBGC ( crypto, "WEP %p CRC mismatch: expect %08x, get %08x\n",
202
+		       crypto, icv, crc );
203
+		free_iob ( iob );
204
+		return NULL;
205
+	}
206
+	return iob;
207
+}
208
+
209
+/** WEP cryptosystem for 802.11 */
210
+struct net80211_crypto wep_crypto __net80211_crypto = {
211
+	.algorithm = NET80211_CRYPT_WEP,
212
+	.init = wep_init,
213
+	.encrypt = wep_encrypt,
214
+	.decrypt = wep_decrypt,
215
+	.priv_len = sizeof ( struct wep_ctx ),
216
+};
217
+
218
+/**
219
+ * Initialize trivial 802.11 security handshaker
220
+ *
221
+ * @v dev	802.11 device
222
+ * @v ctx	Security handshaker
223
+ *
224
+ * This simply fetches a WEP key from netX/key, and if it exists,
225
+ * installs WEP cryptography on the 802.11 device. No real handshaking
226
+ * is performed.
227
+ */
228
+static int trivial_init ( struct net80211_device *dev )
229
+{
230
+	u8 key[WEP_MAX_KEY];	/* support up to 128-bit keys */
231
+	int len;
232
+	int rc;
233
+
234
+	if ( dev->associating &&
235
+	     dev->associating->crypto == NET80211_CRYPT_NONE )
236
+		return 0;	/* no crypto? OK. */
237
+
238
+	len = fetch_setting ( netdev_settings ( dev->netdev ),
239
+			      &net80211_key_setting, key, WEP_MAX_KEY );
240
+
241
+	if ( len <= 0 ) {
242
+		DBGC ( dev, "802.11 %p cannot do WEP without a key\n", dev );
243
+		return -EACCES;
244
+	}
245
+
246
+	/* Full 128-bit keys are a nonstandard extension, but they're
247
+	   utterly trivial to support, so we do. */
248
+	if ( len != 5 && len != 13 && len != 16 ) {
249
+		DBGC ( dev, "802.11 %p invalid WEP key length %d\n",
250
+		       dev, len );
251
+		return -EINVAL;
252
+	}
253
+
254
+	DBGC ( dev, "802.11 %p installing %d-bit WEP\n", dev, len * 8 );
255
+
256
+	rc = sec80211_install ( &dev->crypto, NET80211_CRYPT_WEP, key, len,
257
+				NULL );
258
+	if ( rc < 0 )
259
+		return rc;
260
+
261
+	return 0;
262
+}
263
+
264
+/**
265
+ * Check for key change on trivial 802.11 security handshaker
266
+ *
267
+ * @v dev	802.11 device
268
+ * @v ctx	Security handshaker
269
+ */
270
+static int trivial_change_key ( struct net80211_device *dev )
271
+{
272
+	u8 key[WEP_MAX_KEY];
273
+	int len;
274
+	int change = 0;
275
+
276
+	/* If going from WEP to clear, or something else to WEP, reassociate. */
277
+	if ( ! dev->crypto || ( dev->crypto->init != wep_init ) )
278
+		change ^= 1;
279
+
280
+	len = fetch_setting ( netdev_settings ( dev->netdev ),
281
+			      &net80211_key_setting, key, WEP_MAX_KEY );
282
+	if ( len <= 0 )
283
+		change ^= 1;
284
+
285
+	/* Changing crypto type => return nonzero to reassociate. */
286
+	if ( change )
287
+		return -EINVAL;
288
+
289
+	/* Going from no crypto to still no crypto => nothing to do. */
290
+	if ( len <= 0 )
291
+		return 0;
292
+
293
+	/* Otherwise, reinitialise WEP with new key. */
294
+	return wep_init ( dev->crypto, key, len, NULL );
295
+}
296
+
297
+/** Trivial 802.11 security handshaker */
298
+struct net80211_handshaker trivial_handshaker __net80211_handshaker = {
299
+	.protocol = NET80211_SECPROT_NONE,
300
+	.init = trivial_init,
301
+	.change_key = trivial_change_key,
302
+	.priv_len = 0,
303
+};

Loading…
Cancel
Save