|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2009 Joshua Oreman <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <ipxe/net80211.h> ! 22: #include <ipxe/crypto.h> ! 23: #include <ipxe/hmac.h> ! 24: #include <ipxe/sha1.h> ! 25: #include <ipxe/aes.h> ! 26: #include <ipxe/wpa.h> ! 27: #include <byteswap.h> ! 28: #include <errno.h> ! 29: ! 30: /** @file ! 31: * ! 32: * Backend for WPA using the CCMP encryption method ! 33: */ ! 34: ! 35: /** Context for CCMP encryption and decryption */ ! 36: struct ccmp_ctx ! 37: { ! 38: /** AES context - only ever used for encryption */ ! 39: u8 aes_ctx[AES_CTX_SIZE]; ! 40: ! 41: /** Most recently sent packet number */ ! 42: u64 tx_seq; ! 43: ! 44: /** Most recently received packet number */ ! 45: u64 rx_seq; ! 46: }; ! 47: ! 48: /** Header structure at the beginning of CCMP frame data */ ! 49: struct ccmp_head ! 50: { ! 51: u8 pn_lo[2]; /**< Bytes 0 and 1 of packet number */ ! 52: u8 _rsvd; /**< Reserved byte */ ! 53: u8 kid; /**< Key ID and ExtIV byte */ ! 54: u8 pn_hi[4]; /**< Bytes 2-5 (2 first) of packet number */ ! 55: } __attribute__ (( packed )); ! 56: ! 57: ! 58: /** CCMP header overhead */ ! 59: #define CCMP_HEAD_LEN 8 ! 60: ! 61: /** CCMP MIC trailer overhead */ ! 62: #define CCMP_MIC_LEN 8 ! 63: ! 64: /** CCMP nonce length */ ! 65: #define CCMP_NONCE_LEN 13 ! 66: ! 67: /** CCMP nonce structure */ ! 68: struct ccmp_nonce ! 69: { ! 70: u8 prio; /**< Packet priority, 0 for non-QoS */ ! 71: u8 a2[ETH_ALEN]; /**< Address 2 from packet header (sender) */ ! 72: u8 pn[6]; /**< Packet number */ ! 73: } __attribute__ (( packed )); ! 74: ! 75: /** CCMP additional authentication data length (for non-QoS, non-WDS frames) */ ! 76: #define CCMP_AAD_LEN 22 ! 77: ! 78: /** CCMP additional authentication data structure */ ! 79: struct ccmp_aad ! 80: { ! 81: u16 fc; /**< Frame Control field */ ! 82: u8 a1[6]; /**< Address 1 */ ! 83: u8 a2[6]; /**< Address 2 */ ! 84: u8 a3[6]; /**< Address 3 */ ! 85: u16 seq; /**< Sequence Control field */ ! 86: /* Address 4 and QoS Control are included if present */ ! 87: } __attribute__ (( packed )); ! 88: ! 89: /** Mask for Frame Control field in AAD */ ! 90: #define CCMP_AAD_FC_MASK 0xC38F ! 91: ! 92: /** Mask for Sequence Control field in AAD */ ! 93: #define CCMP_AAD_SEQ_MASK 0x000F ! 94: ! 95: ! 96: /** ! 97: * Convert 6-byte LSB packet number to 64-bit integer ! 98: * ! 99: * @v pn Pointer to 6-byte packet number ! 100: * @ret v 64-bit integer value of @a pn ! 101: */ ! 102: static u64 pn_to_u64 ( const u8 *pn ) ! 103: { ! 104: int i; ! 105: u64 ret = 0; ! 106: ! 107: for ( i = 5; i >= 0; i-- ) { ! 108: ret <<= 8; ! 109: ret |= pn[i]; ! 110: } ! 111: ! 112: return ret; ! 113: } ! 114: ! 115: /** ! 116: * Convert 64-bit integer to 6-byte packet number ! 117: * ! 118: * @v v 64-bit integer ! 119: * @v msb If TRUE, reverse the output PN to be in MSB order ! 120: * @ret pn 6-byte packet number ! 121: * ! 122: * The PN is stored in LSB order in the packet header and in MSB order ! 123: * in the nonce. WHYYYYY? ! 124: */ ! 125: static void u64_to_pn ( u64 v, u8 *pn, int msb ) ! 126: { ! 127: int i; ! 128: u8 *pnp = pn + ( msb ? 5 : 0 ); ! 129: int delta = ( msb ? -1 : +1 ); ! 130: ! 131: for ( i = 0; i < 6; i++ ) { ! 132: *pnp = v & 0xFF; ! 133: pnp += delta; ! 134: v >>= 8; ! 135: } ! 136: } ! 137: ! 138: /** Value for @a msb argument of u64_to_pn() for MSB output */ ! 139: #define PN_MSB 1 ! 140: ! 141: /** Value for @a msb argument of u64_to_pn() for LSB output */ ! 142: #define PN_LSB 0 ! 143: ! 144: ! 145: ! 146: /** ! 147: * Initialise CCMP state and install key ! 148: * ! 149: * @v crypto CCMP cryptosystem structure ! 150: * @v key Pointer to 16-byte temporal key to install ! 151: * @v keylen Length of key (16 bytes) ! 152: * @v rsc Initial receive sequence counter ! 153: */ ! 154: static int ccmp_init ( struct net80211_crypto *crypto, const void *key, ! 155: int keylen, const void *rsc ) ! 156: { ! 157: struct ccmp_ctx *ctx = crypto->priv; ! 158: ! 159: if ( keylen != 16 ) ! 160: return -EINVAL; ! 161: ! 162: if ( rsc ) ! 163: ctx->rx_seq = pn_to_u64 ( rsc ); ! 164: ! 165: cipher_setkey ( &aes_algorithm, ctx->aes_ctx, key, keylen ); ! 166: ! 167: return 0; ! 168: } ! 169: ! 170: ! 171: /** ! 172: * Encrypt or decrypt data stream using AES in Counter mode ! 173: * ! 174: * @v ctx CCMP cryptosystem context ! 175: * @v nonce Nonce value, 13 bytes ! 176: * @v srcv Data to encrypt or decrypt ! 177: * @v len Number of bytes pointed to by @a src ! 178: * @v msrcv MIC value to encrypt or decrypt (may be NULL) ! 179: * @ret destv Encrypted or decrypted data ! 180: * @ret mdestv Encrypted or decrypted MIC value ! 181: * ! 182: * This assumes CCMP parameters of L=2 and M=8. The algorithm is ! 183: * defined in RFC 3610. ! 184: */ ! 185: static void ccmp_ctr_xor ( struct ccmp_ctx *ctx, const void *nonce, ! 186: const void *srcv, void *destv, int len, ! 187: const void *msrcv, void *mdestv ) ! 188: { ! 189: u8 A[16], S[16]; ! 190: u16 ctr; ! 191: int i; ! 192: const u8 *src = srcv, *msrc = msrcv; ! 193: u8 *dest = destv, *mdest = mdestv; ! 194: ! 195: A[0] = 0x01; /* flags, L' = L - 1 = 1, other bits rsvd */ ! 196: memcpy ( A + 1, nonce, CCMP_NONCE_LEN ); ! 197: ! 198: if ( msrcv ) { ! 199: A[14] = A[15] = 0; ! 200: ! 201: cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 ); ! 202: ! 203: for ( i = 0; i < 8; i++ ) { ! 204: *mdest++ = *msrc++ ^ S[i]; ! 205: } ! 206: } ! 207: ! 208: for ( ctr = 1 ;; ctr++ ) { ! 209: A[14] = ctr >> 8; ! 210: A[15] = ctr & 0xFF; ! 211: ! 212: cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 ); ! 213: ! 214: for ( i = 0; i < len && i < 16; i++ ) ! 215: *dest++ = *src++ ^ S[i]; ! 216: ! 217: if ( len <= 16 ) ! 218: break; /* we're done */ ! 219: ! 220: len -= 16; ! 221: } ! 222: } ! 223: ! 224: ! 225: /** ! 226: * Advance one block in CBC-MAC calculation ! 227: * ! 228: * @v aes_ctx AES encryption context with key set ! 229: * @v B Cleartext block to incorporate (16 bytes) ! 230: * @v X Previous ciphertext block (16 bytes) ! 231: * @ret B Clobbered ! 232: * @ret X New ciphertext block (16 bytes) ! 233: * ! 234: * This function does X := E[key] ( X ^ B ). ! 235: */ ! 236: static void ccmp_feed_cbc_mac ( void *aes_ctx, u8 *B, u8 *X ) ! 237: { ! 238: int i; ! 239: for ( i = 0; i < 16; i++ ) ! 240: B[i] ^= X[i]; ! 241: cipher_encrypt ( &aes_algorithm, aes_ctx, B, X, 16 ); ! 242: } ! 243: ! 244: ! 245: /** ! 246: * Calculate MIC on plaintext data using CBC-MAC ! 247: * ! 248: * @v ctx CCMP cryptosystem context ! 249: * @v nonce Nonce value, 13 bytes ! 250: * @v data Data to calculate MIC over ! 251: * @v datalen Length of @a data ! 252: * @v aad Additional authentication data, for MIC but not encryption ! 253: * @ret mic MIC value (unencrypted), 8 bytes ! 254: * ! 255: * @a aadlen is assumed to be 22 bytes long, as it always is for ! 256: * 802.11 use when transmitting non-QoS, not-between-APs frames (the ! 257: * only type we deal with). ! 258: */ ! 259: static void ccmp_cbc_mac ( struct ccmp_ctx *ctx, const void *nonce, ! 260: const void *data, u16 datalen, ! 261: const void *aad, void *mic ) ! 262: { ! 263: u8 X[16], B[16]; ! 264: ! 265: /* Zeroth block: flags, nonce, length */ ! 266: ! 267: /* Rsv AAD - M'- - L'- ! 268: * 0 1 0 1 1 0 0 1 for an 8-byte MAC and 2-byte message length ! 269: */ ! 270: B[0] = 0x59; ! 271: memcpy ( B + 1, nonce, CCMP_NONCE_LEN ); ! 272: B[14] = datalen >> 8; ! 273: B[15] = datalen & 0xFF; ! 274: ! 275: cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, B, X, 16 ); ! 276: ! 277: /* First block: AAD length field and 14 bytes of AAD */ ! 278: B[0] = 0; ! 279: B[1] = CCMP_AAD_LEN; ! 280: memcpy ( B + 2, aad, 14 ); ! 281: ! 282: ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); ! 283: ! 284: /* Second block: Remaining 8 bytes of AAD, 8 bytes zero pad */ ! 285: memcpy ( B, aad + 14, 8 ); ! 286: memset ( B + 8, 0, 8 ); ! 287: ! 288: ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); ! 289: ! 290: /* Message blocks */ ! 291: while ( datalen ) { ! 292: if ( datalen >= 16 ) { ! 293: memcpy ( B, data, 16 ); ! 294: datalen -= 16; ! 295: } else { ! 296: memcpy ( B, data, datalen ); ! 297: memset ( B + datalen, 0, 16 - datalen ); ! 298: datalen = 0; ! 299: } ! 300: ! 301: ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); ! 302: ! 303: data += 16; ! 304: } ! 305: ! 306: /* Get MIC from final value of X */ ! 307: memcpy ( mic, X, 8 ); ! 308: } ! 309: ! 310: ! 311: /** ! 312: * Encapsulate and encrypt a packet using CCMP ! 313: * ! 314: * @v crypto CCMP cryptosystem ! 315: * @v iob I/O buffer containing cleartext packet ! 316: * @ret eiob I/O buffer containing encrypted packet ! 317: */ ! 318: struct io_buffer * ccmp_encrypt ( struct net80211_crypto *crypto, ! 319: struct io_buffer *iob ) ! 320: { ! 321: struct ccmp_ctx *ctx = crypto->priv; ! 322: struct ieee80211_frame *hdr = iob->data; ! 323: struct io_buffer *eiob; ! 324: const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; ! 325: int datalen = iob_len ( iob ) - hdrlen; ! 326: struct ccmp_head head; ! 327: struct ccmp_nonce nonce; ! 328: struct ccmp_aad aad; ! 329: u8 mic[8], tx_pn[6]; ! 330: void *edata, *emic; ! 331: ! 332: ctx->tx_seq++; ! 333: u64_to_pn ( ctx->tx_seq, tx_pn, PN_LSB ); ! 334: ! 335: /* Allocate memory */ ! 336: eiob = alloc_iob ( iob_len ( iob ) + CCMP_HEAD_LEN + CCMP_MIC_LEN ); ! 337: if ( ! eiob ) ! 338: return NULL; ! 339: ! 340: /* Copy frame header */ ! 341: memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen ); ! 342: hdr = eiob->data; ! 343: hdr->fc |= IEEE80211_FC_PROTECTED; ! 344: ! 345: /* Fill in packet number and extended IV */ ! 346: memcpy ( head.pn_lo, tx_pn, 2 ); ! 347: memcpy ( head.pn_hi, tx_pn + 2, 4 ); ! 348: head.kid = 0x20; /* have Extended IV, key ID 0 */ ! 349: head._rsvd = 0; ! 350: memcpy ( iob_put ( eiob, sizeof ( head ) ), &head, sizeof ( head ) ); ! 351: ! 352: /* Form nonce */ ! 353: nonce.prio = 0; ! 354: memcpy ( nonce.a2, hdr->addr2, ETH_ALEN ); ! 355: u64_to_pn ( ctx->tx_seq, nonce.pn, PN_MSB ); ! 356: ! 357: /* Form additional authentication data */ ! 358: aad.fc = hdr->fc & CCMP_AAD_FC_MASK; ! 359: memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */ ! 360: aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK; ! 361: ! 362: /* Calculate MIC over the data */ ! 363: ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, mic ); ! 364: ! 365: /* Copy and encrypt data and MIC */ ! 366: edata = iob_put ( eiob, datalen ); ! 367: emic = iob_put ( eiob, CCMP_MIC_LEN ); ! 368: ccmp_ctr_xor ( ctx, &nonce, ! 369: iob->data + hdrlen, edata, datalen, ! 370: mic, emic ); ! 371: ! 372: /* Done! */ ! 373: DBGC2 ( ctx, "WPA-CCMP %p: encrypted packet %p -> %p\n", ctx, ! 374: iob, eiob ); ! 375: ! 376: return eiob; ! 377: } ! 378: ! 379: /** ! 380: * Decrypt a packet using CCMP ! 381: * ! 382: * @v crypto CCMP cryptosystem ! 383: * @v eiob I/O buffer containing encrypted packet ! 384: * @ret iob I/O buffer containing cleartext packet ! 385: */ ! 386: static struct io_buffer * ccmp_decrypt ( struct net80211_crypto *crypto, ! 387: struct io_buffer *eiob ) ! 388: { ! 389: struct ccmp_ctx *ctx = crypto->priv; ! 390: struct ieee80211_frame *hdr; ! 391: struct io_buffer *iob; ! 392: const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; ! 393: int datalen = iob_len ( eiob ) - hdrlen - CCMP_HEAD_LEN - CCMP_MIC_LEN; ! 394: struct ccmp_head *head; ! 395: struct ccmp_nonce nonce; ! 396: struct ccmp_aad aad; ! 397: u8 rx_pn[6], their_mic[8], our_mic[8]; ! 398: ! 399: iob = alloc_iob ( hdrlen + datalen ); ! 400: if ( ! iob ) ! 401: return NULL; ! 402: ! 403: /* Copy frame header */ ! 404: memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen ); ! 405: hdr = iob->data; ! 406: hdr->fc &= ~IEEE80211_FC_PROTECTED; ! 407: ! 408: /* Check and update RX packet number */ ! 409: head = eiob->data + hdrlen; ! 410: memcpy ( rx_pn, head->pn_lo, 2 ); ! 411: memcpy ( rx_pn + 2, head->pn_hi, 4 ); ! 412: ! 413: if ( pn_to_u64 ( rx_pn ) <= ctx->rx_seq ) { ! 414: DBGC ( ctx, "WPA-CCMP %p: packet received out of order " ! 415: "(%012llx <= %012llx)\n", ctx, pn_to_u64 ( rx_pn ), ! 416: ctx->rx_seq ); ! 417: free_iob ( iob ); ! 418: return NULL; ! 419: } ! 420: ! 421: ctx->rx_seq = pn_to_u64 ( rx_pn ); ! 422: DBGC2 ( ctx, "WPA-CCMP %p: RX packet number %012llx\n", ctx, ctx->rx_seq ); ! 423: ! 424: /* Form nonce */ ! 425: nonce.prio = 0; ! 426: memcpy ( nonce.a2, hdr->addr2, ETH_ALEN ); ! 427: u64_to_pn ( ctx->rx_seq, nonce.pn, PN_MSB ); ! 428: ! 429: /* Form additional authentication data */ ! 430: aad.fc = ( hdr->fc & CCMP_AAD_FC_MASK ) | IEEE80211_FC_PROTECTED; ! 431: memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */ ! 432: aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK; ! 433: ! 434: /* Copy-decrypt data and MIC */ ! 435: ccmp_ctr_xor ( ctx, &nonce, eiob->data + hdrlen + sizeof ( *head ), ! 436: iob_put ( iob, datalen ), datalen, ! 437: eiob->tail - CCMP_MIC_LEN, their_mic ); ! 438: ! 439: /* Check MIC */ ! 440: ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, ! 441: our_mic ); ! 442: ! 443: if ( memcmp ( their_mic, our_mic, CCMP_MIC_LEN ) != 0 ) { ! 444: DBGC2 ( ctx, "WPA-CCMP %p: MIC failure\n", ctx ); ! 445: free_iob ( iob ); ! 446: return NULL; ! 447: } ! 448: ! 449: DBGC2 ( ctx, "WPA-CCMP %p: decrypted packet %p -> %p\n", ctx, ! 450: eiob, iob ); ! 451: ! 452: return iob; ! 453: } ! 454: ! 455: ! 456: /** CCMP cryptosystem */ ! 457: struct net80211_crypto ccmp_crypto __net80211_crypto = { ! 458: .algorithm = NET80211_CRYPT_CCMP, ! 459: .init = ccmp_init, ! 460: .encrypt = ccmp_encrypt, ! 461: .decrypt = ccmp_decrypt, ! 462: .priv_len = sizeof ( struct ccmp_ctx ), ! 463: }; ! 464: ! 465: ! 466: ! 467: ! 468: /** ! 469: * Calculate HMAC-SHA1 MIC for EAPOL-Key frame ! 470: * ! 471: * @v kck Key Confirmation Key, 16 bytes ! 472: * @v msg Message to calculate MIC over ! 473: * @v len Number of bytes to calculate MIC over ! 474: * @ret mic Calculated MIC, 16 bytes long ! 475: */ ! 476: static void ccmp_kie_mic ( const void *kck, const void *msg, size_t len, ! 477: void *mic ) ! 478: { ! 479: u8 sha1_ctx[SHA1_CTX_SIZE]; ! 480: u8 kckb[16]; ! 481: u8 hash[SHA1_SIZE]; ! 482: size_t kck_len = 16; ! 483: ! 484: memcpy ( kckb, kck, kck_len ); ! 485: ! 486: hmac_init ( &sha1_algorithm, sha1_ctx, kckb, &kck_len ); ! 487: hmac_update ( &sha1_algorithm, sha1_ctx, msg, len ); ! 488: hmac_final ( &sha1_algorithm, sha1_ctx, kckb, &kck_len, hash ); ! 489: ! 490: memcpy ( mic, hash, 16 ); ! 491: } ! 492: ! 493: /** ! 494: * Decrypt key data in EAPOL-Key frame ! 495: * ! 496: * @v kek Key Encryption Key, 16 bytes ! 497: * @v iv Initialisation vector, 16 bytes (unused) ! 498: * @v msg Message to decrypt ! 499: * @v len Length of message ! 500: * @ret msg Decrypted message in place of original ! 501: * @ret len Adjusted downward for 8 bytes of overhead ! 502: * @ret rc Return status code ! 503: * ! 504: * The returned message may still contain padding of 0xDD followed by ! 505: * zero or more 0x00 octets. It is impossible to remove the padding ! 506: * without parsing the IEs in the packet (another design decision that ! 507: * tends to make one question the 802.11i committee's intelligence...) ! 508: */ ! 509: static int ccmp_kie_decrypt ( const void *kek, const void *iv __unused, ! 510: void *msg, u16 *len ) ! 511: { ! 512: if ( *len % 8 != 0 ) ! 513: return -EINVAL; ! 514: ! 515: if ( aes_unwrap ( kek, msg, msg, *len / 8 - 1 ) != 0 ) ! 516: return -EINVAL; ! 517: ! 518: *len -= 8; ! 519: ! 520: return 0; ! 521: } ! 522: ! 523: /** CCMP-style key integrity and encryption handler */ ! 524: struct wpa_kie ccmp_kie __wpa_kie = { ! 525: .version = EAPOL_KEY_VERSION_WPA2, ! 526: .mic = ccmp_kie_mic, ! 527: .decrypt = ccmp_kie_decrypt, ! 528: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.