iPXE
wpa.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  */
00019 
00020 FILE_LICENCE ( GPL2_OR_LATER );
00021 
00022 #include <ipxe/net80211.h>
00023 #include <ipxe/sec80211.h>
00024 #include <ipxe/wpa.h>
00025 #include <ipxe/eapol.h>
00026 #include <ipxe/crypto.h>
00027 #include <ipxe/arc4.h>
00028 #include <ipxe/crc32.h>
00029 #include <ipxe/sha1.h>
00030 #include <ipxe/hmac.h>
00031 #include <ipxe/list.h>
00032 #include <ipxe/ethernet.h>
00033 #include <ipxe/rbg.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <errno.h>
00037 #include <byteswap.h>
00038 
00039 /** @file
00040  *
00041  * Handler for the aspects of WPA handshaking that are independent of
00042  * 802.1X/PSK or TKIP/CCMP; this mostly involves the 4-Way Handshake.
00043  */
00044 
00045 /** List of WPA contexts in active use. */
00046 struct list_head wpa_contexts = LIST_HEAD_INIT ( wpa_contexts );
00047 
00048 
00049 /**
00050  * Return an error code and deauthenticate
00051  *
00052  * @v ctx       WPA common context
00053  * @v rc        Return status code
00054  * @ret rc      The passed return status code
00055  */
00056 static int wpa_fail ( struct wpa_common_ctx *ctx, int rc )
00057 {
00058         net80211_deauthenticate ( ctx->dev, rc );
00059         return rc;
00060 }
00061 
00062 
00063 /**
00064  * Find a cryptosystem handler structure from a crypto ID
00065  *
00066  * @v crypt     Cryptosystem ID
00067  * @ret crypto  Cryptosystem handler structure
00068  *
00069  * If support for @a crypt is not compiled in to iPXE, or if @a crypt
00070  * is NET80211_CRYPT_UNKNOWN, returns @c NULL.
00071  */
00072 static struct net80211_crypto *
00073 wpa_find_cryptosystem ( enum net80211_crypto_alg crypt )
00074 {
00075         struct net80211_crypto *crypto;
00076 
00077         for_each_table_entry ( crypto, NET80211_CRYPTOS ) {
00078                 if ( crypto->algorithm == crypt )
00079                         return crypto;
00080         }
00081 
00082         return NULL;
00083 }
00084 
00085 
00086 /**
00087  * Find WPA key integrity and encryption handler from key version field
00088  *
00089  * @v ver       Version bits of EAPOL-Key info field
00090  * @ret kie     Key integrity and encryption handler
00091  */
00092 struct wpa_kie * wpa_find_kie ( int version )
00093 {
00094         struct wpa_kie *kie;
00095 
00096         for_each_table_entry ( kie, WPA_KIES ) {
00097                 if ( kie->version == version )
00098                         return kie;
00099         }
00100 
00101         return NULL;
00102 }
00103 
00104 
00105 /**
00106  * Construct RSN or WPA information element
00107  *
00108  * @v dev       802.11 device
00109  * @ret ie_ret  RSN or WPA information element
00110  * @ret rc      Return status code
00111  *
00112  * This function allocates, fills, and returns a RSN or WPA
00113  * information element suitable for including in an association
00114  * request frame to the network identified by @c dev->associating.
00115  * If it is impossible to construct an information element consistent
00116  * with iPXE's capabilities that is compatible with that network, or
00117  * if none should be sent because that network's beacon included no
00118  * security information, returns an error indication and leaves
00119  * @a ie_ret unchanged.
00120  *
00121  * The returned IE will be of the same type (RSN or WPA) as was
00122  * included in the beacon for the network it is destined for.
00123  */
00124 int wpa_make_rsn_ie ( struct net80211_device *dev, union ieee80211_ie **ie_ret )
00125 {
00126         u8 *rsn, *rsn_end;
00127         int is_rsn;
00128         u32 group_cipher;
00129         enum net80211_crypto_alg gcrypt;
00130         int ie_len;
00131         u8 *iep;
00132         struct ieee80211_ie_rsn *ie;
00133         struct ieee80211_frame *hdr;
00134         struct ieee80211_beacon *beacon;
00135 
00136         if ( ! dev->associating ) {
00137                 DBG ( "WPA: Can't make RSN IE for a non-associating device\n" );
00138                 return -EINVAL;
00139         }
00140 
00141         hdr = dev->associating->beacon->data;
00142         beacon = ( struct ieee80211_beacon * ) hdr->data;
00143         rsn = sec80211_find_rsn ( beacon->info_element,
00144                                   dev->associating->beacon->tail, &is_rsn,
00145                                   &rsn_end );
00146         if ( ! rsn ) {
00147                 DBG ( "WPA: Can't make RSN IE when we didn't get one\n" );
00148                 return -EINVAL;
00149         }
00150 
00151         rsn += 2;               /* skip version */
00152         group_cipher = *( u32 * ) rsn;
00153         gcrypt = sec80211_rsn_get_net80211_crypt ( group_cipher );
00154 
00155         if ( ! wpa_find_cryptosystem ( gcrypt ) ||
00156              ! wpa_find_cryptosystem ( dev->associating->crypto ) ) {
00157                 DBG ( "WPA: No support for (GC:%d, PC:%d)\n",
00158                       gcrypt, dev->associating->crypto );
00159                 return -ENOTSUP;
00160         }
00161 
00162         /* Everything looks good - make our IE. */
00163 
00164         /* WPA IEs need 4 more bytes for the OUI+type */
00165         ie_len = ieee80211_rsn_size ( 1, 1, 0, is_rsn ) + ( 4 * ! is_rsn );
00166         iep = malloc ( ie_len );
00167         if ( ! iep )
00168                 return -ENOMEM;
00169 
00170         *ie_ret = ( union ieee80211_ie * ) iep;
00171 
00172         /* Store ID and length bytes. */
00173         *iep++ = ( is_rsn ? IEEE80211_IE_RSN : IEEE80211_IE_VENDOR );
00174         *iep++ = ie_len - 2;
00175 
00176         /* Store OUI+type for WPA IEs. */
00177         if ( ! is_rsn ) {
00178                 *( u32 * ) iep = IEEE80211_WPA_OUI_VEN;
00179                 iep += 4;
00180         }
00181 
00182         /* If this is a WPA IE, the id and len bytes in the
00183            ieee80211_ie_rsn structure will not be valid, but by doing
00184            the cast we can fill all the other fields much more
00185            readily. */
00186 
00187         ie = ( struct ieee80211_ie_rsn * ) ( iep - 2 );
00188         ie->version = IEEE80211_RSN_VERSION;
00189         ie->group_cipher = group_cipher;
00190         ie->pairwise_count = 1;
00191         ie->pairwise_cipher[0] =
00192                 sec80211_rsn_get_crypto_desc ( dev->associating->crypto,
00193                                                is_rsn );
00194         ie->akm_count = 1;
00195         ie->akm_list[0] =
00196                 sec80211_rsn_get_akm_desc ( dev->associating->handshaking,
00197                                             is_rsn );
00198         if ( is_rsn ) {
00199                 ie->rsn_capab = 0;
00200                 ie->pmkid_count = 0;
00201         }
00202 
00203         return 0;
00204 }
00205 
00206 
00207 /**
00208  * Set up generic WPA support to handle 4-Way Handshake
00209  *
00210  * @v dev       802.11 device
00211  * @v ctx       WPA common context
00212  * @v pmk       Pairwise Master Key to use for session
00213  * @v pmk_len   Length of PMK, almost always 32
00214  * @ret rc      Return status code
00215  */
00216 int wpa_start ( struct net80211_device *dev, struct wpa_common_ctx *ctx,
00217                 const void *pmk, size_t pmk_len )
00218 {
00219         struct io_buffer *iob;
00220         struct ieee80211_frame *hdr;
00221         struct ieee80211_beacon *beacon;
00222         u8 *ap_rsn_ie = NULL, *ap_rsn_ie_end;
00223 
00224         if ( ! dev->rsn_ie || ! dev->associating )
00225                 return -EINVAL;
00226 
00227         ctx->dev = dev;
00228         memcpy ( ctx->pmk, pmk, ctx->pmk_len = pmk_len );
00229         ctx->state = WPA_READY;
00230         ctx->replay = ~0ULL;
00231 
00232         iob = dev->associating->beacon;
00233         hdr = iob->data;
00234         beacon = ( struct ieee80211_beacon * ) hdr->data;
00235         ap_rsn_ie = sec80211_find_rsn ( beacon->info_element, iob->tail,
00236                                         &ctx->ap_rsn_is_rsn, &ap_rsn_ie_end );
00237         if ( ap_rsn_ie ) {
00238                 ctx->ap_rsn_ie = malloc ( ap_rsn_ie_end - ap_rsn_ie );
00239                 if ( ! ctx->ap_rsn_ie )
00240                         return -ENOMEM;
00241                 memcpy ( ctx->ap_rsn_ie, ap_rsn_ie, ap_rsn_ie_end - ap_rsn_ie );
00242                 ctx->ap_rsn_ie_len = ap_rsn_ie_end - ap_rsn_ie;
00243         } else {
00244                 return -ENOENT;
00245         }
00246 
00247         ctx->crypt = dev->associating->crypto;
00248         ctx->gcrypt = NET80211_CRYPT_UNKNOWN;
00249 
00250         list_add_tail ( &ctx->list, &wpa_contexts );
00251         return 0;
00252 }
00253 
00254 
00255 /**
00256  * Disable handling of received WPA handshake frames
00257  *
00258  * @v dev       802.11 device
00259  */
00260 void wpa_stop ( struct net80211_device *dev )
00261 {
00262         struct wpa_common_ctx *ctx, *tmp;
00263 
00264         list_for_each_entry_safe ( ctx, tmp, &wpa_contexts, list ) {
00265                 if ( ctx->dev == dev ) {
00266                         free ( ctx->ap_rsn_ie );
00267                         ctx->ap_rsn_ie = NULL;
00268                         list_del ( &ctx->list );
00269                 }
00270         }
00271 }
00272 
00273 
00274 /**
00275  * Derive pairwise transient key
00276  *
00277  * @v ctx       WPA common context
00278  */
00279 static void wpa_derive_ptk ( struct wpa_common_ctx *ctx )
00280 {
00281         struct {
00282                 u8 mac1[ETH_ALEN];
00283                 u8 mac2[ETH_ALEN];
00284                 u8 nonce1[WPA_NONCE_LEN];
00285                 u8 nonce2[WPA_NONCE_LEN];
00286         } __attribute__ (( packed )) ptk_data;
00287 
00288         /* The addresses and nonces are stored in numerical order (!) */
00289 
00290         if ( memcmp ( ctx->dev->netdev->ll_addr, ctx->dev->bssid,
00291                       ETH_ALEN ) < 0 ) {
00292                 memcpy ( ptk_data.mac1, ctx->dev->netdev->ll_addr, ETH_ALEN );
00293                 memcpy ( ptk_data.mac2, ctx->dev->bssid, ETH_ALEN );
00294         } else {
00295                 memcpy ( ptk_data.mac1, ctx->dev->bssid, ETH_ALEN );
00296                 memcpy ( ptk_data.mac2, ctx->dev->netdev->ll_addr, ETH_ALEN );
00297         }
00298 
00299         if ( memcmp ( ctx->Anonce, ctx->Snonce, WPA_NONCE_LEN ) < 0 ) {
00300                 memcpy ( ptk_data.nonce1, ctx->Anonce, WPA_NONCE_LEN );
00301                 memcpy ( ptk_data.nonce2, ctx->Snonce, WPA_NONCE_LEN );
00302         } else {
00303                 memcpy ( ptk_data.nonce1, ctx->Snonce, WPA_NONCE_LEN );
00304                 memcpy ( ptk_data.nonce2, ctx->Anonce, WPA_NONCE_LEN );
00305         }
00306 
00307         DBGC2 ( ctx, "WPA %p A1 %s, A2 %s\n", ctx, eth_ntoa ( ptk_data.mac1 ),
00308                eth_ntoa ( ptk_data.mac2 ) );
00309         DBGC2 ( ctx, "WPA %p Nonce1, Nonce2:\n", ctx );
00310         DBGC2_HD ( ctx, ptk_data.nonce1, WPA_NONCE_LEN );
00311         DBGC2_HD ( ctx, ptk_data.nonce2, WPA_NONCE_LEN );
00312 
00313         prf_sha1 ( ctx->pmk, ctx->pmk_len,
00314                    "Pairwise key expansion",
00315                    &ptk_data, sizeof ( ptk_data ),
00316                    &ctx->ptk, sizeof ( ctx->ptk ) );
00317 
00318         DBGC2 ( ctx, "WPA %p PTK:\n", ctx );
00319         DBGC2_HD ( ctx, &ctx->ptk, sizeof ( ctx->ptk ) );
00320 }
00321 
00322 
00323 /**
00324  * Install pairwise transient key
00325  *
00326  * @v ctx       WPA common context
00327  * @v len       Key length (16 for CCMP, 32 for TKIP)
00328  * @ret rc      Return status code
00329  */
00330 static inline int wpa_install_ptk ( struct wpa_common_ctx *ctx, int len )
00331 {
00332         DBGC ( ctx, "WPA %p: installing %d-byte pairwise transient key\n",
00333                ctx, len );
00334         DBGC2_HD ( ctx, &ctx->ptk.tk, len );
00335 
00336         return sec80211_install ( &ctx->dev->crypto, ctx->crypt,
00337                                   &ctx->ptk.tk, len, NULL );
00338 }
00339 
00340 /**
00341  * Install group transient key
00342  *
00343  * @v ctx       WPA common context
00344  * @v len       Key length (16 for CCMP, 32 for TKIP)
00345  * @v rsc       Receive sequence counter field in EAPOL-Key packet
00346  * @ret rc      Return status code
00347  */
00348 static inline int wpa_install_gtk ( struct wpa_common_ctx *ctx, int len,
00349                                     const void *rsc )
00350 {
00351         DBGC ( ctx, "WPA %p: installing %d-byte group transient key\n",
00352                ctx, len );
00353         DBGC2_HD ( ctx, &ctx->gtk.tk, len );
00354 
00355         return sec80211_install ( &ctx->dev->gcrypto, ctx->gcrypt,
00356                                   &ctx->gtk.tk, len, rsc );
00357 }
00358 
00359 /**
00360  * Search for group transient key, and install it if found
00361  *
00362  * @v ctx       WPA common context
00363  * @v ie        Pointer to first IE in key data field
00364  * @v ie_end    Pointer to first byte not in key data field
00365  * @v rsc       Receive sequence counter field in EAPOL-Key packet
00366  * @ret rc      Return status code
00367  */
00368 static int wpa_maybe_install_gtk ( struct wpa_common_ctx *ctx,
00369                                    union ieee80211_ie *ie, void *ie_end,
00370                                    const void *rsc )
00371 {
00372         struct wpa_kde *kde;
00373 
00374         if ( ! ieee80211_ie_bound ( ie, ie_end ) )
00375                 return -ENOENT;
00376 
00377         while ( ie ) {
00378                 if ( ie->id == IEEE80211_IE_VENDOR &&
00379                      ie->vendor.oui == WPA_KDE_GTK )
00380                         break;
00381 
00382                 ie = ieee80211_next_ie ( ie, ie_end );
00383         }
00384 
00385         if ( ! ie )
00386                 return -ENOENT;
00387 
00388         if ( ie->len - 6u > sizeof ( ctx->gtk.tk ) ) {
00389                 DBGC ( ctx, "WPA %p: GTK KDE is too long (%d bytes, max %zd)\n",
00390                        ctx, ie->len - 4, sizeof ( ctx->gtk.tk ) );
00391                 return -EINVAL;
00392         }
00393 
00394         /* XXX We ignore key ID for now. */
00395         kde = ( struct wpa_kde * ) ie;
00396         memcpy ( &ctx->gtk.tk, &kde->gtk_encap.gtk, kde->len - 6 );
00397 
00398         return wpa_install_gtk ( ctx, kde->len - 6, rsc );
00399 }
00400 
00401 
00402 /**
00403  * Allocate I/O buffer for construction of outgoing EAPOL-Key frame
00404  *
00405  * @v kdlen     Maximum number of bytes in the Key Data field
00406  * @ret iob     Newly allocated I/O buffer
00407  *
00408  * The returned buffer will have space reserved for the link-layer and
00409  * EAPOL headers, and will have @c iob->tail pointing to the start of
00410  * the Key Data field. Thus, it is necessary to use iob_put() in
00411  * filling the Key Data.
00412  */
00413 static struct io_buffer * wpa_alloc_frame ( int kdlen )
00414 {
00415         struct io_buffer *ret = alloc_iob ( sizeof ( struct eapol_key_pkt ) +
00416                                             kdlen + EAPOL_HDR_LEN +
00417                                             MAX_LL_HEADER_LEN );
00418         if ( ! ret )
00419                 return NULL;
00420 
00421         iob_reserve ( ret, MAX_LL_HEADER_LEN + EAPOL_HDR_LEN );
00422         memset ( iob_put ( ret, sizeof ( struct eapol_key_pkt ) ), 0,
00423                  sizeof ( struct eapol_key_pkt ) );
00424 
00425         return ret;
00426 }
00427 
00428 
00429 /**
00430  * Send EAPOL-Key packet
00431  *
00432  * @v iob       I/O buffer, with sufficient headroom for headers
00433  * @v dev       802.11 device
00434  * @v kie       Key integrity and encryption handler
00435  * @v is_rsn    If TRUE, handshake uses new RSN format
00436  * @ret rc      Return status code
00437  *
00438  * If a KIE is specified, the MIC will be filled in before transmission.
00439  */
00440 static int wpa_send_eapol ( struct io_buffer *iob, struct wpa_common_ctx *ctx,
00441                             struct wpa_kie *kie )
00442 {
00443         struct eapol_key_pkt *pkt = iob->data;
00444         struct eapol_frame *eapol = iob_push ( iob, EAPOL_HDR_LEN );
00445 
00446         pkt->info = htons ( pkt->info );
00447         pkt->keysize = htons ( pkt->keysize );
00448         pkt->datalen = htons ( pkt->datalen );
00449         pkt->replay = cpu_to_be64 ( pkt->replay );
00450         eapol->version = EAPOL_THIS_VERSION;
00451         eapol->type = EAPOL_TYPE_KEY;
00452         eapol->length = htons ( iob->tail - iob->data - sizeof ( *eapol ) );
00453 
00454         memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
00455         if ( kie )
00456                 kie->mic ( &ctx->ptk.kck, eapol, EAPOL_HDR_LEN +
00457                            sizeof ( *pkt ) + ntohs ( pkt->datalen ),
00458                            pkt->mic );
00459 
00460         return net_tx ( iob, ctx->dev->netdev, &eapol_protocol,
00461                         ctx->dev->bssid, ctx->dev->netdev->ll_addr );
00462 }
00463 
00464 
00465 /**
00466  * Send second frame in 4-Way Handshake
00467  *
00468  * @v ctx       WPA common context
00469  * @v pkt       First frame, to which this is a reply
00470  * @v is_rsn    If TRUE, handshake uses new RSN format
00471  * @v kie       Key integrity and encryption handler
00472  * @ret rc      Return status code
00473  */
00474 static int wpa_send_2_of_4 ( struct wpa_common_ctx *ctx,
00475                              struct eapol_key_pkt *pkt, int is_rsn,
00476                              struct wpa_kie *kie )
00477 {
00478         struct io_buffer *iob = wpa_alloc_frame ( ctx->dev->rsn_ie->len + 2 );
00479         struct eapol_key_pkt *npkt;
00480 
00481         if ( ! iob )
00482                 return -ENOMEM;
00483 
00484         npkt = iob->data;
00485         memcpy ( npkt, pkt, sizeof ( *pkt ) );
00486         npkt->info &= ~EAPOL_KEY_INFO_KEY_ACK;
00487         npkt->info |= EAPOL_KEY_INFO_KEY_MIC;
00488         if ( is_rsn )
00489                 npkt->keysize = 0;
00490         memcpy ( npkt->nonce, ctx->Snonce, sizeof ( npkt->nonce ) );
00491         npkt->datalen = ctx->dev->rsn_ie->len + 2;
00492         memcpy ( iob_put ( iob, npkt->datalen ), ctx->dev->rsn_ie,
00493                  npkt->datalen );
00494 
00495         DBGC ( ctx, "WPA %p: sending 2/4\n", ctx );
00496 
00497         return wpa_send_eapol ( iob, ctx, kie );
00498 }
00499 
00500 
00501 /**
00502  * Handle receipt of first frame in 4-Way Handshake
00503  *
00504  * @v ctx       WPA common context
00505  * @v pkt       EAPOL-Key packet
00506  * @v is_rsn    If TRUE, frame uses new RSN format
00507  * @v kie       Key integrity and encryption handler
00508  * @ret rc      Return status code
00509  */
00510 static int wpa_handle_1_of_4 ( struct wpa_common_ctx *ctx,
00511                                struct eapol_key_pkt *pkt, int is_rsn,
00512                                struct wpa_kie *kie )
00513 {
00514         if ( ctx->state == WPA_WAITING )
00515                 return -EINVAL;
00516 
00517         ctx->state = WPA_WORKING;
00518         memcpy ( ctx->Anonce, pkt->nonce, sizeof ( ctx->Anonce ) );
00519         if ( ! ctx->have_Snonce ) {
00520                 rbg_generate ( NULL, 0, 0, ctx->Snonce,
00521                                sizeof ( ctx->Snonce ) );
00522                 ctx->have_Snonce = 1;
00523         }
00524 
00525         DBGC ( ctx, "WPA %p: received 1/4, looks OK\n", ctx );
00526 
00527         wpa_derive_ptk ( ctx );
00528 
00529         return wpa_send_2_of_4 ( ctx, pkt, is_rsn, kie );
00530 }
00531 
00532 
00533 /**
00534  * Send fourth frame in 4-Way Handshake, or second in Group Key Handshake
00535  *
00536  * @v ctx       WPA common context
00537  * @v pkt       EAPOL-Key packet for frame to which we're replying
00538  * @v is_rsn    If TRUE, frame uses new RSN format
00539  * @v kie       Key integrity and encryption handler
00540  * @ret rc      Return status code
00541  */
00542 static int wpa_send_final ( struct wpa_common_ctx *ctx,
00543                             struct eapol_key_pkt *pkt, int is_rsn,
00544                             struct wpa_kie *kie )
00545 {
00546         struct io_buffer *iob = wpa_alloc_frame ( 0 );
00547         struct eapol_key_pkt *npkt;
00548 
00549         if ( ! iob )
00550                 return -ENOMEM;
00551 
00552         npkt = iob->data;
00553         memcpy ( npkt, pkt, sizeof ( *pkt ) );
00554         npkt->info &= ~( EAPOL_KEY_INFO_KEY_ACK | EAPOL_KEY_INFO_INSTALL |
00555                          EAPOL_KEY_INFO_KEY_ENC );
00556         if ( is_rsn )
00557                 npkt->keysize = 0;
00558         memset ( npkt->nonce, 0, sizeof ( npkt->nonce ) );
00559         memset ( npkt->iv, 0, sizeof ( npkt->iv ) );
00560         npkt->datalen = 0;
00561 
00562         if ( npkt->info & EAPOL_KEY_INFO_TYPE )
00563                 DBGC ( ctx, "WPA %p: sending 4/4\n", ctx );
00564         else
00565                 DBGC ( ctx, "WPA %p: sending 2/2\n", ctx );
00566 
00567         return wpa_send_eapol ( iob, ctx, kie );
00568 
00569 }
00570 
00571 
00572 /**
00573  * Handle receipt of third frame in 4-Way Handshake
00574  *
00575  * @v ctx       WPA common context
00576  * @v pkt       EAPOL-Key packet
00577  * @v is_rsn    If TRUE, frame uses new RSN format
00578  * @v kie       Key integrity and encryption handler
00579  * @ret rc      Return status code
00580  */
00581 static int wpa_handle_3_of_4 ( struct wpa_common_ctx *ctx,
00582                                struct eapol_key_pkt *pkt, int is_rsn,
00583                                struct wpa_kie *kie )
00584 {
00585         int rc;
00586         u8 *this_rsn, *this_rsn_end;
00587         u8 *new_rsn, *new_rsn_end;
00588         int this_is_rsn, new_is_rsn;
00589 
00590         if ( ctx->state == WPA_WAITING )
00591                 return -EINVAL;
00592 
00593         ctx->state = WPA_WORKING;
00594 
00595         /* Check nonce */
00596         if ( memcmp ( ctx->Anonce, pkt->nonce, WPA_NONCE_LEN ) != 0 ) {
00597                 DBGC ( ctx, "WPA %p ALERT: nonce mismatch in 3/4\n", ctx );
00598                 return wpa_fail ( ctx, -EACCES );
00599         }
00600 
00601         /* Check RSN IE */
00602         this_rsn = sec80211_find_rsn ( ( union ieee80211_ie * ) pkt->data,
00603                                        pkt->data + pkt->datalen,
00604                                        &this_is_rsn, &this_rsn_end );
00605         if ( this_rsn )
00606                 new_rsn = sec80211_find_rsn ( ( union ieee80211_ie * )
00607                                                       this_rsn_end,
00608                                               pkt->data + pkt->datalen,
00609                                               &new_is_rsn, &new_rsn_end );
00610         else
00611                 new_rsn = NULL;
00612 
00613         if ( ! ctx->ap_rsn_ie || ! this_rsn ||
00614              ctx->ap_rsn_ie_len != ( this_rsn_end - this_rsn ) ||
00615              ctx->ap_rsn_is_rsn != this_is_rsn ||
00616              memcmp ( ctx->ap_rsn_ie, this_rsn, ctx->ap_rsn_ie_len ) != 0 ) {
00617                 DBGC ( ctx, "WPA %p ALERT: RSN mismatch in 3/4\n", ctx );
00618                 DBGC2 ( ctx, "WPA %p RSNs (in 3/4, in beacon):\n", ctx );
00619                 DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn );
00620                 DBGC2_HD ( ctx, ctx->ap_rsn_ie, ctx->ap_rsn_ie_len );
00621                 return wpa_fail ( ctx, -EACCES );
00622         }
00623 
00624         /* Don't switch if they just supplied both styles of IE
00625            simultaneously; we need two RSN IEs or two WPA IEs to
00626            switch ciphers. They'll be immediately consecutive because
00627            of ordering guarantees. */
00628         if ( new_rsn && this_is_rsn == new_is_rsn ) {
00629                 struct net80211_wlan *assoc = ctx->dev->associating;
00630                 DBGC ( ctx, "WPA %p: accommodating bait-and-switch tactics\n",
00631                        ctx );
00632                 DBGC2 ( ctx, "WPA %p RSNs (in 3/4+beacon, new in 3/4):\n",
00633                         ctx );
00634                 DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn );
00635                 DBGC2_HD ( ctx, new_rsn, new_rsn_end - new_rsn );
00636 
00637                 if ( ( rc = sec80211_detect_ie ( new_is_rsn, new_rsn,
00638                                                  new_rsn_end,
00639                                                  &assoc->handshaking,
00640                                                  &assoc->crypto ) ) != 0 )
00641                         DBGC ( ctx, "WPA %p: bait-and-switch invalid, staying "
00642                                "with original request\n", ctx );
00643         } else {
00644                 new_rsn = this_rsn;
00645                 new_is_rsn = this_is_rsn;
00646                 new_rsn_end = this_rsn_end;
00647         }
00648 
00649         /* Grab group cryptosystem ID */
00650         ctx->gcrypt = sec80211_rsn_get_net80211_crypt ( *( u32 * )
00651                                                         ( new_rsn + 2 ) );
00652 
00653         /* Check for a GTK, if info field is encrypted */
00654         if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) {
00655                 rc = wpa_maybe_install_gtk ( ctx,
00656                                              ( union ieee80211_ie * ) pkt->data,
00657                                              pkt->data + pkt->datalen,
00658                                              pkt->rsc );
00659                 if ( rc < 0 ) {
00660                         DBGC ( ctx, "WPA %p did not install GTK in 3/4: %s\n",
00661                                ctx, strerror ( rc ) );
00662                         if ( rc != -ENOENT )
00663                                 return wpa_fail ( ctx, rc );
00664                 }
00665         }
00666 
00667         DBGC ( ctx, "WPA %p: received 3/4, looks OK\n", ctx );
00668 
00669         /* Send final message */
00670         rc = wpa_send_final ( ctx, pkt, is_rsn, kie );
00671         if ( rc < 0 )
00672                 return wpa_fail ( ctx, rc );
00673 
00674         /* Install PTK */
00675         rc = wpa_install_ptk ( ctx, pkt->keysize );
00676         if ( rc < 0 ) {
00677                 DBGC ( ctx, "WPA %p failed to install PTK: %s\n", ctx,
00678                        strerror ( rc ) );
00679                 return wpa_fail ( ctx, rc );
00680         }
00681 
00682         /* Mark us as needing a new Snonce if we rekey */
00683         ctx->have_Snonce = 0;
00684 
00685         /* Done! */
00686         ctx->state = WPA_SUCCESS;
00687         return 0;
00688 }
00689 
00690 
00691 /**
00692  * Handle receipt of first frame in Group Key Handshake
00693  *
00694  * @v ctx       WPA common context
00695  * @v pkt       EAPOL-Key packet
00696  * @v is_rsn    If TRUE, frame uses new RSN format
00697  * @v kie       Key integrity and encryption handler
00698  * @ret rc      Return status code
00699  */
00700 static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx,
00701                                struct eapol_key_pkt *pkt, int is_rsn,
00702                                struct wpa_kie *kie )
00703 {
00704         int rc;
00705 
00706         /*
00707          * WPA and RSN do this completely differently.
00708          *
00709          * The idea of encoding the GTK (or PMKID, or various other
00710          * things) into a KDE that looks like an information element
00711          * is an RSN innovation; old WPA code never encapsulates
00712          * things like that. If it looks like an info element, it
00713          * really is (for the WPA IE check in frames 2/4 and 3/4). The
00714          * "key data encrypted" bit in the info field is also specific
00715          * to RSN.
00716          *
00717          * So from an old WPA host, 3/4 does not contain an
00718          * encapsulated GTK. The first frame of the GK handshake
00719          * contains it, encrypted, but without a KDE wrapper, and with
00720          * the key ID field (which iPXE doesn't use) shoved away in
00721          * the reserved bits in the info field, and the TxRx bit
00722          * stealing the Install bit's spot.
00723          */
00724 
00725         if ( is_rsn && ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) ) {
00726                 rc = wpa_maybe_install_gtk ( ctx,
00727                                              ( union ieee80211_ie * ) pkt->data,
00728                                              pkt->data + pkt->datalen,
00729                                              pkt->rsc );
00730                 if ( rc < 0 ) {
00731                         DBGC ( ctx, "WPA %p: failed to install GTK in 1/2: "
00732                                "%s\n", ctx, strerror ( rc ) );
00733                         return wpa_fail ( ctx, rc );
00734                 }
00735         } else {
00736                 rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data,
00737                                     &pkt->datalen );
00738                 if ( rc < 0 ) {
00739                         DBGC ( ctx, "WPA %p: failed to decrypt GTK: %s\n",
00740                                ctx, strerror ( rc ) );
00741                         return rc; /* non-fatal */
00742                 }
00743                 if ( pkt->datalen > sizeof ( ctx->gtk.tk ) ) {
00744                         DBGC ( ctx, "WPA %p: too much GTK data (%d > %zd)\n",
00745                                ctx, pkt->datalen, sizeof ( ctx->gtk.tk ) );
00746                         return wpa_fail ( ctx, -EINVAL );
00747                 }
00748 
00749                 memcpy ( &ctx->gtk.tk, pkt->data, pkt->datalen );
00750                 wpa_install_gtk ( ctx, pkt->datalen, pkt->rsc );
00751         }
00752 
00753         DBGC ( ctx, "WPA %p: received 1/2, looks OK\n", ctx );
00754 
00755         return wpa_send_final ( ctx, pkt, is_rsn, kie );
00756 }
00757 
00758 
00759 /**
00760  * Handle receipt of EAPOL-Key frame for WPA
00761  *
00762  * @v iob       I/O buffer
00763  * @v netdev    Network device
00764  * @v ll_dest   Link-layer destination address
00765  * @v ll_source Source link-layer address
00766  */
00767 static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev,
00768                           const void *ll_dest __unused,
00769                           const void *ll_source )
00770 {
00771         struct net80211_device *dev = net80211_get ( netdev );
00772         struct eapol_key_pkt *pkt = iob->data;
00773         int is_rsn, found_ctx;
00774         struct wpa_common_ctx *ctx;
00775         int rc = 0;
00776         struct wpa_kie *kie;
00777         u8 their_mic[16], our_mic[16];
00778 
00779         if ( pkt->type != EAPOL_KEY_TYPE_WPA &&
00780              pkt->type != EAPOL_KEY_TYPE_RSN ) {
00781                 DBG ( "EAPOL-Key: packet not of 802.11 type\n" );
00782                 rc = -EINVAL;
00783                 goto drop;
00784         }
00785 
00786         is_rsn = ( pkt->type == EAPOL_KEY_TYPE_RSN );
00787 
00788         if ( ! dev ) {
00789                 DBG ( "EAPOL-Key: packet not from 802.11\n" );
00790                 rc = -EINVAL;
00791                 goto drop;
00792         }
00793 
00794         if ( memcmp ( dev->bssid, ll_source, ETH_ALEN ) != 0 ) {
00795                 DBG ( "EAPOL-Key: packet not from associated AP\n" );
00796                 rc = -EINVAL;
00797                 goto drop;
00798         }
00799 
00800         if ( ! ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_ACK ) ) {
00801                 DBG ( "EAPOL-Key: packet sent in wrong direction\n" );
00802                 rc = -EINVAL;
00803                 goto drop;
00804         }
00805 
00806         found_ctx = 0;
00807         list_for_each_entry ( ctx, &wpa_contexts, list ) {
00808                 if ( ctx->dev == dev ) {
00809                         found_ctx = 1;
00810                         break;
00811                 }
00812         }
00813 
00814         if ( ! found_ctx ) {
00815                 DBG ( "EAPOL-Key: no WPA context to handle packet for %p\n",
00816                       dev );
00817                 rc = -ENOENT;
00818                 goto drop;
00819         }
00820 
00821         if ( ( void * ) ( pkt + 1 ) + ntohs ( pkt->datalen ) > iob->tail ) {
00822                 DBGC ( ctx, "WPA %p: packet truncated (has %zd extra bytes, "
00823                        "states %d)\n", ctx, iob->tail - ( void * ) ( pkt + 1 ),
00824                        ntohs ( pkt->datalen ) );
00825                 rc = -EINVAL;
00826                 goto drop;
00827         }
00828 
00829         /* Get a handle on key integrity/encryption handler */
00830         kie = wpa_find_kie ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION );
00831         if ( ! kie ) {
00832                 DBGC ( ctx, "WPA %p: no support for packet version %d\n", ctx,
00833                        ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION );
00834                 rc = wpa_fail ( ctx, -ENOTSUP );
00835                 goto drop;
00836         }
00837 
00838         /* Check MIC */
00839         if ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_MIC ) {
00840                 memcpy ( their_mic, pkt->mic, sizeof ( pkt->mic ) );
00841                 memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
00842                 kie->mic ( &ctx->ptk.kck, ( void * ) pkt - EAPOL_HDR_LEN,
00843                            EAPOL_HDR_LEN + sizeof ( *pkt ) +
00844                            ntohs ( pkt->datalen ), our_mic );
00845                 DBGC2 ( ctx, "WPA %p MIC comparison (theirs, ours):\n", ctx );
00846                 DBGC2_HD ( ctx, their_mic, 16 );
00847                 DBGC2_HD ( ctx, our_mic, 16 );
00848                 if ( memcmp ( their_mic, our_mic, sizeof ( pkt->mic ) ) != 0 ) {
00849                         DBGC ( ctx, "WPA %p: EAPOL MIC failure\n", ctx );
00850                         goto drop;
00851                 }
00852         }
00853 
00854         /* Fix byte order to local */
00855         pkt->info = ntohs ( pkt->info );
00856         pkt->keysize = ntohs ( pkt->keysize );
00857         pkt->datalen = ntohs ( pkt->datalen );
00858         pkt->replay = be64_to_cpu ( pkt->replay );
00859 
00860         /* Check replay counter */
00861         if ( ctx->replay != ~0ULL && ctx->replay >= pkt->replay ) {
00862                 DBGC ( ctx, "WPA %p ALERT: Replay detected! "
00863                        "(%08x:%08x >= %08x:%08x)\n", ctx,
00864                        ( u32 ) ( ctx->replay >> 32 ), ( u32 ) ctx->replay,
00865                        ( u32 ) ( pkt->replay >> 32 ), ( u32 ) pkt->replay );
00866                 rc = 0;         /* ignore without error */
00867                 goto drop;
00868         }
00869         ctx->replay = pkt->replay;
00870 
00871         /* Decrypt key data */
00872         if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) {
00873                 rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data,
00874                                     &pkt->datalen );
00875                 if ( rc < 0 ) {
00876                         DBGC ( ctx, "WPA %p: failed to decrypt packet: %s\n",
00877                                ctx, strerror ( rc ) );
00878                         goto drop;
00879                 }
00880         }
00881 
00882         /* Hand it off to appropriate handler */
00883         switch ( pkt->info & ( EAPOL_KEY_INFO_TYPE |
00884                                EAPOL_KEY_INFO_KEY_MIC ) ) {
00885         case EAPOL_KEY_TYPE_PTK:
00886                 rc = wpa_handle_1_of_4 ( ctx, pkt, is_rsn, kie );
00887                 break;
00888 
00889         case EAPOL_KEY_TYPE_PTK | EAPOL_KEY_INFO_KEY_MIC:
00890                 rc = wpa_handle_3_of_4 ( ctx, pkt, is_rsn, kie );
00891                 break;
00892 
00893         case EAPOL_KEY_TYPE_GTK | EAPOL_KEY_INFO_KEY_MIC:
00894                 rc = wpa_handle_1_of_2 ( ctx, pkt, is_rsn, kie );
00895                 break;
00896 
00897         default:
00898                 DBGC ( ctx, "WPA %p: Invalid combination of key flags %04x\n",
00899                        ctx, pkt->info );
00900                 rc = -EINVAL;
00901                 break;
00902         }
00903 
00904  drop:
00905         free_iob ( iob );
00906         return rc;
00907 }
00908 
00909 struct eapol_handler eapol_key_handler __eapol_handler = {
00910         .type = EAPOL_TYPE_KEY,
00911         .rx = eapol_key_rx,
00912 };
00913 
00914 /* WPA always needs EAPOL in order to be useful */
00915 REQUIRING_SYMBOL ( eapol_key_handler );
00916 REQUIRE_OBJECT ( eapol );