1 /*-
2  * Copyright (c) 2004 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * Alternatively, this software may be distributed under the terms of the
17  * GNU General Public License ("GPL") version 2 as published by the Free
18  * Software Foundation.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * WEP test module.
34  *
35  * Test vectors come from section I.7.2 of P802.11i/D7.0, October 2003.
36  *
37  * To use this tester load the net80211 layer (either as a module or
38  * by statically configuring it into your kernel), then insmod this
39  * module.  It should automatically run all test cases and print
40  * information for each.  To run one or more tests you can specify a
41  * tests parameter to the module that is a bit mask of the set of tests
42  * you want; e.g. insmod wep_test tests=7 will run only test mpdu's
43  * 1, 2, and 3.
44  */
45 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/systm.h>
48 #include <sys/mbuf.h>
49 #include <sys/module.h>
50 
51 #include <sys/socket.h>
52 
53 #include <net/if.h>
54 #include <net/if_var.h>
55 #include <net/if_media.h>
56 
57 #include <net80211/ieee80211_var.h>
58 
59 /*
60 MPDU data
61  aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 22
62  0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 00 00
63  20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 43 41 43
64  41 43 41 43 41 43 41 41 41 00 00 20 00 01
65 
66 RC4 encryption is performed as follows:
67 17
68 18  Key  fb 02 9e 30 31 32 33 34
69 Plaintext
70  aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01
71  22 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00
72  00 00 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43
73  43 41 43 41 43 41 43 41 43 41 41 41 00 00 20 00 01 1b d0 b6 04
74 Ciphertext
75  f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d
76  5f 58 a5 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14
77  1d 48 5f 8a a8 36 de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10
78  40 b2 4b 7d 1a 69 38 56 ed 0d 43 98 e7 ae e3 bf 0e 2a 2c a8 f7
79 The plaintext consists of the MPDU data, followed by a 4-octet CRC-32
80 calculated over the MPDU data.
81 19  The expanded MPDU, after WEP encapsulation, is as follows:
82 20
83 21  IV  fb 02 9e 80
84 MPDU  data
85  f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d 5f 58 a5
86  03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14 1d 48 5f 8a a8 36
87  de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10 40 b2 4b 7d 1a 69 38 56 ed
88  0d 43 98 e7 ae e3 bf 0e
89 ICV  2a 2c a8 f7
90 */
91 static const u_int8_t test1_key[] = {		/* TK (w/o IV) */
92 	0x30, 0x31, 0x32, 0x33, 0x34,
93 };
94 static const u_int8_t test1_plaintext[] = {	/* Plaintext MPDU */
95 	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,	/* 802.11 Header */
96 	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
97 	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
98 	0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00,	/* Plaintext data */
99 	0x45, 0x00, 0x00, 0x4e, 0x66, 0x1a, 0x00, 0x00,
100 	0x80, 0x11, 0xbe, 0x64, 0x0a, 0x00, 0x01, 0x22,
101 	0x0a, 0xff, 0xff, 0xff, 0x00, 0x89, 0x00, 0x89,
102 	0x00, 0x3a, 0x00, 0x00, 0x80, 0xa6, 0x01, 0x10,
103 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 	0x20, 0x45, 0x43, 0x45, 0x4a, 0x45, 0x48, 0x45,
105 	0x43, 0x46, 0x43, 0x45, 0x50, 0x46, 0x45, 0x45,
106 	0x49, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43,
107 	0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41,
108 	0x41, 0x00, 0x00, 0x20, 0x00, 0x01,
109 };
110 static const u_int8_t test1_encrypted[] = {	/* Encrypted MPDU */
111 	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
112 	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
113 	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
114 	0xfb, 0x02, 0x9e, 0x80, 0xf6, 0x9c, 0x58, 0x06,
115 	0xbd, 0x6c, 0xe8, 0x46, 0x26, 0xbc, 0xbe, 0xfb,
116 	0x94, 0x74, 0x65, 0x0a, 0xad, 0x1f, 0x79, 0x09,
117 	0xb0, 0xf6, 0x4d, 0x5f, 0x58, 0xa5, 0x03, 0xa2,
118 	0x58, 0xb7, 0xed, 0x22, 0xeb, 0x0e, 0xa6, 0x49,
119 	0x30, 0xd3, 0xa0, 0x56, 0xa5, 0x57, 0x42, 0xfc,
120 	0xce, 0x14, 0x1d, 0x48, 0x5f, 0x8a, 0xa8, 0x36,
121 	0xde, 0xa1, 0x8d, 0xf4, 0x2c, 0x53, 0x80, 0x80,
122 	0x5a, 0xd0, 0xc6, 0x1a, 0x5d, 0x6f, 0x58, 0xf4,
123 	0x10, 0x40, 0xb2, 0x4b, 0x7d, 0x1a, 0x69, 0x38,
124 	0x56, 0xed, 0x0d, 0x43, 0x98, 0xe7, 0xae, 0xe3,
125 	0xbf, 0x0e, 0x2a, 0x2c, 0xa8, 0xf7,
126 };
127 
128 /* XXX fix byte order of iv */
129 #define	TEST(n,name,cipher,keyix,iv0,iv1,iv2,iv3) { \
130 	name, IEEE80211_CIPHER_##cipher,keyix, { iv2,iv1,iv0,iv3 }, \
131 	test##n##_key,   sizeof(test##n##_key), \
132 	test##n##_plaintext, sizeof(test##n##_plaintext), \
133 	test##n##_encrypted, sizeof(test##n##_encrypted) \
134 }
135 
136 struct ciphertest {
137 	const char	*name;
138 	int		cipher;
139 	int		keyix;
140 	u_int8_t	iv[4];
141 	const u_int8_t	*key;
142 	size_t		key_len;
143 	const u_int8_t	*plaintext;
144 	size_t		plaintext_len;
145 	const u_int8_t	*encrypted;
146 	size_t		encrypted_len;
147 } weptests[] = {
148 	TEST(1, "WEP test mpdu 1", WEP, 2, 0xfb, 0x02, 0x9e, 0x80),
149 };
150 
151 static void
152 dumpdata(const char *tag, const void *p, size_t len)
153 {
154 	int i;
155 
156 	printf("%s: 0x%p len %u", tag, p, len);
157 	for (i = 0; i < len; i++) {
158 		if ((i % 16) == 0)
159 			printf("\n%03d:", i);
160 		printf(" %02x", ((const u_int8_t *)p)[i]);
161 	}
162 	printf("\n");
163 }
164 
165 static void
166 cmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen)
167 {
168 	int i;
169 
170 	for (i = 0; i < genlen; i++)
171 		if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) {
172 			printf("first difference at byte %u\n", i);
173 			break;
174 		}
175 	dumpdata("Generated", gen, genlen);
176 	dumpdata("Reference", ref, reflen);
177 }
178 
179 struct wep_ctx_hw {			/* for use with h/w support */
180 	struct ieee80211vap *wc_vap;	/* for diagnostics+statistics */
181 	struct ieee80211com *wc_ic;
182 	uint32_t        wc_iv;		/* initial vector for crypto */
183 };
184 
185 static int
186 runtest(struct ieee80211vap *vap, struct ciphertest *t)
187 {
188 	struct ieee80211_key *key = &vap->iv_nw_keys[t->keyix];
189 	struct mbuf *m = NULL;
190 	const struct ieee80211_cipher *cip;
191 	struct wep_ctx_hw *ctx;
192 	int hdrlen;
193 
194 	printf("%s: ", t->name);
195 
196 	/*
197 	 * Setup key.
198 	 */
199 	memset(key, 0, sizeof(*key));
200 	key->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
201 	key->wk_cipher = &ieee80211_cipher_none;
202 	if (!ieee80211_crypto_newkey(vap, t->cipher,
203 	    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key)) {
204 		printf("FAIL: ieee80211_crypto_newkey failed\n");
205 		goto bad;
206 	}
207 
208 	memcpy(key->wk_key, t->key, t->key_len);
209 	key->wk_keylen = t->key_len;
210 	if (!ieee80211_crypto_setkey(vap, key)) {
211 		printf("FAIL: ieee80211_crypto_setkey failed\n");
212 		goto bad;
213 	}
214 
215 	/*
216 	 * Craft frame from plaintext data.
217 	 */
218 	cip = key->wk_cipher;
219 	m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
220 	memcpy(mtod(m, void *), t->encrypted, t->encrypted_len);
221 	m->m_len = t->encrypted_len;
222 	m->m_pkthdr.len = m->m_len;
223 	hdrlen = ieee80211_anyhdrsize(mtod(m, void *));
224 
225 	/*
226 	 * Decrypt frame.
227 	 */
228 	if (!cip->ic_decap(key, m, hdrlen)) {
229 		printf("FAIL: wep decap failed\n");
230 		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
231 			t->plaintext, t->plaintext_len);
232 		goto bad;
233 	}
234 	/*
235 	 * Verify: frame length, frame contents.
236 	 */
237 	if (m->m_pkthdr.len != t->plaintext_len) {
238 		printf("FAIL: decap botch; length mismatch\n");
239 		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
240 			t->plaintext, t->plaintext_len);
241 		goto bad;
242 	} else if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) {
243 		printf("FAIL: decap botch; data does not compare\n");
244 		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
245 			t->plaintext, t->plaintext_len);
246 		goto bad;
247 	}
248 
249 	/*
250 	 * Encrypt frame.
251 	 */
252 	ctx = (struct wep_ctx_hw *) key->wk_private;
253 	ctx->wc_vap = vap;
254 	ctx->wc_ic = vap->iv_ic;
255 	memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv));	/* for encap/encrypt */
256 	if (!cip->ic_encap(key, m)) {
257 		printf("FAIL: wep encap failed\n");
258 		goto bad;
259 	}
260 	/*
261 	 * Verify: frame length, frame contents.
262 	 */
263 	if (m->m_pkthdr.len != t->encrypted_len) {
264 		printf("FAIL: encap data length mismatch\n");
265 		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
266 			t->encrypted, t->encrypted_len);
267 		goto bad;
268 	} else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) {
269 		printf("FAIL: encrypt data does not compare\n");
270 		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
271 			t->encrypted, t->encrypted_len);
272 		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
273 		goto bad;
274 	}
275 	m_freem(m);
276 	ieee80211_crypto_delkey(vap, key);
277 	printf("PASS\n");
278 	return 1;
279 bad:
280 	if (m != NULL)
281 		m_freem(m);
282 	ieee80211_crypto_delkey(vap, key);
283 	return 0;
284 }
285 
286 /*
287  * Module glue.
288  */
289 
290 static	int tests = -1;
291 static	int debug = 0;
292 
293 static int
294 init_crypto_wep_test(void)
295 {
296 	struct ieee80211com ic;
297 	struct ieee80211vap vap;
298 	struct ifnet ifp;
299 	int i, pass, total;
300 
301 	memset(&ic, 0, sizeof(ic));
302 	memset(&vap, 0, sizeof(vap));
303 	memset(&ifp, 0, sizeof(ifp));
304 
305 	ieee80211_crypto_attach(&ic);
306 
307 	/* some minimal initialization */
308 	strncpy(ifp.if_xname, "test_ccmp", sizeof(ifp.if_xname));
309 	vap.iv_ic = &ic;
310 	vap.iv_ifp = &ifp;
311 	if (debug)
312 		vap.iv_debug = IEEE80211_MSG_CRYPTO;
313 	ieee80211_crypto_vattach(&vap);
314 
315 	pass = 0;
316 	total = 0;
317 	for (i = 0; i < nitems(weptests); i++)
318 		if (tests & (1<<i)) {
319 			total++;
320 			pass += runtest(&vap, &weptests[i]);
321 		}
322 	printf("%u of %u 802.11i WEP test vectors passed\n", pass, total);
323 
324 	ieee80211_crypto_vdetach(&vap);
325 	ieee80211_crypto_detach(&ic);
326 
327 	return (pass == total ? 0 : -1);
328 }
329 
330 static int
331 test_wep_modevent(module_t mod, int type, void *unused)
332 {
333 	switch (type) {
334 	case MOD_LOAD:
335 		(void) init_crypto_wep_test();
336 		return 0;
337 	case MOD_UNLOAD:
338 		return 0;
339 	}
340 	return EINVAL;
341 }
342 
343 static moduledata_t test_wep_mod = {
344 	"test_wep",
345 	test_wep_modevent,
346 	0
347 };
348 DECLARE_MODULE(test_wep, test_wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
349 MODULE_VERSION(test_wep, 1);
350 MODULE_DEPEND(test_wep, wlan, 1, 1, 1);
351