#include <gpxe/net80211.h>
#include <gpxe/sec80211.h>
#include <gpxe/wpa.h>
#include <gpxe/eapol.h>
#include <gpxe/crypto.h>
#include <gpxe/arc4.h>
#include <gpxe/crc32.h>
#include <gpxe/sha1.h>
#include <gpxe/hmac.h>
#include <gpxe/list.h>
#include <gpxe/ethernet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
Go to the source code of this file.
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| static int | wpa_fail (struct wpa_common_ctx *ctx, int rc) |
| Return an error code and deauthenticate. | |
| static struct net80211_crypto * | wpa_find_cryptosystem (enum net80211_crypto_alg crypt) |
| Find a cryptosystem handler structure from a crypto ID. | |
| struct wpa_kie * | wpa_find_kie (int version) |
| Find WPA key integrity and encryption handler from key version field. | |
| int | wpa_make_rsn_ie (struct net80211_device *dev, union ieee80211_ie **ie_ret) |
| Construct RSN or WPA information element. | |
| int | wpa_start (struct net80211_device *dev, struct wpa_common_ctx *ctx, const void *pmk, size_t pmk_len) |
| Set up generic WPA support to handle 4-Way Handshake. | |
| void | wpa_stop (struct net80211_device *dev) |
| Disable handling of received WPA handshake frames. | |
| int | wpa_check_pmkid (struct wpa_common_ctx *ctx, const u8 *pmkid) |
| Check PMKID consistency. | |
| static void | wpa_derive_ptk (struct wpa_common_ctx *ctx) |
| Derive pairwise transient key. | |
| static int | wpa_install_ptk (struct wpa_common_ctx *ctx, int len) |
| Install pairwise transient key. | |
| static int | wpa_install_gtk (struct wpa_common_ctx *ctx, int len, const void *rsc) |
| Install group transient key. | |
| static int | wpa_maybe_install_gtk (struct wpa_common_ctx *ctx, union ieee80211_ie *ie, void *ie_end, const void *rsc) |
| Search for group transient key, and install it if found. | |
| static struct io_buffer * | wpa_alloc_frame (int kdlen) |
| Allocate I/O buffer for construction of outgoing EAPOL-Key frame. | |
| static int | wpa_send_eapol (struct io_buffer *iob, struct wpa_common_ctx *ctx, struct wpa_kie *kie) |
| Send EAPOL-Key packet. | |
| static int | wpa_send_2_of_4 (struct wpa_common_ctx *ctx, struct eapol_key_pkt *pkt, int is_rsn, struct wpa_kie *kie) |
| Send second frame in 4-Way Handshake. | |
| static int | wpa_handle_1_of_4 (struct wpa_common_ctx *ctx, struct eapol_key_pkt *pkt, int is_rsn, struct wpa_kie *kie) |
| Handle receipt of first frame in 4-Way Handshake. | |
| static int | wpa_send_final (struct wpa_common_ctx *ctx, struct eapol_key_pkt *pkt, int is_rsn, struct wpa_kie *kie) |
| Send fourth frame in 4-Way Handshake, or second in Group Key Handshake. | |
| static int | wpa_handle_3_of_4 (struct wpa_common_ctx *ctx, struct eapol_key_pkt *pkt, int is_rsn, struct wpa_kie *kie) |
| Handle receipt of third frame in 4-Way Handshake. | |
| static int | wpa_handle_1_of_2 (struct wpa_common_ctx *ctx, struct eapol_key_pkt *pkt, int is_rsn, struct wpa_kie *kie) |
| Handle receipt of first frame in Group Key Handshake. | |
| static int | eapol_key_rx (struct io_buffer *iob, struct net_device *netdev, const void *ll_source) |
| Handle receipt of EAPOL-Key frame for WPA. | |
| REQUIRE_OBJECT (eapol) | |
Variables | |
| struct list_head | wpa_contexts = LIST_HEAD_INIT ( wpa_contexts ) |
| List of WPA contexts in active use. | |
| struct eapol_handler eapol_key_handler | __eapol_handler |
Definition in file wpa.c.
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| static int wpa_fail | ( | struct wpa_common_ctx * | ctx, | |
| int | rc | |||
| ) | [static] |
Return an error code and deauthenticate.
| ctx | WPA common context | |
| rc | Return status code |
| rc | The passed return status code |
Definition at line 53 of file wpa.c.
References wpa_common_ctx::dev, and net80211_deauthenticate().
Referenced by eapol_key_rx(), wpa_handle_1_of_2(), wpa_handle_1_of_4(), and wpa_handle_3_of_4().
00054 { 00055 net80211_deauthenticate ( ctx->dev, rc ); 00056 return rc; 00057 }
| static struct net80211_crypto* wpa_find_cryptosystem | ( | enum net80211_crypto_alg | crypt | ) | [static, read] |
Find a cryptosystem handler structure from a crypto ID.
| crypt | Cryptosystem ID |
| crypto | Cryptosystem handler structure |
NULL.
Definition at line 70 of file wpa.c.
References net80211_crypto::algorithm, for_each_table_entry, NET80211_CRYPTOS, and NULL.
Referenced by wpa_make_rsn_ie().
00071 { 00072 struct net80211_crypto *crypto; 00073 00074 for_each_table_entry ( crypto, NET80211_CRYPTOS ) { 00075 if ( crypto->algorithm == crypt ) 00076 return crypto; 00077 } 00078 00079 return NULL; 00080 }
| struct wpa_kie* wpa_find_kie | ( | int | version | ) | [read] |
Find WPA key integrity and encryption handler from key version field.
| ver | Version bits of EAPOL-Key info field |
| kie | Key integrity and encryption handler |
Definition at line 89 of file wpa.c.
References for_each_table_entry, NULL, wpa_kie::version, and WPA_KIES.
Referenced by eapol_key_rx().
00090 { 00091 struct wpa_kie *kie; 00092 00093 for_each_table_entry ( kie, WPA_KIES ) { 00094 if ( kie->version == version ) 00095 return kie; 00096 } 00097 00098 return NULL; 00099 }
| int wpa_make_rsn_ie | ( | struct net80211_device * | dev, | |
| union ieee80211_ie ** | ie_ret | |||
| ) |
Construct RSN or WPA information element.
| dev | 802.11 device |
| ie_ret | RSN or WPA information element | |
| rc | Return status code |
dev->associating. If it is impossible to construct an information element consistent with gPXE's capabilities that is compatible with that network, or if none should be sent because that network's beacon included no security information, returns an error indication and leaves ie_ret unchanged.The returned IE will be of the same type (RSN or WPA) as was included in the beacon for the network it is destined for.
Definition at line 121 of file wpa.c.
References ieee80211_ie_rsn::akm_count, ieee80211_ie_rsn::akm_list, net80211_device::associating, net80211_wlan::beacon, net80211_wlan::crypto, ieee80211_frame::data, io_buffer::data, DBG, EINVAL, ENOMEM, ENOTSUP, ieee80211_ie_rsn::group_cipher, net80211_wlan::handshaking, ieee80211_beacon, IEEE80211_IE_RSN, IEEE80211_IE_VENDOR, ieee80211_rsn_size(), IEEE80211_RSN_VERSION, IEEE80211_WPA_OUI_VEN, malloc(), ieee80211_ie_rsn::pairwise_cipher, ieee80211_ie_rsn::pairwise_count, ieee80211_ie_rsn::pmkid_count, ieee80211_ie_rsn::rsn_capab, sec80211_find_rsn(), sec80211_rsn_get_akm_desc(), sec80211_rsn_get_crypto_desc(), sec80211_rsn_get_net80211_crypt(), io_buffer::tail, u32, u8, ieee80211_ie_rsn::version, and wpa_find_cryptosystem().
Referenced by wpa_psk_init().
00122 { 00123 u8 *rsn, *rsn_end; 00124 int is_rsn; 00125 u32 group_cipher; 00126 enum net80211_crypto_alg gcrypt; 00127 int ie_len; 00128 u8 *iep; 00129 struct ieee80211_ie_rsn *ie; 00130 struct ieee80211_frame *hdr; 00131 struct ieee80211_beacon *beacon; 00132 00133 if ( ! dev->associating ) { 00134 DBG ( "WPA: Can't make RSN IE for a non-associating device\n" ); 00135 return -EINVAL; 00136 } 00137 00138 hdr = dev->associating->beacon->data; 00139 beacon = ( struct ieee80211_beacon * ) hdr->data; 00140 rsn = sec80211_find_rsn ( beacon->info_element, 00141 dev->associating->beacon->tail, &is_rsn, 00142 &rsn_end ); 00143 if ( ! rsn ) { 00144 DBG ( "WPA: Can't make RSN IE when we didn't get one\n" ); 00145 return -EINVAL; 00146 } 00147 00148 rsn += 2; /* skip version */ 00149 group_cipher = *( u32 * ) rsn; 00150 gcrypt = sec80211_rsn_get_net80211_crypt ( group_cipher ); 00151 00152 if ( ! wpa_find_cryptosystem ( gcrypt ) || 00153 ! wpa_find_cryptosystem ( dev->associating->crypto ) ) { 00154 DBG ( "WPA: No support for (GC:%d, PC:%d)\n", 00155 gcrypt, dev->associating->crypto ); 00156 return -ENOTSUP; 00157 } 00158 00159 /* Everything looks good - make our IE. */ 00160 00161 /* WPA IEs need 4 more bytes for the OUI+type */ 00162 ie_len = ieee80211_rsn_size ( 1, 1, 0, is_rsn ) + ( 4 * ! is_rsn ); 00163 iep = malloc ( ie_len ); 00164 if ( ! iep ) 00165 return -ENOMEM; 00166 00167 *ie_ret = ( union ieee80211_ie * ) iep; 00168 00169 /* Store ID and length bytes. */ 00170 *iep++ = ( is_rsn ? IEEE80211_IE_RSN : IEEE80211_IE_VENDOR ); 00171 *iep++ = ie_len - 2; 00172 00173 /* Store OUI+type for WPA IEs. */ 00174 if ( ! is_rsn ) { 00175 *( u32 * ) iep = IEEE80211_WPA_OUI_VEN; 00176 iep += 4; 00177 } 00178 00179 /* If this is a WPA IE, the id and len bytes in the 00180 ieee80211_ie_rsn structure will not be valid, but by doing 00181 the cast we can fill all the other fields much more 00182 readily. */ 00183 00184 ie = ( struct ieee80211_ie_rsn * ) ( iep - 2 ); 00185 ie->version = IEEE80211_RSN_VERSION; 00186 ie->group_cipher = group_cipher; 00187 ie->pairwise_count = 1; 00188 ie->pairwise_cipher[0] = 00189 sec80211_rsn_get_crypto_desc ( dev->associating->crypto, 00190 is_rsn ); 00191 ie->akm_count = 1; 00192 ie->akm_list[0] = 00193 sec80211_rsn_get_akm_desc ( dev->associating->handshaking, 00194 is_rsn ); 00195 if ( is_rsn ) { 00196 ie->rsn_capab = 0; 00197 ie->pmkid_count = 0; 00198 } 00199 00200 return 0; 00201 }
| int wpa_start | ( | struct net80211_device * | dev, | |
| struct wpa_common_ctx * | ctx, | |||
| const void * | pmk, | |||
| size_t | pmk_len | |||
| ) |
Set up generic WPA support to handle 4-Way Handshake.
| dev | 802.11 device | |
| ctx | WPA common context | |
| pmk | Pairwise Master Key to use for session | |
| pmk_len | Length of PMK, almost always 32 |
| rc | Return status code |
Definition at line 213 of file wpa.c.
References wpa_common_ctx::ap_rsn_ie, wpa_common_ctx::ap_rsn_ie_len, wpa_common_ctx::ap_rsn_is_rsn, net80211_device::associating, net80211_wlan::beacon, wpa_common_ctx::crypt, net80211_wlan::crypto, ieee80211_frame::data, io_buffer::data, wpa_common_ctx::dev, EINVAL, ENOENT, ENOMEM, wpa_common_ctx::gcrypt, ieee80211_beacon, wpa_common_ctx::list, list_add_tail, malloc(), memcpy, NET80211_CRYPT_UNKNOWN, NULL, wpa_common_ctx::pmk, wpa_common_ctx::pmk_len, wpa_common_ctx::replay, net80211_device::rsn_ie, sec80211_find_rsn(), wpa_common_ctx::state, io_buffer::tail, u8, and WPA_READY.
Referenced by wpa_psk_start().
00215 { 00216 struct io_buffer *iob; 00217 struct ieee80211_frame *hdr; 00218 struct ieee80211_beacon *beacon; 00219 u8 *ap_rsn_ie = NULL, *ap_rsn_ie_end; 00220 00221 if ( ! dev->rsn_ie || ! dev->associating ) 00222 return -EINVAL; 00223 00224 ctx->dev = dev; 00225 memcpy ( ctx->pmk, pmk, ctx->pmk_len = pmk_len ); 00226 ctx->state = WPA_READY; 00227 ctx->replay = ~0ULL; 00228 00229 iob = dev->associating->beacon; 00230 hdr = iob->data; 00231 beacon = ( struct ieee80211_beacon * ) hdr->data; 00232 ap_rsn_ie = sec80211_find_rsn ( beacon->info_element, iob->tail, 00233 &ctx->ap_rsn_is_rsn, &ap_rsn_ie_end ); 00234 if ( ap_rsn_ie ) { 00235 ctx->ap_rsn_ie = malloc ( ap_rsn_ie_end - ap_rsn_ie ); 00236 if ( ! ctx->ap_rsn_ie ) 00237 return -ENOMEM; 00238 memcpy ( ctx->ap_rsn_ie, ap_rsn_ie, ap_rsn_ie_end - ap_rsn_ie ); 00239 ctx->ap_rsn_ie_len = ap_rsn_ie_end - ap_rsn_ie; 00240 } else { 00241 return -ENOENT; 00242 } 00243 00244 ctx->crypt = dev->associating->crypto; 00245 ctx->gcrypt = NET80211_CRYPT_UNKNOWN; 00246 00247 list_add_tail ( &ctx->list, &wpa_contexts ); 00248 return 0; 00249 }
| void wpa_stop | ( | struct net80211_device * | dev | ) |
Disable handling of received WPA handshake frames.
| dev | 802.11 device |
Definition at line 257 of file wpa.c.
References wpa_common_ctx::ap_rsn_ie, wpa_common_ctx::dev, free(), wpa_common_ctx::list, list_del, list_for_each_entry_safe, and NULL.
Referenced by wpa_psk_stop().
00258 { 00259 struct wpa_common_ctx *ctx, *tmp; 00260 00261 list_for_each_entry_safe ( ctx, tmp, &wpa_contexts, list ) { 00262 if ( ctx->dev == dev ) { 00263 free ( ctx->ap_rsn_ie ); 00264 ctx->ap_rsn_ie = NULL; 00265 list_del ( &ctx->list ); 00266 } 00267 } 00268 }
| int wpa_check_pmkid | ( | struct wpa_common_ctx * | ctx, | |
| const u8 * | pmkid | |||
| ) |
Check PMKID consistency.
| ctx | WPA common context | |
| pmkid | PMKID to check against (16 bytes long) |
| rc | Zero if they match, or a negative error code if not |
Definition at line 278 of file wpa.c.
References __attribute__, net80211_device::bssid, wpa_common_ctx::dev, EACCES, ETH_ALEN, hmac_final(), hmac_init(), hmac_update(), net_device::ll_addr, memcmp(), memcpy, name, net80211_device::netdev, packed, wpa_common_ctx::pmk, wpa_common_ctx::pmk_len, sha1_algorithm, SHA1_CTX_SIZE, SHA1_SIZE, u8, and WPA_PMKID_LEN.
Referenced by wpa_handle_1_of_4().
00279 { 00280 u8 sha1_ctx[SHA1_CTX_SIZE]; 00281 u8 my_pmkid[SHA1_SIZE]; 00282 u8 pmk[ctx->pmk_len]; 00283 size_t pmk_len; 00284 struct { 00285 char name[8]; 00286 u8 aa[ETH_ALEN]; 00287 u8 spa[ETH_ALEN]; 00288 } __attribute__ (( packed )) pmkid_data; 00289 00290 memcpy ( pmk, ctx->pmk, ctx->pmk_len ); 00291 pmk_len = ctx->pmk_len; 00292 00293 memcpy ( pmkid_data.name, "PMK Name", 8 ); 00294 memcpy ( pmkid_data.aa, ctx->dev->bssid, ETH_ALEN ); 00295 memcpy ( pmkid_data.spa, ctx->dev->netdev->ll_addr, ETH_ALEN ); 00296 00297 hmac_init ( &sha1_algorithm, sha1_ctx, pmk, &pmk_len ); 00298 hmac_update ( &sha1_algorithm, sha1_ctx, &pmkid_data, 00299 sizeof ( pmkid_data ) ); 00300 hmac_final ( &sha1_algorithm, sha1_ctx, pmk, &pmk_len, my_pmkid ); 00301 00302 if ( memcmp ( my_pmkid, pmkid, WPA_PMKID_LEN ) != 0 ) 00303 return -EACCES; 00304 00305 return 0; 00306 }
| static void wpa_derive_ptk | ( | struct wpa_common_ctx * | ctx | ) | [static] |
Derive pairwise transient key.
| ctx | WPA common context |
Definition at line 314 of file wpa.c.
References __attribute__, wpa_common_ctx::Anonce, net80211_device::bssid, DBGC2, DBGC2_HD, wpa_common_ctx::dev, ETH_ALEN, eth_ntoa(), net_device::ll_addr, memcmp(), memcpy, net80211_device::netdev, packed, wpa_common_ctx::pmk, wpa_common_ctx::pmk_len, prf_sha1(), wpa_common_ctx::ptk, wpa_common_ctx::Snonce, u8, and WPA_NONCE_LEN.
Referenced by wpa_handle_1_of_4().
00315 { 00316 struct { 00317 u8 mac1[ETH_ALEN]; 00318 u8 mac2[ETH_ALEN]; 00319 u8 nonce1[WPA_NONCE_LEN]; 00320 u8 nonce2[WPA_NONCE_LEN]; 00321 } __attribute__ (( packed )) ptk_data; 00322 00323 /* The addresses and nonces are stored in numerical order (!) */ 00324 00325 if ( memcmp ( ctx->dev->netdev->ll_addr, ctx->dev->bssid, 00326 ETH_ALEN ) < 0 ) { 00327 memcpy ( ptk_data.mac1, ctx->dev->netdev->ll_addr, ETH_ALEN ); 00328 memcpy ( ptk_data.mac2, ctx->dev->bssid, ETH_ALEN ); 00329 } else { 00330 memcpy ( ptk_data.mac1, ctx->dev->bssid, ETH_ALEN ); 00331 memcpy ( ptk_data.mac2, ctx->dev->netdev->ll_addr, ETH_ALEN ); 00332 } 00333 00334 if ( memcmp ( ctx->Anonce, ctx->Snonce, WPA_NONCE_LEN ) < 0 ) { 00335 memcpy ( ptk_data.nonce1, ctx->Anonce, WPA_NONCE_LEN ); 00336 memcpy ( ptk_data.nonce2, ctx->Snonce, WPA_NONCE_LEN ); 00337 } else { 00338 memcpy ( ptk_data.nonce1, ctx->Snonce, WPA_NONCE_LEN ); 00339 memcpy ( ptk_data.nonce2, ctx->Anonce, WPA_NONCE_LEN ); 00340 } 00341 00342 DBGC2 ( ctx, "WPA %p A1 %s, A2 %s\n", ctx, eth_ntoa ( ptk_data.mac1 ), 00343 eth_ntoa ( ptk_data.mac2 ) ); 00344 DBGC2 ( ctx, "WPA %p Nonce1, Nonce2:\n", ctx ); 00345 DBGC2_HD ( ctx, ptk_data.nonce1, WPA_NONCE_LEN ); 00346 DBGC2_HD ( ctx, ptk_data.nonce2, WPA_NONCE_LEN ); 00347 00348 prf_sha1 ( ctx->pmk, ctx->pmk_len, 00349 "Pairwise key expansion", 00350 &ptk_data, sizeof ( ptk_data ), 00351 &ctx->ptk, sizeof ( ctx->ptk ) ); 00352 00353 DBGC2 ( ctx, "WPA %p PTK:\n", ctx ); 00354 DBGC2_HD ( ctx, &ctx->ptk, sizeof ( ctx->ptk ) ); 00355 }
| static int wpa_install_ptk | ( | struct wpa_common_ctx * | ctx, | |
| int | len | |||
| ) | [inline, static] |
Install pairwise transient key.
| ctx | WPA common context | |
| len | Key length (16 for CCMP, 32 for TKIP) |
| rc | Return status code |
Definition at line 365 of file wpa.c.
References wpa_common_ctx::crypt, net80211_device::crypto, DBGC, DBGC2_HD, wpa_common_ctx::dev, NULL, wpa_common_ctx::ptk, sec80211_install(), and wpa_ptk::tk.
Referenced by wpa_handle_3_of_4().
00366 { 00367 DBGC ( ctx, "WPA %p: installing %d-byte pairwise transient key\n", 00368 ctx, len ); 00369 DBGC2_HD ( ctx, &ctx->ptk.tk, len ); 00370 00371 return sec80211_install ( &ctx->dev->crypto, ctx->crypt, 00372 &ctx->ptk.tk, len, NULL ); 00373 }
| static int wpa_install_gtk | ( | struct wpa_common_ctx * | ctx, | |
| int | len, | |||
| const void * | rsc | |||
| ) | [inline, static] |
Install group transient key.
| ctx | WPA common context | |
| len | Key length (16 for CCMP, 32 for TKIP) | |
| rsc | Receive sequence counter field in EAPOL-Key packet |
| rc | Return status code |
Definition at line 383 of file wpa.c.
References DBGC, DBGC2_HD, wpa_common_ctx::dev, wpa_common_ctx::gcrypt, net80211_device::gcrypto, wpa_common_ctx::gtk, sec80211_install(), and wpa_gtk::tk.
Referenced by wpa_handle_1_of_2(), and wpa_maybe_install_gtk().
00385 { 00386 DBGC ( ctx, "WPA %p: installing %d-byte group transient key\n", 00387 ctx, len ); 00388 DBGC2_HD ( ctx, &ctx->gtk.tk, len ); 00389 00390 return sec80211_install ( &ctx->dev->gcrypto, ctx->gcrypt, 00391 &ctx->gtk.tk, len, rsc ); 00392 }
| static int wpa_maybe_install_gtk | ( | struct wpa_common_ctx * | ctx, | |
| union ieee80211_ie * | ie, | |||
| void * | ie_end, | |||
| const void * | rsc | |||
| ) | [static] |
Search for group transient key, and install it if found.
| ctx | WPA common context | |
| ie | Pointer to first IE in key data field | |
| ie_end | Pointer to first byte not in key data field | |
| rsc | Receive sequence counter field in EAPOL-Key packet |
| rc | Return status code |
Definition at line 403 of file wpa.c.
References DBGC, EINVAL, ENOENT, wpa_kde_gtk_encap::gtk, wpa_common_ctx::gtk, wpa_kde::gtk_encap, ieee80211_ie::id, ieee80211_ie_bound(), IEEE80211_IE_VENDOR, ieee80211_next_ie(), wpa_kde::len, ieee80211_ie::len, memcpy, ieee80211_ie_vendor::oui, wpa_gtk::tk, ieee80211_ie::vendor, wpa_install_gtk(), and WPA_KDE_GTK.
Referenced by wpa_handle_1_of_2(), and wpa_handle_3_of_4().
00406 { 00407 struct wpa_kde *kde; 00408 00409 if ( ! ieee80211_ie_bound ( ie, ie_end ) ) 00410 return -ENOENT; 00411 00412 while ( ie ) { 00413 if ( ie->id == IEEE80211_IE_VENDOR && 00414 ie->vendor.oui == WPA_KDE_GTK ) 00415 break; 00416 00417 ie = ieee80211_next_ie ( ie, ie_end ); 00418 } 00419 00420 if ( ! ie ) 00421 return -ENOENT; 00422 00423 if ( ie->len - 6u > sizeof ( ctx->gtk.tk ) ) { 00424 DBGC ( ctx, "WPA %p: GTK KDE is too long (%d bytes, max %d)\n", 00425 ctx, ie->len - 4, sizeof ( ctx->gtk.tk ) ); 00426 return -EINVAL; 00427 } 00428 00429 /* XXX We ignore key ID for now. */ 00430 kde = ( struct wpa_kde * ) ie; 00431 memcpy ( &ctx->gtk.tk, &kde->gtk_encap.gtk, kde->len - 6 ); 00432 00433 return wpa_install_gtk ( ctx, kde->len - 6, rsc ); 00434 }
| static struct io_buffer* wpa_alloc_frame | ( | int | kdlen | ) | [static, read] |
Allocate I/O buffer for construction of outgoing EAPOL-Key frame.
| kdlen | Maximum number of bytes in the Key Data field |
| iob | Newly allocated I/O buffer |
iob->tail pointing to the start of the Key Data field. Thus, it is necessary to use iob_put() in filling the Key Data.
Definition at line 448 of file wpa.c.
References alloc_iob(), EAPOL_HDR_LEN, iob_put, iob_reserve, MAX_LL_HEADER_LEN, memset(), and NULL.
Referenced by wpa_send_2_of_4(), and wpa_send_final().
00449 { 00450 struct io_buffer *ret = alloc_iob ( sizeof ( struct eapol_key_pkt ) + 00451 kdlen + EAPOL_HDR_LEN + 00452 MAX_LL_HEADER_LEN ); 00453 if ( ! ret ) 00454 return NULL; 00455 00456 iob_reserve ( ret, MAX_LL_HEADER_LEN + EAPOL_HDR_LEN ); 00457 memset ( iob_put ( ret, sizeof ( struct eapol_key_pkt ) ), 0, 00458 sizeof ( struct eapol_key_pkt ) ); 00459 00460 return ret; 00461 }
| static int wpa_send_eapol | ( | struct io_buffer * | iob, | |
| struct wpa_common_ctx * | ctx, | |||
| struct wpa_kie * | kie | |||
| ) | [static] |
Send EAPOL-Key packet.
| iob | I/O buffer, with sufficient headroom for headers | |
| dev | 802.11 device | |
| kie | Key integrity and encryption handler | |
| is_rsn | If TRUE, handshake uses new RSN format |
| rc | Return status code |
Definition at line 475 of file wpa.c.
References net80211_device::bssid, cpu_to_be64, io_buffer::data, eapol_key_pkt::datalen, wpa_common_ctx::dev, EAPOL_HDR_LEN, EAPOL_THIS_VERSION, EAPOL_TYPE_KEY, htons, eapol_key_pkt::info, iob_push, wpa_ptk::kck, eapol_key_pkt::keysize, eapol_frame::length, memset(), wpa_kie::mic, eapol_key_pkt::mic, net_tx(), net80211_device::netdev, ntohs, wpa_common_ctx::ptk, eapol_key_pkt::replay, io_buffer::tail, eapol_frame::type, and eapol_frame::version.
Referenced by wpa_send_2_of_4(), and wpa_send_final().
00477 { 00478 struct eapol_key_pkt *pkt = iob->data; 00479 struct eapol_frame *eapol = iob_push ( iob, EAPOL_HDR_LEN ); 00480 00481 pkt->info = htons ( pkt->info ); 00482 pkt->keysize = htons ( pkt->keysize ); 00483 pkt->datalen = htons ( pkt->datalen ); 00484 pkt->replay = cpu_to_be64 ( pkt->replay ); 00485 eapol->version = EAPOL_THIS_VERSION; 00486 eapol->type = EAPOL_TYPE_KEY; 00487 eapol->length = htons ( iob->tail - iob->data - sizeof ( *eapol ) ); 00488 00489 memset ( pkt->mic, 0, sizeof ( pkt->mic ) ); 00490 if ( kie ) 00491 kie->mic ( &ctx->ptk.kck, eapol, EAPOL_HDR_LEN + 00492 sizeof ( *pkt ) + ntohs ( pkt->datalen ), 00493 pkt->mic ); 00494 00495 return net_tx ( iob, ctx->dev->netdev, &eapol_protocol, 00496 ctx->dev->bssid ); 00497 }
| static int wpa_send_2_of_4 | ( | struct wpa_common_ctx * | ctx, | |
| struct eapol_key_pkt * | pkt, | |||
| int | is_rsn, | |||
| struct wpa_kie * | kie | |||
| ) | [static] |
Send second frame in 4-Way Handshake.
| ctx | WPA common context | |
| pkt | First frame, to which this is a reply | |
| is_rsn | If TRUE, handshake uses new RSN format | |
| kie | Key integrity and encryption handler |
| rc | Return status code |
Definition at line 509 of file wpa.c.
References io_buffer::data, eapol_key_pkt::datalen, DBGC, wpa_common_ctx::dev, EAPOL_KEY_INFO_KEY_ACK, EAPOL_KEY_INFO_KEY_MIC, ENOMEM, eapol_key_pkt::info, iob_put, eapol_key_pkt::keysize, ieee80211_ie::len, memcpy, eapol_key_pkt::nonce, net80211_device::rsn_ie, wpa_common_ctx::Snonce, wpa_alloc_frame(), and wpa_send_eapol().
Referenced by wpa_handle_1_of_4().
00512 { 00513 struct io_buffer *iob = wpa_alloc_frame ( ctx->dev->rsn_ie->len + 2 ); 00514 struct eapol_key_pkt *npkt; 00515 00516 if ( ! iob ) 00517 return -ENOMEM; 00518 00519 npkt = iob->data; 00520 memcpy ( npkt, pkt, sizeof ( *pkt ) ); 00521 npkt->info &= ~EAPOL_KEY_INFO_KEY_ACK; 00522 npkt->info |= EAPOL_KEY_INFO_KEY_MIC; 00523 if ( is_rsn ) 00524 npkt->keysize = 0; 00525 memcpy ( npkt->nonce, ctx->Snonce, sizeof ( npkt->nonce ) ); 00526 npkt->datalen = ctx->dev->rsn_ie->len + 2; 00527 memcpy ( iob_put ( iob, npkt->datalen ), ctx->dev->rsn_ie, 00528 npkt->datalen ); 00529 00530 DBGC ( ctx, "WPA %p: sending 2/4\n", ctx ); 00531 00532 return wpa_send_eapol ( iob, ctx, kie ); 00533 }
| static int wpa_handle_1_of_4 | ( | struct wpa_common_ctx * | ctx, | |
| struct eapol_key_pkt * | pkt, | |||
| int | is_rsn, | |||
| struct wpa_kie * | kie | |||
| ) | [static] |
Handle receipt of first frame in 4-Way Handshake.
| ctx | WPA common context | |
| pkt | EAPOL-Key packet | |
| is_rsn | If TRUE, frame uses new RSN format | |
| kie | Key integrity and encryption handler |
| rc | Return status code |
Definition at line 545 of file wpa.c.
References wpa_common_ctx::Anonce, ieee80211_ie_vendor::data, eapol_key_pkt::data, eapol_key_pkt::datalen, DBGC, EINVAL, get_random_bytes(), wpa_common_ctx::have_Snonce, ieee80211_ie::id, ieee80211_ie_bound(), IEEE80211_IE_VENDOR, ieee80211_next_ie(), memcpy, eapol_key_pkt::nonce, ieee80211_ie_vendor::oui, wpa_common_ctx::Snonce, wpa_common_ctx::state, ieee80211_ie::vendor, wpa_check_pmkid(), wpa_derive_ptk(), wpa_fail(), WPA_KDE_PMKID, wpa_send_2_of_4(), WPA_WAITING, and WPA_WORKING.
Referenced by eapol_key_rx().
00548 { 00549 int rc; 00550 00551 if ( ctx->state == WPA_WAITING ) 00552 return -EINVAL; 00553 00554 ctx->state = WPA_WORKING; 00555 memcpy ( ctx->Anonce, pkt->nonce, sizeof ( ctx->Anonce ) ); 00556 if ( ! ctx->have_Snonce ) { 00557 get_random_bytes ( ctx->Snonce, sizeof ( ctx->Snonce ) ); 00558 ctx->have_Snonce = 1; 00559 } 00560 00561 if ( is_rsn && pkt->datalen ) { 00562 union ieee80211_ie *ie = ( union ieee80211_ie * ) pkt->data; 00563 void *ie_end = pkt->data + pkt->datalen; 00564 00565 if ( ! ieee80211_ie_bound ( ie, ie_end ) ) { 00566 DBGC ( ctx, "WPA %p: malformed PMKID KDE\n", ctx ); 00567 return wpa_fail ( ctx, -EINVAL ); 00568 } 00569 00570 while ( ie ) { 00571 if ( ie->id == IEEE80211_IE_VENDOR && 00572 ie->vendor.oui == WPA_KDE_PMKID ) { 00573 rc = wpa_check_pmkid ( ctx, ie->vendor.data ); 00574 if ( rc < 0 ) { 00575 DBGC ( ctx, "WPA %p ALERT: PMKID " 00576 "mismatch in 1/4\n", ctx ); 00577 return wpa_fail ( ctx, rc ); 00578 } 00579 } 00580 00581 ie = ieee80211_next_ie ( ie, ie_end ); 00582 } 00583 } 00584 00585 DBGC ( ctx, "WPA %p: received 1/4, looks OK\n", ctx ); 00586 00587 wpa_derive_ptk ( ctx ); 00588 00589 return wpa_send_2_of_4 ( ctx, pkt, is_rsn, kie ); 00590 }
| static int wpa_send_final | ( | struct wpa_common_ctx * | ctx, | |
| struct eapol_key_pkt * | pkt, | |||
| int | is_rsn, | |||
| struct wpa_kie * | kie | |||
| ) | [static] |
Send fourth frame in 4-Way Handshake, or second in Group Key Handshake.
| ctx | WPA common context | |
| pkt | EAPOL-Key packet for frame to which we're replying | |
| is_rsn | If TRUE, frame uses new RSN format | |
| kie | Key integrity and encryption handler |
| rc | Return status code |
Definition at line 602 of file wpa.c.
References io_buffer::data, eapol_key_pkt::datalen, DBGC, EAPOL_KEY_INFO_INSTALL, EAPOL_KEY_INFO_KEY_ACK, EAPOL_KEY_INFO_KEY_ENC, EAPOL_KEY_INFO_TYPE, ENOMEM, eapol_key_pkt::info, eapol_key_pkt::iv, eapol_key_pkt::keysize, memcpy, memset(), eapol_key_pkt::nonce, wpa_alloc_frame(), and wpa_send_eapol().
Referenced by wpa_handle_1_of_2(), and wpa_handle_3_of_4().
00605 { 00606 struct io_buffer *iob = wpa_alloc_frame ( 0 ); 00607 struct eapol_key_pkt *npkt; 00608 00609 if ( ! iob ) 00610 return -ENOMEM; 00611 00612 npkt = iob->data; 00613 memcpy ( npkt, pkt, sizeof ( *pkt ) ); 00614 npkt->info &= ~( EAPOL_KEY_INFO_KEY_ACK | EAPOL_KEY_INFO_INSTALL | 00615 EAPOL_KEY_INFO_KEY_ENC ); 00616 if ( is_rsn ) 00617 npkt->keysize = 0; 00618 memset ( npkt->nonce, 0, sizeof ( npkt->nonce ) ); 00619 memset ( npkt->iv, 0, sizeof ( npkt->iv ) ); 00620 npkt->datalen = 0; 00621 00622 if ( npkt->info & EAPOL_KEY_INFO_TYPE ) 00623 DBGC ( ctx, "WPA %p: sending 4/4\n", ctx ); 00624 else 00625 DBGC ( ctx, "WPA %p: sending 2/2\n", ctx ); 00626 00627 return wpa_send_eapol ( iob, ctx, kie ); 00628 00629 }
| static int wpa_handle_3_of_4 | ( | struct wpa_common_ctx * | ctx, | |
| struct eapol_key_pkt * | pkt, | |||
| int | is_rsn, | |||
| struct wpa_kie * | kie | |||
| ) | [static] |
Handle receipt of third frame in 4-Way Handshake.
| ctx | WPA common context | |
| pkt | EAPOL-Key packet | |
| is_rsn | If TRUE, frame uses new RSN format | |
| kie | Key integrity and encryption handler |
| rc | Return status code |
Definition at line 641 of file wpa.c.
References wpa_common_ctx::Anonce, wpa_common_ctx::ap_rsn_ie, wpa_common_ctx::ap_rsn_ie_len, wpa_common_ctx::ap_rsn_is_rsn, net80211_device::associating, net80211_wlan::crypto, eapol_key_pkt::data, eapol_key_pkt::datalen, DBGC, DBGC2, DBGC2_HD, wpa_common_ctx::dev, EACCES, EAPOL_KEY_INFO_KEY_ENC, EINVAL, ENOENT, wpa_common_ctx::gcrypt, net80211_wlan::handshaking, wpa_common_ctx::have_Snonce, eapol_key_pkt::info, eapol_key_pkt::keysize, memcmp(), eapol_key_pkt::nonce, NULL, eapol_key_pkt::rsc, sec80211_detect_ie(), sec80211_find_rsn(), sec80211_rsn_get_net80211_crypt(), wpa_common_ctx::state, strerror(), u32, u8, wpa_fail(), wpa_install_ptk(), wpa_maybe_install_gtk(), WPA_NONCE_LEN, wpa_send_final(), WPA_SUCCESS, WPA_WAITING, and WPA_WORKING.
Referenced by eapol_key_rx().
00644 { 00645 int rc; 00646 u8 *this_rsn, *this_rsn_end; 00647 u8 *new_rsn, *new_rsn_end; 00648 int this_is_rsn, new_is_rsn; 00649 00650 if ( ctx->state == WPA_WAITING ) 00651 return -EINVAL; 00652 00653 ctx->state = WPA_WORKING; 00654 00655 /* Check nonce */ 00656 if ( memcmp ( ctx->Anonce, pkt->nonce, WPA_NONCE_LEN ) != 0 ) { 00657 DBGC ( ctx, "WPA %p ALERT: nonce mismatch in 3/4\n", ctx ); 00658 return wpa_fail ( ctx, -EACCES ); 00659 } 00660 00661 /* Check RSN IE */ 00662 this_rsn = sec80211_find_rsn ( ( union ieee80211_ie * ) pkt->data, 00663 pkt->data + pkt->datalen, 00664 &this_is_rsn, &this_rsn_end ); 00665 if ( this_rsn ) 00666 new_rsn = sec80211_find_rsn ( ( union ieee80211_ie * ) 00667 this_rsn_end, 00668 pkt->data + pkt->datalen, 00669 &new_is_rsn, &new_rsn_end ); 00670 else 00671 new_rsn = NULL; 00672 00673 if ( ! ctx->ap_rsn_ie || ! this_rsn || 00674 ctx->ap_rsn_ie_len != ( this_rsn_end - this_rsn ) || 00675 ctx->ap_rsn_is_rsn != this_is_rsn || 00676 memcmp ( ctx->ap_rsn_ie, this_rsn, ctx->ap_rsn_ie_len ) != 0 ) { 00677 DBGC ( ctx, "WPA %p ALERT: RSN mismatch in 3/4\n", ctx ); 00678 DBGC2 ( ctx, "WPA %p RSNs (in 3/4, in beacon):\n", ctx ); 00679 DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn ); 00680 DBGC2_HD ( ctx, ctx->ap_rsn_ie, ctx->ap_rsn_ie_len ); 00681 return wpa_fail ( ctx, -EACCES ); 00682 } 00683 00684 /* Don't switch if they just supplied both styles of IE 00685 simultaneously; we need two RSN IEs or two WPA IEs to 00686 switch ciphers. They'll be immediately consecutive because 00687 of ordering guarantees. */ 00688 if ( new_rsn && this_is_rsn == new_is_rsn ) { 00689 struct net80211_wlan *assoc = ctx->dev->associating; 00690 DBGC ( ctx, "WPA %p: accommodating bait-and-switch tactics\n", 00691 ctx ); 00692 DBGC2 ( ctx, "WPA %p RSNs (in 3/4+beacon, new in 3/4):\n", 00693 ctx ); 00694 DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn ); 00695 DBGC2_HD ( ctx, new_rsn, new_rsn_end - new_rsn ); 00696 00697 if ( ( rc = sec80211_detect_ie ( new_is_rsn, new_rsn, 00698 new_rsn_end, 00699 &assoc->handshaking, 00700 &assoc->crypto ) ) != 0 ) 00701 DBGC ( ctx, "WPA %p: bait-and-switch invalid, staying " 00702 "with original request\n", ctx ); 00703 } else { 00704 new_rsn = this_rsn; 00705 new_is_rsn = this_is_rsn; 00706 new_rsn_end = this_rsn_end; 00707 } 00708 00709 /* Grab group cryptosystem ID */ 00710 ctx->gcrypt = sec80211_rsn_get_net80211_crypt ( *( u32 * ) 00711 ( new_rsn + 2 ) ); 00712 00713 /* Check for a GTK, if info field is encrypted */ 00714 if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) { 00715 rc = wpa_maybe_install_gtk ( ctx, 00716 ( union ieee80211_ie * ) pkt->data, 00717 pkt->data + pkt->datalen, 00718 pkt->rsc ); 00719 if ( rc < 0 ) { 00720 DBGC ( ctx, "WPA %p did not install GTK in 3/4: %s\n", 00721 ctx, strerror ( rc ) ); 00722 if ( rc != -ENOENT ) 00723 return wpa_fail ( ctx, rc ); 00724 } 00725 } 00726 00727 DBGC ( ctx, "WPA %p: received 3/4, looks OK\n", ctx ); 00728 00729 /* Send final message */ 00730 rc = wpa_send_final ( ctx, pkt, is_rsn, kie ); 00731 if ( rc < 0 ) 00732 return wpa_fail ( ctx, rc ); 00733 00734 /* Install PTK */ 00735 rc = wpa_install_ptk ( ctx, pkt->keysize ); 00736 if ( rc < 0 ) { 00737 DBGC ( ctx, "WPA %p failed to install PTK: %s\n", ctx, 00738 strerror ( rc ) ); 00739 return wpa_fail ( ctx, rc ); 00740 } 00741 00742 /* Mark us as needing a new Snonce if we rekey */ 00743 ctx->have_Snonce = 0; 00744 00745 /* Done! */ 00746 ctx->state = WPA_SUCCESS; 00747 return 0; 00748 }
| static int wpa_handle_1_of_2 | ( | struct wpa_common_ctx * | ctx, | |
| struct eapol_key_pkt * | pkt, | |||
| int | is_rsn, | |||
| struct wpa_kie * | kie | |||
| ) | [static] |
Handle receipt of first frame in Group Key Handshake.
| ctx | WPA common context | |
| pkt | EAPOL-Key packet | |
| is_rsn | If TRUE, frame uses new RSN format | |
| kie | Key integrity and encryption handler |
| rc | Return status code |
Definition at line 760 of file wpa.c.
References eapol_key_pkt::data, eapol_key_pkt::datalen, DBGC, wpa_kie::decrypt, EAPOL_KEY_INFO_KEY_ENC, EINVAL, wpa_common_ctx::gtk, eapol_key_pkt::info, eapol_key_pkt::iv, wpa_ptk::kek, memcpy, wpa_common_ctx::ptk, eapol_key_pkt::rsc, strerror(), wpa_gtk::tk, wpa_fail(), wpa_install_gtk(), wpa_maybe_install_gtk(), and wpa_send_final().
Referenced by eapol_key_rx().
00763 { 00764 int rc; 00765 00766 /* 00767 * WPA and RSN do this completely differently. 00768 * 00769 * The idea of encoding the GTK (or PMKID, or various other 00770 * things) into a KDE that looks like an information element 00771 * is an RSN innovation; old WPA code never encapsulates 00772 * things like that. If it looks like an info element, it 00773 * really is (for the WPA IE check in frames 2/4 and 3/4). The 00774 * "key data encrypted" bit in the info field is also specific 00775 * to RSN. 00776 * 00777 * So from an old WPA host, 3/4 does not contain an 00778 * encapsulated GTK. The first frame of the GK handshake 00779 * contains it, encrypted, but without a KDE wrapper, and with 00780 * the key ID field (which gPXE doesn't use) shoved away in 00781 * the reserved bits in the info field, and the TxRx bit 00782 * stealing the Install bit's spot. 00783 */ 00784 00785 if ( is_rsn && ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) ) { 00786 rc = wpa_maybe_install_gtk ( ctx, 00787 ( union ieee80211_ie * ) pkt->data, 00788 pkt->data + pkt->datalen, 00789 pkt->rsc ); 00790 if ( rc < 0 ) { 00791 DBGC ( ctx, "WPA %p: failed to install GTK in 1/2: " 00792 "%s\n", ctx, strerror ( rc ) ); 00793 return wpa_fail ( ctx, rc ); 00794 } 00795 } else { 00796 rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data, 00797 &pkt->datalen ); 00798 if ( rc < 0 ) { 00799 DBGC ( ctx, "WPA %p: failed to decrypt GTK: %s\n", 00800 ctx, strerror ( rc ) ); 00801 return rc; /* non-fatal */ 00802 } 00803 if ( pkt->datalen > sizeof ( ctx->gtk.tk ) ) { 00804 DBGC ( ctx, "WPA %p: too much GTK data (%d > %d)\n", 00805 ctx, pkt->datalen, sizeof ( ctx->gtk.tk ) ); 00806 return wpa_fail ( ctx, -EINVAL ); 00807 } 00808 00809 memcpy ( &ctx->gtk.tk, pkt->data, pkt->datalen ); 00810 wpa_install_gtk ( ctx, pkt->datalen, pkt->rsc ); 00811 } 00812 00813 DBGC ( ctx, "WPA %p: received 1/2, looks OK\n", ctx ); 00814 00815 return wpa_send_final ( ctx, pkt, is_rsn, kie ); 00816 }
| static int eapol_key_rx | ( | struct io_buffer * | iob, | |
| struct net_device * | netdev, | |||
| const void * | ll_source | |||
| ) | [static] |
Handle receipt of EAPOL-Key frame for WPA.
| iob | I/O buffer | |
| netdev | Network device | |
| ll_source | Source link-layer address |
Definition at line 826 of file wpa.c.
References be64_to_cpu, net80211_device::bssid, eapol_key_pkt::data, io_buffer::data, eapol_key_pkt::datalen, DBG, DBGC, DBGC2, DBGC2_HD, wpa_kie::decrypt, wpa_common_ctx::dev, EAPOL_HDR_LEN, EAPOL_KEY_INFO_KEY_ACK, EAPOL_KEY_INFO_KEY_ENC, EAPOL_KEY_INFO_KEY_MIC, EAPOL_KEY_INFO_TYPE, EAPOL_KEY_INFO_VERSION, EAPOL_KEY_TYPE_GTK, EAPOL_KEY_TYPE_PTK, EAPOL_KEY_TYPE_RSN, EAPOL_KEY_TYPE_WPA, EINVAL, ENOENT, ENOTSUP, ETH_ALEN, free_iob(), eapol_key_pkt::info, eapol_key_pkt::iv, wpa_ptk::kck, wpa_ptk::kek, eapol_key_pkt::keysize, list_for_each_entry, memcmp(), memcpy, memset(), wpa_kie::mic, eapol_key_pkt::mic, net80211_get(), ntohs, wpa_common_ctx::ptk, wpa_common_ctx::replay, eapol_key_pkt::replay, strerror(), io_buffer::tail, eapol_key_pkt::type, u32, u8, wpa_fail(), wpa_find_kie(), wpa_handle_1_of_2(), wpa_handle_1_of_4(), and wpa_handle_3_of_4().
00828 { 00829 struct net80211_device *dev = net80211_get ( netdev ); 00830 struct eapol_key_pkt *pkt = iob->data; 00831 int is_rsn, found_ctx; 00832 struct wpa_common_ctx *ctx; 00833 int rc = 0; 00834 struct wpa_kie *kie; 00835 u8 their_mic[16], our_mic[16]; 00836 00837 if ( pkt->type != EAPOL_KEY_TYPE_WPA && 00838 pkt->type != EAPOL_KEY_TYPE_RSN ) { 00839 DBG ( "EAPOL-Key: packet not of 802.11 type\n" ); 00840 rc = -EINVAL; 00841 goto drop; 00842 } 00843 00844 is_rsn = ( pkt->type == EAPOL_KEY_TYPE_RSN ); 00845 00846 if ( ! dev ) { 00847 DBG ( "EAPOL-Key: packet not from 802.11\n" ); 00848 rc = -EINVAL; 00849 goto drop; 00850 } 00851 00852 if ( memcmp ( dev->bssid, ll_source, ETH_ALEN ) != 0 ) { 00853 DBG ( "EAPOL-Key: packet not from associated AP\n" ); 00854 rc = -EINVAL; 00855 goto drop; 00856 } 00857 00858 if ( ! ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_ACK ) ) { 00859 DBG ( "EAPOL-Key: packet sent in wrong direction\n" ); 00860 rc = -EINVAL; 00861 goto drop; 00862 } 00863 00864 found_ctx = 0; 00865 list_for_each_entry ( ctx, &wpa_contexts, list ) { 00866 if ( ctx->dev == dev ) { 00867 found_ctx = 1; 00868 break; 00869 } 00870 } 00871 00872 if ( ! found_ctx ) { 00873 DBG ( "EAPOL-Key: no WPA context to handle packet for %p\n", 00874 dev ); 00875 rc = -ENOENT; 00876 goto drop; 00877 } 00878 00879 if ( ( void * ) ( pkt + 1 ) + ntohs ( pkt->datalen ) > iob->tail ) { 00880 DBGC ( ctx, "WPA %p: packet truncated (has %d extra bytes, " 00881 "states %d)\n", ctx, iob->tail - ( void * ) ( pkt + 1 ), 00882 ntohs ( pkt->datalen ) ); 00883 rc = -EINVAL; 00884 goto drop; 00885 } 00886 00887 /* Get a handle on key integrity/encryption handler */ 00888 kie = wpa_find_kie ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION ); 00889 if ( ! kie ) { 00890 DBGC ( ctx, "WPA %p: no support for packet version %d\n", ctx, 00891 ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION ); 00892 rc = wpa_fail ( ctx, -ENOTSUP ); 00893 goto drop; 00894 } 00895 00896 /* Check MIC */ 00897 if ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_MIC ) { 00898 memcpy ( their_mic, pkt->mic, sizeof ( pkt->mic ) ); 00899 memset ( pkt->mic, 0, sizeof ( pkt->mic ) ); 00900 kie->mic ( &ctx->ptk.kck, ( void * ) pkt - EAPOL_HDR_LEN, 00901 EAPOL_HDR_LEN + sizeof ( *pkt ) + 00902 ntohs ( pkt->datalen ), our_mic ); 00903 DBGC2 ( ctx, "WPA %p MIC comparison (theirs, ours):\n", ctx ); 00904 DBGC2_HD ( ctx, their_mic, 16 ); 00905 DBGC2_HD ( ctx, our_mic, 16 ); 00906 if ( memcmp ( their_mic, our_mic, sizeof ( pkt->mic ) ) != 0 ) { 00907 DBGC ( ctx, "WPA %p: EAPOL MIC failure\n", ctx ); 00908 goto drop; 00909 } 00910 } 00911 00912 /* Fix byte order to local */ 00913 pkt->info = ntohs ( pkt->info ); 00914 pkt->keysize = ntohs ( pkt->keysize ); 00915 pkt->datalen = ntohs ( pkt->datalen ); 00916 pkt->replay = be64_to_cpu ( pkt->replay ); 00917 00918 /* Check replay counter */ 00919 if ( ctx->replay != ~0ULL && ctx->replay >= pkt->replay ) { 00920 DBGC ( ctx, "WPA %p ALERT: Replay detected! " 00921 "(%08x:%08x >= %08x:%08x)\n", ctx, 00922 ( u32 ) ( ctx->replay >> 32 ), ( u32 ) ctx->replay, 00923 ( u32 ) ( pkt->replay >> 32 ), ( u32 ) pkt->replay ); 00924 rc = 0; /* ignore without error */ 00925 goto drop; 00926 } 00927 ctx->replay = pkt->replay; 00928 00929 /* Decrypt key data */ 00930 if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) { 00931 rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data, 00932 &pkt->datalen ); 00933 if ( rc < 0 ) { 00934 DBGC ( ctx, "WPA %p: failed to decrypt packet: %s\n", 00935 ctx, strerror ( rc ) ); 00936 goto drop; 00937 } 00938 } 00939 00940 /* Hand it off to appropriate handler */ 00941 switch ( pkt->info & ( EAPOL_KEY_INFO_TYPE | 00942 EAPOL_KEY_INFO_KEY_MIC ) ) { 00943 case EAPOL_KEY_TYPE_PTK: 00944 rc = wpa_handle_1_of_4 ( ctx, pkt, is_rsn, kie ); 00945 break; 00946 00947 case EAPOL_KEY_TYPE_PTK | EAPOL_KEY_INFO_KEY_MIC: 00948 rc = wpa_handle_3_of_4 ( ctx, pkt, is_rsn, kie ); 00949 break; 00950 00951 case EAPOL_KEY_TYPE_GTK | EAPOL_KEY_INFO_KEY_MIC: 00952 rc = wpa_handle_1_of_2 ( ctx, pkt, is_rsn, kie ); 00953 break; 00954 00955 default: 00956 DBGC ( ctx, "WPA %p: Invalid combination of key flags %04x\n", 00957 ctx, pkt->info ); 00958 rc = -EINVAL; 00959 break; 00960 } 00961 00962 drop: 00963 free_iob ( iob ); 00964 return rc; 00965 }
| REQUIRE_OBJECT | ( | eapol | ) |
| struct list_head wpa_contexts = LIST_HEAD_INIT ( wpa_contexts ) |
| struct eapol_handler eapol_key_handler __eapol_handler |
Initial value:
{
.type = EAPOL_TYPE_KEY,
.rx = eapol_key_rx,
}
1.5.7.1