1219019Sgabor/*- 2219019Sgabor * Copyright (c) 2004 Sam Leffler, Errno Consulting 3219019Sgabor * All rights reserved. 4219019Sgabor * 5219019Sgabor * Redistribution and use in source and binary forms, with or without 6219019Sgabor * modification, are permitted provided that the following conditions 7219019Sgabor * are met: 8219019Sgabor * 1. Redistributions of source code must retain the above copyright 9219019Sgabor * notice, this list of conditions and the following disclaimer. 10219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 11219019Sgabor * notice, this list of conditions and the following disclaimer in the 12219019Sgabor * documentation and/or other materials provided with the distribution. 13219019Sgabor * 3. The name of the author may not be used to endorse or promote products 14219019Sgabor * derived from this software without specific prior written permission. 15219019Sgabor * 16219019Sgabor * Alternatively, this software may be distributed under the terms of the 17219019Sgabor * GNU General Public License ("GPL") version 2 as published by the Free 18219019Sgabor * Software Foundation. 19219019Sgabor * 20219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21219019Sgabor * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22219019Sgabor * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23219019Sgabor * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24219019Sgabor * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25219019Sgabor * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26219019Sgabor * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27219019Sgabor * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28219019Sgabor * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29219019Sgabor * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30219019Sgabor * 31219019Sgabor * $FreeBSD$ 32219019Sgabor */ 33219019Sgabor 34219019Sgabor/* 35219019Sgabor * WEP test module. 36219019Sgabor * 37219019Sgabor * Test vectors come from section I.7.2 of P802.11i/D7.0, October 2003. 38219019Sgabor * 39219019Sgabor * To use this tester load the net80211 layer (either as a module or 40219019Sgabor * by statically configuring it into your kernel), then insmod this 41219019Sgabor * module. It should automatically run all test cases and print 42219019Sgabor * information for each. To run one or more tests you can specify a 43219019Sgabor * tests parameter to the module that is a bit mask of the set of tests 44219019Sgabor * you want; e.g. insmod wep_test tests=7 will run only test mpdu's 45219019Sgabor * 1, 2, and 3. 46219019Sgabor */ 47219019Sgabor#include <sys/param.h> 48219019Sgabor#include <sys/kernel.h> 49219019Sgabor#include <sys/systm.h> 50219019Sgabor#include <sys/mbuf.h> 51219019Sgabor#include <sys/module.h> 52219019Sgabor 53219019Sgabor#include <sys/socket.h> 54219019Sgabor 55219019Sgabor#include <net/if.h> 56219019Sgabor#include <net/if_media.h> 57219019Sgabor 58219019Sgabor#include <net80211/ieee80211_var.h> 59219019Sgabor 60219019Sgabor/* 61219019SgaborMPDU data 62219019Sgabor aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 22 63219019Sgabor 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 00 00 64219019Sgabor 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 43 41 43 65283908Stijl 41 43 41 43 41 43 41 41 41 00 00 20 00 01 66219019Sgabor 67219019SgaborRC4 encryption is performed as follows: 68219019Sgabor17 69219019Sgabor18 Key fb 02 9e 30 31 32 33 34 70219019SgaborPlaintext 71219019Sgabor aa aa 03 00 00 00 08 00 45 00 00 4e 66 1a 00 00 80 11 be 64 0a 00 01 72219019Sgabor 22 0a ff ff ff 00 89 00 89 00 3a 00 00 80 a6 01 10 00 01 00 00 00 00 73219019Sgabor 00 00 20 45 43 45 4a 45 48 45 43 46 43 45 50 46 45 45 49 45 46 46 43 74219019Sgabor 43 41 43 41 43 41 43 41 43 41 41 41 00 00 20 00 01 1b d0 b6 04 75219019SgaborCiphertext 76219019Sgabor f6 9c 58 06 bd 6c e8 46 26 bc be fb 94 74 65 0a ad 1f 79 09 b0 f6 4d 77219019Sgabor 5f 58 a5 03 a2 58 b7 ed 22 eb 0e a6 49 30 d3 a0 56 a5 57 42 fc ce 14 78219019Sgabor 1d 48 5f 8a a8 36 de a1 8d f4 2c 53 80 80 5a d0 c6 1a 5d 6f 58 f4 10 79219019Sgabor 40 b2 4b 7d 1a 69 38 56 ed 0d 43 98 e7 ae e3 bf 0e 2a 2c a8 f7 80219019SgaborThe plaintext consists of the MPDU data, followed by a 4-octet CRC-32 81219019Sgaborcalculated over the MPDU data. 82219019Sgabor19 The expanded MPDU, after WEP encapsulation, is as follows: 83219019Sgabor20 84219019Sgabor21 IV fb 02 9e 80 85219019SgaborMPDU data 86219019Sgabor 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 87219019Sgabor 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 88219019Sgabor 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 89260264Sdim 0d 43 98 e7 ae e3 bf 0e 90219019SgaborICV 2a 2c a8 f7 91219019Sgabor*/ 92219019Sgaborstatic const u_int8_t test1_key[] = { /* TK (w/o IV) */ 93219019Sgabor 0x30, 0x31, 0x32, 0x33, 0x34, 94219019Sgabor}; 95219019Sgaborstatic const u_int8_t test1_plaintext[] = { /* Plaintext MPDU */ 96219019Sgabor 0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28, /* 802.11 Header */ 97219019Sgabor 0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, 98219019Sgabor 0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33, 99219019Sgabor 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, /* Plaintext data */ 100219019Sgabor 0x45, 0x00, 0x00, 0x4e, 0x66, 0x1a, 0x00, 0x00, 101219019Sgabor 0x80, 0x11, 0xbe, 0x64, 0x0a, 0x00, 0x01, 0x22, 102219019Sgabor 0x0a, 0xff, 0xff, 0xff, 0x00, 0x89, 0x00, 0x89, 103219019Sgabor 0x00, 0x3a, 0x00, 0x00, 0x80, 0xa6, 0x01, 0x10, 104219019Sgabor 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105219019Sgabor 0x20, 0x45, 0x43, 0x45, 0x4a, 0x45, 0x48, 0x45, 106219019Sgabor 0x43, 0x46, 0x43, 0x45, 0x50, 0x46, 0x45, 0x45, 107260264Sdim 0x49, 0x45, 0x46, 0x46, 0x43, 0x43, 0x41, 0x43, 108219019Sgabor 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x41, 109219019Sgabor 0x41, 0x00, 0x00, 0x20, 0x00, 0x01, 110219019Sgabor}; 111219019Sgaborstatic const u_int8_t test1_encrypted[] = { /* Encrypted MPDU */ 112219019Sgabor 0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28, 113219019Sgabor 0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, 114219019Sgabor 0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33, 115219019Sgabor 0xfb, 0x02, 0x9e, 0x80, 0xf6, 0x9c, 0x58, 0x06, 116219019Sgabor 0xbd, 0x6c, 0xe8, 0x46, 0x26, 0xbc, 0xbe, 0xfb, 117258496Stijl 0x94, 0x74, 0x65, 0x0a, 0xad, 0x1f, 0x79, 0x09, 118219019Sgabor 0xb0, 0xf6, 0x4d, 0x5f, 0x58, 0xa5, 0x03, 0xa2, 119258496Stijl 0x58, 0xb7, 0xed, 0x22, 0xeb, 0x0e, 0xa6, 0x49, 120219019Sgabor 0x30, 0xd3, 0xa0, 0x56, 0xa5, 0x57, 0x42, 0xfc, 121219019Sgabor 0xce, 0x14, 0x1d, 0x48, 0x5f, 0x8a, 0xa8, 0x36, 122219019Sgabor 0xde, 0xa1, 0x8d, 0xf4, 0x2c, 0x53, 0x80, 0x80, 123219019Sgabor 0x5a, 0xd0, 0xc6, 0x1a, 0x5d, 0x6f, 0x58, 0xf4, 124219019Sgabor 0x10, 0x40, 0xb2, 0x4b, 0x7d, 0x1a, 0x69, 0x38, 125219019Sgabor 0x56, 0xed, 0x0d, 0x43, 0x98, 0xe7, 0xae, 0xe3, 126219019Sgabor 0xbf, 0x0e, 0x2a, 0x2c, 0xa8, 0xf7, 127219019Sgabor}; 128219019Sgabor 129219019Sgabor/* XXX fix byte order of iv */ 130219019Sgabor#define TEST(n,name,cipher,keyix,iv0,iv1,iv2,iv3) { \ 131219019Sgabor name, IEEE80211_CIPHER_##cipher,keyix, { iv2,iv1,iv0,iv3 }, \ 132219019Sgabor test##n##_key, sizeof(test##n##_key), \ 133219019Sgabor test##n##_plaintext, sizeof(test##n##_plaintext), \ 134219019Sgabor test##n##_encrypted, sizeof(test##n##_encrypted) \ 135219019Sgabor} 136219019Sgabor 137219019Sgaborstruct ciphertest { 138219019Sgabor const char *name; 139219019Sgabor int cipher; 140219019Sgabor int keyix; 141219019Sgabor u_int8_t iv[4]; 142219019Sgabor const u_int8_t *key; 143219019Sgabor size_t key_len; 144219019Sgabor const u_int8_t *plaintext; 145219019Sgabor size_t plaintext_len; 146219019Sgabor const u_int8_t *encrypted; 147219019Sgabor size_t encrypted_len; 148219019Sgabor} weptests[] = { 149219019Sgabor TEST(1, "WEP test mpdu 1", WEP, 2, 0xfb, 0x02, 0x9e, 0x80), 150219019Sgabor}; 151219019Sgabor 152219019Sgaborstatic void 153282275Stijldumpdata(const char *tag, const void *p, size_t len) 154219019Sgabor{ 155219019Sgabor int i; 156282275Stijl 157219019Sgabor printf("%s: 0x%p len %u", tag, p, len); 158219019Sgabor for (i = 0; i < len; i++) { 159283908Stijl if ((i % 16) == 0) 160219019Sgabor printf("\n%03d:", i); 161219019Sgabor printf(" %02x", ((const u_int8_t *)p)[i]); 162219019Sgabor } 163219019Sgabor printf("\n"); 164219019Sgabor} 165219019Sgabor 166219019Sgaborstatic void 167219019Sgaborcmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen) 168219019Sgabor{ 169219019Sgabor int i; 170219019Sgabor 171219019Sgabor for (i = 0; i < genlen; i++) 172219019Sgabor if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) { 173219019Sgabor printf("first difference at byte %u\n", i); 174219019Sgabor break; 175219019Sgabor } 176219019Sgabor dumpdata("Generated", gen, genlen); 177219019Sgabor dumpdata("Reference", ref, reflen); 178219019Sgabor} 179219019Sgabor 180219019Sgaborstruct wep_ctx_hw { /* for use with h/w support */ 181219019Sgabor struct ieee80211com *wc_ic; /* for diagnostics */ 182219019Sgabor u_int32_t wc_iv; /* initial vector for crypto */ 183219019Sgabor}; 184219019Sgabor 185219019Sgaborstatic int 186219019Sgaborruntest(struct ieee80211com *ic, struct ciphertest *t) 187219019Sgabor{ 188219019Sgabor struct ieee80211_key key; 189219019Sgabor struct mbuf *m = NULL; 190219019Sgabor const struct ieee80211_cipher *cip; 191219019Sgabor u_int8_t mac[IEEE80211_ADDR_LEN]; 192219019Sgabor struct wep_ctx_hw *ctx; 193219019Sgabor 194219019Sgabor printf("%s: ", t->name); 195219019Sgabor 196219019Sgabor /* 197219019Sgabor * Setup key. 198219019Sgabor */ 199219019Sgabor memset(&key, 0, sizeof(key)); 200219019Sgabor key.wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; 201219019Sgabor key.wk_cipher = &ieee80211_cipher_none; 202219019Sgabor if (!ieee80211_crypto_newkey(ic, t->cipher, 203258496Stijl IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, &key)) { 204258496Stijl printf("FAIL: ieee80211_crypto_newkey failed\n"); 205258496Stijl goto bad; 206219019Sgabor } 207219019Sgabor 208219019Sgabor memcpy(key.wk_key, t->key, t->key_len); 209219019Sgabor key.wk_keylen = t->key_len; 210219019Sgabor if (!ieee80211_crypto_setkey(ic, &key, mac)) { 211219019Sgabor printf("FAIL: ieee80211_crypto_setkey failed\n"); 212219019Sgabor goto bad; 213219019Sgabor } 214219019Sgabor cip = key.wk_cipher; 215219019Sgabor 216219019Sgabor /* 217219019Sgabor * Craft frame from plaintext data. 218219019Sgabor */ 219219019Sgabor cip = key.wk_cipher; 220219019Sgabor m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR); 221219019Sgabor memcpy(mtod(m, void *), t->encrypted, t->encrypted_len); 222219019Sgabor m->m_len = t->encrypted_len; 223219019Sgabor m->m_pkthdr.len = m->m_len; 224219019Sgabor 225219019Sgabor /* 226219019Sgabor * Decrypt frame. 227219019Sgabor */ 228219019Sgabor if (!cip->ic_decap(&key, m)) { 229219019Sgabor printf("FAIL: wep decap failed\n"); 230219019Sgabor cmpfail(mtod(m, const void *), m->m_pkthdr.len, 231219019Sgabor t->plaintext, t->plaintext_len); 232219019Sgabor goto bad; 233219019Sgabor } 234219019Sgabor /* 235219019Sgabor * Verify: frame length, frame contents. 236219019Sgabor */ 237219019Sgabor if (m->m_pkthdr.len != t->plaintext_len) { 238219019Sgabor printf("FAIL: decap botch; length mismatch\n"); 239219019Sgabor cmpfail(mtod(m, const void *), m->m_pkthdr.len, 240219019Sgabor t->plaintext, t->plaintext_len); 241219019Sgabor goto bad; 242282275Stijl } else if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) { 243219019Sgabor printf("FAIL: decap botch; data does not compare\n"); 244219019Sgabor cmpfail(mtod(m, const void *), m->m_pkthdr.len, 245219019Sgabor t->plaintext, t->plaintext_len); 246219019Sgabor goto bad; 247219019Sgabor } 248219019Sgabor 249219019Sgabor /* 250219019Sgabor * Encrypt frame. 251219019Sgabor */ 252219019Sgabor ctx = (struct wep_ctx_hw *) key.wk_private; 253219019Sgabor memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv)); /* for encap/encrypt */ 254219019Sgabor if (!cip->ic_encap(&key, m, t->keyix<<6)) { 255283908Stijl printf("FAIL: wep encap failed\n"); 256283908Stijl goto bad; 257283908Stijl } 258283908Stijl /* 259219019Sgabor * Verify: frame length, frame contents. 260283908Stijl */ 261283908Stijl if (m->m_pkthdr.len != t->encrypted_len) { 262283908Stijl printf("FAIL: encap data length mismatch\n"); 263283908Stijl cmpfail(mtod(m, const void *), m->m_pkthdr.len, 264283908Stijl t->encrypted, t->encrypted_len); 265283908Stijl goto bad; 266283908Stijl } else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) { 267283908Stijl printf("FAIL: encrypt data does not compare\n"); 268258496Stijl cmpfail(mtod(m, const void *), m->m_pkthdr.len, 269219019Sgabor t->encrypted, t->encrypted_len); 270283908Stijl dumpdata("Plaintext", t->plaintext, t->plaintext_len); 271219019Sgabor goto bad; 272219019Sgabor } 273219019Sgabor m_freem(m); 274219019Sgabor ieee80211_crypto_delkey(ic, &key); 275219019Sgabor printf("PASS\n"); 276283908Stijl return 1; 277283908Stijlbad: 278283908Stijl if (m != NULL) 279283908Stijl m_freem(m); 280219019Sgabor ieee80211_crypto_delkey(ic, &key); 281219019Sgabor return 0; 282219019Sgabor} 283219019Sgabor 284219019Sgabor/* 285219019Sgabor * Module glue. 286219019Sgabor */ 287219019Sgabor 288219019Sgaborstatic int tests = -1; 289219019Sgaborstatic int debug = 0; 290219019Sgabor 291219019Sgaborstatic int 292219019Sgaborinit_crypto_wep_test(void) 293219019Sgabor{ 294219019Sgabor#define N(a) (sizeof(a)/sizeof(a[0])) 295219019Sgabor struct ieee80211com ic; 296219019Sgabor int i, pass, total; 297219019Sgabor 298219019Sgabor memset(&ic, 0, sizeof(ic)); 299219019Sgabor if (debug) 300219019Sgabor ic.ic_debug = IEEE80211_MSG_CRYPTO; 301219019Sgabor ieee80211_crypto_attach(&ic); 302219019Sgabor pass = 0; 303219019Sgabor total = 0; 304219019Sgabor for (i = 0; i < N(weptests); i++) 305219019Sgabor if (tests & (1<<i)) { 306219019Sgabor total++; 307219019Sgabor pass += runtest(&ic, &weptests[i]); 308219019Sgabor } 309219019Sgabor printf("%u of %u 802.11i WEP test vectors passed\n", pass, total); 310219019Sgabor ieee80211_crypto_detach(&ic); 311219019Sgabor return (pass == total ? 0 : -1); 312219019Sgabor#undef N 313219019Sgabor} 314219019Sgabor 315219019Sgaborstatic int 316219019Sgabortest_wep_modevent(module_t mod, int type, void *unused) 317219019Sgabor{ 318219019Sgabor switch (type) { 319219019Sgabor case MOD_LOAD: 320219019Sgabor (void) init_crypto_wep_test(); 321219019Sgabor return 0; 322219019Sgabor case MOD_UNLOAD: 323219019Sgabor return 0; 324219019Sgabor } 325219019Sgabor return EINVAL; 326219019Sgabor} 327219019Sgabor 328219019Sgaborstatic moduledata_t test_wep_mod = { 329219019Sgabor "test_wep", 330219019Sgabor test_wep_modevent, 331219019Sgabor 0 332219019Sgabor}; 333219019SgaborDECLARE_MODULE(test_wep, test_wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 334219019SgaborMODULE_VERSION(test_wep, 1); 335219019SgaborMODULE_DEPEND(test_wep, wlan, 1, 1, 1); 336219019Sgabor