|
|
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 <stdlib.h> ! 22: #include <string.h> ! 23: #include <errno.h> ! 24: #include <ipxe/ieee80211.h> ! 25: #include <ipxe/net80211.h> ! 26: #include <ipxe/sec80211.h> ! 27: ! 28: /** @file ! 29: * ! 30: * General secured-network routines required whenever any secure ! 31: * network support at all is compiled in. This involves things like ! 32: * installing keys, determining the type of security used by a probed ! 33: * network, and some small helper functions that take advantage of ! 34: * static data in this file. ! 35: */ ! 36: ! 37: /* Unsupported cryptosystem error numbers */ ! 38: #define ENOTSUP_WEP __einfo_error ( EINFO_ENOTSUP_WEP ) ! 39: #define EINFO_ENOTSUP_WEP __einfo_uniqify ( EINFO_ENOTSUP, \ ! 40: ( 0x10 | NET80211_CRYPT_WEP ), "WEP not supported" ) ! 41: #define ENOTSUP_TKIP __einfo_error ( EINFO_ENOTSUP_TKIP ) ! 42: #define EINFO_ENOTSUP_TKIP __einfo_uniqify ( EINFO_ENOTSUP, \ ! 43: ( 0x10 | NET80211_CRYPT_TKIP ), "TKIP not supported" ) ! 44: #define ENOTSUP_CCMP __einfo_error ( EINFO_ENOTSUP_CCMP ) ! 45: #define EINFO_ENOTSUP_CCMP __einfo_uniqify ( EINFO_ENOTSUP, \ ! 46: ( 0x10 | NET80211_CRYPT_CCMP ), "CCMP not supported" ) ! 47: #define ENOTSUP_CRYPT( crypt ) \ ! 48: EUNIQ ( ENOTSUP, ( 0x10 | (crypt) ), \ ! 49: ENOTSUP_WEP, ENOTSUP_TKIP, ENOTSUP_CCMP ) ! 50: ! 51: /** Mapping from net80211 crypto/secprot types to RSN OUI descriptors */ ! 52: struct descriptor_map { ! 53: /** Value of net80211_crypto_alg or net80211_security_proto */ ! 54: u32 net80211_type; ! 55: ! 56: /** OUI+type in appropriate byte order, masked to exclude vendor */ ! 57: u32 oui_type; ! 58: }; ! 59: ! 60: /** Magic number in @a oui_type showing end of list */ ! 61: #define END_MAGIC 0xFFFFFFFF ! 62: ! 63: /** Mapping between net80211 cryptosystems and 802.11i cipher IDs */ ! 64: static struct descriptor_map rsn_cipher_map[] = { ! 65: { .net80211_type = NET80211_CRYPT_WEP, ! 66: .oui_type = IEEE80211_RSN_CTYPE_WEP40 }, ! 67: ! 68: { .net80211_type = NET80211_CRYPT_WEP, ! 69: .oui_type = IEEE80211_RSN_CTYPE_WEP104 }, ! 70: ! 71: { .net80211_type = NET80211_CRYPT_TKIP, ! 72: .oui_type = IEEE80211_RSN_CTYPE_TKIP }, ! 73: ! 74: { .net80211_type = NET80211_CRYPT_CCMP, ! 75: .oui_type = IEEE80211_RSN_CTYPE_CCMP }, ! 76: ! 77: { .net80211_type = NET80211_CRYPT_UNKNOWN, ! 78: .oui_type = END_MAGIC }, ! 79: }; ! 80: ! 81: /** Mapping between net80211 handshakers and 802.11i AKM IDs */ ! 82: static struct descriptor_map rsn_akm_map[] = { ! 83: { .net80211_type = NET80211_SECPROT_EAP, ! 84: .oui_type = IEEE80211_RSN_ATYPE_8021X }, ! 85: ! 86: { .net80211_type = NET80211_SECPROT_PSK, ! 87: .oui_type = IEEE80211_RSN_ATYPE_PSK }, ! 88: ! 89: { .net80211_type = NET80211_SECPROT_UNKNOWN, ! 90: .oui_type = END_MAGIC }, ! 91: }; ! 92: ! 93: ! 94: /** ! 95: * Install 802.11 cryptosystem ! 96: * ! 97: * @v which Pointer to the cryptosystem structure to install in ! 98: * @v crypt Cryptosystem ID number ! 99: * @v key Encryption key to use ! 100: * @v len Length of encryption key ! 101: * @v rsc Initial receive sequence counter, if applicable ! 102: * @ret rc Return status code ! 103: * ! 104: * The encryption key will not be accessed via the provided pointer ! 105: * after this function returns, so you may keep it on the stack. ! 106: * ! 107: * @a which must point to either @c dev->crypto (for the normal case ! 108: * of installing a unicast cryptosystem) or @c dev->gcrypto (to ! 109: * install a cryptosystem that will be used only for decrypting ! 110: * group-source frames). ! 111: */ ! 112: int sec80211_install ( struct net80211_crypto **which, ! 113: enum net80211_crypto_alg crypt, ! 114: const void *key, int len, const void *rsc ) ! 115: { ! 116: struct net80211_crypto *crypto = *which; ! 117: struct net80211_crypto *tbl_crypto; ! 118: ! 119: /* Remove old crypto if it exists */ ! 120: free ( *which ); ! 121: *which = NULL; ! 122: ! 123: if ( crypt == NET80211_CRYPT_NONE ) { ! 124: DBG ( "802.11-Sec not installing null cryptography\n" ); ! 125: return 0; ! 126: } ! 127: ! 128: /* Find cryptosystem to use */ ! 129: for_each_table_entry ( tbl_crypto, NET80211_CRYPTOS ) { ! 130: if ( tbl_crypto->algorithm == crypt ) { ! 131: crypto = zalloc ( sizeof ( *crypto ) + ! 132: tbl_crypto->priv_len ); ! 133: if ( ! crypto ) { ! 134: DBG ( "802.11-Sec out of memory\n" ); ! 135: return -ENOMEM; ! 136: } ! 137: ! 138: memcpy ( crypto, tbl_crypto, sizeof ( *crypto ) ); ! 139: crypto->priv = ( ( void * ) crypto + ! 140: sizeof ( *crypto ) ); ! 141: break; ! 142: } ! 143: } ! 144: ! 145: if ( ! crypto ) { ! 146: DBG ( "802.11-Sec no support for cryptosystem %d\n", crypt ); ! 147: return -ENOTSUP_CRYPT ( crypt ); ! 148: } ! 149: ! 150: *which = crypto; ! 151: ! 152: DBG ( "802.11-Sec installing cryptosystem %d as %p with key of " ! 153: "length %d\n", crypt, crypto, len ); ! 154: ! 155: return crypto->init ( crypto, key, len, rsc ); ! 156: } ! 157: ! 158: ! 159: /** ! 160: * Determine net80211 crypto or handshaking type value to return for RSN info ! 161: * ! 162: * @v rsnp Pointer to next descriptor count field in RSN IE ! 163: * @v rsn_end Pointer to end of RSN IE ! 164: * @v map Descriptor map to use ! 165: * @v tbl_start Start of linker table to examine for iPXE support ! 166: * @v tbl_end End of linker table to examine for iPXE support ! 167: * @ret rsnp Updated to point to first byte after descriptors ! 168: * @ret map_ent Descriptor map entry of translation to use ! 169: * ! 170: * The entries in the linker table must be either net80211_crypto or ! 171: * net80211_handshaker structures, and @a tbl_stride must be set to ! 172: * sizeof() the appropriate one. ! 173: * ! 174: * This function expects @a rsnp to point at a two-byte descriptor ! 175: * count followed by a list of four-byte cipher or AKM descriptors; it ! 176: * will return @c NULL if the input packet is malformed, and otherwise ! 177: * set @a rsnp to the first byte it has not looked at. It will return ! 178: * the first cipher in the list that is supported by the current build ! 179: * of iPXE, or the first of all if none are supported. ! 180: * ! 181: * We play rather fast and loose with type checking, because this ! 182: * function is only called from two well-defined places in the ! 183: * RSN-checking code. Don't try to use it for anything else. ! 184: */ ! 185: static struct descriptor_map * rsn_pick_desc ( u8 **rsnp, u8 *rsn_end, ! 186: struct descriptor_map *map, ! 187: void *tbl_start, void *tbl_end ) ! 188: { ! 189: int ndesc; ! 190: int ok = 0; ! 191: struct descriptor_map *map_ent, *map_ret = NULL; ! 192: u8 *rsn = *rsnp; ! 193: void *tblp; ! 194: size_t tbl_stride = ( map == rsn_cipher_map ? ! 195: sizeof ( struct net80211_crypto ) : ! 196: sizeof ( struct net80211_handshaker ) ); ! 197: ! 198: if ( map != rsn_cipher_map && map != rsn_akm_map ) ! 199: return NULL; ! 200: ! 201: /* Determine which types we support */ ! 202: for ( tblp = tbl_start; tblp < tbl_end; tblp += tbl_stride ) { ! 203: struct net80211_crypto *crypto = tblp; ! 204: struct net80211_handshaker *hs = tblp; ! 205: ! 206: if ( map == rsn_cipher_map ) ! 207: ok |= ( 1 << crypto->algorithm ); ! 208: else ! 209: ok |= ( 1 << hs->protocol ); ! 210: } ! 211: ! 212: /* RSN sanity checks */ ! 213: if ( rsn + 2 > rsn_end ) { ! 214: DBG ( "RSN detect: malformed descriptor count\n" ); ! 215: return NULL; ! 216: } ! 217: ! 218: ndesc = *( u16 * ) rsn; ! 219: rsn += 2; ! 220: ! 221: if ( ! ndesc ) { ! 222: DBG ( "RSN detect: no descriptors\n" ); ! 223: return NULL; ! 224: } ! 225: ! 226: /* Determine which net80211 crypto types are listed */ ! 227: while ( ndesc-- ) { ! 228: u32 desc; ! 229: ! 230: if ( rsn + 4 > rsn_end ) { ! 231: DBG ( "RSN detect: malformed descriptor (%d left)\n", ! 232: ndesc ); ! 233: return NULL; ! 234: } ! 235: ! 236: desc = *( u32 * ) rsn; ! 237: rsn += 4; ! 238: ! 239: for ( map_ent = map; map_ent->oui_type != END_MAGIC; map_ent++ ) ! 240: if ( map_ent->oui_type == ( desc & OUI_TYPE_MASK ) ) ! 241: break; ! 242: ! 243: /* Use first cipher as a fallback */ ! 244: if ( ! map_ret ) ! 245: map_ret = map_ent; ! 246: ! 247: /* Once we find one we support, use it */ ! 248: if ( ok & ( 1 << map_ent->net80211_type ) ) { ! 249: map_ret = map_ent; ! 250: break; ! 251: } ! 252: } ! 253: ! 254: if ( ndesc > 0 ) ! 255: rsn += 4 * ndesc; ! 256: ! 257: *rsnp = rsn; ! 258: return map_ret; ! 259: } ! 260: ! 261: ! 262: /** ! 263: * Find the RSN or WPA information element in the provided beacon frame ! 264: * ! 265: * @v ie Pointer to first information element to check ! 266: * @v ie_end Pointer to end of information element space ! 267: * @ret is_rsn TRUE if returned IE is RSN, FALSE if it's WPA ! 268: * @ret end Pointer to byte immediately after last byte of data ! 269: * @ret data Pointer to first byte of data (the `version' field) ! 270: * ! 271: * If both an RSN and a WPA information element are found, this ! 272: * function will return the first one seen, which by ordering rules ! 273: * should always prefer the newer RSN IE. ! 274: * ! 275: * If no RSN or WPA infomration element is found, returns @c NULL and ! 276: * leaves @a is_rsn and @a end in an undefined state. ! 277: * ! 278: * This function will not return a pointer to an information element ! 279: * that states it extends past the tail of the io_buffer, or whose @a ! 280: * version field is incorrect. ! 281: */ ! 282: u8 * sec80211_find_rsn ( union ieee80211_ie *ie, void *ie_end, ! 283: int *is_rsn, u8 **end ) ! 284: { ! 285: u8 *rsn = NULL; ! 286: ! 287: if ( ! ieee80211_ie_bound ( ie, ie_end ) ) ! 288: return NULL; ! 289: ! 290: while ( ie ) { ! 291: if ( ie->id == IEEE80211_IE_VENDOR && ! 292: ie->vendor.oui == IEEE80211_WPA_OUI_VEN ) { ! 293: DBG ( "RSN detect: old-style WPA IE found\n" ); ! 294: rsn = &ie->vendor.data[0]; ! 295: *end = rsn + ie->len - 4; ! 296: *is_rsn = 0; ! 297: } else if ( ie->id == IEEE80211_IE_RSN ) { ! 298: DBG ( "RSN detect: 802.11i RSN IE found\n" ); ! 299: rsn = ( u8 * ) &ie->rsn.version; ! 300: *end = rsn + ie->len; ! 301: *is_rsn = 1; ! 302: } ! 303: ! 304: if ( rsn && ( *end > ( u8 * ) ie_end || rsn >= *end || ! 305: *( u16 * ) rsn != IEEE80211_RSN_VERSION ) ) { ! 306: DBG ( "RSN detect: malformed RSN IE or unknown " ! 307: "version, keep trying\n" ); ! 308: rsn = NULL; ! 309: } ! 310: ! 311: if ( rsn ) ! 312: break; ! 313: ! 314: ie = ieee80211_next_ie ( ie, ie_end ); ! 315: } ! 316: ! 317: if ( ! ie ) { ! 318: DBG ( "RSN detect: no RSN IE found\n" ); ! 319: return NULL; ! 320: } ! 321: ! 322: return rsn; ! 323: } ! 324: ! 325: ! 326: /** ! 327: * Detect crypto and AKM types from RSN information element ! 328: * ! 329: * @v is_rsn If TRUE, IE is a new-style RSN information element ! 330: * @v start Pointer to first byte of @a version field ! 331: * @v end Pointer to first byte not in the RSN IE ! 332: * @ret secprot Security handshaking protocol used by network ! 333: * @ret crypt Cryptosystem used by network ! 334: * @ret rc Return status code ! 335: * ! 336: * If the IE cannot be parsed, returns an error indication and leaves ! 337: * @a secprot and @a crypt unchanged. ! 338: */ ! 339: int sec80211_detect_ie ( int is_rsn, u8 *start, u8 *end, ! 340: enum net80211_security_proto *secprot, ! 341: enum net80211_crypto_alg *crypt ) ! 342: { ! 343: enum net80211_security_proto sp; ! 344: enum net80211_crypto_alg cr; ! 345: struct descriptor_map *map; ! 346: u8 *rsn = start; ! 347: ! 348: /* Set some defaults */ ! 349: cr = ( is_rsn ? NET80211_CRYPT_CCMP : NET80211_CRYPT_TKIP ); ! 350: sp = NET80211_SECPROT_EAP; ! 351: ! 352: rsn += 2; /* version - already checked */ ! 353: rsn += 4; /* group cipher - we don't use it here */ ! 354: ! 355: if ( rsn >= end ) ! 356: goto done; ! 357: ! 358: /* Pick crypto algorithm */ ! 359: map = rsn_pick_desc ( &rsn, end, rsn_cipher_map, ! 360: table_start ( NET80211_CRYPTOS ), ! 361: table_end ( NET80211_CRYPTOS ) ); ! 362: if ( ! map ) ! 363: goto invalid_rsn; ! 364: ! 365: cr = map->net80211_type; ! 366: ! 367: if ( rsn >= end ) ! 368: goto done; ! 369: ! 370: /* Pick handshaking algorithm */ ! 371: map = rsn_pick_desc ( &rsn, end, rsn_akm_map, ! 372: table_start ( NET80211_HANDSHAKERS ), ! 373: table_end ( NET80211_HANDSHAKERS ) ); ! 374: if ( ! map ) ! 375: goto invalid_rsn; ! 376: ! 377: sp = map->net80211_type; ! 378: ! 379: done: ! 380: DBG ( "RSN detect: OK, crypto type %d, secprot type %d\n", cr, sp ); ! 381: *secprot = sp; ! 382: *crypt = cr; ! 383: return 0; ! 384: ! 385: invalid_rsn: ! 386: DBG ( "RSN detect: invalid RSN IE\n" ); ! 387: return -EINVAL; ! 388: } ! 389: ! 390: ! 391: /** ! 392: * Detect the cryptosystem and handshaking protocol used by an 802.11 network ! 393: * ! 394: * @v iob I/O buffer containing beacon frame ! 395: * @ret secprot Security handshaking protocol used by network ! 396: * @ret crypt Cryptosystem used by network ! 397: * @ret rc Return status code ! 398: * ! 399: * This function uses weak linkage, as it must be called from generic ! 400: * contexts but should only be linked in if some encryption is ! 401: * supported; you must test its address against @c NULL before calling ! 402: * it. If it does not exist, any network with the PRIVACY bit set in ! 403: * beacon->capab should be considered unknown. ! 404: */ ! 405: int sec80211_detect ( struct io_buffer *iob, ! 406: enum net80211_security_proto *secprot, ! 407: enum net80211_crypto_alg *crypt ) ! 408: { ! 409: struct ieee80211_frame *hdr = iob->data; ! 410: struct ieee80211_beacon *beacon = ! 411: ( struct ieee80211_beacon * ) hdr->data; ! 412: u8 *rsn, *rsn_end; ! 413: int is_rsn, rc; ! 414: ! 415: *crypt = NET80211_CRYPT_UNKNOWN; ! 416: *secprot = NET80211_SECPROT_UNKNOWN; ! 417: ! 418: /* Find RSN or WPA IE */ ! 419: if ( ! ( rsn = sec80211_find_rsn ( beacon->info_element, iob->tail, ! 420: &is_rsn, &rsn_end ) ) ) { ! 421: /* No security IE at all; either WEP or no security. */ ! 422: *secprot = NET80211_SECPROT_NONE; ! 423: ! 424: if ( beacon->capability & IEEE80211_CAPAB_PRIVACY ) ! 425: *crypt = NET80211_CRYPT_WEP; ! 426: else ! 427: *crypt = NET80211_CRYPT_NONE; ! 428: ! 429: return 0; ! 430: } ! 431: ! 432: /* Determine type of security */ ! 433: if ( ( rc = sec80211_detect_ie ( is_rsn, rsn, rsn_end, secprot, ! 434: crypt ) ) == 0 ) ! 435: return 0; ! 436: ! 437: /* If we get here, the RSN IE was invalid */ ! 438: ! 439: *crypt = NET80211_CRYPT_UNKNOWN; ! 440: *secprot = NET80211_SECPROT_UNKNOWN; ! 441: DBG ( "Failed to handle RSN IE:\n" ); ! 442: DBG_HD ( rsn, rsn_end - rsn ); ! 443: return rc; ! 444: } ! 445: ! 446: ! 447: /** ! 448: * Determine RSN descriptor for specified net80211 ID ! 449: * ! 450: * @v id net80211 ID value ! 451: * @v rsnie Whether to return a new-format (RSN IE) descriptor ! 452: * @v map Map to use in translation ! 453: * @ret desc RSN descriptor, or 0 on error ! 454: * ! 455: * If @a rsnie is false, returns an old-format (WPA vendor IE) ! 456: * descriptor. ! 457: */ ! 458: static u32 rsn_get_desc ( unsigned id, int rsnie, struct descriptor_map *map ) ! 459: { ! 460: u32 vendor = ( rsnie ? IEEE80211_RSN_OUI : IEEE80211_WPA_OUI ); ! 461: ! 462: for ( ; map->oui_type != END_MAGIC; map++ ) { ! 463: if ( map->net80211_type == id ) ! 464: return map->oui_type | vendor; ! 465: } ! 466: ! 467: return 0; ! 468: } ! 469: ! 470: /** ! 471: * Determine RSN descriptor for specified net80211 cryptosystem number ! 472: * ! 473: * @v crypt Cryptosystem number ! 474: * @v rsnie Whether to return a new-format (RSN IE) descriptor ! 475: * @ret desc RSN descriptor ! 476: * ! 477: * If @a rsnie is false, returns an old-format (WPA vendor IE) ! 478: * descriptor. ! 479: */ ! 480: u32 sec80211_rsn_get_crypto_desc ( enum net80211_crypto_alg crypt, int rsnie ) ! 481: { ! 482: return rsn_get_desc ( crypt, rsnie, rsn_cipher_map ); ! 483: } ! 484: ! 485: /** ! 486: * Determine RSN descriptor for specified net80211 handshaker number ! 487: * ! 488: * @v secprot Handshaker number ! 489: * @v rsnie Whether to return a new-format (RSN IE) descriptor ! 490: * @ret desc RSN descriptor ! 491: * ! 492: * If @a rsnie is false, returns an old-format (WPA vendor IE) ! 493: * descriptor. ! 494: */ ! 495: u32 sec80211_rsn_get_akm_desc ( enum net80211_security_proto secprot, ! 496: int rsnie ) ! 497: { ! 498: return rsn_get_desc ( secprot, rsnie, rsn_akm_map ); ! 499: } ! 500: ! 501: /** ! 502: * Determine net80211 cryptosystem number from RSN descriptor ! 503: * ! 504: * @v desc RSN descriptor ! 505: * @ret crypt net80211 cryptosystem enumeration value ! 506: */ ! 507: enum net80211_crypto_alg sec80211_rsn_get_net80211_crypt ( u32 desc ) ! 508: { ! 509: struct descriptor_map *map = rsn_cipher_map; ! 510: ! 511: for ( ; map->oui_type != END_MAGIC; map++ ) { ! 512: if ( map->oui_type == ( desc & OUI_TYPE_MASK ) ) ! 513: break; ! 514: } ! 515: ! 516: return map->net80211_type; ! 517: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.