#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <gpxe/ieee80211.h>
#include <gpxe/net80211.h>
#include <gpxe/sec80211.h>
Go to the source code of this file.
Data Structures | |
| struct | descriptor_map |
| Mapping from net80211 crypto/secprot types to RSN OUI descriptors. More... | |
Defines | |
| #define | END_MAGIC 0xFFFFFFFF |
| Magic number in oui_type showing end of list. | |
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| int | sec80211_install (struct net80211_crypto **which, enum net80211_crypto_alg crypt, const void *key, int len, const void *rsc) |
| Install 802.11 cryptosystem. | |
| static struct descriptor_map * | rsn_pick_desc (u8 **rsnp, u8 *rsn_end, struct descriptor_map *map, void *tbl_start, void *tbl_end) |
| Determine net80211 crypto or handshaking type value to return for RSN info. | |
| u8 * | sec80211_find_rsn (union ieee80211_ie *ie, void *ie_end, int *is_rsn, u8 **end) |
| Find the RSN or WPA information element in the provided beacon frame. | |
| int | sec80211_detect_ie (int is_rsn, u8 *start, u8 *end, enum net80211_security_proto *secprot, enum net80211_crypto_alg *crypt) |
| Detect crypto and AKM types from RSN information element. | |
| int | _sec80211_detect (struct io_buffer *iob, enum net80211_security_proto *secprot, enum net80211_crypto_alg *crypt) |
| Detect the cryptosystem and handshaking protocol used by an 802.11 network. | |
| static u32 | rsn_get_desc (unsigned id, int rsnie, struct descriptor_map *map) |
| Determine RSN descriptor for specified net80211 ID. | |
| u32 | sec80211_rsn_get_crypto_desc (enum net80211_crypto_alg crypt, int rsnie) |
| Determine RSN descriptor for specified net80211 cryptosystem number. | |
| u32 | sec80211_rsn_get_akm_desc (enum net80211_security_proto secprot, int rsnie) |
| Determine RSN descriptor for specified net80211 handshaker number. | |
| enum net80211_crypto_alg | sec80211_rsn_get_net80211_crypt (u32 desc) |
| Determine net80211 cryptosystem number from RSN descriptor. | |
Variables | |
| static struct descriptor_map | rsn_cipher_map [] |
| Mapping between net80211 cryptosystems and 802.11i cipher IDs. | |
| static struct descriptor_map | rsn_akm_map [] |
| Mapping between net80211 handshakers and 802.11i AKM IDs. | |
This involves things like installing keys, determining the type of security used by a probed network, and some small helper functions that take advantage of static data in this file.
Definition in file sec80211.c.
| #define END_MAGIC 0xFFFFFFFF |
Magic number in oui_type showing end of list.
Definition at line 47 of file sec80211.c.
Referenced by rsn_get_desc(), and sec80211_rsn_get_net80211_crypt().
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| int sec80211_install | ( | struct net80211_crypto ** | which, | |
| enum net80211_crypto_alg | crypt, | |||
| const void * | key, | |||
| int | len, | |||
| const void * | rsc | |||
| ) |
Install 802.11 cryptosystem.
| which | Pointer to the cryptosystem structure to install in | |
| crypt | Cryptosystem ID number | |
| key | Encryption key to use | |
| len | Length of encryption key | |
| rsc | Initial receive sequence counter, if applicable |
| rc | Return status code |
which must point to either dev->crypto (for the normal case of installing a unicast cryptosystem) or dev->gcrypto (to install a cryptosystem that will be used only for decrypting group-source frames).
Definition at line 98 of file sec80211.c.
References net80211_crypto::algorithm, DBG, ENOMEM, ENOTSUP, EUNIQ_10, for_each_table_entry, free(), net80211_crypto::init, memcpy, NET80211_CRYPT_NONE, NET80211_CRYPTOS, NULL, net80211_crypto::priv, net80211_crypto::priv_len, and zalloc().
Referenced by trivial_init(), wpa_install_gtk(), and wpa_install_ptk().
00101 { 00102 struct net80211_crypto *crypto = *which; 00103 struct net80211_crypto *tbl_crypto; 00104 00105 /* Remove old crypto if it exists */ 00106 free ( *which ); 00107 *which = NULL; 00108 00109 if ( crypt == NET80211_CRYPT_NONE ) { 00110 DBG ( "802.11-Sec not installing null cryptography\n" ); 00111 return 0; 00112 } 00113 00114 /* Find cryptosystem to use */ 00115 for_each_table_entry ( tbl_crypto, NET80211_CRYPTOS ) { 00116 if ( tbl_crypto->algorithm == crypt ) { 00117 crypto = zalloc ( sizeof ( *crypto ) + 00118 tbl_crypto->priv_len ); 00119 if ( ! crypto ) { 00120 DBG ( "802.11-Sec out of memory\n" ); 00121 return -ENOMEM; 00122 } 00123 00124 memcpy ( crypto, tbl_crypto, sizeof ( *crypto ) ); 00125 crypto->priv = ( ( void * ) crypto + 00126 sizeof ( *crypto ) ); 00127 break; 00128 } 00129 } 00130 00131 if ( ! crypto ) { 00132 DBG ( "802.11-Sec no support for cryptosystem %d\n", crypt ); 00133 return -( ENOTSUP | EUNIQ_10 | ( crypt << 8 ) ); 00134 } 00135 00136 *which = crypto; 00137 00138 DBG ( "802.11-Sec installing cryptosystem %d as %p with key of " 00139 "length %d\n", crypt, crypto, len ); 00140 00141 return crypto->init ( crypto, key, len, rsc ); 00142 }
| static struct descriptor_map* rsn_pick_desc | ( | u8 ** | rsnp, | |
| u8 * | rsn_end, | |||
| struct descriptor_map * | map, | |||
| void * | tbl_start, | |||
| void * | tbl_end | |||
| ) | [static, read] |
Determine net80211 crypto or handshaking type value to return for RSN info.
| rsnp | Pointer to next descriptor count field in RSN IE | |
| rsn_end | Pointer to end of RSN IE | |
| map | Descriptor map to use | |
| tbl_start | Start of linker table to examine for gPXE support | |
| tbl_end | End of linker table to examine for gPXE support |
| rsnp | Updated to point to first byte after descriptors | |
| map_ent | Descriptor map entry of translation to use |
This function expects rsnp to point at a two-byte descriptor count followed by a list of four-byte cipher or AKM descriptors; it will return NULL if the input packet is malformed, and otherwise set rsnp to the first byte it has not looked at. It will return the first cipher in the list that is supported by the current build of gPXE, or the first of all if none are supported.
We play rather fast and loose with type checking, because this function is only called from two well-defined places in the RSN-checking code. Don't try to use it for anything else.
Definition at line 171 of file sec80211.c.
Referenced by sec80211_detect_ie().
00174 { 00175 int ndesc; 00176 int ok = 0; 00177 struct descriptor_map *map_ent, *map_ret = NULL; 00178 u8 *rsn = *rsnp; 00179 void *tblp; 00180 size_t tbl_stride = ( map == rsn_cipher_map ? 00181 sizeof ( struct net80211_crypto ) : 00182 sizeof ( struct net80211_handshaker ) ); 00183 00184 if ( map != rsn_cipher_map && map != rsn_akm_map ) 00185 return NULL; 00186 00187 /* Determine which types we support */ 00188 for ( tblp = tbl_start; tblp < tbl_end; tblp += tbl_stride ) { 00189 struct net80211_crypto *crypto = tblp; 00190 struct net80211_handshaker *hs = tblp; 00191 00192 if ( map == rsn_cipher_map ) 00193 ok |= ( 1 << crypto->algorithm ); 00194 else 00195 ok |= ( 1 << hs->protocol ); 00196 } 00197 00198 /* RSN sanity checks */ 00199 if ( rsn + 2 > rsn_end ) { 00200 DBG ( "RSN detect: malformed descriptor count\n" ); 00201 return NULL; 00202 } 00203 00204 ndesc = *( u16 * ) rsn; 00205 rsn += 2; 00206 00207 if ( ! ndesc ) { 00208 DBG ( "RSN detect: no descriptors\n" ); 00209 return NULL; 00210 } 00211 00212 /* Determine which net80211 crypto types are listed */ 00213 while ( ndesc-- ) { 00214 u32 desc; 00215 00216 if ( rsn + 4 > rsn_end ) { 00217 DBG ( "RSN detect: malformed descriptor (%d left)\n", 00218 ndesc ); 00219 return NULL; 00220 } 00221 00222 desc = *( u32 * ) rsn; 00223 rsn += 4; 00224 00225 for ( map_ent = map; map_ent->oui_type != END_MAGIC; map_ent++ ) 00226 if ( map_ent->oui_type == ( desc & OUI_TYPE_MASK ) ) 00227 break; 00228 00229 /* Use first cipher as a fallback */ 00230 if ( ! map_ret ) 00231 map_ret = map_ent; 00232 00233 /* Once we find one we support, use it */ 00234 if ( ok & ( 1 << map_ent->net80211_type ) ) { 00235 map_ret = map_ent; 00236 break; 00237 } 00238 } 00239 00240 if ( ndesc > 0 ) 00241 rsn += 4 * ndesc; 00242 00243 *rsnp = rsn; 00244 return map_ret; 00245 }
| u8* sec80211_find_rsn | ( | union ieee80211_ie * | ie, | |
| void * | ie_end, | |||
| int * | is_rsn, | |||
| u8 ** | end | |||
| ) |
Find the RSN or WPA information element in the provided beacon frame.
| ie | Pointer to first information element to check | |
| ie_end | Pointer to end of information element space |
| is_rsn | TRUE if returned IE is RSN, FALSE if it's WPA | |
| end | Pointer to byte immediately after last byte of data | |
| data | Pointer to first byte of data (the `version' field) |
If no RSN or WPA infomration element is found, returns NULL and leaves is_rsn and end in an undefined state.
This function will not return a pointer to an information element that states it extends past the tail of the io_buffer, or whose version field is incorrect.
Definition at line 268 of file sec80211.c.
References DBG, ieee80211_ie_bound(), IEEE80211_IE_RSN, IEEE80211_IE_VENDOR, ieee80211_next_ie(), IEEE80211_RSN_VERSION, IEEE80211_WPA_OUI_VEN, NULL, u16, and u8.
Referenced by _sec80211_detect(), wpa_handle_3_of_4(), wpa_make_rsn_ie(), and wpa_start().
00270 { 00271 u8 *rsn = NULL; 00272 00273 if ( ! ieee80211_ie_bound ( ie, ie_end ) ) 00274 return NULL; 00275 00276 while ( ie ) { 00277 if ( ie->id == IEEE80211_IE_VENDOR && 00278 ie->vendor.oui == IEEE80211_WPA_OUI_VEN ) { 00279 DBG ( "RSN detect: old-style WPA IE found\n" ); 00280 rsn = &ie->vendor.data[0]; 00281 *end = rsn + ie->len - 4; 00282 *is_rsn = 0; 00283 } else if ( ie->id == IEEE80211_IE_RSN ) { 00284 DBG ( "RSN detect: 802.11i RSN IE found\n" ); 00285 rsn = ( u8 * ) &ie->rsn.version; 00286 *end = rsn + ie->len; 00287 *is_rsn = 1; 00288 } 00289 00290 if ( rsn && ( *end > ( u8 * ) ie_end || rsn >= *end || 00291 *( u16 * ) rsn != IEEE80211_RSN_VERSION ) ) { 00292 DBG ( "RSN detect: malformed RSN IE or unknown " 00293 "version, keep trying\n" ); 00294 rsn = NULL; 00295 } 00296 00297 if ( rsn ) 00298 break; 00299 00300 ie = ieee80211_next_ie ( ie, ie_end ); 00301 } 00302 00303 if ( ! ie ) { 00304 DBG ( "RSN detect: no RSN IE found\n" ); 00305 return NULL; 00306 } 00307 00308 return rsn; 00309 }
| int sec80211_detect_ie | ( | int | is_rsn, | |
| u8 * | start, | |||
| u8 * | end, | |||
| enum net80211_security_proto * | secprot, | |||
| enum net80211_crypto_alg * | crypt | |||
| ) |
Detect crypto and AKM types from RSN information element.
| is_rsn | If TRUE, IE is a new-style RSN information element | |
| start | Pointer to first byte of version field | |
| end | Pointer to first byte not in the RSN IE |
| secprot | Security handshaking protocol used by network | |
| crypt | Cryptosystem used by network | |
| rc | Return status code |
Definition at line 325 of file sec80211.c.
References cr, DBG, EINVAL, NET80211_CRYPT_CCMP, NET80211_CRYPT_TKIP, NET80211_CRYPTOS, NET80211_HANDSHAKERS, NET80211_SECPROT_EAP, descriptor_map::net80211_type, rsn_pick_desc(), table_end, table_start, and u8.
Referenced by _sec80211_detect(), and wpa_handle_3_of_4().
00328 { 00329 enum net80211_security_proto sp; 00330 enum net80211_crypto_alg cr; 00331 struct descriptor_map *map; 00332 u8 *rsn = start; 00333 00334 /* Set some defaults */ 00335 cr = ( is_rsn ? NET80211_CRYPT_CCMP : NET80211_CRYPT_TKIP ); 00336 sp = NET80211_SECPROT_EAP; 00337 00338 rsn += 2; /* version - already checked */ 00339 rsn += 4; /* group cipher - we don't use it here */ 00340 00341 if ( rsn >= end ) 00342 goto done; 00343 00344 /* Pick crypto algorithm */ 00345 map = rsn_pick_desc ( &rsn, end, rsn_cipher_map, 00346 table_start ( NET80211_CRYPTOS ), 00347 table_end ( NET80211_CRYPTOS ) ); 00348 if ( ! map ) 00349 goto invalid_rsn; 00350 00351 cr = map->net80211_type; 00352 00353 if ( rsn >= end ) 00354 goto done; 00355 00356 /* Pick handshaking algorithm */ 00357 map = rsn_pick_desc ( &rsn, end, rsn_akm_map, 00358 table_start ( NET80211_HANDSHAKERS ), 00359 table_end ( NET80211_HANDSHAKERS ) ); 00360 if ( ! map ) 00361 goto invalid_rsn; 00362 00363 sp = map->net80211_type; 00364 00365 done: 00366 DBG ( "RSN detect: OK, crypto type %d, secprot type %d\n", cr, sp ); 00367 *secprot = sp; 00368 *crypt = cr; 00369 return 0; 00370 00371 invalid_rsn: 00372 DBG ( "RSN detect: invalid RSN IE\n" ); 00373 return -EINVAL; 00374 }
| int _sec80211_detect | ( | struct io_buffer * | iob, | |
| enum net80211_security_proto * | secprot, | |||
| enum net80211_crypto_alg * | crypt | |||
| ) |
Detect the cryptosystem and handshaking protocol used by an 802.11 network.
| iob | I/O buffer containing beacon frame |
| secprot | Security handshaking protocol used by network | |
| crypt | Cryptosystem used by network | |
| rc | Return status code |
NULL before calling it. If it does not exist, any network with the PRIVACY bit set in beacon->capab should be considered unknown.
Definition at line 391 of file sec80211.c.
References ieee80211_frame::data, io_buffer::data, DBG, DBG_HD, ieee80211_beacon, IEEE80211_CAPAB_PRIVACY, NET80211_CRYPT_NONE, NET80211_CRYPT_UNKNOWN, NET80211_CRYPT_WEP, NET80211_SECPROT_NONE, NET80211_SECPROT_UNKNOWN, sec80211_detect_ie(), sec80211_find_rsn(), io_buffer::tail, and u8.
Referenced by sec80211_detect().
00394 { 00395 struct ieee80211_frame *hdr = iob->data; 00396 struct ieee80211_beacon *beacon = 00397 ( struct ieee80211_beacon * ) hdr->data; 00398 u8 *rsn, *rsn_end; 00399 int is_rsn, rc; 00400 00401 *crypt = NET80211_CRYPT_UNKNOWN; 00402 *secprot = NET80211_SECPROT_UNKNOWN; 00403 00404 /* Find RSN or WPA IE */ 00405 if ( ! ( rsn = sec80211_find_rsn ( beacon->info_element, iob->tail, 00406 &is_rsn, &rsn_end ) ) ) { 00407 /* No security IE at all; either WEP or no security. */ 00408 *secprot = NET80211_SECPROT_NONE; 00409 00410 if ( beacon->capability & IEEE80211_CAPAB_PRIVACY ) 00411 *crypt = NET80211_CRYPT_WEP; 00412 else 00413 *crypt = NET80211_CRYPT_NONE; 00414 00415 return 0; 00416 } 00417 00418 /* Determine type of security */ 00419 if ( ( rc = sec80211_detect_ie ( is_rsn, rsn, rsn_end, secprot, 00420 crypt ) ) == 0 ) 00421 return 0; 00422 00423 /* If we get here, the RSN IE was invalid */ 00424 00425 *crypt = NET80211_CRYPT_UNKNOWN; 00426 *secprot = NET80211_SECPROT_UNKNOWN; 00427 DBG ( "Failed to handle RSN IE:\n" ); 00428 DBG_HD ( rsn, rsn_end - rsn ); 00429 return rc; 00430 }
| static u32 rsn_get_desc | ( | unsigned | id, | |
| int | rsnie, | |||
| struct descriptor_map * | map | |||
| ) | [static] |
Determine RSN descriptor for specified net80211 ID.
| id | net80211 ID value | |
| rsnie | Whether to return a new-format (RSN IE) descriptor | |
| map | Map to use in translation |
| desc | RSN descriptor, or 0 on error |
Definition at line 444 of file sec80211.c.
References END_MAGIC, IEEE80211_RSN_OUI, IEEE80211_WPA_OUI, descriptor_map::net80211_type, descriptor_map::oui_type, u32, and vendor.
Referenced by sec80211_rsn_get_akm_desc(), and sec80211_rsn_get_crypto_desc().
00445 { 00446 u32 vendor = ( rsnie ? IEEE80211_RSN_OUI : IEEE80211_WPA_OUI ); 00447 00448 for ( ; map->oui_type != END_MAGIC; map++ ) { 00449 if ( map->net80211_type == id ) 00450 return map->oui_type | vendor; 00451 } 00452 00453 return 0; 00454 }
| u32 sec80211_rsn_get_crypto_desc | ( | enum net80211_crypto_alg | crypt, | |
| int | rsnie | |||
| ) |
Determine RSN descriptor for specified net80211 cryptosystem number.
| crypt | Cryptosystem number | |
| rsnie | Whether to return a new-format (RSN IE) descriptor |
| desc | RSN descriptor |
Definition at line 466 of file sec80211.c.
References rsn_get_desc().
Referenced by wpa_make_rsn_ie().
00467 { 00468 return rsn_get_desc ( crypt, rsnie, rsn_cipher_map ); 00469 }
| u32 sec80211_rsn_get_akm_desc | ( | enum net80211_security_proto | secprot, | |
| int | rsnie | |||
| ) |
Determine RSN descriptor for specified net80211 handshaker number.
| secprot | Handshaker number | |
| rsnie | Whether to return a new-format (RSN IE) descriptor |
| desc | RSN descriptor |
Definition at line 481 of file sec80211.c.
References rsn_get_desc().
Referenced by wpa_make_rsn_ie().
00483 { 00484 return rsn_get_desc ( secprot, rsnie, rsn_akm_map ); 00485 }
| enum net80211_crypto_alg sec80211_rsn_get_net80211_crypt | ( | u32 | desc | ) |
Determine net80211 cryptosystem number from RSN descriptor.
| desc | RSN descriptor |
| crypt | net80211 cryptosystem enumeration value |
Definition at line 493 of file sec80211.c.
References END_MAGIC, descriptor_map::net80211_type, descriptor_map::oui_type, and OUI_TYPE_MASK.
Referenced by wpa_handle_3_of_4(), and wpa_make_rsn_ie().
00494 { 00495 struct descriptor_map *map = rsn_cipher_map; 00496 00497 for ( ; map->oui_type != END_MAGIC; map++ ) { 00498 if ( map->oui_type == ( desc & OUI_TYPE_MASK ) ) 00499 break; 00500 } 00501 00502 return map->net80211_type; 00503 }
struct descriptor_map rsn_cipher_map[] [static] |
Initial value:
{
{ .net80211_type = NET80211_CRYPT_WEP,
.oui_type = IEEE80211_RSN_CTYPE_WEP40 },
{ .net80211_type = NET80211_CRYPT_WEP,
.oui_type = IEEE80211_RSN_CTYPE_WEP104 },
{ .net80211_type = NET80211_CRYPT_TKIP,
.oui_type = IEEE80211_RSN_CTYPE_TKIP },
{ .net80211_type = NET80211_CRYPT_CCMP,
.oui_type = IEEE80211_RSN_CTYPE_CCMP },
{ .net80211_type = NET80211_CRYPT_UNKNOWN,
.oui_type = END_MAGIC },
}
Definition at line 50 of file sec80211.c.
struct descriptor_map rsn_akm_map[] [static] |
Initial value:
{
{ .net80211_type = NET80211_SECPROT_EAP,
.oui_type = IEEE80211_RSN_ATYPE_8021X },
{ .net80211_type = NET80211_SECPROT_PSK,
.oui_type = IEEE80211_RSN_ATYPE_PSK },
{ .net80211_type = NET80211_SECPROT_UNKNOWN,
.oui_type = END_MAGIC },
}
Definition at line 68 of file sec80211.c.
1.5.7.1