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> 46289762Savos#include <net/if_var.h> 47138578Ssam#include <net/if_media.h> 48138578Ssam 49138578Ssam#include <net80211/ieee80211_var.h> 50138578Ssam 51138578Ssam/* 52138578SsamKey 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 53138578Ssam 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 34 54138578SsamPN 0x000000000001 55138578SsamIV 00 20 01 20 00 00 00 00 56138578SsamPhase1 bb 58 07 1f 9e 93 b4 38 25 4b 57138578SsamPhase2 00 20 01 4c fe 67 be d2 7c 86 7b 1b f8 02 8b 1c 58138578Ssam*/ 59138578Ssam 60138578Ssamstatic const u_int8_t test1_key[] = { 61138578Ssam 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 62138578Ssam 0x34, 0x56, 0x78, 0x90, 0x12, 63138578Ssam 64138578Ssam 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, /* TX MIC */ 65138578Ssam /* 66138578Ssam * NB: 11i test vector specifies a RX MIC key different 67138578Ssam * from the TX key. But this doesn't work to enmic, 68138578Ssam * encrypt, then decrypt, demic. So instead we use 69138578Ssam * the same key for doing the MIC in each direction. 70138578Ssam * 71138578Ssam * XXX need additional vectors to test alternate MIC keys 72138578Ssam */ 73138578Ssam#if 0 74138578Ssam 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, /* 11i RX MIC */ 75138578Ssam#else 76138578Ssam 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, /* TX copy */ 77138578Ssam#endif 78138578Ssam}; 79138578Ssamstatic const u_int8_t test1_phase1[] = { 80138578Ssam 0xbb, 0x58, 0x07, 0x1f, 0x9e, 0x93, 0xb4, 0x38, 0x25, 0x4b 81138578Ssam}; 82138578Ssamstatic const u_int8_t test1_phase2[] = { 83138578Ssam 0x00, 0x20, 0x01, 0x4c, 0xfe, 0x67, 0xbe, 0xd2, 0x7c, 0x86, 84138578Ssam 0x7b, 0x1b, 0xf8, 0x02, 0x8b, 0x1c, 85138578Ssam}; 86138578Ssam 87138578Ssam/* Plaintext MPDU with MIC */ 88138578Ssamstatic const u_int8_t test1_plaintext[] = { 89138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07, 90138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02, 91138578Ssam0xaa,0xaa,0x03,0x00,0x00,0x00,0x08,0x00,0x45,0x00,0x00,0x54,0x00,0x00,0x40,0x00, 92138578Ssam0x40,0x01,0xa5,0x55,0xc0,0xa8,0x0a,0x02,0xc0,0xa8,0x0a,0x01,0x08,0x00,0x3a,0xb0, 93138578Ssam0x00,0x00,0x00,0x00,0xcd,0x4c,0x05,0x00,0x00,0x00,0x00,0x00,0x08,0x09,0x0a,0x0b, 94138578Ssam0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b, 95138578Ssam0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b, 96138578Ssam0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 97138578Ssam/* MIC */ 0x68,0x81,0xa3,0xf3,0xd6,0x48,0xd0,0x3c 98138578Ssam}; 99138578Ssam 100138578Ssam/* Encrypted MPDU with MIC and ICV */ 101138578Ssamstatic const u_int8_t test1_encrypted[] = { 102138578Ssam0x08,0x42,0x2c,0x00,0x02,0x03,0x04,0x05,0x06,0x08,0x02,0x03,0x04,0x05,0x06,0x07, 103138578Ssam0x02,0x03,0x04,0x05,0x06,0x07,0xd0,0x02,0x00,0x20,0x01,0x20,0x00,0x00,0x00,0x00, 104138578Ssam0xc0,0x0e,0x14,0xfc,0xe7,0xcf,0xab,0xc7,0x75,0x47,0xe6,0x66,0xe5,0x7c,0x0d,0xac, 105138578Ssam0x70,0x4a,0x1e,0x35,0x8a,0x88,0xc1,0x1c,0x8e,0x2e,0x28,0x2e,0x38,0x01,0x02,0x7a, 106138578Ssam0x46,0x56,0x05,0x5e,0xe9,0x3e,0x9c,0x25,0x47,0x02,0xe9,0x73,0x58,0x05,0xdd,0xb5, 107138578Ssam0x76,0x9b,0xa7,0x3f,0x1e,0xbb,0x56,0xe8,0x44,0xef,0x91,0x22,0x85,0xd3,0xdd,0x6e, 108138578Ssam0x54,0x1e,0x82,0x38,0x73,0x55,0x8a,0xdb,0xa0,0x79,0x06,0x8a,0xbd,0x7f,0x7f,0x50, 109138578Ssam0x95,0x96,0x75,0xac,0xc4,0xb4,0xde,0x9a,0xa9,0x9c,0x05,0xf2,0x89,0xa7,0xc5,0x2f, 110138578Ssam0xee,0x5b,0xfc,0x14,0xf6,0xf8,0xe5,0xf8 111138578Ssam}; 112138578Ssam 113138578Ssam#define TEST(n,name,cipher,keyix,pn) { \ 114138578Ssam name, IEEE80211_CIPHER_##cipher,keyix, pn##LL, \ 115138578Ssam test##n##_key, sizeof(test##n##_key), \ 116138578Ssam test##n##_phase1, sizeof(test##n##_phase1), \ 117138578Ssam test##n##_phase2, sizeof(test##n##_phase2), \ 118138578Ssam test##n##_plaintext, sizeof(test##n##_plaintext), \ 119138578Ssam test##n##_encrypted, sizeof(test##n##_encrypted) \ 120138578Ssam} 121138578Ssam 122138578Ssamstruct ciphertest { 123138578Ssam const char *name; 124138578Ssam int cipher; 125138578Ssam int keyix; 126138578Ssam u_int64_t pn; 127138578Ssam const u_int8_t *key; 128138578Ssam size_t key_len; 129138578Ssam const u_int8_t *phase1; 130138578Ssam size_t phase1_len; 131138578Ssam const u_int8_t *phase2; 132138578Ssam size_t phase2_len; 133138578Ssam const u_int8_t *plaintext; 134138578Ssam size_t plaintext_len; 135138578Ssam const u_int8_t *encrypted; 136138578Ssam size_t encrypted_len; 137138578Ssam} tkiptests[] = { 138138578Ssam TEST(1, "TKIP test mpdu 1", TKIP, 0, 0), 139138578Ssam}; 140138578Ssam 141138578Ssamstruct tkip_ctx { 142138578Ssam struct ieee80211com *tc_ic; /* for diagnostics */ 143138578Ssam 144138578Ssam uint16_t tx_ttak[5]; 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 182289762Savosruntest(struct ieee80211vap *vap, struct ciphertest *t) 183138578Ssam{ 184138578Ssam struct tkip_ctx *ctx; 185289762Savos struct ieee80211_key *key = &vap->iv_nw_keys[t->keyix]; 186138578Ssam struct mbuf *m = NULL; 187138578Ssam const struct ieee80211_cipher *cip; 188138578Ssam u_int len; 189289762Savos int hdrlen; 190138578Ssam 191138578Ssam printf("%s: ", t->name); 192138578Ssam 193138578Ssam /* 194138578Ssam * Setup key. 195138578Ssam */ 196289762Savos memset(key, 0, sizeof(*key)); 197289762Savos key->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; 198289762Savos key->wk_cipher = &ieee80211_cipher_none; 199289762Savos if (!ieee80211_crypto_newkey(vap, t->cipher, 200289762Savos IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key)) { 201138578Ssam printf("FAIL: ieee80211_crypto_newkey failed\n"); 202138578Ssam goto bad; 203138578Ssam } 204138578Ssam 205289762Savos memcpy(key->wk_key, t->key, t->key_len); 206289762Savos key->wk_keylen = 128/NBBY; 207289762Savos memset(key->wk_keyrsc, 0, sizeof(key->wk_keyrsc)); 208289762Savos key->wk_keytsc = t->pn; 209289762Savos if (!ieee80211_crypto_setkey(vap, key)) { 210138578Ssam printf("FAIL: ieee80211_crypto_setkey failed\n"); 211138578Ssam goto bad; 212138578Ssam } 213138578Ssam 214138578Ssam /* 215138578Ssam * Craft frame from plaintext data. 216138578Ssam */ 217289762Savos 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; 224289762Savos hdrlen = ieee80211_anyhdrsize(mtod(m, void *)); 225138578Ssam 226138578Ssam /* 227138578Ssam * Add MIC. 228138578Ssam */ 229289762Savos if (!ieee80211_crypto_enmic(vap, key, m, 1)) { 230138578Ssam printf("FAIL: tkip enmic failed\n"); 231138578Ssam goto bad; 232138578Ssam } 233138578Ssam /* 234138578Ssam * Verify: frame length, frame contents. 235138578Ssam */ 236138578Ssam if (m->m_pkthdr.len != t->plaintext_len) { 237138578Ssam printf("FAIL: enmic botch; length mismatch\n"); 238138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 239138578Ssam t->plaintext, t->plaintext_len); 240138578Ssam goto bad; 241138578Ssam } 242138578Ssam if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) { 243138578Ssam printf("FAIL: enmic botch\n"); 244138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 245138578Ssam t->plaintext, t->plaintext_len); 246138578Ssam goto bad; 247138578Ssam } 248138578Ssam /* 249138578Ssam * Encrypt frame w/ MIC. 250138578Ssam */ 251289762Savos if (!cip->ic_encap(key, m)) { 252138578Ssam printf("FAIL: tkip encap failed\n"); 253138578Ssam goto bad; 254138578Ssam } 255138578Ssam /* 256138578Ssam * Verify: phase1, phase2, frame length, frame contents. 257138578Ssam */ 258289762Savos ctx = key->wk_private; 259138578Ssam if (memcmp(ctx->tx_ttak, t->phase1, t->phase1_len)) { 260138578Ssam printf("FAIL: encrypt phase1 botch\n"); 261138578Ssam cmpfail(ctx->tx_ttak, sizeof(ctx->tx_ttak), 262138578Ssam t->phase1, t->phase1_len); 263138578Ssam goto bad; 264138578Ssam } else if (memcmp(ctx->tx_rc4key, t->phase2, t->phase2_len)) { 265138578Ssam printf("FAIL: encrypt phase2 botch\n"); 266138578Ssam cmpfail(ctx->tx_rc4key, sizeof(ctx->tx_rc4key), 267138578Ssam t->phase2, t->phase2_len); 268138578Ssam goto bad; 269138578Ssam } else if (m->m_pkthdr.len != t->encrypted_len) { 270138578Ssam printf("FAIL: encrypt data length mismatch\n"); 271138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 272138578Ssam t->encrypted, t->encrypted_len); 273138578Ssam goto bad; 274138578Ssam } else if (memcmp(mtod(m, const void *), t->encrypted, m->m_pkthdr.len)) { 275138578Ssam printf("FAIL: encrypt data does not compare\n"); 276138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 277138578Ssam t->encrypted, t->encrypted_len); 278138578Ssam dumpdata("Plaintext", t->plaintext, t->plaintext_len); 279138578Ssam goto bad; 280138578Ssam } 281138578Ssam 282138578Ssam /* 283138578Ssam * Decrypt frame. 284138578Ssam */ 285289762Savos if (!cip->ic_decap(key, m, hdrlen)) { 286138578Ssam printf("tkip decap failed\n"); 287138578Ssam /* 288138578Ssam * Check reason for failure: phase1, phase2, frame data (ICV). 289138578Ssam */ 290138578Ssam if (memcmp(ctx->rx_ttak, t->phase1, t->phase1_len)) { 291138578Ssam printf("FAIL: decrypt phase1 botch\n"); 292138578Ssam cmpfail(ctx->rx_ttak, sizeof(ctx->rx_ttak), 293138578Ssam t->phase1, t->phase1_len); 294138578Ssam } else if (memcmp(ctx->rx_rc4key, t->phase2, t->phase2_len)) { 295138578Ssam printf("FAIL: decrypt phase2 botch\n"); 296138578Ssam cmpfail(ctx->rx_rc4key, sizeof(ctx->rx_rc4key), 297138578Ssam t->phase2, t->phase2_len); 298138578Ssam } else { 299138578Ssam printf("FAIL: decrypt data does not compare\n"); 300138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 301138578Ssam t->plaintext, t->plaintext_len); 302138578Ssam } 303138578Ssam goto bad; 304138578Ssam } 305138578Ssam /* 306138578Ssam * Verify: frame length, frame contents. 307138578Ssam */ 308138578Ssam if (m->m_pkthdr.len != t->plaintext_len) { 309138578Ssam printf("FAIL: decap botch; length mismatch\n"); 310138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 311138578Ssam t->plaintext, t->plaintext_len); 312138578Ssam goto bad; 313138578Ssam } 314138578Ssam if (memcmp(mtod(m, const void *), t->plaintext, t->plaintext_len)) { 315138578Ssam printf("FAIL: decap botch; data does not compare\n"); 316138578Ssam cmpfail(mtod(m, const void *), m->m_pkthdr.len, 317138578Ssam t->plaintext, t->plaintext_len); 318138578Ssam goto bad; 319138578Ssam } 320138578Ssam /* 321138578Ssam * De-MIC decrypted frame. 322138578Ssam */ 323289762Savos if (!ieee80211_crypto_demic(vap, key, m, 1)) { 324138578Ssam printf("FAIL: tkip demic failed\n"); 325138578Ssam goto bad; 326138578Ssam } 327138578Ssam /* XXX check frame length and contents... */ 328289762Savos m_freem(m); 329289762Savos ieee80211_crypto_delkey(vap, key); 330138578Ssam printf("PASS\n"); 331138578Ssam return 1; 332138578Ssambad: 333138578Ssam if (m != NULL) 334138578Ssam m_freem(m); 335289762Savos ieee80211_crypto_delkey(vap, key); 336138578Ssam return 0; 337138578Ssam} 338138578Ssam 339138578Ssam/* 340138578Ssam * Module glue. 341138578Ssam */ 342138578Ssam 343138578Ssamstatic int debug = 0; 344138578Ssamstatic int tests = -1; 345138578Ssam 346138578Ssamstatic int 347138578Ssaminit_crypto_tkip_test(void) 348138578Ssam{ 349138578Ssam struct ieee80211com ic; 350289762Savos struct ieee80211vap vap; 351289762Savos struct ifnet ifp; 352138578Ssam int i, pass, total; 353138578Ssam 354138578Ssam memset(&ic, 0, sizeof(ic)); 355289762Savos memset(&vap, 0, sizeof(vap)); 356289762Savos memset(&ifp, 0, sizeof(ifp)); 357289762Savos 358138578Ssam ieee80211_crypto_attach(&ic); 359138578Ssam 360289762Savos /* some minimal initialization */ 361289762Savos strncpy(ifp.if_xname, "test_ccmp", sizeof(ifp.if_xname)); 362289762Savos vap.iv_ic = ⁣ 363289762Savos vap.iv_ifp = &ifp; 364289762Savos if (debug) 365289762Savos vap.iv_debug = IEEE80211_MSG_CRYPTO; 366289762Savos ieee80211_crypto_vattach(&vap); 367289762Savos 368138578Ssam pass = 0; 369138578Ssam total = 0; 370289762Savos for (i = 0; i < nitems(tkiptests); i++) 371138578Ssam if (tests & (1<<i)) { 372138578Ssam total++; 373289762Savos pass += runtest(&vap, &tkiptests[i]); 374138578Ssam } 375138578Ssam printf("%u of %u 802.11i TKIP test vectors passed\n", pass, total); 376289762Savos 377289762Savos ieee80211_crypto_vdetach(&vap); 378138578Ssam ieee80211_crypto_detach(&ic); 379289762Savos 380138578Ssam return (pass == total ? 0 : -1); 381138578Ssam} 382138578Ssam 383138578Ssamstatic int 384138578Ssamtest_tkip_modevent(module_t mod, int type, void *unused) 385138578Ssam{ 386138578Ssam switch (type) { 387138578Ssam case MOD_LOAD: 388138578Ssam (void) init_crypto_tkip_test(); 389138578Ssam return 0; 390138578Ssam case MOD_UNLOAD: 391138578Ssam return 0; 392138578Ssam } 393138578Ssam return EINVAL; 394138578Ssam} 395138578Ssam 396138578Ssamstatic moduledata_t test_tkip_mod = { 397138578Ssam "test_tkip", 398138578Ssam test_tkip_modevent, 399241394Skevlo 0 400138578Ssam}; 401138578SsamDECLARE_MODULE(test_tkip, test_tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 402138578SsamMODULE_VERSION(test_tkip, 1); 403138578SsamMODULE_DEPEND(test_tkip, wlan, 1, 1, 1); 404