1138578Ssam/*- 2138578Ssam * Copyright (c) 2004 Sam Leffler, Errno Consulting 3138578Ssam * All rights reserved. 4138578Ssam * 5138578Ssam * Redistribution and use in source and binary forms, with or without 6138578Ssam * modification, are permitted provided that the following conditions 7138578Ssam * are met: 8138578Ssam * 1. Redistributions of source code must retain the above copyright 9138578Ssam * notice, this list of conditions and the following disclaimer. 10138578Ssam * 2. Redistributions in binary form must reproduce the above copyright 11138578Ssam * notice, this list of conditions and the following disclaimer in the 12138578Ssam * documentation and/or other materials provided with the distribution. 13138578Ssam * 3. The name of the author may not be used to endorse or promote products 14138578Ssam * derived from this software without specific prior written permission. 15138578Ssam * 16138578Ssam * Alternatively, this software may be distributed under the terms of the 17138578Ssam * GNU General Public License ("GPL") version 2 as published by the Free 18138578Ssam * Software Foundation. 19138578Ssam * 20138578Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21138578Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22138578Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23138578Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24138578Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25138578Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26138578Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27138578Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28138578Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29138578Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30138578Ssam * 31138578Ssam * $FreeBSD$ 32138578Ssam */ 33138578Ssam 34138578Ssam/* 35138578Ssam * TKIP test module. 36138578Ssam */ 37138578Ssam#include <sys/param.h> 38138578Ssam#include <sys/kernel.h> 39138578Ssam#include <sys/systm.h> 40138578Ssam#include <sys/mbuf.h> 41138578Ssam#include <sys/module.h> 42138578Ssam 43138578Ssam#include <sys/socket.h> 44138578Ssam 45138578Ssam#include <net/if.h> 46138578Ssam#include <net/if_media.h> 47138578Ssam 48138578Ssam#include <net80211/ieee80211_var.h> 49138578Ssam 50138578Ssam/* 51138578SsamKey 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 52138578Ssam 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 34 53138578SsamPN 0x000000000001 54138578SsamIV 00 20 01 20 00 00 00 00 55138578SsamPhase1 bb 58 07 1f 9e 93 b4 38 25 4b 56138578SsamPhase2 00 20 01 4c fe 67 be d2 7c 86 7b 1b f8 02 8b 1c 57138578Ssam*/ 58138578Ssam 59138578Ssamstatic const u_int8_t test1_key[] = { 60138578Ssam 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 61138578Ssam 0x34, 0x56, 0x78, 0x90, 0x12, 62138578Ssam 63138578Ssam 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, /* TX MIC */ 64138578Ssam /* 65138578Ssam * NB: 11i test vector specifies a RX MIC key different 66138578Ssam * from the TX key. But this doesn't work to enmic, 67138578Ssam * encrypt, then decrypt, demic. So instead we use 68138578Ssam * the same key for doing the MIC in each direction. 69138578Ssam * 70138578Ssam * XXX need additional vectors to test alternate MIC keys 71138578Ssam */ 72138578Ssam#if 0 73138578Ssam 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, /* 11i RX MIC */ 74138578Ssam#else 75138578Ssam 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, /* TX copy */ 76138578Ssam#endif 77138578Ssam}; 78138578Ssamstatic const u_int8_t test1_phase1[] = { 79138578Ssam 0xbb, 0x58, 0x07, 0x1f, 0x9e, 0x93, 0xb4, 0x38, 0x25, 0x4b 80138578Ssam}; 81138578Ssamstatic const u_int8_t test1_phase2[] = { 82138578Ssam 0x00, 0x20, 0x01, 0x4c, 0xfe, 0x67, 0xbe, 0xd2, 0x7c, 0x86, 83138578Ssam 0x7b, 0x1b, 0xf8, 0x02, 0x8b, 0x1c, 84138578Ssam}; 85138578Ssam 86138578Ssam/* Plaintext MPDU with MIC */ 87138578Ssamstatic const u_int8_t test1_plaintext[] = { 88138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07, 89138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02, 90138578Ssam0xaa,0xaa,0x03,0x00,0x00,0x00,0x08,0x00,0x45,0x00,0x00,0x54,0x00,0x00,0x40,0x00, 91138578Ssam0x40,0x01,0xa5,0x55,0xc0,0xa8,0x0a,0x02,0xc0,0xa8,0x0a,0x01,0x08,0x00,0x3a,0xb0, 92138578Ssam0x00,0x00,0x00,0x00,0xcd,0x4c,0x05,0x00,0x00,0x00,0x00,0x00,0x08,0x09,0x0a,0x0b, 93138578Ssam0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b, 94138578Ssam0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b, 95138578Ssam0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 96138578Ssam/* MIC */ 0x68,0x81,0xa3,0xf3,0xd6,0x48,0xd0,0x3c 97138578Ssam}; 98138578Ssam 99138578Ssam/* Encrypted MPDU with MIC and ICV */ 100138578Ssamstatic const u_int8_t test1_encrypted[] = { 101138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07, 102138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02,0x00,0x20,0x01,0x20,0x00,0x00,0x00,0x00, 103138578Ssam0xc0,0x0e,0x14,0xfc,0xe7,0xcf,0xab,0xc7,0x75,0x47,0xe6,0x66,0xe5,0x7c,0x0d,0xac, 104138578Ssam0x70,0x4a,0x1e,0x35,0x8a,0x88,0xc1,0x1c,0x8e,0x2e,0x28,0x2e,0x38,0x01,0x02,0x7a, 105138578Ssam0x46,0x56,0x05,0x5e,0xe9,0x3e,0x9c,0x25,0x47,0x02,0xe9,0x73,0x58,0x05,0xdd,0xb5, 106138578Ssam0x76,0x9b,0xa7,0x3f,0x1e,0xbb,0x56,0xe8,0x44,0xef,0x91,0x22,0x85,0xd3,0xdd,0x6e, 107138578Ssam0x54,0x1e,0x82,0x38,0x73,0x55,0x8a,0xdb,0xa0,0x79,0x06,0x8a,0xbd,0x7f,0x7f,0x50, 108138578Ssam0x95,0x96,0x75,0xac,0xc4,0xb4,0xde,0x9a,0xa9,0x9c,0x05,0xf2,0x89,0xa7,0xc5,0x2f, 109138578Ssam0xee,0x5b,0xfc,0x14,0xf6,0xf8,0xe5,0xf8 110138578Ssam}; 111138578Ssam 112138578Ssam#define TEST(n,name,cipher,keyix,pn) { \ 113138578Ssam name, IEEE80211_CIPHER_##cipher,keyix, pn##LL, \ 114138578Ssam test##n##_key, sizeof(test##n##_key), \ 115138578Ssam test##n##_phase1, sizeof(test##n##_phase1), \ 116138578Ssam test##n##_phase2, sizeof(test##n##_phase2), \ 117138578Ssam test##n##_plaintext, sizeof(test##n##_plaintext), \ 118138578Ssam test##n##_encrypted, sizeof(test##n##_encrypted) \ 119138578Ssam} 120138578Ssam 121138578Ssamstruct ciphertest { 122138578Ssam const char *name; 123138578Ssam int cipher; 124138578Ssam int keyix; 125138578Ssam u_int64_t pn; 126138578Ssam const u_int8_t *key; 127138578Ssam size_t key_len; 128138578Ssam const u_int8_t *phase1; 129138578Ssam size_t phase1_len; 130138578Ssam const u_int8_t *phase2; 131138578Ssam size_t phase2_len; 132138578Ssam const u_int8_t *plaintext; 133138578Ssam size_t plaintext_len; 134138578Ssam const u_int8_t *encrypted; 135138578Ssam size_t encrypted_len; 136138578Ssam} tkiptests[] = { 137138578Ssam TEST(1, "TKIP test mpdu 1", TKIP, 0, 0), 138138578Ssam}; 139138578Ssam 140138578Ssamstruct tkip_ctx { 141138578Ssam struct ieee80211com *tc_ic; /* for diagnostics */ 142138578Ssam 143138578Ssam uint16_t tx_ttak[5]; 144138578Ssam int tx_phase1_done; 145138578Ssam uint8_t tx_rc4key[16]; 146138578Ssam 147138578Ssam uint16_t rx_ttak[5]; 148138578Ssam int rx_phase1_done; 149138578Ssam uint8_t rx_rc4key[16]; 150138578Ssam uint64_t rx_rsc; /* held until MIC verified */ 151138578Ssam}; 152138578Ssam 153138578Ssamstatic void 154138578Ssamdumpdata(const char *tag, const void *p, size_t len) 155138578Ssam{ 156138578Ssam int i; 157138578Ssam 158138578Ssam printf("%s: 0x%p len %u", tag, p, len); 159138578Ssam for (i = 0; i < len; i++) { 160138578Ssam if ((i % 16) == 0) 161138578Ssam printf("\n%03d:", i); 162138578Ssam printf(" %02x", ((const u_int8_t *)p)[i]); 163138578Ssam } 164138578Ssam printf("\n"); 165138578Ssam} 166138578Ssam 167138578Ssamstatic void 168138578Ssamcmpfail(const void *gen, size_t genlen, const void *ref, size_t reflen) 169138578Ssam{ 170138578Ssam int i; 171138578Ssam 172138578Ssam for (i = 0; i < genlen; i++) 173138578Ssam if (((const u_int8_t *)gen)[i] != ((const u_int8_t *)ref)[i]) { 174138578Ssam printf("first difference at byte %u\n", i); 175138578Ssam break; 176138578Ssam } 177138578Ssam dumpdata("Generated", gen, genlen); 178138578Ssam dumpdata("Reference", ref, reflen); 179138578Ssam} 180138578Ssam 181138578Ssamstatic int 182138578Ssamruntest(struct ieee80211com *ic, struct ciphertest *t) 183138578Ssam{ 184138578Ssam struct tkip_ctx *ctx; 185138578Ssam struct ieee80211_key key; 186138578Ssam struct mbuf *m = NULL; 187138578Ssam const struct ieee80211_cipher *cip; 188138578Ssam u_int8_t mac[IEEE80211_ADDR_LEN]; 189138578Ssam u_int len; 190138578Ssam 191138578Ssam printf("%s: ", t->name); 192138578Ssam 193138578Ssam /* 194138578Ssam * Setup key. 195138578Ssam */ 196138578Ssam memset(&key, 0, sizeof(key)); 197138578Ssam key.wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; 198138578Ssam key.wk_cipher = &ieee80211_cipher_none; 199145904Savatar if (!ieee80211_crypto_newkey(ic, IEEE80211_CIPHER_TKIP, 200145904Savatar IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, &key)) { 201138578Ssam printf("FAIL: ieee80211_crypto_newkey failed\n"); 202138578Ssam goto bad; 203138578Ssam } 204138578Ssam 205138578Ssam memcpy(key.wk_key, t->key, t->key_len); 206138578Ssam key.wk_keylen = 128/NBBY; 207138578Ssam key.wk_keyrsc = 0; 208138578Ssam key.wk_keytsc = t->pn; 209138578Ssam if (!ieee80211_crypto_setkey(ic, &key, mac)) { 210138578Ssam printf("FAIL: ieee80211_crypto_setkey failed\n"); 211138578Ssam goto bad; 212138578Ssam } 213138578Ssam 214138578Ssam /* 215138578Ssam * Craft frame from plaintext data. 216138578Ssam */ 217138578Ssam cip = key.wk_cipher; 218138578Ssam m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR); 219138578Ssam m->m_data += cip->ic_header; 220138578Ssam len = t->plaintext_len - IEEE80211_WEP_MICLEN; 221138578Ssam memcpy(mtod(m, void *), t->plaintext, len); 222138578Ssam m->m_len = len; 223138578Ssam m->m_pkthdr.len = m->m_len; 224138578Ssam 225138578Ssam /* 226138578Ssam * Add MIC. 227138578Ssam */ 228138578Ssam if (!ieee80211_crypto_enmic(ic, &key, m)) { 229138578Ssam printf("FAIL: tkip enmic failed\n"); 230138578Ssam goto bad; 231138578Ssam } 232138578Ssam /* 233138578Ssam * Verify: frame length, frame contents. 234138578Ssam */ 235138578Ssam if (m->m_pkthdr.len != t->plaintext_len) { 236138578Ssam printf("FAIL: enmic botch; length mismatch\n"); 237138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 238138578Ssam t->plaintext, t->plaintext_len); 239138578Ssam goto bad; 240138578Ssam } 241138578Ssam if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) { 242138578Ssam printf("FAIL: enmic botch\n"); 243138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 244138578Ssam t->plaintext, t->plaintext_len); 245138578Ssam goto bad; 246138578Ssam } 247138578Ssam /* 248138578Ssam * Encrypt frame w/ MIC. 249138578Ssam */ 250138578Ssam if (!cip->ic_encap(&key, m, t->keyix<<6)) { 251138578Ssam printf("FAIL: tkip encap failed\n"); 252138578Ssam goto bad; 253138578Ssam } 254138578Ssam /* 255138578Ssam * Verify: phase1, phase2, frame length, frame contents. 256138578Ssam */ 257138578Ssam ctx = key.wk_private; 258138578Ssam if (memcmp(ctx->tx_ttak, t->phase1, t->phase1_len)) { 259138578Ssam printf("FAIL: encrypt phase1 botch\n"); 260138578Ssam cmpfail(ctx->tx_ttak, sizeof(ctx->tx_ttak), 261138578Ssam t->phase1, t->phase1_len); 262138578Ssam goto bad; 263138578Ssam } else if (memcmp(ctx->tx_rc4key, t->phase2, t->phase2_len)) { 264138578Ssam printf("FAIL: encrypt phase2 botch\n"); 265138578Ssam cmpfail(ctx->tx_rc4key, sizeof(ctx->tx_rc4key), 266138578Ssam t->phase2, t->phase2_len); 267138578Ssam goto bad; 268138578Ssam } else if (m->m_pkthdr.len != t->encrypted_len) { 269138578Ssam printf("FAIL: encrypt data length mismatch\n"); 270138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 271138578Ssam t->encrypted, t->encrypted_len); 272138578Ssam goto bad; 273138578Ssam } else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) { 274138578Ssam printf("FAIL: encrypt data does not compare\n"); 275138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 276138578Ssam t->encrypted, t->encrypted_len); 277138578Ssam dumpdata("Plaintext", t->plaintext, t->plaintext_len); 278138578Ssam goto bad; 279138578Ssam } 280138578Ssam 281138578Ssam /* 282138578Ssam * Decrypt frame. 283138578Ssam */ 284138578Ssam if (!cip->ic_decap(&key, m)) { 285138578Ssam printf("tkip decap failed\n"); 286138578Ssam /* 287138578Ssam * Check reason for failure: phase1, phase2, frame data (ICV). 288138578Ssam */ 289138578Ssam if (memcmp(ctx->rx_ttak, t->phase1, t->phase1_len)) { 290138578Ssam printf("FAIL: decrypt phase1 botch\n"); 291138578Ssam cmpfail(ctx->rx_ttak, sizeof(ctx->rx_ttak), 292138578Ssam t->phase1, t->phase1_len); 293138578Ssam } else if (memcmp(ctx->rx_rc4key, t->phase2, t->phase2_len)) { 294138578Ssam printf("FAIL: decrypt phase2 botch\n"); 295138578Ssam cmpfail(ctx->rx_rc4key, sizeof(ctx->rx_rc4key), 296138578Ssam t->phase2, t->phase2_len); 297138578Ssam } else { 298138578Ssam printf("FAIL: decrypt data does not compare\n"); 299138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 300138578Ssam t->plaintext, t->plaintext_len); 301138578Ssam } 302138578Ssam goto bad; 303138578Ssam } 304138578Ssam /* 305138578Ssam * Verify: frame length, frame contents. 306138578Ssam */ 307138578Ssam if (m->m_pkthdr.len != t->plaintext_len) { 308138578Ssam printf("FAIL: decap botch; length mismatch\n"); 309138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 310138578Ssam t->plaintext, t->plaintext_len); 311138578Ssam goto bad; 312138578Ssam } 313138578Ssam if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) { 314138578Ssam printf("FAIL: decap botch; data does not compare\n"); 315138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 316138578Ssam t->plaintext, t->plaintext_len); 317138578Ssam goto bad; 318138578Ssam } 319138578Ssam /* 320138578Ssam * De-MIC decrypted frame. 321138578Ssam */ 322138578Ssam if (!ieee80211_crypto_demic(ic, &key, m)) { 323138578Ssam printf("FAIL: tkip demic failed\n"); 324138578Ssam goto bad; 325138578Ssam } 326138578Ssam /* XXX check frame length and contents... */ 327138578Ssam printf("PASS\n"); 328138578Ssam return 1; 329138578Ssambad: 330138578Ssam if (m != NULL) 331138578Ssam m_freem(m); 332138578Ssam ieee80211_crypto_delkey(ic, &key); 333138578Ssam return 0; 334138578Ssam} 335138578Ssam 336138578Ssam/* 337138578Ssam * Module glue. 338138578Ssam */ 339138578Ssam 340138578Ssamstatic int debug = 0; 341138578Ssamstatic int tests = -1; 342138578Ssam 343138578Ssamstatic int 344138578Ssaminit_crypto_tkip_test(void) 345138578Ssam{ 346138578Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 347138578Ssam struct ieee80211com ic; 348138578Ssam int i, pass, total; 349138578Ssam 350138578Ssam memset(&ic, 0, sizeof(ic)); 351138578Ssam if (debug) 352138578Ssam ic.ic_debug = IEEE80211_MSG_CRYPTO; 353138578Ssam ieee80211_crypto_attach(&ic); 354138578Ssam 355138578Ssam pass = 0; 356138578Ssam total = 0; 357138578Ssam for (i = 0; i < N(tkiptests); i++) 358138578Ssam if (tests & (1<<i)) { 359138578Ssam total++; 360138578Ssam pass += runtest(&ic, &tkiptests[i]); 361138578Ssam } 362138578Ssam printf("%u of %u 802.11i TKIP test vectors passed\n", pass, total); 363138578Ssam ieee80211_crypto_detach(&ic); 364138578Ssam return (pass == total ? 0 : -1); 365138578Ssam#undef N 366138578Ssam} 367138578Ssam 368138578Ssamstatic int 369138578Ssamtest_tkip_modevent(module_t mod, int type, void *unused) 370138578Ssam{ 371138578Ssam switch (type) { 372138578Ssam case MOD_LOAD: 373138578Ssam (void) init_crypto_tkip_test(); 374138578Ssam return 0; 375138578Ssam case MOD_UNLOAD: 376138578Ssam return 0; 377138578Ssam } 378138578Ssam return EINVAL; 379138578Ssam} 380138578Ssam 381138578Ssamstatic moduledata_t test_tkip_mod = { 382138578Ssam "test_tkip", 383138578Ssam test_tkip_modevent, 384241394Skevlo 0 385138578Ssam}; 386138578SsamDECLARE_MODULE(test_tkip, test_tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 387138578SsamMODULE_VERSION(test_tkip, 1); 388138578SsamMODULE_DEPEND(test_tkip, wlan, 1, 1, 1); 389