[eapol] Replace EAPoL code

Replace the GPL2+-only EAPoL code (currently used only for WPA) with
new code licensed under GPL2+-or-UBDL.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/141/merge
Michael Brown 2021-01-19 12:34:10 +00:00
parent 8606204595
commit 274ad69012
3 changed files with 110 additions and 147 deletions

View File

@ -1,114 +1,58 @@
/*
* Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef _IPXE_EAPOL_H
#define _IPXE_EAPOL_H
/** @file
*
* Definitions for EAPOL (Extensible Authentication Protocol over
* LANs) frames. Definitions for the packets usually encapsulated in
* them are elsewhere.
* Extensible Authentication Protocol over LAN (EAPoL)
*
*/
#include <ipxe/tables.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/netdevice.h>
#include <ipxe/tables.h>
FILE_LICENCE ( GPL2_OR_LATER );
/**
* @defgroup eapol_type EAPOL archetype identifiers
* @{
*/
#define EAPOL_TYPE_EAP 0 /**< EAP authentication handshake packet */
#define EAPOL_TYPE_START 1 /**< Request by Peer to begin (no data) */
#define EAPOL_TYPE_LOGOFF 2 /**< Request by Peer to terminate (no data) */
#define EAPOL_TYPE_KEY 3 /**< EAPOL-Key packet */
/** @} */
/** Expected EAPOL version field value
*
* Version 2 is often seen and has no format differences from version 1;
* however, many older APs will completely drop version-2 packets, so
* we advertise ourselves as version 1.
*/
#define EAPOL_THIS_VERSION 1
/** Length of an EAPOL frame header */
#define EAPOL_HDR_LEN 4
/** An EAPOL frame
*
* This may encapsulate an eap_pkt, an eapol_key_pkt, or a Start or
* Logoff request with no data attached. It is transmitted directly in
* an Ethernet frame, with no IP packet header.
*/
struct eapol_frame
{
/** EAPOL version identifier, always 1 */
u8 version;
/** EAPOL archetype identifier indicating format of payload */
u8 type;
/** Length of payload, in network byte order */
u16 length;
/** Payload, if @a type is EAP or EAPOL-Key */
u8 data[0];
/** EAPoL header */
struct eapol_header {
/** Version */
uint8_t version;
/** Type */
uint8_t type;
/** Payload length */
uint16_t len;
} __attribute__ (( packed ));
/** 802.1X-2001 */
#define EAPOL_VERSION_2001 1
/** An EAPOL frame type handler
*
* Normally there will be at most two of these, one for EAP and one
* for EAPOL-Key frames. The EAPOL interface code handles Start and
* Logoff directly.
*/
struct eapol_handler
{
/** EAPOL archetype identifier for payload this handler will handle */
u8 type;
/** EAPoL key */
#define EAPOL_TYPE_KEY 5
/** Receive EAPOL-encapsulated packet of specified type
/** An EAPoL handler */
struct eapol_handler {
/** Type */
uint8_t type;
/**
* Process received packet
*
* @v iob I/O buffer containing packet payload
* @v netdev Network device from which packet was received
* @V ll_dest Destination link-layer address
* @v ll_source Source link-layer address
* @ret rc Return status code
* @v iobuf I/O buffer
* @v netdev Network device
* @v ll_source Link-layer source address
* @ret rc Return status code
*
* The I/O buffer will have the EAPOL header pulled off it, so
* @c iob->data points to the first byte of the payload.
*
* This function takes ownership of the I/O buffer passed to it.
* This method takes ownership of the I/O buffer.
*/
int ( * rx ) ( struct io_buffer *iob, struct net_device *netdev,
const void *ll_dest, const void *ll_source );
int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev,
const void *ll_source );
};
#define EAPOL_HANDLERS __table ( struct eapol_handler, "eapol_handlers" )
#define __eapol_handler __table_entry ( EAPOL_HANDLERS, 01 )
/** EAPoL handler table */
#define EAPOL_HANDLERS __table ( struct eapol_handler, "eapol_handlers" )
/** Declare an EAPoL handler */
#define __eapol_handler __table_entry ( EAPOL_HANDLERS, 01 )
extern struct net_protocol eapol_protocol __net_protocol;
#endif /* _IPXE_EAPOL_H */

View File

@ -414,12 +414,13 @@ static int wpa_maybe_install_gtk ( struct wpa_common_ctx *ctx,
static struct io_buffer * wpa_alloc_frame ( int kdlen )
{
struct io_buffer *ret = alloc_iob ( sizeof ( struct eapol_key_pkt ) +
kdlen + EAPOL_HDR_LEN +
kdlen +
sizeof ( struct eapol_header ) +
MAX_LL_HEADER_LEN );
if ( ! ret )
return NULL;
iob_reserve ( ret, MAX_LL_HEADER_LEN + EAPOL_HDR_LEN );
iob_reserve ( ret, MAX_LL_HEADER_LEN + sizeof ( struct eapol_header ) );
memset ( iob_put ( ret, sizeof ( struct eapol_key_pkt ) ), 0,
sizeof ( struct eapol_key_pkt ) );
@ -442,19 +443,19 @@ static int wpa_send_eapol ( struct io_buffer *iob, struct wpa_common_ctx *ctx,
struct wpa_kie *kie )
{
struct eapol_key_pkt *pkt = iob->data;
struct eapol_frame *eapol = iob_push ( iob, EAPOL_HDR_LEN );
struct eapol_header *eapol = iob_push ( iob, sizeof ( *eapol ) );
pkt->info = htons ( pkt->info );
pkt->keysize = htons ( pkt->keysize );
pkt->datalen = htons ( pkt->datalen );
pkt->replay = cpu_to_be64 ( pkt->replay );
eapol->version = EAPOL_THIS_VERSION;
eapol->version = EAPOL_VERSION_2001;
eapol->type = EAPOL_TYPE_KEY;
eapol->length = htons ( iob->tail - iob->data - sizeof ( *eapol ) );
eapol->len = htons ( iob->tail - iob->data - sizeof ( *eapol ) );
memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
if ( kie )
kie->mic ( &ctx->ptk.kck, eapol, EAPOL_HDR_LEN +
kie->mic ( &ctx->ptk.kck, eapol, sizeof ( *eapol ) +
sizeof ( *pkt ) + ntohs ( pkt->datalen ),
pkt->mic );
@ -762,21 +763,23 @@ static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx,
*
* @v iob I/O buffer
* @v netdev Network device
* @v ll_dest Link-layer destination address
* @v ll_source Source link-layer address
*/
static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev,
const void *ll_dest __unused,
const void *ll_source )
{
struct net80211_device *dev = net80211_get ( netdev );
struct eapol_key_pkt *pkt = iob->data;
struct eapol_header *eapol;
struct eapol_key_pkt *pkt;
int is_rsn, found_ctx;
struct wpa_common_ctx *ctx;
int rc = 0;
struct wpa_kie *kie;
u8 their_mic[16], our_mic[16];
eapol = iob->data;
pkt = ( ( ( void * ) eapol ) + sizeof ( *eapol ) );
if ( pkt->type != EAPOL_KEY_TYPE_WPA &&
pkt->type != EAPOL_KEY_TYPE_RSN ) {
DBG ( "EAPOL-Key: packet not of 802.11 type\n" );
@ -840,8 +843,8 @@ static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev,
if ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_MIC ) {
memcpy ( their_mic, pkt->mic, sizeof ( pkt->mic ) );
memset ( pkt->mic, 0, sizeof ( pkt->mic ) );
kie->mic ( &ctx->ptk.kck, ( void * ) pkt - EAPOL_HDR_LEN,
EAPOL_HDR_LEN + sizeof ( *pkt ) +
kie->mic ( &ctx->ptk.kck, eapol,
sizeof ( *eapol ) + sizeof ( *pkt ) +
ntohs ( pkt->datalen ), our_mic );
DBGC2 ( ctx, "WPA %p MIC comparison (theirs, ours):\n", ctx );
DBGC2_HD ( ctx, their_mic, 16 );

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -15,74 +15,90 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER );
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <assert.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/iobuf.h>
#include <ipxe/if_ether.h>
#include <ipxe/netdevice.h>
#include <ipxe/eapol.h>
/** @file
*
* 802.1X Extensible Authentication Protocol over LANs demultiplexer
* Extensible Authentication Protocol over LAN (EAPoL)
*
*/
#include <ipxe/netdevice.h>
#include <ipxe/iobuf.h>
#include <ipxe/if_ether.h>
#include <ipxe/eapol.h>
#include <errno.h>
#include <byteswap.h>
/**
* Receive EAPOL network-layer packet
* Process EAPoL packet
*
* @v iob I/O buffer
* @v netdev Network device
* @v ll_dest Link-layer destination address
* @v ll_source Link-layer source address
* @v flags Packet flags
*
* This function takes ownership of the I/O buffer passed to it.
* @v iobuf I/O buffer
* @v netdev Network device
* @v ll_dest Link-layer destination address
* @v ll_source Link-layer source address
* @v flags Packet flags
* @ret rc Return status code
*/
static int eapol_rx ( struct io_buffer *iob, struct net_device *netdev,
const void *ll_dest, const void *ll_source,
static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev,
const void *ll_dest __unused, const void *ll_source,
unsigned int flags __unused ) {
struct eapol_frame *eapol = iob->data;
struct eapol_header *eapol;
struct eapol_handler *handler;
size_t remaining;
size_t len;
int rc;
if ( iob_len ( iob ) < EAPOL_HDR_LEN ) {
free_iob ( iob );
return -EINVAL;
/* Sanity checks */
if ( iob_len ( iobuf ) < sizeof ( *eapol ) ) {
DBGC ( netdev, "EAPOL %s underlength header:\n",
netdev->name );
DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
rc = -EINVAL;
goto drop;
}
eapol = iobuf->data;
remaining = ( iob_len ( iobuf ) - sizeof ( *eapol ) );
len = ntohs ( eapol->len );
if ( len > remaining ) {
DBGC ( netdev, "EAPOL %s v%d type %d len %zd underlength "
"payload:\n", netdev->name, eapol->version,
eapol->type, len );
DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
rc = -EINVAL;
goto drop;
}
/* Strip any trailing padding */
iob_unput ( iobuf, ( len - remaining ) );
/* Handle according to type */
for_each_table_entry ( handler, EAPOL_HANDLERS ) {
if ( handler->type == eapol->type ) {
iob_pull ( iob, EAPOL_HDR_LEN );
return handler->rx ( iob, netdev, ll_dest, ll_source );
return handler->rx ( iob_disown ( iobuf ) , netdev,
ll_source );
}
}
rc = -ENOTSUP;
DBGC ( netdev, "EAPOL %s v%d type %d unsupported\n",
netdev->name, eapol->version, eapol->type );
DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
free_iob ( iob );
return -( ENOTSUP | ( ( eapol->type & 0x1f ) << 8 ) );
drop:
free_iob ( iobuf );
return rc;
}
/**
* Transcribe EAPOL network-layer address
*
* @v net_addr Network-layer address
* @ret str String representation of network-layer address
*
* EAPOL doesn't have network-layer addresses, so we just return the
* string @c "<EAPOL>".
*/
static const char * eapol_ntoa ( const void *net_addr __unused )
{
return "<EAPOL>";
}
/** EAPOL network protocol */
/** EAPoL protocol */
struct net_protocol eapol_protocol __net_protocol = {
.name = "EAPOL",
.rx = eapol_rx,
.ntoa = eapol_ntoa,
.net_proto = htons ( ETH_P_EAPOL ),
.rx = eapol_rx,
};