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  * $FreeBSD$
32  */
33 
34 /*
35  * WEP test module.
36  *
37  * Test vectors come from section I.7.2 of P802.11i/D7.0, October 2003.
38  *
39  * To use this tester load the net80211 layer (either as a module or
40  * by statically configuring it into your kernel), then insmod this
41  * module.  It should automatically run all test cases and print
42  * information for each.  To run one or more tests you can specify a
43  * tests parameter to the module that is a bit mask of the set of tests
44  * you want; e.g. insmod wep_test tests=7 will run only test mpdu's
45  * 1, 2, and 3.
46  */
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/systm.h>
50 #include <sys/mbuf.h>
51 #include <sys/module.h>
52 
53 #include <sys/socket.h>
54 
55 #include <net/if.h>
56 #include <net/if_media.h>
57 
58 #include <net80211/ieee80211_var.h>
59 
60 /*
61 MPDU data
62  aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 22
63  0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 00 00
64  20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 43 41 43
65  41 43 41 43 41 43 41 41 41 00 00 20 00 01
66 
67 RC4 encryption is performed as follows:
68 17
69 18  Key  fb 02 9e 30 31 32 33 34
70 Plaintext
71  aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01
72  22 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00
73  00 00 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43
74  43 41 43 41 43 41 43 41 43 41 41 41 00 00 20 00 01 1b d0 b6 04
75 Ciphertext
76  f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d
77  5f 58 a5 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14
78  1d 48 5f 8a a8 36 de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10
79  40 b2 4b 7d 1a 69 38 56 ed 0d 43 98 e7 ae e3 bf 0e 2a 2c a8 f7
80 The plaintext consists of the MPDU data, followed by a 4-octet CRC-32
81 calculated over the MPDU data.
82 19  The expanded MPDU, after WEP encapsulation, is as follows:
83 20
84 21  IV  fb 02 9e 80
85 MPDU  data
86  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
87  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
88  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
89  0d 43 98 e7 ae e3 bf 0e
90 ICV  2a 2c a8 f7
91 */
92 static const u_int8_t test1_key[] = {		/* TK (w/o IV) */
93 	0x30, 0x31, 0x32, 0x33, 0x34,
94 };
95 static const u_int8_t test1_plaintext[] = {	/* Plaintext MPDU */
96 	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,	/* 802.11 Header */
97 	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
98 	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
99 	0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00,	/* Plaintext data */
100 	0x45, 0x00, 0x00, 0x4e, 0x66, 0x1a, 0x00, 0x00,
101 	0x80, 0x11, 0xbe, 0x64, 0x0a, 0x00, 0x01, 0x22,
102 	0x0a, 0xff, 0xff, 0xff, 0x00, 0x89, 0x00, 0x89,
103 	0x00, 0x3a, 0x00, 0x00, 0x80, 0xa6, 0x01, 0x10,
104 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 	0x20, 0x45, 0x43, 0x45, 0x4a, 0x45, 0x48, 0x45,
106 	0x43, 0x46, 0x43, 0x45, 0x50, 0x46, 0x45, 0x45,
107 	0x49, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43,
108 	0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41,
109 	0x41, 0x00, 0x00, 0x20, 0x00, 0x01,
110 };
111 static const u_int8_t test1_encrypted[] = {	/* Encrypted MPDU */
112 	0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28,
113 	0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08,
114 	0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33,
115 	0xfb, 0x02, 0x9e, 0x80, 0xf6, 0x9c, 0x58, 0x06,
116 	0xbd, 0x6c, 0xe8, 0x46, 0x26, 0xbc, 0xbe, 0xfb,
117 	0x94, 0x74, 0x65, 0x0a, 0xad, 0x1f, 0x79, 0x09,
118 	0xb0, 0xf6, 0x4d, 0x5f, 0x58, 0xa5, 0x03, 0xa2,
119 	0x58, 0xb7, 0xed, 0x22, 0xeb, 0x0e, 0xa6, 0x49,
120 	0x30, 0xd3, 0xa0, 0x56, 0xa5, 0x57, 0x42, 0xfc,
121 	0xce, 0x14, 0x1d, 0x48, 0x5f, 0x8a, 0xa8, 0x36,
122 	0xde, 0xa1, 0x8d, 0xf4, 0x2c, 0x53, 0x80, 0x80,
123 	0x5a, 0xd0, 0xc6, 0x1a, 0x5d, 0x6f, 0x58, 0xf4,
124 	0x10, 0x40, 0xb2, 0x4b, 0x7d, 0x1a, 0x69, 0x38,
125 	0x56, 0xed, 0x0d, 0x43, 0x98, 0xe7, 0xae, 0xe3,
126 	0xbf, 0x0e, 0x2a, 0x2c, 0xa8, 0xf7,
127 };
128 
129 /* XXX fix byte order of iv */
130 #define	TEST(n,name,cipher,keyix,iv0,iv1,iv2,iv3) { \
131 	name, IEEE80211_CIPHER_##cipher,keyix, { iv2,iv1,iv0,iv3 }, \
132 	test##n##_key,   sizeof(test##n##_key), \
133 	test##n##_plaintext, sizeof(test##n##_plaintext), \
134 	test##n##_encrypted, sizeof(test##n##_encrypted) \
135 }
136 
137 struct ciphertest {
138 	const char	*name;
139 	int		cipher;
140 	int		keyix;
141 	u_int8_t	iv[4];
142 	const u_int8_t	*key;
143 	size_t		key_len;
144 	const u_int8_t	*plaintext;
145 	size_t		plaintext_len;
146 	const u_int8_t	*encrypted;
147 	size_t		encrypted_len;
148 } weptests[] = {
149 	TEST(1, "WEP test mpdu 1", WEP, 2, 0xfb, 0x02, 0x9e, 0x80),
150 };
151 
152 static void
153 dumpdata(const char *tag, const void *p, size_t len)
154 {
155 	int i;
156 
157 	printf("%s: 0x%p len %u", tag, p, len);
158 	for (i = 0; i < len; i++) {
159 		if ((i % 16) == 0)
160 			printf("\n%03d:", i);
161 		printf(" %02x", ((const u_int8_t *)p)[i]);
162 	}
163 	printf("\n");
164 }
165 
166 static void
167 cmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen)
168 {
169 	int i;
170 
171 	for (i = 0; i < genlen; i++)
172 		if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) {
173 			printf("first difference at byte %u\n", i);
174 			break;
175 		}
176 	dumpdata("Generated", gen, genlen);
177 	dumpdata("Reference", ref, reflen);
178 }
179 
180 struct wep_ctx_hw {			/* for use with h/w support */
181 	struct ieee80211com *wc_ic;	/* for diagnostics */
182 	u_int32_t	wc_iv;		/* initial vector for crypto */
183 };
184 
185 static int
186 runtest(struct ieee80211com *ic, struct ciphertest *t)
187 {
188 	struct ieee80211_key key;
189 	struct mbuf *m = NULL;
190 	const struct ieee80211_cipher *cip;
191 	u_int8_t mac[IEEE80211_ADDR_LEN];
192 	struct wep_ctx_hw *ctx;
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(ic, 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(ic, &key, mac)) {
211 		printf("FAIL: ieee80211_crypto_setkey failed\n");
212 		goto bad;
213 	}
214 	cip = key.wk_cipher;
215 
216 	/*
217 	 * Craft frame from plaintext data.
218 	 */
219 	cip = key.wk_cipher;
220 	m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR);
221 	memcpy(mtod(m, void *), t->encrypted, t->encrypted_len);
222 	m->m_len = t->encrypted_len;
223 	m->m_pkthdr.len = m->m_len;
224 
225 	/*
226 	 * Decrypt frame.
227 	 */
228 	if (!cip->ic_decap(&key, m)) {
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, sizeof(t->plaintext));
246 		goto bad;
247 	}
248 
249 	/*
250 	 * Encrypt frame.
251 	 */
252 	ctx = (struct wep_ctx_hw *) key.wk_private;
253 	memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv));	/* for encap/encrypt */
254 	if (!cip->ic_encap(&key, m, t->keyix<<6)) {
255 		printf("FAIL: wep encap failed\n");
256 		goto bad;
257 	}
258 	/*
259 	 * Verify: frame length, frame contents.
260 	 */
261 	if (m->m_pkthdr.len != t->encrypted_len) {
262 		printf("FAIL: encap data length mismatch\n");
263 		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
264 			t->encrypted, t->encrypted_len);
265 		goto bad;
266 	} else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) {
267 		printf("FAIL: encrypt data does not compare\n");
268 		cmpfail(mtod(m, const void *), m->m_pkthdr.len,
269 			t->encrypted, t->encrypted_len);
270 		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
271 		goto bad;
272 	}
273 	m_freem(m);
274 	ieee80211_crypto_delkey(ic, &key);
275 	printf("PASS\n");
276 	return 1;
277 bad:
278 	if (m != NULL)
279 		m_freem(m);
280 	ieee80211_crypto_delkey(ic, &key);
281 	return 0;
282 }
283 
284 /*
285  * Module glue.
286  */
287 
288 static	int tests = -1;
289 static	int debug = 0;
290 
291 static int
292 init_crypto_wep_test(void)
293 {
294 #define	N(a)	(sizeof(a)/sizeof(a[0]))
295 	struct ieee80211com ic;
296 	int i, pass, total;
297 
298 	memset(&ic, 0, sizeof(ic));
299 	if (debug)
300 		ic.ic_debug = IEEE80211_MSG_CRYPTO;
301 	ieee80211_crypto_attach(&ic);
302 	pass = 0;
303 	total = 0;
304 	for (i = 0; i < N(weptests); i++)
305 		if (tests & (1<<i)) {
306 			total++;
307 			pass += runtest(&ic, &weptests[i]);
308 		}
309 	printf("%u of %u 802.11i WEP test vectors passed\n", pass, total);
310 	ieee80211_crypto_detach(&ic);
311 	return (pass == total ? 0 : -1);
312 #undef N
313 }
314 
315 static int
316 test_wep_modevent(module_t mod, int type, void *unused)
317 {
318 	switch (type) {
319 	case MOD_LOAD:
320 		(void) init_crypto_wep_test();
321 		return 0;
322 	case MOD_UNLOAD:
323 		return 0;
324 	}
325 	return EINVAL;
326 }
327 
328 static moduledata_t test_wep_mod = {
329 	"test_wep",
330 	test_wep_modevent,
331 	0
332 };
333 DECLARE_MODULE(test_wep, test_wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
334 MODULE_VERSION(test_wep, 1);
335 MODULE_DEPEND(test_wep, wlan, 1, 1, 1);
336