Annotation of qemu/roms/ipxe/src/net/80211/wpa.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2009 Joshua Oreman <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: #include <ipxe/net80211.h>
        !            22: #include <ipxe/sec80211.h>
        !            23: #include <ipxe/wpa.h>
        !            24: #include <ipxe/eapol.h>
        !            25: #include <ipxe/crypto.h>
        !            26: #include <ipxe/arc4.h>
        !            27: #include <ipxe/crc32.h>
        !            28: #include <ipxe/sha1.h>
        !            29: #include <ipxe/hmac.h>
        !            30: #include <ipxe/list.h>
        !            31: #include <ipxe/ethernet.h>
        !            32: #include <stdlib.h>
        !            33: #include <string.h>
        !            34: #include <errno.h>
        !            35: 
        !            36: /** @file
        !            37:  *
        !            38:  * Handler for the aspects of WPA handshaking that are independent of
        !            39:  * 802.1X/PSK or TKIP/CCMP; this mostly involves the 4-Way Handshake.
        !            40:  */
        !            41: 
        !            42: /** List of WPA contexts in active use. */
        !            43: struct list_head wpa_contexts = LIST_HEAD_INIT ( wpa_contexts );
        !            44: 
        !            45: 
        !            46: /**
        !            47:  * Return an error code and deauthenticate
        !            48:  *
        !            49:  * @v ctx      WPA common context
        !            50:  * @v rc       Return status code
        !            51:  * @ret rc     The passed return status code
        !            52:  */
        !            53: static int wpa_fail ( struct wpa_common_ctx *ctx, int rc )
        !            54: {
        !            55:        net80211_deauthenticate ( ctx->dev, rc );
        !            56:        return rc;
        !            57: }
        !            58: 
        !            59: 
        !            60: /**
        !            61:  * Find a cryptosystem handler structure from a crypto ID
        !            62:  *
        !            63:  * @v crypt    Cryptosystem ID
        !            64:  * @ret crypto Cryptosystem handler structure
        !            65:  *
        !            66:  * If support for @a crypt is not compiled in to iPXE, or if @a crypt
        !            67:  * is NET80211_CRYPT_UNKNOWN, returns @c NULL.
        !            68:  */
        !            69: static struct net80211_crypto *
        !            70: wpa_find_cryptosystem ( enum net80211_crypto_alg crypt )
        !            71: {
        !            72:        struct net80211_crypto *crypto;
        !            73: 
        !            74:        for_each_table_entry ( crypto, NET80211_CRYPTOS ) {
        !            75:                if ( crypto->algorithm == crypt )
        !            76:                        return crypto;
        !            77:        }
        !            78: 
        !            79:        return NULL;
        !            80: }
        !            81: 
        !            82: 
        !            83: /**
        !            84:  * Find WPA key integrity and encryption handler from key version field
        !            85:  *
        !            86:  * @v ver      Version bits of EAPOL-Key info field
        !            87:  * @ret kie    Key integrity and encryption handler
        !            88:  */
        !            89: struct wpa_kie * wpa_find_kie ( int version )
        !            90: {
        !            91:        struct wpa_kie *kie;
        !            92: 
        !            93:        for_each_table_entry ( kie, WPA_KIES ) {
        !            94:                if ( kie->version == version )
        !            95:                        return kie;
        !            96:        }
        !            97: 
        !            98:        return NULL;
        !            99: }
        !           100: 
        !           101: 
        !           102: /**
        !           103:  * Construct RSN or WPA information element
        !           104:  *
        !           105:  * @v dev      802.11 device
        !           106:  * @ret ie_ret RSN or WPA information element
        !           107:  * @ret rc     Return status code
        !           108:  *
        !           109:  * This function allocates, fills, and returns a RSN or WPA
        !           110:  * information element suitable for including in an association
        !           111:  * request frame to the network identified by @c dev->associating.
        !           112:  * If it is impossible to construct an information element consistent
        !           113:  * with iPXE's capabilities that is compatible with that network, or
        !           114:  * if none should be sent because that network's beacon included no
        !           115:  * security information, returns an error indication and leaves
        !           116:  * @a ie_ret unchanged.
        !           117:  *
        !           118:  * The returned IE will be of the same type (RSN or WPA) as was
        !           119:  * included in the beacon for the network it is destined for.
        !           120:  */
        !           121: int wpa_make_rsn_ie ( struct net80211_device *dev, union ieee80211_ie **ie_ret )
        !           122: {
        !           123:        u8 *rsn, *rsn_end;
        !           124:        int is_rsn;
        !           125:        u32 group_cipher;
        !           126:        enum net80211_crypto_alg gcrypt;
        !           127:        int ie_len;
        !           128:        u8 *iep;
        !           129:        struct ieee80211_ie_rsn *ie;
        !           130:        struct ieee80211_frame *hdr;
        !           131:        struct ieee80211_beacon *beacon;
        !           132: 
        !           133:        if ( ! dev->associating ) {
        !           134:                DBG ( "WPA: Can't make RSN IE for a non-associating device\n" );
        !           135:                return -EINVAL;
        !           136:        }
        !           137: 
        !           138:        hdr = dev->associating->beacon->data;
        !           139:        beacon = ( struct ieee80211_beacon * ) hdr->data;
        !           140:        rsn = sec80211_find_rsn ( beacon->info_element,
        !           141:                                  dev->associating->beacon->tail, &is_rsn,
        !           142:                                  &rsn_end );
        !           143:        if ( ! rsn ) {
        !           144:                DBG ( "WPA: Can't make RSN IE when we didn't get one\n" );
        !           145:                return -EINVAL;
        !           146:        }
        !           147: 
        !           148:        rsn += 2;               /* skip version */
        !           149:        group_cipher = *( u32 * ) rsn;
        !           150:        gcrypt = sec80211_rsn_get_net80211_crypt ( group_cipher );
        !           151: 
        !           152:        if ( ! wpa_find_cryptosystem ( gcrypt ) ||
        !           153:             ! wpa_find_cryptosystem ( dev->associating->crypto ) ) {
        !           154:                DBG ( "WPA: No support for (GC:%d, PC:%d)\n",
        !           155:                      gcrypt, dev->associating->crypto );
        !           156:                return -ENOTSUP;
        !           157:        }
        !           158: 
        !           159:        /* Everything looks good - make our IE. */
        !           160: 
        !           161:        /* WPA IEs need 4 more bytes for the OUI+type */
        !           162:        ie_len = ieee80211_rsn_size ( 1, 1, 0, is_rsn ) + ( 4 * ! is_rsn );
        !           163:        iep = malloc ( ie_len );
        !           164:        if ( ! iep )
        !           165:                return -ENOMEM;
        !           166: 
        !           167:        *ie_ret = ( union ieee80211_ie * ) iep;
        !           168: 
        !           169:        /* Store ID and length bytes. */
        !           170:        *iep++ = ( is_rsn ? IEEE80211_IE_RSN : IEEE80211_IE_VENDOR );
        !           171:        *iep++ = ie_len - 2;
        !           172: 
        !           173:        /* Store OUI+type for WPA IEs. */
        !           174:        if ( ! is_rsn ) {
        !           175:                *( u32 * ) iep = IEEE80211_WPA_OUI_VEN;
        !           176:                iep += 4;
        !           177:        }
        !           178: 
        !           179:        /* If this is a WPA IE, the id and len bytes in the
        !           180:           ieee80211_ie_rsn structure will not be valid, but by doing
        !           181:           the cast we can fill all the other fields much more
        !           182:           readily. */
        !           183: 
        !           184:        ie = ( struct ieee80211_ie_rsn * ) ( iep - 2 );
        !           185:        ie->version = IEEE80211_RSN_VERSION;
        !           186:        ie->group_cipher = group_cipher;
        !           187:        ie->pairwise_count = 1;
        !           188:        ie->pairwise_cipher[0] =
        !           189:                sec80211_rsn_get_crypto_desc ( dev->associating->crypto,
        !           190:                                               is_rsn );
        !           191:        ie->akm_count = 1;
        !           192:        ie->akm_list[0] =
        !           193:                sec80211_rsn_get_akm_desc ( dev->associating->handshaking,
        !           194:                                            is_rsn );
        !           195:        if ( is_rsn ) {
        !           196:                ie->rsn_capab = 0;
        !           197:                ie->pmkid_count = 0;
        !           198:        }
        !           199: 
        !           200:        return 0;
        !           201: }
        !           202: 
        !           203: 
        !           204: /**
        !           205:  * Set up generic WPA support to handle 4-Way Handshake
        !           206:  *
        !           207:  * @v dev      802.11 device
        !           208:  * @v ctx      WPA common context
        !           209:  * @v pmk      Pairwise Master Key to use for session
        !           210:  * @v pmk_len  Length of PMK, almost always 32
        !           211:  * @ret rc     Return status code
        !           212:  */
        !           213: int wpa_start ( struct net80211_device *dev, struct wpa_common_ctx *ctx,
        !           214:                const void *pmk, size_t pmk_len )
        !           215: {
        !           216:        struct io_buffer *iob;
        !           217:        struct ieee80211_frame *hdr;
        !           218:        struct ieee80211_beacon *beacon;
        !           219:        u8 *ap_rsn_ie = NULL, *ap_rsn_ie_end;
        !           220: 
        !           221:        if ( ! dev->rsn_ie || ! dev->associating )
        !           222:                return -EINVAL;
        !           223: 
        !           224:        ctx->dev = dev;
        !           225:        memcpy ( ctx->pmk, pmk, ctx->pmk_len = pmk_len );
        !           226:        ctx->state = WPA_READY;
        !           227:        ctx->replay = ~0ULL;
        !           228: 
        !           229:        iob = dev->associating->beacon;
        !           230:        hdr = iob->data;
        !           231:        beacon = ( struct ieee80211_beacon * ) hdr->data;
        !           232:        ap_rsn_ie = sec80211_find_rsn ( beacon->info_element, iob->tail,
        !           233:                                        &ctx->ap_rsn_is_rsn, &ap_rsn_ie_end );
        !           234:        if ( ap_rsn_ie ) {
        !           235:                ctx->ap_rsn_ie = malloc ( ap_rsn_ie_end - ap_rsn_ie );
        !           236:                if ( ! ctx->ap_rsn_ie )
        !           237:                        return -ENOMEM;
        !           238:                memcpy ( ctx->ap_rsn_ie, ap_rsn_ie, ap_rsn_ie_end - ap_rsn_ie );
        !           239:                ctx->ap_rsn_ie_len = ap_rsn_ie_end - ap_rsn_ie;
        !           240:        } else {
        !           241:                return -ENOENT;
        !           242:        }
        !           243: 
        !           244:        ctx->crypt = dev->associating->crypto;
        !           245:        ctx->gcrypt = NET80211_CRYPT_UNKNOWN;
        !           246: 
        !           247:        list_add_tail ( &ctx->list, &wpa_contexts );
        !           248:        return 0;
        !           249: }
        !           250: 
        !           251: 
        !           252: /**
        !           253:  * Disable handling of received WPA handshake frames
        !           254:  *
        !           255:  * @v dev      802.11 device
        !           256:  */
        !           257: void wpa_stop ( struct net80211_device *dev )
        !           258: {
        !           259:        struct wpa_common_ctx *ctx, *tmp;
        !           260: 
        !           261:        list_for_each_entry_safe ( ctx, tmp, &wpa_contexts, list ) {
        !           262:                if ( ctx->dev == dev ) {
        !           263:                        free ( ctx->ap_rsn_ie );
        !           264:                        ctx->ap_rsn_ie = NULL;
        !           265:                        list_del ( &ctx->list );
        !           266:                }
        !           267:        }
        !           268: }
        !           269: 
        !           270: 
        !           271: /**
        !           272:  * Derive pairwise transient key
        !           273:  *
        !           274:  * @v ctx      WPA common context
        !           275:  */
        !           276: static void wpa_derive_ptk ( struct wpa_common_ctx *ctx )
        !           277: {
        !           278:        struct {
        !           279:                u8 mac1[ETH_ALEN];
        !           280:                u8 mac2[ETH_ALEN];
        !           281:                u8 nonce1[WPA_NONCE_LEN];
        !           282:                u8 nonce2[WPA_NONCE_LEN];
        !           283:        } __attribute__ (( packed )) ptk_data;
        !           284: 
        !           285:        /* The addresses and nonces are stored in numerical order (!) */
        !           286: 
        !           287:        if ( memcmp ( ctx->dev->netdev->ll_addr, ctx->dev->bssid,
        !           288:                      ETH_ALEN ) < 0 ) {
        !           289:                memcpy ( ptk_data.mac1, ctx->dev->netdev->ll_addr, ETH_ALEN );
        !           290:                memcpy ( ptk_data.mac2, ctx->dev->bssid, ETH_ALEN );
        !           291:        } else {
        !           292:                memcpy ( ptk_data.mac1, ctx->dev->bssid, ETH_ALEN );
        !           293:                memcpy ( ptk_data.mac2, ctx->dev->netdev->ll_addr, ETH_ALEN );
        !           294:        }
        !           295: 
        !           296:        if ( memcmp ( ctx->Anonce, ctx->Snonce, WPA_NONCE_LEN ) < 0 ) {
        !           297:                memcpy ( ptk_data.nonce1, ctx->Anonce, WPA_NONCE_LEN );
        !           298:                memcpy ( ptk_data.nonce2, ctx->Snonce, WPA_NONCE_LEN );
        !           299:        } else {
        !           300:                memcpy ( ptk_data.nonce1, ctx->Snonce, WPA_NONCE_LEN );
        !           301:                memcpy ( ptk_data.nonce2, ctx->Anonce, WPA_NONCE_LEN );
        !           302:        }
        !           303: 
        !           304:        DBGC2 ( ctx, "WPA %p A1 %s, A2 %s\n", ctx, eth_ntoa ( ptk_data.mac1 ),
        !           305:               eth_ntoa ( ptk_data.mac2 ) );
        !           306:        DBGC2 ( ctx, "WPA %p Nonce1, Nonce2:\n", ctx );
        !           307:        DBGC2_HD ( ctx, ptk_data.nonce1, WPA_NONCE_LEN );
        !           308:        DBGC2_HD ( ctx, ptk_data.nonce2, WPA_NONCE_LEN );
        !           309: 
        !           310:        prf_sha1 ( ctx->pmk, ctx->pmk_len,
        !           311:                   "Pairwise key expansion",
        !           312:                   &ptk_data, sizeof ( ptk_data ),
        !           313:                   &ctx->ptk, sizeof ( ctx->ptk ) );
        !           314: 
        !           315:        DBGC2 ( ctx, "WPA %p PTK:\n", ctx );
        !           316:        DBGC2_HD ( ctx, &ctx->ptk, sizeof ( ctx->ptk ) );
        !           317: }
        !           318: 
        !           319: 
        !           320: /**
        !           321:  * Install pairwise transient key
        !           322:  *
        !           323:  * @v ctx      WPA common context
        !           324:  * @v len      Key length (16 for CCMP, 32 for TKIP)
        !           325:  * @ret rc     Return status code
        !           326:  */
        !           327: static inline int wpa_install_ptk ( struct wpa_common_ctx *ctx, int len )
        !           328: {
        !           329:        DBGC ( ctx, "WPA %p: installing %d-byte pairwise transient key\n",
        !           330:               ctx, len );
        !           331:        DBGC2_HD ( ctx, &ctx->ptk.tk, len );
        !           332: 
        !           333:        return sec80211_install ( &ctx->dev->crypto, ctx->crypt,
        !           334:                                  &ctx->ptk.tk, len, NULL );
        !           335: }
        !           336: 
        !           337: /**
        !           338:  * Install group transient key
        !           339:  *
        !           340:  * @v ctx      WPA common context
        !           341:  * @v len      Key length (16 for CCMP, 32 for TKIP)
        !           342:  * @v rsc      Receive sequence counter field in EAPOL-Key packet
        !           343:  * @ret rc     Return status code
        !           344:  */
        !           345: static inline int wpa_install_gtk ( struct wpa_common_ctx *ctx, int len,
        !           346:                                    const void *rsc )
        !           347: {
        !           348:        DBGC ( ctx, "WPA %p: installing %d-byte group transient key\n",
        !           349:               ctx, len );
        !           350:        DBGC2_HD ( ctx, &ctx->gtk.tk, len );
        !           351: 
        !           352:        return sec80211_install ( &ctx->dev->gcrypto, ctx->gcrypt,
        !           353:                                  &ctx->gtk.tk, len, rsc );
        !           354: }
        !           355: 
        !           356: /**
        !           357:  * Search for group transient key, and install it if found
        !           358:  *
        !           359:  * @v ctx      WPA common context
        !           360:  * @v ie       Pointer to first IE in key data field
        !           361:  * @v ie_end   Pointer to first byte not in key data field
        !           362:  * @v rsc      Receive sequence counter field in EAPOL-Key packet
        !           363:  * @ret rc     Return status code
        !           364:  */
        !           365: static int wpa_maybe_install_gtk ( struct wpa_common_ctx *ctx,
        !           366:                                   union ieee80211_ie *ie, void *ie_end,
        !           367:                                   const void *rsc )
        !           368: {
        !           369:        struct wpa_kde *kde;
        !           370: 
        !           371:        if ( ! ieee80211_ie_bound ( ie, ie_end ) )
        !           372:                return -ENOENT;
        !           373: 
        !           374:        while ( ie ) {
        !           375:                if ( ie->id == IEEE80211_IE_VENDOR &&
        !           376:                     ie->vendor.oui == WPA_KDE_GTK )
        !           377:                        break;
        !           378: 
        !           379:                ie = ieee80211_next_ie ( ie, ie_end );
        !           380:        }
        !           381: 
        !           382:        if ( ! ie )
        !           383:                return -ENOENT;
        !           384: 
        !           385:        if ( ie->len - 6u > sizeof ( ctx->gtk.tk ) ) {
        !           386:                DBGC ( ctx, "WPA %p: GTK KDE is too long (%d bytes, max %zd)\n",
        !           387:                       ctx, ie->len - 4, sizeof ( ctx->gtk.tk ) );
        !           388:                return -EINVAL;
        !           389:        }
        !           390: 
        !           391:        /* XXX We ignore key ID for now. */
        !           392:        kde = ( struct wpa_kde * ) ie;
        !           393:        memcpy ( &ctx->gtk.tk, &kde->gtk_encap.gtk, kde->len - 6 );
        !           394: 
        !           395:        return wpa_install_gtk ( ctx, kde->len - 6, rsc );
        !           396: }
        !           397: 
        !           398: 
        !           399: /**
        !           400:  * Allocate I/O buffer for construction of outgoing EAPOL-Key frame
        !           401:  *
        !           402:  * @v kdlen    Maximum number of bytes in the Key Data field
        !           403:  * @ret iob    Newly allocated I/O buffer
        !           404:  *
        !           405:  * The returned buffer will have space reserved for the link-layer and
        !           406:  * EAPOL headers, and will have @c iob->tail pointing to the start of
        !           407:  * the Key Data field. Thus, it is necessary to use iob_put() in
        !           408:  * filling the Key Data.
        !           409:  */
        !           410: static struct io_buffer * wpa_alloc_frame ( int kdlen )
        !           411: {
        !           412:        struct io_buffer *ret = alloc_iob ( sizeof ( struct eapol_key_pkt ) +
        !           413:                                            kdlen + EAPOL_HDR_LEN +
        !           414:                                            MAX_LL_HEADER_LEN );
        !           415:        if ( ! ret )
        !           416:                return NULL;
        !           417: 
        !           418:        iob_reserve ( ret, MAX_LL_HEADER_LEN + EAPOL_HDR_LEN );
        !           419:        memset ( iob_put ( ret, sizeof ( struct eapol_key_pkt ) ), 0,
        !           420:                 sizeof ( struct eapol_key_pkt ) );
        !           421: 
        !           422:        return ret;
        !           423: }
        !           424: 
        !           425: 
        !           426: /**
        !           427:  * Send EAPOL-Key packet
        !           428:  *
        !           429:  * @v iob      I/O buffer, with sufficient headroom for headers
        !           430:  * @v dev      802.11 device
        !           431:  * @v kie      Key integrity and encryption handler
        !           432:  * @v is_rsn   If TRUE, handshake uses new RSN format
        !           433:  * @ret rc     Return status code
        !           434:  *
        !           435:  * If a KIE is specified, the MIC will be filled in before transmission.
        !           436:  */
        !           437: static int wpa_send_eapol ( struct io_buffer *iob, struct wpa_common_ctx *ctx,
        !           438:                            struct wpa_kie *kie )
        !           439: {
        !           440:        struct eapol_key_pkt *pkt = iob->data;
        !           441:        struct eapol_frame *eapol = iob_push ( iob, EAPOL_HDR_LEN );
        !           442: 
        !           443:        pkt->info = htons ( pkt->info );
        !           444:        pkt->keysize = htons ( pkt->keysize );
        !           445:        pkt->datalen = htons ( pkt->datalen );
        !           446:        pkt->replay = cpu_to_be64 ( pkt->replay );
        !           447:        eapol->version = EAPOL_THIS_VERSION;
        !           448:        eapol->type = EAPOL_TYPE_KEY;
        !           449:        eapol->length = htons ( iob->tail - iob->data - sizeof ( *eapol ) );
        !           450: 
        !           451:        memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
        !           452:        if ( kie )
        !           453:                kie->mic ( &ctx->ptk.kck, eapol, EAPOL_HDR_LEN +
        !           454:                           sizeof ( *pkt ) + ntohs ( pkt->datalen ),
        !           455:                           pkt->mic );
        !           456: 
        !           457:        return net_tx ( iob, ctx->dev->netdev, &eapol_protocol,
        !           458:                        ctx->dev->bssid, ctx->dev->netdev->ll_addr );
        !           459: }
        !           460: 
        !           461: 
        !           462: /**
        !           463:  * Send second frame in 4-Way Handshake
        !           464:  *
        !           465:  * @v ctx      WPA common context
        !           466:  * @v pkt      First frame, to which this is a reply
        !           467:  * @v is_rsn   If TRUE, handshake uses new RSN format
        !           468:  * @v kie      Key integrity and encryption handler
        !           469:  * @ret rc     Return status code
        !           470:  */
        !           471: static int wpa_send_2_of_4 ( struct wpa_common_ctx *ctx,
        !           472:                             struct eapol_key_pkt *pkt, int is_rsn,
        !           473:                             struct wpa_kie *kie )
        !           474: {
        !           475:        struct io_buffer *iob = wpa_alloc_frame ( ctx->dev->rsn_ie->len + 2 );
        !           476:        struct eapol_key_pkt *npkt;
        !           477: 
        !           478:        if ( ! iob )
        !           479:                return -ENOMEM;
        !           480: 
        !           481:        npkt = iob->data;
        !           482:        memcpy ( npkt, pkt, sizeof ( *pkt ) );
        !           483:        npkt->info &= ~EAPOL_KEY_INFO_KEY_ACK;
        !           484:        npkt->info |= EAPOL_KEY_INFO_KEY_MIC;
        !           485:        if ( is_rsn )
        !           486:                npkt->keysize = 0;
        !           487:        memcpy ( npkt->nonce, ctx->Snonce, sizeof ( npkt->nonce ) );
        !           488:        npkt->datalen = ctx->dev->rsn_ie->len + 2;
        !           489:        memcpy ( iob_put ( iob, npkt->datalen ), ctx->dev->rsn_ie,
        !           490:                 npkt->datalen );
        !           491: 
        !           492:        DBGC ( ctx, "WPA %p: sending 2/4\n", ctx );
        !           493: 
        !           494:        return wpa_send_eapol ( iob, ctx, kie );
        !           495: }
        !           496: 
        !           497: 
        !           498: /**
        !           499:  * Handle receipt of first frame in 4-Way Handshake
        !           500:  *
        !           501:  * @v ctx      WPA common context
        !           502:  * @v pkt      EAPOL-Key packet
        !           503:  * @v is_rsn   If TRUE, frame uses new RSN format
        !           504:  * @v kie      Key integrity and encryption handler
        !           505:  * @ret rc     Return status code
        !           506:  */
        !           507: static int wpa_handle_1_of_4 ( struct wpa_common_ctx *ctx,
        !           508:                               struct eapol_key_pkt *pkt, int is_rsn,
        !           509:                               struct wpa_kie *kie )
        !           510: {
        !           511:        if ( ctx->state == WPA_WAITING )
        !           512:                return -EINVAL;
        !           513: 
        !           514:        ctx->state = WPA_WORKING;
        !           515:        memcpy ( ctx->Anonce, pkt->nonce, sizeof ( ctx->Anonce ) );
        !           516:        if ( ! ctx->have_Snonce ) {
        !           517:                get_random_bytes ( ctx->Snonce, sizeof ( ctx->Snonce ) );
        !           518:                ctx->have_Snonce = 1;
        !           519:        }
        !           520: 
        !           521:        DBGC ( ctx, "WPA %p: received 1/4, looks OK\n", ctx );
        !           522: 
        !           523:        wpa_derive_ptk ( ctx );
        !           524: 
        !           525:        return wpa_send_2_of_4 ( ctx, pkt, is_rsn, kie );
        !           526: }
        !           527: 
        !           528: 
        !           529: /**
        !           530:  * Send fourth frame in 4-Way Handshake, or second in Group Key Handshake
        !           531:  *
        !           532:  * @v ctx      WPA common context
        !           533:  * @v pkt      EAPOL-Key packet for frame to which we're replying
        !           534:  * @v is_rsn   If TRUE, frame uses new RSN format
        !           535:  * @v kie      Key integrity and encryption handler
        !           536:  * @ret rc     Return status code
        !           537:  */
        !           538: static int wpa_send_final ( struct wpa_common_ctx *ctx,
        !           539:                            struct eapol_key_pkt *pkt, int is_rsn,
        !           540:                            struct wpa_kie *kie )
        !           541: {
        !           542:        struct io_buffer *iob = wpa_alloc_frame ( 0 );
        !           543:        struct eapol_key_pkt *npkt;
        !           544: 
        !           545:        if ( ! iob )
        !           546:                return -ENOMEM;
        !           547: 
        !           548:        npkt = iob->data;
        !           549:        memcpy ( npkt, pkt, sizeof ( *pkt ) );
        !           550:        npkt->info &= ~( EAPOL_KEY_INFO_KEY_ACK | EAPOL_KEY_INFO_INSTALL |
        !           551:                         EAPOL_KEY_INFO_KEY_ENC );
        !           552:        if ( is_rsn )
        !           553:                npkt->keysize = 0;
        !           554:        memset ( npkt->nonce, 0, sizeof ( npkt->nonce ) );
        !           555:        memset ( npkt->iv, 0, sizeof ( npkt->iv ) );
        !           556:        npkt->datalen = 0;
        !           557: 
        !           558:        if ( npkt->info & EAPOL_KEY_INFO_TYPE )
        !           559:                DBGC ( ctx, "WPA %p: sending 4/4\n", ctx );
        !           560:        else
        !           561:                DBGC ( ctx, "WPA %p: sending 2/2\n", ctx );
        !           562: 
        !           563:        return wpa_send_eapol ( iob, ctx, kie );
        !           564: 
        !           565: }
        !           566: 
        !           567: 
        !           568: /**
        !           569:  * Handle receipt of third frame in 4-Way Handshake
        !           570:  *
        !           571:  * @v ctx      WPA common context
        !           572:  * @v pkt      EAPOL-Key packet
        !           573:  * @v is_rsn   If TRUE, frame uses new RSN format
        !           574:  * @v kie      Key integrity and encryption handler
        !           575:  * @ret rc     Return status code
        !           576:  */
        !           577: static int wpa_handle_3_of_4 ( struct wpa_common_ctx *ctx,
        !           578:                               struct eapol_key_pkt *pkt, int is_rsn,
        !           579:                               struct wpa_kie *kie )
        !           580: {
        !           581:        int rc;
        !           582:        u8 *this_rsn, *this_rsn_end;
        !           583:        u8 *new_rsn, *new_rsn_end;
        !           584:        int this_is_rsn, new_is_rsn;
        !           585: 
        !           586:        if ( ctx->state == WPA_WAITING )
        !           587:                return -EINVAL;
        !           588: 
        !           589:        ctx->state = WPA_WORKING;
        !           590: 
        !           591:        /* Check nonce */
        !           592:        if ( memcmp ( ctx->Anonce, pkt->nonce, WPA_NONCE_LEN ) != 0 ) {
        !           593:                DBGC ( ctx, "WPA %p ALERT: nonce mismatch in 3/4\n", ctx );
        !           594:                return wpa_fail ( ctx, -EACCES );
        !           595:        }
        !           596: 
        !           597:        /* Check RSN IE */
        !           598:        this_rsn = sec80211_find_rsn ( ( union ieee80211_ie * ) pkt->data,
        !           599:                                       pkt->data + pkt->datalen,
        !           600:                                       &this_is_rsn, &this_rsn_end );
        !           601:        if ( this_rsn )
        !           602:                new_rsn = sec80211_find_rsn ( ( union ieee80211_ie * )
        !           603:                                                      this_rsn_end,
        !           604:                                              pkt->data + pkt->datalen,
        !           605:                                              &new_is_rsn, &new_rsn_end );
        !           606:        else
        !           607:                new_rsn = NULL;
        !           608: 
        !           609:        if ( ! ctx->ap_rsn_ie || ! this_rsn ||
        !           610:             ctx->ap_rsn_ie_len != ( this_rsn_end - this_rsn ) ||
        !           611:             ctx->ap_rsn_is_rsn != this_is_rsn ||
        !           612:             memcmp ( ctx->ap_rsn_ie, this_rsn, ctx->ap_rsn_ie_len ) != 0 ) {
        !           613:                DBGC ( ctx, "WPA %p ALERT: RSN mismatch in 3/4\n", ctx );
        !           614:                DBGC2 ( ctx, "WPA %p RSNs (in 3/4, in beacon):\n", ctx );
        !           615:                DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn );
        !           616:                DBGC2_HD ( ctx, ctx->ap_rsn_ie, ctx->ap_rsn_ie_len );
        !           617:                return wpa_fail ( ctx, -EACCES );
        !           618:        }
        !           619: 
        !           620:        /* Don't switch if they just supplied both styles of IE
        !           621:           simultaneously; we need two RSN IEs or two WPA IEs to
        !           622:           switch ciphers. They'll be immediately consecutive because
        !           623:           of ordering guarantees. */
        !           624:        if ( new_rsn && this_is_rsn == new_is_rsn ) {
        !           625:                struct net80211_wlan *assoc = ctx->dev->associating;
        !           626:                DBGC ( ctx, "WPA %p: accommodating bait-and-switch tactics\n",
        !           627:                       ctx );
        !           628:                DBGC2 ( ctx, "WPA %p RSNs (in 3/4+beacon, new in 3/4):\n",
        !           629:                        ctx );
        !           630:                DBGC2_HD ( ctx, this_rsn, this_rsn_end - this_rsn );
        !           631:                DBGC2_HD ( ctx, new_rsn, new_rsn_end - new_rsn );
        !           632: 
        !           633:                if ( ( rc = sec80211_detect_ie ( new_is_rsn, new_rsn,
        !           634:                                                 new_rsn_end,
        !           635:                                                 &assoc->handshaking,
        !           636:                                                 &assoc->crypto ) ) != 0 )
        !           637:                        DBGC ( ctx, "WPA %p: bait-and-switch invalid, staying "
        !           638:                               "with original request\n", ctx );
        !           639:        } else {
        !           640:                new_rsn = this_rsn;
        !           641:                new_is_rsn = this_is_rsn;
        !           642:                new_rsn_end = this_rsn_end;
        !           643:        }
        !           644: 
        !           645:        /* Grab group cryptosystem ID */
        !           646:        ctx->gcrypt = sec80211_rsn_get_net80211_crypt ( *( u32 * )
        !           647:                                                        ( new_rsn + 2 ) );
        !           648: 
        !           649:        /* Check for a GTK, if info field is encrypted */
        !           650:        if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) {
        !           651:                rc = wpa_maybe_install_gtk ( ctx,
        !           652:                                             ( union ieee80211_ie * ) pkt->data,
        !           653:                                             pkt->data + pkt->datalen,
        !           654:                                             pkt->rsc );
        !           655:                if ( rc < 0 ) {
        !           656:                        DBGC ( ctx, "WPA %p did not install GTK in 3/4: %s\n",
        !           657:                               ctx, strerror ( rc ) );
        !           658:                        if ( rc != -ENOENT )
        !           659:                                return wpa_fail ( ctx, rc );
        !           660:                }
        !           661:        }
        !           662: 
        !           663:        DBGC ( ctx, "WPA %p: received 3/4, looks OK\n", ctx );
        !           664: 
        !           665:        /* Send final message */
        !           666:        rc = wpa_send_final ( ctx, pkt, is_rsn, kie );
        !           667:        if ( rc < 0 )
        !           668:                return wpa_fail ( ctx, rc );
        !           669: 
        !           670:        /* Install PTK */
        !           671:        rc = wpa_install_ptk ( ctx, pkt->keysize );
        !           672:        if ( rc < 0 ) {
        !           673:                DBGC ( ctx, "WPA %p failed to install PTK: %s\n", ctx,
        !           674:                       strerror ( rc ) );
        !           675:                return wpa_fail ( ctx, rc );
        !           676:        }
        !           677: 
        !           678:        /* Mark us as needing a new Snonce if we rekey */
        !           679:        ctx->have_Snonce = 0;
        !           680: 
        !           681:        /* Done! */
        !           682:        ctx->state = WPA_SUCCESS;
        !           683:        return 0;
        !           684: }
        !           685: 
        !           686: 
        !           687: /**
        !           688:  * Handle receipt of first frame in Group Key Handshake
        !           689:  *
        !           690:  * @v ctx      WPA common context
        !           691:  * @v pkt      EAPOL-Key packet
        !           692:  * @v is_rsn   If TRUE, frame uses new RSN format
        !           693:  * @v kie      Key integrity and encryption handler
        !           694:  * @ret rc     Return status code
        !           695:  */
        !           696: static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx,
        !           697:                               struct eapol_key_pkt *pkt, int is_rsn,
        !           698:                               struct wpa_kie *kie )
        !           699: {
        !           700:        int rc;
        !           701: 
        !           702:        /*
        !           703:         * WPA and RSN do this completely differently.
        !           704:         *
        !           705:         * The idea of encoding the GTK (or PMKID, or various other
        !           706:         * things) into a KDE that looks like an information element
        !           707:         * is an RSN innovation; old WPA code never encapsulates
        !           708:         * things like that. If it looks like an info element, it
        !           709:         * really is (for the WPA IE check in frames 2/4 and 3/4). The
        !           710:         * "key data encrypted" bit in the info field is also specific
        !           711:         * to RSN.
        !           712:         *
        !           713:         * So from an old WPA host, 3/4 does not contain an
        !           714:         * encapsulated GTK. The first frame of the GK handshake
        !           715:         * contains it, encrypted, but without a KDE wrapper, and with
        !           716:         * the key ID field (which iPXE doesn't use) shoved away in
        !           717:         * the reserved bits in the info field, and the TxRx bit
        !           718:         * stealing the Install bit's spot.
        !           719:         */
        !           720: 
        !           721:        if ( is_rsn && ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) ) {
        !           722:                rc = wpa_maybe_install_gtk ( ctx,
        !           723:                                             ( union ieee80211_ie * ) pkt->data,
        !           724:                                             pkt->data + pkt->datalen,
        !           725:                                             pkt->rsc );
        !           726:                if ( rc < 0 ) {
        !           727:                        DBGC ( ctx, "WPA %p: failed to install GTK in 1/2: "
        !           728:                               "%s\n", ctx, strerror ( rc ) );
        !           729:                        return wpa_fail ( ctx, rc );
        !           730:                }
        !           731:        } else {
        !           732:                rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data,
        !           733:                                    &pkt->datalen );
        !           734:                if ( rc < 0 ) {
        !           735:                        DBGC ( ctx, "WPA %p: failed to decrypt GTK: %s\n",
        !           736:                               ctx, strerror ( rc ) );
        !           737:                        return rc; /* non-fatal */
        !           738:                }
        !           739:                if ( pkt->datalen > sizeof ( ctx->gtk.tk ) ) {
        !           740:                        DBGC ( ctx, "WPA %p: too much GTK data (%d > %zd)\n",
        !           741:                               ctx, pkt->datalen, sizeof ( ctx->gtk.tk ) );
        !           742:                        return wpa_fail ( ctx, -EINVAL );
        !           743:                }
        !           744: 
        !           745:                memcpy ( &ctx->gtk.tk, pkt->data, pkt->datalen );
        !           746:                wpa_install_gtk ( ctx, pkt->datalen, pkt->rsc );
        !           747:        }
        !           748: 
        !           749:        DBGC ( ctx, "WPA %p: received 1/2, looks OK\n", ctx );
        !           750: 
        !           751:        return wpa_send_final ( ctx, pkt, is_rsn, kie );
        !           752: }
        !           753: 
        !           754: 
        !           755: /**
        !           756:  * Handle receipt of EAPOL-Key frame for WPA
        !           757:  *
        !           758:  * @v iob      I/O buffer
        !           759:  * @v netdev   Network device
        !           760:  * @v ll_dest  Link-layer destination address
        !           761:  * @v ll_source        Source link-layer address
        !           762:  */
        !           763: static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev,
        !           764:                          const void *ll_dest __unused,
        !           765:                          const void *ll_source )
        !           766: {
        !           767:        struct net80211_device *dev = net80211_get ( netdev );
        !           768:        struct eapol_key_pkt *pkt = iob->data;
        !           769:        int is_rsn, found_ctx;
        !           770:        struct wpa_common_ctx *ctx;
        !           771:        int rc = 0;
        !           772:        struct wpa_kie *kie;
        !           773:        u8 their_mic[16], our_mic[16];
        !           774: 
        !           775:        if ( pkt->type != EAPOL_KEY_TYPE_WPA &&
        !           776:             pkt->type != EAPOL_KEY_TYPE_RSN ) {
        !           777:                DBG ( "EAPOL-Key: packet not of 802.11 type\n" );
        !           778:                rc = -EINVAL;
        !           779:                goto drop;
        !           780:        }
        !           781: 
        !           782:        is_rsn = ( pkt->type == EAPOL_KEY_TYPE_RSN );
        !           783: 
        !           784:        if ( ! dev ) {
        !           785:                DBG ( "EAPOL-Key: packet not from 802.11\n" );
        !           786:                rc = -EINVAL;
        !           787:                goto drop;
        !           788:        }
        !           789: 
        !           790:        if ( memcmp ( dev->bssid, ll_source, ETH_ALEN ) != 0 ) {
        !           791:                DBG ( "EAPOL-Key: packet not from associated AP\n" );
        !           792:                rc = -EINVAL;
        !           793:                goto drop;
        !           794:        }
        !           795: 
        !           796:        if ( ! ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_ACK ) ) {
        !           797:                DBG ( "EAPOL-Key: packet sent in wrong direction\n" );
        !           798:                rc = -EINVAL;
        !           799:                goto drop;
        !           800:        }
        !           801: 
        !           802:        found_ctx = 0;
        !           803:        list_for_each_entry ( ctx, &wpa_contexts, list ) {
        !           804:                if ( ctx->dev == dev ) {
        !           805:                        found_ctx = 1;
        !           806:                        break;
        !           807:                }
        !           808:        }
        !           809: 
        !           810:        if ( ! found_ctx ) {
        !           811:                DBG ( "EAPOL-Key: no WPA context to handle packet for %p\n",
        !           812:                      dev );
        !           813:                rc = -ENOENT;
        !           814:                goto drop;
        !           815:        }
        !           816: 
        !           817:        if ( ( void * ) ( pkt + 1 ) + ntohs ( pkt->datalen ) > iob->tail ) {
        !           818:                DBGC ( ctx, "WPA %p: packet truncated (has %zd extra bytes, "
        !           819:                       "states %d)\n", ctx, iob->tail - ( void * ) ( pkt + 1 ),
        !           820:                       ntohs ( pkt->datalen ) );
        !           821:                rc = -EINVAL;
        !           822:                goto drop;
        !           823:        }
        !           824: 
        !           825:        /* Get a handle on key integrity/encryption handler */
        !           826:        kie = wpa_find_kie ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION );
        !           827:        if ( ! kie ) {
        !           828:                DBGC ( ctx, "WPA %p: no support for packet version %d\n", ctx,
        !           829:                       ntohs ( pkt->info ) & EAPOL_KEY_INFO_VERSION );
        !           830:                rc = wpa_fail ( ctx, -ENOTSUP );
        !           831:                goto drop;
        !           832:        }
        !           833: 
        !           834:        /* Check MIC */
        !           835:        if ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_MIC ) {
        !           836:                memcpy ( their_mic, pkt->mic, sizeof ( pkt->mic ) );
        !           837:                memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
        !           838:                kie->mic ( &ctx->ptk.kck, ( void * ) pkt - EAPOL_HDR_LEN,
        !           839:                           EAPOL_HDR_LEN + sizeof ( *pkt ) +
        !           840:                           ntohs ( pkt->datalen ), our_mic );
        !           841:                DBGC2 ( ctx, "WPA %p MIC comparison (theirs, ours):\n", ctx );
        !           842:                DBGC2_HD ( ctx, their_mic, 16 );
        !           843:                DBGC2_HD ( ctx, our_mic, 16 );
        !           844:                if ( memcmp ( their_mic, our_mic, sizeof ( pkt->mic ) ) != 0 ) {
        !           845:                        DBGC ( ctx, "WPA %p: EAPOL MIC failure\n", ctx );
        !           846:                        goto drop;
        !           847:                }
        !           848:        }
        !           849: 
        !           850:        /* Fix byte order to local */
        !           851:        pkt->info = ntohs ( pkt->info );
        !           852:        pkt->keysize = ntohs ( pkt->keysize );
        !           853:        pkt->datalen = ntohs ( pkt->datalen );
        !           854:        pkt->replay = be64_to_cpu ( pkt->replay );
        !           855: 
        !           856:        /* Check replay counter */
        !           857:        if ( ctx->replay != ~0ULL && ctx->replay >= pkt->replay ) {
        !           858:                DBGC ( ctx, "WPA %p ALERT: Replay detected! "
        !           859:                       "(%08x:%08x >= %08x:%08x)\n", ctx,
        !           860:                       ( u32 ) ( ctx->replay >> 32 ), ( u32 ) ctx->replay,
        !           861:                       ( u32 ) ( pkt->replay >> 32 ), ( u32 ) pkt->replay );
        !           862:                rc = 0;         /* ignore without error */
        !           863:                goto drop;
        !           864:        }
        !           865:        ctx->replay = pkt->replay;
        !           866: 
        !           867:        /* Decrypt key data */
        !           868:        if ( pkt->info & EAPOL_KEY_INFO_KEY_ENC ) {
        !           869:                rc = kie->decrypt ( &ctx->ptk.kek, pkt->iv, pkt->data,
        !           870:                                    &pkt->datalen );
        !           871:                if ( rc < 0 ) {
        !           872:                        DBGC ( ctx, "WPA %p: failed to decrypt packet: %s\n",
        !           873:                               ctx, strerror ( rc ) );
        !           874:                        goto drop;
        !           875:                }
        !           876:        }
        !           877: 
        !           878:        /* Hand it off to appropriate handler */
        !           879:        switch ( pkt->info & ( EAPOL_KEY_INFO_TYPE |
        !           880:                               EAPOL_KEY_INFO_KEY_MIC ) ) {
        !           881:        case EAPOL_KEY_TYPE_PTK:
        !           882:                rc = wpa_handle_1_of_4 ( ctx, pkt, is_rsn, kie );
        !           883:                break;
        !           884: 
        !           885:        case EAPOL_KEY_TYPE_PTK | EAPOL_KEY_INFO_KEY_MIC:
        !           886:                rc = wpa_handle_3_of_4 ( ctx, pkt, is_rsn, kie );
        !           887:                break;
        !           888: 
        !           889:        case EAPOL_KEY_TYPE_GTK | EAPOL_KEY_INFO_KEY_MIC:
        !           890:                rc = wpa_handle_1_of_2 ( ctx, pkt, is_rsn, kie );
        !           891:                break;
        !           892: 
        !           893:        default:
        !           894:                DBGC ( ctx, "WPA %p: Invalid combination of key flags %04x\n",
        !           895:                       ctx, pkt->info );
        !           896:                rc = -EINVAL;
        !           897:                break;
        !           898:        }
        !           899: 
        !           900:  drop:
        !           901:        free_iob ( iob );
        !           902:        return rc;
        !           903: }
        !           904: 
        !           905: struct eapol_handler eapol_key_handler __eapol_handler = {
        !           906:        .type = EAPOL_TYPE_KEY,
        !           907:        .rx = eapol_key_rx,
        !           908: };
        !           909: 
        !           910: /* WPA always needs EAPOL in order to be useful */
        !           911: REQUIRE_OBJECT ( eapol );

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.