wpa.c File Reference

Handler for the aspects of WPA handshaking that are independent of 802.1X/PSK or TKIP/CCMP; this mostly involves the 4-Way Handshake. More...

#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_cryptowpa_find_cryptosystem (enum net80211_crypto_alg crypt)
 Find a cryptosystem handler structure from a crypto ID.
struct wpa_kiewpa_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_bufferwpa_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


Detailed Description

Handler for the aspects of WPA handshaking that are independent of 802.1X/PSK or TKIP/CCMP; this mostly involves the 4-Way Handshake.

Definition in file wpa.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

static int wpa_fail ( struct wpa_common_ctx ctx,
int  rc 
) [static]

Return an error code and deauthenticate.

Parameters:
ctx WPA common context
rc Return status code
Return values:
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.

Parameters:
crypt Cryptosystem ID
Return values:
crypto Cryptosystem handler structure
If support for crypt is not compiled in to gPXE, or if crypt is NET80211_CRYPT_UNKNOWN, returns 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.

Parameters:
ver Version bits of EAPOL-Key info field
Return values:
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.

Parameters:
dev 802.11 device
Return values:
ie_ret RSN or WPA information element
rc Return status code
This function allocates, fills, and returns a RSN or WPA information element suitable for including in an association request frame to the network identified by 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.

Parameters:
dev 802.11 device
ctx WPA common context
pmk Pairwise Master Key to use for session
pmk_len Length of PMK, almost always 32
Return values:
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.

Parameters:
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.

Parameters:
ctx WPA common context
pmkid PMKID to check against (16 bytes long)
Return values:
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.

Parameters:
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.

Parameters:
ctx WPA common context
len Key length (16 for CCMP, 32 for TKIP)
Return values:
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.

Parameters:
ctx WPA common context
len Key length (16 for CCMP, 32 for TKIP)
rsc Receive sequence counter field in EAPOL-Key packet
Return values:
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.

Parameters:
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
Return values:
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.

Parameters:
kdlen Maximum number of bytes in the Key Data field
Return values:
iob Newly allocated I/O buffer
The returned buffer will have space reserved for the link-layer and EAPOL headers, and will have 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.

Parameters:
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
Return values:
rc Return status code
If a KIE is specified, the MIC will be filled in before transmission.

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.

Parameters:
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
Return values:
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.

Parameters:
ctx WPA common context
pkt EAPOL-Key packet
is_rsn If TRUE, frame uses new RSN format
kie Key integrity and encryption handler
Return values:
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.

Parameters:
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
Return values:
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.

Parameters:
ctx WPA common context
pkt EAPOL-Key packet
is_rsn If TRUE, frame uses new RSN format
kie Key integrity and encryption handler
Return values:
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.

Parameters:
ctx WPA common context
pkt EAPOL-Key packet
is_rsn If TRUE, frame uses new RSN format
kie Key integrity and encryption handler
Return values:
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.

Parameters:
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   ) 


Variable Documentation

struct list_head wpa_contexts = LIST_HEAD_INIT ( wpa_contexts )

List of WPA contexts in active use.

Definition at line 43 of file wpa.c.

struct eapol_handler eapol_key_handler __eapol_handler

Initial value:

 {
        .type = EAPOL_TYPE_KEY,
        .rx = eapol_key_rx,
}

Definition at line 967 of file wpa.c.


Generated on Tue Apr 6 20:01:54 2010 for gPXE by  doxygen 1.5.7.1