2007-01-12 00:54:13 +00:00
/* airpdcap.c
*
* $ Id $
* Copyright ( c ) 2006 CACE Technologies , Davis ( California )
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*/
2007-01-01 20:07:23 +00:00
/****************************************************************************/
/* File includes */
2007-01-08 21:19:46 +00:00
# include <epan/tvbuff.h>
# include <epan/crc32.h>
2007-01-11 02:42:34 +00:00
# include <epan/strutil.h>
2007-02-13 20:57:22 +00:00
# include <epan/ws_strsplit.h>
2007-02-20 18:44:22 +00:00
# include <epan/emem.h>
2007-04-22 18:26:45 +00:00
# include <epan/pint.h>
2007-01-08 21:19:46 +00:00
2006-12-05 21:06:09 +00:00
# include "airpdcap_system.h"
# include "airpdcap_int.h"
2007-01-12 00:33:32 +00:00
# include "crypt-sha1.h"
2007-01-02 22:49:57 +00:00
# include "crypt-md5.h"
2006-12-05 21:06:09 +00:00
2006-12-27 23:05:55 +00:00
# include "airpdcap_debug.h"
2006-12-05 21:06:09 +00:00
2007-01-11 02:42:34 +00:00
# include "wep-wpadefs.h"
2007-01-01 20:07:23 +00:00
/****************************************************************************/
/****************************************************************************/
/* Constant definitions */
2006-12-05 21:06:09 +00:00
# define AIRPDCAP_SHA_DIGEST_LEN 20
2007-01-01 20:07:23 +00:00
/* EAPOL definitions */
2006-12-27 23:05:55 +00:00
/**
* Length of the EAPOL - Key key confirmation key ( KCK ) used to calculate
* MIC over EAPOL frame and validate an EAPOL packet ( 128 bits )
*/
2006-12-05 21:06:09 +00:00
# define AIRPDCAP_WPA_KCK_LEN 16
2006-12-27 23:05:55 +00:00
/**
* Offset of the Key MIC in the EAPOL packet body
*/
2006-12-05 21:06:09 +00:00
# define AIRPDCAP_WPA_MICKEY_OFFSET 77
2006-12-27 23:05:55 +00:00
/**
* Maximum length of the EAPOL packet ( it depends on the maximum MAC
* frame size )
*/
2006-12-05 21:06:09 +00:00
# define AIRPDCAP_WPA_MAX_EAPOL_LEN 4095
2006-12-27 23:05:55 +00:00
/**
* EAPOL Key Descriptor Version 1 , used for all EAPOL - Key frames to and
* from a STA when neither the group nor pairwise ciphers are CCMP for
* Key Descriptor 1.
* @ note
* Defined in 802.11 i - 2004 , page 78
*/
2006-12-05 21:06:09 +00:00
# define AIRPDCAP_WPA_KEY_VER_CCMP 1
2006-12-27 23:05:55 +00:00
/**
* EAPOL Key Descriptor Version 2 , used for all EAPOL - Key frames to and
* from a STA when either the pairwise or the group cipher is AES - CCMP
* for Key Descriptor 2.
* / note
* Defined in 802.11 i - 2004 , page 78
*/
2006-12-05 21:06:09 +00:00
# define AIRPDCAP_WPA_KEY_VER_AES_CCMP 2
2007-01-01 20:07:23 +00:00
/****************************************************************************/
/****************************************************************************/
/* Macro definitions */
2006-12-05 21:06:09 +00:00
extern const UINT32 crc32_table [ 256 ] ;
# define CRC(crc, ch) (crc = (crc >> 8) ^ crc32_table[(crc ^ (ch)) & 0xff])
# define AIRPDCAP_GET_TK(ptk) (ptk + 32)
2007-01-01 20:07:23 +00:00
/****************************************************************************/
/****************************************************************************/
/* Type definitions */
/* Internal function prototype declarations */
2006-12-05 21:06:09 +00:00
# ifdef __cplusplus
extern " C " {
# endif
2006-12-27 23:05:55 +00:00
/**
* It is a step of the PBKDF2 ( specifically the PKCS # 5 v2 .0 ) defined in
* the RFC 2898 to derive a key ( used as PMK in WPA )
* @ param password [ IN ] pointer to a password ( sequence of between 8 and
* 63 ASCII encoded characters )
* @ param ssid [ IN ] pointer to the SSID string encoded in max 32 ASCII
* encoded characters
* @ param iterations [ IN ] times to hash the password ( 4096 for WPA )
* @ param count [ IN ] ? ? ?
* @ param output [ OUT ] pointer to a preallocated buffer of
* AIRPDCAP_SHA_DIGEST_LEN characters that will contain a part of the key
*/
2007-01-26 21:54:59 +00:00
static INT AirPDcapRsnaPwd2PskStep (
2007-06-27 19:02:58 +00:00
const guint8 * ppbytes ,
const guint passLength ,
2007-05-20 22:40:35 +00:00
const CHAR * ssid ,
const size_t ssidLength ,
const INT iterations ,
const INT count ,
UCHAR * output )
;
2006-12-27 23:05:55 +00:00
/**
* It calculates the passphrase - to - PSK mapping reccomanded for use with
* RSNAs . This implementation uses the PBKDF2 method defined in the RFC
* 2898.
* @ param password [ IN ] pointer to a password ( sequence of between 8 and
* 63 ASCII encoded characters )
* @ param ssid [ IN ] pointer to the SSID string encoded in max 32 ASCII
* encoded characters
* @ param output [ OUT ] calculated PSK ( to use as PMK in WPA )
* @ note
* Described in 802.11 i - 2004 , page 165
*/
2007-01-26 21:54:59 +00:00
static INT AirPDcapRsnaPwd2Psk (
2007-06-27 19:02:58 +00:00
const CHAR * passphrase ,
2007-05-20 22:40:35 +00:00
const CHAR * ssid ,
const size_t ssidLength ,
UCHAR * output )
;
2006-12-27 23:05:55 +00:00
2007-01-26 21:54:59 +00:00
static INT AirPDcapRsnaMng (
2007-05-20 22:40:35 +00:00
UCHAR * decrypt_data ,
2007-06-14 22:09:14 +00:00
guint mac_header_len ,
guint * decrypt_len ,
2007-05-20 22:40:35 +00:00
PAIRPDCAP_KEY_ITEM key ,
AIRPDCAP_SEC_ASSOCIATION * sa ,
2007-06-14 22:09:14 +00:00
INT offset )
2007-05-20 22:40:35 +00:00
;
2006-12-27 23:05:55 +00:00
2007-01-26 21:54:59 +00:00
static INT AirPDcapWepMng (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
UCHAR * decrypt_data ,
2007-06-14 22:09:14 +00:00
guint mac_header_len ,
guint * decrypt_len ,
2007-05-20 22:40:35 +00:00
PAIRPDCAP_KEY_ITEM key ,
AIRPDCAP_SEC_ASSOCIATION * sa ,
2007-06-14 22:09:14 +00:00
INT offset )
2007-05-20 22:40:35 +00:00
;
2006-12-27 23:05:55 +00:00
2007-01-26 21:54:59 +00:00
static INT AirPDcapRsna4WHandshake (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
const UCHAR * data ,
AIRPDCAP_SEC_ASSOCIATION * sa ,
PAIRPDCAP_KEY_ITEM key ,
INT offset )
;
2006-12-27 23:05:55 +00:00
/**
* It checks whether the specified key is corrected or not .
* @ note
* For a standard WEP key the length will be changed to the standard
* length , and the type changed in a generic WEP key .
* @ param key [ IN ] pointer to the key to validate
* @ return
* - TRUE : the key contains valid fields and values
* - FALSE : the key has some invalid field or value
*/
2007-01-26 21:54:59 +00:00
static INT AirPDcapValidateKey (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_KEY_ITEM key )
;
2006-12-27 23:05:55 +00:00
2007-01-26 21:54:59 +00:00
static INT AirPDcapRsnaMicCheck (
2007-05-20 22:40:35 +00:00
UCHAR * eapol ,
USHORT eapol_len ,
UCHAR KCK [ AIRPDCAP_WPA_KCK_LEN ] ,
USHORT key_ver )
;
2006-12-27 23:05:55 +00:00
/**
* @ param ctx [ IN ] pointer to the current context
* @ param id [ IN ] id of the association ( composed by BSSID and MAC of
* the station )
* @ return
* - index of the Security Association structure if found
* - - 1 , if the specified addresses pair BSSID - STA MAC has not been found
*/
2007-01-26 21:54:59 +00:00
static INT AirPDcapGetSa (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
AIRPDCAP_SEC_ASSOCIATION_ID * id )
;
2006-12-27 23:05:55 +00:00
2007-01-26 21:54:59 +00:00
static INT AirPDcapStoreSa (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
AIRPDCAP_SEC_ASSOCIATION_ID * id )
;
2006-12-27 23:05:55 +00:00
2007-04-22 18:26:45 +00:00
static const UCHAR * AirPDcapGetStaAddress (
2007-05-20 22:40:35 +00:00
const AIRPDCAP_MAC_FRAME_ADDR4 * frame )
;
2006-12-27 23:05:55 +00:00
2007-04-22 18:26:45 +00:00
static const UCHAR * AirPDcapGetBssidAddress (
2007-05-20 22:40:35 +00:00
const AIRPDCAP_MAC_FRAME_ADDR4 * frame )
;
2006-12-27 23:05:55 +00:00
2007-01-26 21:54:59 +00:00
static void AirPDcapRsnaPrfX (
2007-05-20 22:40:35 +00:00
AIRPDCAP_SEC_ASSOCIATION * sa ,
const UCHAR pmk [ 32 ] ,
const UCHAR snonce [ 32 ] ,
const INT x , /* for TKIP 512, for CCMP 384 */
UCHAR * ptk )
;
2006-12-27 23:05:55 +00:00
2007-10-31 00:15:17 +00:00
static void AirPDcapCleanKeys ( PAIRPDCAP_CONTEXT ctx ) ;
2006-12-05 21:06:09 +00:00
# ifdef __cplusplus
}
# endif
2007-01-01 20:07:23 +00:00
/****************************************************************************/
/****************************************************************************/
/* Exported function definitions */
2006-12-05 21:06:09 +00:00
# ifdef __cplusplus
extern " C " {
# endif
2006-12-27 23:05:55 +00:00
INT AirPDcapPacketProcess (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
2007-06-14 22:09:14 +00:00
const guint8 * data ,
const guint mac_header_len ,
const guint tot_len ,
2007-05-20 22:40:35 +00:00
UCHAR * decrypt_data ,
2007-06-14 22:09:14 +00:00
guint * decrypt_len ,
2007-05-20 22:40:35 +00:00
PAIRPDCAP_KEY_ITEM key ,
2007-06-14 22:09:14 +00:00
gboolean mngHandshake ,
gboolean mngDecrypt )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
const UCHAR * address ;
AIRPDCAP_SEC_ASSOCIATION_ID id ;
2007-06-14 22:09:14 +00:00
int index ;
2007-05-20 22:40:35 +00:00
PAIRPDCAP_SEC_ASSOCIATION sa ;
2007-06-14 22:09:14 +00:00
int offset = 0 ;
guint bodyLength ;
const guint8 dot1x_header [ ] = {
2007-05-20 22:40:35 +00:00
0xAA , /* DSAP=SNAP */
0xAA , /* SSAP=SNAP */
0x03 , /* Control field=Unnumbered frame */
0x00 , 0x00 , 0x00 , /* Org. code=encaps. Ethernet */
0x88 , 0x8E /* Type: 802.1X authentication */
} ;
2006-12-05 21:06:09 +00:00
# ifdef _DEBUG
2007-05-20 22:40:35 +00:00
CHAR msgbuf [ 255 ] ;
2006-12-05 21:06:09 +00:00
# endif
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapPacketProcess " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ctx = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " NULL context " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapPacketProcess " ) ;
return AIRPDCAP_RET_UNSUCCESS ;
}
2007-06-14 22:09:14 +00:00
if ( data = = NULL | | tot_len = = 0 ) {
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " NULL data or length=0 " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapPacketProcess " ) ;
return AIRPDCAP_RET_UNSUCCESS ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* check if the packet is of data type */
2007-06-14 22:09:14 +00:00
if ( AIRPDCAP_TYPE ( data [ 0 ] ) ! = AIRPDCAP_TYPE_DATA ) {
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " not data packet " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_NO_DATA ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* check correct packet size, to avoid wrong elaboration of encryption algorithms */
2007-06-14 22:09:14 +00:00
if ( tot_len < ( UINT ) ( mac_header_len + AIRPDCAP_CRYPTED_DATA_MINLEN ) ) {
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " minimum length violated " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_WRONG_DATA_SIZE ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* get BSSID */
2007-06-14 22:09:14 +00:00
if ( ( address = AirPDcapGetBssidAddress ( ( const AIRPDCAP_MAC_FRAME_ADDR4 * ) ( data ) ) ) ! = NULL ) {
2007-05-20 22:40:35 +00:00
memcpy ( id . bssid , address , AIRPDCAP_MAC_LEN ) ;
# ifdef _DEBUG
sprintf ( msgbuf , " BSSID: %2X.%2X.%2X.%2X.%2X.%2X \t " , id . bssid [ 0 ] , id . bssid [ 1 ] , id . bssid [ 2 ] , id . bssid [ 3 ] , id . bssid [ 4 ] , id . bssid [ 5 ] ) ;
# endif
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , msgbuf , AIRPDCAP_DEBUG_LEVEL_3 ) ;
} else {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " BSSID not found " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_REQ_DATA ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* get STA address */
2007-06-14 22:09:14 +00:00
if ( ( address = AirPDcapGetStaAddress ( ( const AIRPDCAP_MAC_FRAME_ADDR4 * ) ( data ) ) ) ! = NULL ) {
2007-05-20 22:40:35 +00:00
memcpy ( id . sta , address , AIRPDCAP_MAC_LEN ) ;
# ifdef _DEBUG
sprintf ( msgbuf , " ST_MAC: %2X.%2X.%2X.%2X.%2X.%2X \t " , id . sta [ 0 ] , id . sta [ 1 ] , id . sta [ 2 ] , id . sta [ 3 ] , id . sta [ 4 ] , id . sta [ 5 ] ) ;
# endif
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , msgbuf , AIRPDCAP_DEBUG_LEVEL_3 ) ;
} else {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " SA not found " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_REQ_DATA ;
}
/* search for a cached Security Association for current BSSID and station MAC */
if ( ( index = AirPDcapGetSa ( ctx , & id ) ) = = - 1 ) {
/* create a new Security Association */
if ( ( index = AirPDcapStoreSa ( ctx , & id ) ) = = - 1 ) {
return AIRPDCAP_RET_UNSUCCESS ;
2007-05-17 17:14:39 +00:00
}
2007-05-20 22:40:35 +00:00
}
2007-05-17 17:14:39 +00:00
2007-05-20 22:40:35 +00:00
/* get the Security Association structure */
sa = & ctx - > sa [ index ] ;
/* cache offset in the packet data (to scan encryption data) */
2007-06-14 22:09:14 +00:00
offset = mac_header_len ;
2007-05-20 22:40:35 +00:00
/* check if data is encrypted (use the WEP bit in the Frame Control field) */
if ( AIRPDCAP_WEP ( data [ 1 ] ) = = 0 )
{
2007-05-17 17:14:39 +00:00
if ( mngHandshake ) {
2007-05-20 22:40:35 +00:00
/* data is sent in cleartext, check if is an authentication message or end the process */
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " Unencrypted data " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
/* check if the packet as an LLC header and the packet is 802.1X authentication (IEEE 802.1X-2004, pg. 24) */
if ( memcmp ( data + offset , dot1x_header , 8 ) = = 0 ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " Authentication: EAPOL packet " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
/* skip LLC header */
offset + = 8 ;
/* check the version of the EAPOL protocol used (IEEE 802.1X-2004, pg. 24) */
/* TODO EAPOL protocol version to check? */
/*if (data[offset]!=2) {
AIRPDCAP_DEBUG_PRINT_LINE ( " EAPOL protocol version not recognized " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_NO_VALID_HANDSHAKE ;
} */
/* check if the packet is a EAPOL-Key (0x03) (IEEE 802.1X-2004, pg. 25) */
if ( data [ offset + 1 ] ! = 3 ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " Not EAPOL-Key " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_NO_VALID_HANDSHAKE ;
2006-12-27 23:05:55 +00:00
}
2007-05-17 17:14:39 +00:00
2007-05-20 22:40:35 +00:00
/* get and check the body length (IEEE 802.1X-2004, pg. 25) */
bodyLength = pntohs ( data + offset + 2 ) ;
2007-06-18 21:58:34 +00:00
if ( ( tot_len - offset - 4 ) < bodyLength ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " EAPOL body too short " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_NO_VALID_HANDSHAKE ;
2007-05-17 17:14:39 +00:00
}
2007-05-20 22:40:35 +00:00
/* skip EAPOL MPDU and go to the first byte of the body */
offset + = 4 ;
2007-05-17 17:14:39 +00:00
2007-05-20 22:40:35 +00:00
/* check if the key descriptor type is valid (IEEE 802.1X-2004, pg. 27) */
if ( /*data[offset]!=0x1 &&*/ /* RC4 Key Descriptor Type (deprecated) */
data [ offset ] ! = 0x2 & & /* IEEE 802.11 Key Descriptor Type */
data [ offset ] ! = 0xFE ) /* TODO what's this value??? */
{
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " Not valid key descriptor type " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_NO_VALID_HANDSHAKE ;
}
2007-05-17 17:14:39 +00:00
2007-05-20 22:40:35 +00:00
/* start with descriptor body */
offset + = 1 ;
2007-05-17 17:14:39 +00:00
2007-05-20 22:40:35 +00:00
/* manage the 4-way handshake to define the key */
return AirPDcapRsna4WHandshake ( ctx , data , sa , key , offset ) ;
} else {
/* cleartext message, not authentication */
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " No authentication data " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_NO_DATA_ENCRYPTED ;
}
}
} else {
if ( mngDecrypt ) {
2007-05-17 17:14:39 +00:00
2007-05-20 22:40:35 +00:00
if ( decrypt_data = = NULL )
return AIRPDCAP_RET_UNSUCCESS ;
2007-05-17 17:14:39 +00:00
2007-05-20 22:40:35 +00:00
/* create new header and data to modify */
2007-06-14 22:09:14 +00:00
* decrypt_len = tot_len ;
2007-05-20 22:40:35 +00:00
memcpy ( decrypt_data , data , * decrypt_len ) ;
/* encrypted data */
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " Encrypted data " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
/* check the Extension IV to distinguish between WEP encryption and WPA encryption */
/* refer to IEEE 802.11i-2004, 8.2.1.2, pag.35 for WEP, */
/* IEEE 802.11i-2004, 8.3.2.2, pag. 45 for TKIP, */
/* IEEE 802.11i-2004, 8.3.3.2, pag. 57 for CCMP */
if ( AIRPDCAP_EXTIV ( data [ offset + 3 ] ) = = 0 ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " WEP encryption " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2007-06-14 22:09:14 +00:00
return AirPDcapWepMng ( ctx , decrypt_data , mac_header_len , decrypt_len , key , sa , offset ) ;
2007-05-20 22:40:35 +00:00
} else {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapPacketProcess " , " TKIP or CCMP encryption " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2007-06-14 22:09:14 +00:00
return AirPDcapRsnaMng ( decrypt_data , mac_header_len , decrypt_len , key , sa , offset ) ;
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_UNSUCCESS ;
2006-12-27 23:05:55 +00:00
}
INT AirPDcapSetKeys (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
AIRPDCAP_KEY_ITEM keys [ ] ,
const size_t keys_nr )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
INT i ;
INT success ;
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapSetKeys " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ctx = = NULL | | keys = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapSetKeys " , " NULL context or NULL keys array " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapSetKeys " ) ;
return 0 ;
}
if ( keys_nr > AIRPDCAP_MAX_KEYS_NR ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapSetKeys " , " Keys number greater than maximum " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapSetKeys " ) ;
return 0 ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* clean keys collection before setting new ones */
AirPDcapCleanKeys ( ctx ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* check and insert keys */
for ( i = 0 , success = 0 ; i < ( INT ) keys_nr ; i + + ) {
if ( AirPDcapValidateKey ( keys + i ) = = TRUE ) {
if ( keys [ i ] . KeyType = = AIRPDCAP_KEY_TYPE_WPA_PWD ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapSetKeys " , " Set a WPA-PWD key " , AIRPDCAP_DEBUG_LEVEL_4 ) ;
AirPDcapRsnaPwd2Psk ( keys [ i ] . UserPwd . Passphrase , keys [ i ] . UserPwd . Ssid , keys [ i ] . UserPwd . SsidLen , keys [ i ] . KeyData . Wpa . Psk ) ;
}
2006-12-05 21:06:09 +00:00
# ifdef _DEBUG
2007-05-20 22:40:35 +00:00
else if ( keys [ i ] . KeyType = = AIRPDCAP_KEY_TYPE_WPA_PMK ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapSetKeys " , " Set a WPA-PMK key " , AIRPDCAP_DEBUG_LEVEL_4 ) ;
} else if ( keys [ i ] . KeyType = = AIRPDCAP_KEY_TYPE_WEP ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapSetKeys " , " Set a WEP key " , AIRPDCAP_DEBUG_LEVEL_4 ) ;
} else {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapSetKeys " , " Set a key " , AIRPDCAP_DEBUG_LEVEL_4 ) ;
}
2006-12-05 21:06:09 +00:00
# endif
2007-05-20 22:40:35 +00:00
memcpy ( & ctx - > keys [ success ] , & keys [ i ] , sizeof ( keys [ i ] ) ) ;
success + + ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
ctx - > keys_nr = success ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapSetKeys " ) ;
return success ;
2006-12-27 23:05:55 +00:00
}
2007-10-31 00:15:17 +00:00
static void
AirPDcapCleanKeys (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapCleanKeys " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ctx = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapCleanKeys " , " NULL context " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapCleanKeys " ) ;
2007-10-31 00:15:17 +00:00
return ;
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
2007-10-31 00:15:17 +00:00
memset ( ctx - > keys , 0 , sizeof ( AIRPDCAP_KEY_ITEM ) * AIRPDCAP_MAX_KEYS_NR ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
ctx - > keys_nr = 0 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapCleanKeys " , " Keys collection cleaned! " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapCleanKeys " ) ;
2006-12-27 23:05:55 +00:00
}
INT AirPDcapGetKeys (
2007-05-20 22:40:35 +00:00
const PAIRPDCAP_CONTEXT ctx ,
AIRPDCAP_KEY_ITEM keys [ ] ,
const size_t keys_nr )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
UINT i ;
UINT j ;
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapGetKeys " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ctx = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapGetKeys " , " NULL context " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapGetKeys " ) ;
return 0 ;
} else if ( keys = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapGetKeys " , " NULL keys array " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapGetKeys " ) ;
return ( INT ) ctx - > keys_nr ;
} else {
for ( i = 0 , j = 0 ; i < ctx - > keys_nr & & i < keys_nr & & i < AIRPDCAP_MAX_KEYS_NR ; i + + ) {
memcpy ( & keys [ j ] , & ctx - > keys [ i ] , sizeof ( keys [ j ] ) ) ;
j + + ;
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapGetKeys " , " Got a key " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapGetKeys " ) ;
return j ;
}
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
/*
* XXX - This won ' t be reliable if a packet containing SSID " B " shows
* up in the middle of a 4 - way handshake for SSID " A " .
* We should probably use a small array or hash table to keep multiple
* SSIDs .
*/
INT AirPDcapSetLastSSID (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
CHAR * pkt_ssid ,
size_t pkt_ssid_len )
2007-01-26 21:54:59 +00:00
{
2007-05-20 22:40:35 +00:00
if ( ! ctx | | ! pkt_ssid | | pkt_ssid_len < 1 | | pkt_ssid_len > WPA_SSID_MAX_SIZE )
return AIRPDCAP_RET_UNSUCCESS ;
2007-01-26 21:54:59 +00:00
2007-05-20 22:40:35 +00:00
memcpy ( ctx - > pkt_ssid , pkt_ssid , pkt_ssid_len ) ;
ctx - > pkt_ssid_len = pkt_ssid_len ;
2007-01-26 21:54:59 +00:00
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_SUCCESS ;
2007-01-26 21:54:59 +00:00
}
2006-12-27 23:05:55 +00:00
INT AirPDcapInitContext (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapInitContext " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ctx = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapInitContext " , " NULL context " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapInitContext " ) ;
return AIRPDCAP_RET_UNSUCCESS ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AirPDcapCleanKeys ( ctx ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
ctx - > first_free_index = 0 ;
ctx - > index = - 1 ;
ctx - > last_stored_index = - 1 ;
ctx - > pkt_ssid_len = 0 ;
2006-12-27 23:05:55 +00:00
2007-10-31 00:15:17 +00:00
memset ( ctx - > sa , 0 , AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR * sizeof ( AIRPDCAP_SEC_ASSOCIATION ) ) ;
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapInitContext " , " Context initialized! " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapInitContext " ) ;
return AIRPDCAP_RET_SUCCESS ;
2006-12-27 23:05:55 +00:00
}
INT AirPDcapDestroyContext (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapDestroyContext " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ctx = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapDestroyContext " , " NULL context " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapDestroyContext " ) ;
return AIRPDCAP_RET_UNSUCCESS ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AirPDcapCleanKeys ( ctx ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
ctx - > first_free_index = 0 ;
ctx - > index = - 1 ;
ctx - > last_stored_index = - 1 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapDestroyContext " , " Context destroyed! " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapDestroyContext " ) ;
return AIRPDCAP_RET_SUCCESS ;
2006-12-27 23:05:55 +00:00
}
2006-12-05 21:06:09 +00:00
# ifdef __cplusplus
}
# endif
2007-01-01 20:07:23 +00:00
/****************************************************************************/
/****************************************************************************/
/* Internal function definitions */
2006-12-05 21:06:09 +00:00
# ifdef __cplusplus
extern " C " {
# endif
2007-01-26 21:54:59 +00:00
static INT
AirPDcapRsnaMng (
2007-05-20 22:40:35 +00:00
UCHAR * decrypt_data ,
2007-06-14 22:09:14 +00:00
guint mac_header_len ,
guint * decrypt_len ,
2007-05-20 22:40:35 +00:00
PAIRPDCAP_KEY_ITEM key ,
AIRPDCAP_SEC_ASSOCIATION * sa ,
2007-06-14 22:09:14 +00:00
INT offset )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
INT ret_value ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( sa - > key = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsnaMng " , " No key associated " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
return AIRPDCAP_RET_REQ_DATA ;
}
if ( sa - > validKey = = FALSE ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsnaMng " , " Key not yet valid " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
return AIRPDCAP_RET_UNSUCCESS ;
}
if ( sa - > wpa . key_ver = = 1 ) {
/* CCMP -> HMAC-MD5 is the EAPOL-Key MIC, RC4 is the EAPOL-Key encryption algorithm */
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsnaMng " , " TKIP " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
ret_value = AirPDcapTkipDecrypt ( decrypt_data + offset , * decrypt_len - offset , decrypt_data + AIRPDCAP_TA_OFFSET , AIRPDCAP_GET_TK ( sa - > wpa . ptk ) ) ;
if ( ret_value )
return ret_value ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsnaMng " , " TKIP DECRYPTED!!! " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
/* remove MIC (8bytes) and ICV (4bytes) from the end of packet */
* decrypt_len - = 12 ;
} else {
/* AES-CCMP -> HMAC-SHA1-128 is the EAPOL-Key MIC, AES wep_key wrap is the EAPOL-Key encryption algorithm */
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsnaMng " , " CCMP " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2006-12-27 23:05:55 +00:00
2007-06-14 22:09:14 +00:00
ret_value = AirPDcapCcmpDecrypt ( decrypt_data , mac_header_len , ( INT ) * decrypt_len , AIRPDCAP_GET_TK ( sa - > wpa . ptk ) ) ;
2007-05-20 22:40:35 +00:00
if ( ret_value )
return ret_value ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsnaMng " , " CCMP DECRYPTED!!! " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
/* remove MIC (8bytes) from the end of packet */
* decrypt_len - = 8 ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* remove protection bit */
decrypt_data [ 1 ] & = 0xBF ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* remove TKIP/CCMP header */
2007-06-14 22:09:14 +00:00
offset = mac_header_len ;
2007-05-20 22:40:35 +00:00
* decrypt_len - = 8 ;
memcpy ( decrypt_data + offset , decrypt_data + offset + 8 , * decrypt_len - offset ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( key ! = NULL ) {
memcpy ( key , sa - > key , sizeof ( AIRPDCAP_KEY_ITEM ) ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( sa - > wpa . key_ver = = AIRPDCAP_WPA_KEY_VER_CCMP )
key - > KeyType = AIRPDCAP_KEY_TYPE_TKIP ;
else if ( sa - > wpa . key_ver = = AIRPDCAP_WPA_KEY_VER_AES_CCMP )
key - > KeyType = AIRPDCAP_KEY_TYPE_CCMP ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_SUCCESS ;
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
static INT
AirPDcapWepMng (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
UCHAR * decrypt_data ,
2007-06-14 22:09:14 +00:00
guint mac_header_len ,
guint * decrypt_len ,
2007-05-20 22:40:35 +00:00
PAIRPDCAP_KEY_ITEM key ,
AIRPDCAP_SEC_ASSOCIATION * sa ,
2007-06-14 22:09:14 +00:00
INT offset )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
UCHAR wep_key [ AIRPDCAP_WEP_KEY_MAXLEN + AIRPDCAP_WEP_IVLEN ] ;
size_t keylen ;
INT ret_value = 1 ;
INT key_index ;
AIRPDCAP_KEY_ITEM * tmp_key ;
UINT8 useCache = FALSE ;
UCHAR * try_data = ep_alloc ( * decrypt_len ) ;
if ( sa - > key ! = NULL )
useCache = TRUE ;
for ( key_index = 0 ; key_index < ( INT ) ctx - > keys_nr ; key_index + + ) {
/* use the cached one, or try all keys */
if ( ! useCache ) {
tmp_key = & ctx - > keys [ key_index ] ;
} else {
if ( sa - > key ! = NULL & & sa - > key - > KeyType = = AIRPDCAP_KEY_TYPE_WEP ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapWepMng " , " Try cached WEP key... " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
tmp_key = sa - > key ;
} else {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapWepMng " , " Cached key is not valid, try another WEP key... " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
tmp_key = & ctx - > keys [ key_index ] ;
}
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* obviously, try only WEP keys... */
if ( tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WEP )
{
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapWepMng " , " Try WEP key... " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
memset ( wep_key , 0 , sizeof ( wep_key ) ) ;
memcpy ( try_data , decrypt_data , * decrypt_len ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* Costruct the WEP seed: copy the IV in first 3 bytes and then the WEP key (refer to 802-11i-2004, 8.2.1.4.3, pag. 36) */
2007-06-14 22:09:14 +00:00
memcpy ( wep_key , try_data + mac_header_len , AIRPDCAP_WEP_IVLEN ) ;
2007-05-20 22:40:35 +00:00
keylen = tmp_key - > KeyData . Wep . WepKeyLen ;
memcpy ( wep_key + AIRPDCAP_WEP_IVLEN , tmp_key - > KeyData . Wep . WepKey , keylen ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
ret_value = AirPDcapWepDecrypt ( wep_key ,
keylen + AIRPDCAP_WEP_IVLEN ,
2007-06-14 22:09:14 +00:00
try_data + ( mac_header_len + AIRPDCAP_WEP_IVLEN + AIRPDCAP_WEP_KIDLEN ) ,
* decrypt_len - ( mac_header_len + AIRPDCAP_WEP_IVLEN + AIRPDCAP_WEP_KIDLEN + AIRPDCAP_CRC_LEN ) ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ret_value = = AIRPDCAP_RET_SUCCESS )
memcpy ( decrypt_data , try_data , * decrypt_len ) ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ! ret_value & & tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WEP ) {
/* the tried key is the correct one, cached in the Security Association */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
sa - > key = tmp_key ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( key ! = NULL ) {
memcpy ( key , & sa - > key , sizeof ( AIRPDCAP_KEY_ITEM ) ) ;
key - > KeyType = AIRPDCAP_KEY_TYPE_WEP ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
break ;
} else {
/* the cached key was not valid, try other keys */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( useCache = = TRUE ) {
useCache = FALSE ;
key_index - - ;
}
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ret_value )
return ret_value ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapWepMng " , " WEP DECRYPTED!!! " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* remove ICV (4bytes) from the end of packet */
* decrypt_len - = 4 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* remove protection bit */
decrypt_data [ 1 ] & = 0xBF ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* remove IC header */
2007-06-14 22:09:14 +00:00
offset = mac_header_len ;
2007-05-20 22:40:35 +00:00
* decrypt_len - = 4 ;
memcpy ( decrypt_data + offset , decrypt_data + offset + AIRPDCAP_WEP_IVLEN + AIRPDCAP_WEP_KIDLEN , * decrypt_len - offset ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_SUCCESS ;
2006-12-27 23:05:55 +00:00
}
/* Refer to IEEE 802.11i-2004, 8.5.3, pag. 85 */
2007-01-26 21:54:59 +00:00
static INT
AirPDcapRsna4WHandshake (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
const UCHAR * data ,
AIRPDCAP_SEC_ASSOCIATION * sa ,
PAIRPDCAP_KEY_ITEM key ,
INT offset )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
AIRPDCAP_KEY_ITEM * tmp_key , pkt_key ;
INT key_index ;
INT ret_value = 1 ;
UCHAR useCache = FALSE ;
UCHAR eapol [ AIRPDCAP_EAPOL_MAX_LEN ] ;
USHORT eapol_len ;
if ( sa - > key ! = NULL )
useCache = TRUE ;
/* a 4-way handshake packet use a Pairwise key type (IEEE 802.11i-2004, pg. 79) */
if ( AIRPDCAP_EAP_KEY ( data [ offset + 1 ] ) ! = 1 ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " Group/STAKey message (not used) " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
return AIRPDCAP_RET_NO_VALID_HANDSHAKE ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* TODO timeouts? reauthentication? */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* TODO consider key-index */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* TODO considera Deauthentications */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " 4-way handshake... " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* manage 4-way handshake packets; this step completes the 802.1X authentication process (IEEE 802.11i-2004, pag. 85) */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* message 1: Authenticator->Supplicant (Sec=0, Mic=0, Ack=1, Inst=0, Key=1(pairwise), KeyRSC=0, Nonce=ANonce, MIC=0) */
if ( AIRPDCAP_EAP_INST ( data [ offset + 1 ] ) = = 0 & &
AIRPDCAP_EAP_ACK ( data [ offset + 1 ] ) = = 1 & &
AIRPDCAP_EAP_MIC ( data [ offset ] ) = = 0 )
{
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " 4-way handshake message 1 " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* On reception of Message 1, the Supplicant determines whether the Key Replay Counter field value has been */
/* used before with the current PMKSA. If the Key Replay Counter field value is less than or equal to the current */
/* local value, the Supplicant discards the message. */
/* -> not checked, the Authenticator will be send another Message 1 (hopefully!) */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* save ANonce (from authenticator) to derive the PTK with the SNonce (from the 2 message) */
memcpy ( sa - > wpa . nonce , data + offset + 12 , 32 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* get the Key Descriptor Version (to select algorithm used in decryption -CCMP or TKIP-) */
sa - > wpa . key_ver = AIRPDCAP_EAP_KEY_DESCR_VER ( data [ offset + 1 ] ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
sa - > handshake = 1 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_SUCCESS_HANDSHAKE ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* message 2|4: Supplicant->Authenticator (Sec=0|1, Mic=1, Ack=0, Inst=0, Key=1(pairwise), KeyRSC=0, Nonce=SNonce|0, MIC=MIC(KCK,EAPOL)) */
if ( AIRPDCAP_EAP_INST ( data [ offset + 1 ] ) = = 0 & &
AIRPDCAP_EAP_ACK ( data [ offset + 1 ] ) = = 0 & &
AIRPDCAP_EAP_MIC ( data [ offset ] ) = = 1 )
{
if ( AIRPDCAP_EAP_SEC ( data [ offset ] ) = = 0 ) {
/* PATCH: some implementations set secure bit to 0 also in the 4th message */
2007-10-16 23:42:33 +00:00
/* to recognize which message is this check if wep_key data length is 0 */
2007-05-20 22:40:35 +00:00
/* in the 4th message */
if ( data [ offset + 92 ] ! = 0 | | data [ offset + 93 ] ! = 0 ) {
/* message 2 */
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " 4-way handshake message 2 " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
/* On reception of Message 2, the Authenticator checks that the key replay counter corresponds to the */
/* outstanding Message 1. If not, it silently discards the message. */
/* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, */
/* the Authenticator silently discards Message 2. */
/* -> not checked; the Supplicant will send another message 2 (hopefully!) */
/* now you can derive the PTK */
for ( key_index = 0 ; key_index < ( INT ) ctx - > keys_nr | | useCache ; key_index + + ) {
/* use the cached one, or try all keys */
if ( ! useCache ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " Try WPA key... " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
tmp_key = & ctx - > keys [ key_index ] ;
} else {
/* there is a cached key in the security association, if it's a WPA key try it... */
if ( sa - > key ! = NULL & &
( sa - > key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PWD | |
sa - > key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PSK | |
sa - > key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PMK ) ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " Try cached WPA key... " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
tmp_key = sa - > key ;
2006-12-27 23:05:55 +00:00
} else {
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " Cached key is of a wrong type, try WPA key... " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
tmp_key = & ctx - > keys [ key_index ] ;
}
}
/* obviously, try only WPA keys... */
if ( tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PWD | |
tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PSK | |
tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PMK )
{
if ( tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PWD & & tmp_key - > UserPwd . SsidLen = = 0 & & ctx - > pkt_ssid_len > 0 & & ctx - > pkt_ssid_len < = AIRPDCAP_WPA_SSID_MAX_LEN ) {
/* We have a "wildcard" SSID. Use the one from the packet. */
memcpy ( & pkt_key , tmp_key , sizeof ( pkt_key ) ) ;
memcpy ( & pkt_key . UserPwd . Ssid , ctx - > pkt_ssid , ctx - > pkt_ssid_len ) ;
pkt_key . UserPwd . SsidLen = ctx - > pkt_ssid_len ;
AirPDcapRsnaPwd2Psk ( pkt_key . UserPwd . Passphrase , pkt_key . UserPwd . Ssid ,
pkt_key . UserPwd . SsidLen , pkt_key . KeyData . Wpa . Psk ) ;
tmp_key = & pkt_key ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* derive the PTK from the BSSID, STA MAC, PMK, SNonce, ANonce */
AirPDcapRsnaPrfX ( sa , /* authenticator nonce, bssid, station mac */
tmp_key - > KeyData . Wpa . Pmk , /* PMK */
data + offset + 12 , /* supplicant nonce */
512 ,
sa - > wpa . ptk ) ;
/* verify the MIC (compare the MIC in the packet included in this message with a MIC calculated with the PTK) */
eapol_len = pntohs ( data + offset - 3 ) + 4 ;
memcpy ( eapol , & data [ offset - 5 ] , ( eapol_len < AIRPDCAP_EAPOL_MAX_LEN ? eapol_len : AIRPDCAP_EAPOL_MAX_LEN ) ) ;
ret_value = AirPDcapRsnaMicCheck ( eapol , /* eapol frame (header also) */
eapol_len , /* eapol frame length */
sa - > wpa . ptk , /* Key Confirmation Key */
AIRPDCAP_EAP_KEY_DESCR_VER ( data [ offset + 1 ] ) ) ; /* EAPOL-Key description version */
/* If the MIC is valid, the Authenticator checks that the RSN information element bit-wise matches */
/* that from the (Re)Association Request message. */
/* i) TODO If these are not exactly the same, the Authenticator uses MLME-DEAUTHENTICATE.request */
/* primitive to terminate the association. */
/* ii) If they do match bit-wise, the Authenticator constructs Message 3. */
}
if ( ! ret_value & &
( tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PWD | |
tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PSK | |
tmp_key - > KeyType = = AIRPDCAP_KEY_TYPE_WPA_PMK ) )
{
/* the temporary key is the correct one, cached in the Security Association */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
sa - > key = tmp_key ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( key ! = NULL ) {
memcpy ( key , & tmp_key , sizeof ( AIRPDCAP_KEY_ITEM ) ) ;
if ( AIRPDCAP_EAP_KEY_DESCR_VER ( data [ offset + 1 ] ) = = AIRPDCAP_WPA_KEY_VER_CCMP )
key - > KeyType = AIRPDCAP_KEY_TYPE_TKIP ;
else if ( AIRPDCAP_EAP_KEY_DESCR_VER ( data [ offset + 1 ] ) = = AIRPDCAP_WPA_KEY_VER_AES_CCMP )
key - > KeyType = AIRPDCAP_KEY_TYPE_CCMP ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
break ;
} else {
/* the cached key was not valid, try other keys */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( useCache = = TRUE ) {
useCache = FALSE ;
key_index - - ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( ret_value ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " handshake step failed " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
return ret_value ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
sa - > handshake = 2 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_SUCCESS_HANDSHAKE ;
} else {
/* message 4 */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* TODO "Note that when the 4-Way Handshake is first used Message 4 is sent in the clear." */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* TODO check MIC and Replay Counter */
/* On reception of Message 4, the Authenticator verifies that the Key Replay Counter field value is one */
/* that it used on this 4-Way Handshake; if it is not, it silently discards the message. */
/* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, the */
/* Authenticator silently discards Message 4. */
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " 4-way handshake message 4 (patched) " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
sa - > handshake = 4 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
sa - > validKey = TRUE ;
2006-12-27 23:05:55 +00:00
return AIRPDCAP_RET_SUCCESS_HANDSHAKE ;
2007-05-20 22:40:35 +00:00
}
/* END OF PATCH */
/* */
} else {
/* message 4 */
/* TODO "Note that when the 4-Way Handshake is first used Message 4 is sent in the clear." */
/* TODO check MIC and Replay Counter */
/* On reception of Message 4, the Authenticator verifies that the Key Replay Counter field value is one */
/* that it used on this 4-Way Handshake; if it is not, it silently discards the message. */
/* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, the */
/* Authenticator silently discards Message 4. */
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " 4-way handshake message 4 " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
sa - > handshake = 4 ;
sa - > validKey = TRUE ;
return AIRPDCAP_RET_SUCCESS_HANDSHAKE ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* message 3: Authenticator->Supplicant (Sec=1, Mic=1, Ack=1, Inst=0/1, Key=1(pairwise), KeyRSC=???, Nonce=ANonce, MIC=1) */
if ( AIRPDCAP_EAP_ACK ( data [ offset + 1 ] ) = = 1 & &
AIRPDCAP_EAP_MIC ( data [ offset ] ) = = 1 )
{
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapRsna4WHandshake " , " 4-way handshake message 3 " , AIRPDCAP_DEBUG_LEVEL_3 ) ;
/* On reception of Message 3, the Supplicant silently discards the message if the Key Replay Counter field */
/* value has already been used or if the ANonce value in Message 3 differs from the ANonce value in Message 1. */
/* -> not checked, the Authenticator will send another message 3 (hopefully!) */
/* TODO check page 88 (RNS) */
return AIRPDCAP_RET_SUCCESS_HANDSHAKE ;
}
return AIRPDCAP_RET_UNSUCCESS ;
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
static INT
AirPDcapRsnaMicCheck (
2007-05-20 22:40:35 +00:00
UCHAR * eapol ,
USHORT eapol_len ,
UCHAR KCK [ AIRPDCAP_WPA_KCK_LEN ] ,
USHORT key_ver )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
UCHAR mic [ AIRPDCAP_WPA_MICKEY_LEN ] ;
UCHAR c_mic [ 20 ] ; /* MIC 16 byte, the HMAC-SHA1 use a buffer of 20 bytes */
/* copy the MIC from the EAPOL packet */
memcpy ( mic , eapol + AIRPDCAP_WPA_MICKEY_OFFSET + 4 , AIRPDCAP_WPA_MICKEY_LEN ) ;
/* set to 0 the MIC in the EAPOL packet (to calculate the MIC) */
memset ( eapol + AIRPDCAP_WPA_MICKEY_OFFSET + 4 , 0 , AIRPDCAP_WPA_MICKEY_LEN ) ;
if ( key_ver = = AIRPDCAP_WPA_KEY_VER_CCMP ) {
/* use HMAC-MD5 for the EAPOL-Key MIC */
md5_hmac ( eapol , eapol_len , KCK , AIRPDCAP_WPA_KCK_LEN , c_mic ) ;
} else if ( key_ver = = AIRPDCAP_WPA_KEY_VER_AES_CCMP ) {
/* use HMAC-SHA1-128 for the EAPOL-Key MIC */
sha1_hmac ( KCK , AIRPDCAP_WPA_KCK_LEN , eapol , eapol_len , c_mic ) ;
} else
/* key descriptor version not recognized */
return AIRPDCAP_RET_UNSUCCESS ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* compare calculated MIC with the Key MIC and return result (0 means success) */
return memcmp ( mic , c_mic , AIRPDCAP_WPA_MICKEY_LEN ) ;
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
static INT
AirPDcapValidateKey (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_KEY_ITEM key )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
size_t len ;
UCHAR ret = TRUE ;
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapValidateKey " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
if ( key = = NULL ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapValidateKey " , " NULL key " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
AIRPDCAP_DEBUG_TRACE_START ( " AirPDcapValidateKey " ) ;
return FALSE ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
switch ( key - > KeyType ) {
case AIRPDCAP_KEY_TYPE_WEP :
/* check key size limits */
len = key - > KeyData . Wep . WepKeyLen ;
if ( len < AIRPDCAP_WEP_KEY_MINLEN | | len > AIRPDCAP_WEP_KEY_MAXLEN ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapValidateKey " , " WEP key: key length not accepted " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
ret = FALSE ;
}
break ;
case AIRPDCAP_KEY_TYPE_WEP_40 :
/* set the standard length and use a generic WEP key type */
key - > KeyData . Wep . WepKeyLen = AIRPDCAP_WEP_40_KEY_LEN ;
key - > KeyType = AIRPDCAP_KEY_TYPE_WEP ;
break ;
case AIRPDCAP_KEY_TYPE_WEP_104 :
/* set the standard length and use a generic WEP key type */
key - > KeyData . Wep . WepKeyLen = AIRPDCAP_WEP_104_KEY_LEN ;
key - > KeyType = AIRPDCAP_KEY_TYPE_WEP ;
break ;
case AIRPDCAP_KEY_TYPE_WPA_PWD :
/* check passphrase and SSID size limits */
len = strlen ( key - > UserPwd . Passphrase ) ;
if ( len < AIRPDCAP_WPA_PASSPHRASE_MIN_LEN | | len > AIRPDCAP_WPA_PASSPHRASE_MAX_LEN ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapValidateKey " , " WPA-PWD key: passphrase length not accepted " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
ret = FALSE ;
}
len = key - > UserPwd . SsidLen ;
if ( len > AIRPDCAP_WPA_SSID_MAX_LEN ) {
AIRPDCAP_DEBUG_PRINT_LINE ( " AirPDcapValidateKey " , " WPA-PWD key: ssid length not accepted " , AIRPDCAP_DEBUG_LEVEL_5 ) ;
ret = FALSE ;
}
break ;
case AIRPDCAP_KEY_TYPE_WPA_PSK :
break ;
case AIRPDCAP_KEY_TYPE_WPA_PMK :
break ;
default :
ret = FALSE ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
AIRPDCAP_DEBUG_TRACE_END ( " AirPDcapValidateKey " ) ;
return ret ;
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
static INT
AirPDcapGetSa (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
AIRPDCAP_SEC_ASSOCIATION_ID * id )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
INT index ;
if ( ctx - > last_stored_index ! = - 1 ) {
/* at least one association was stored */
/* search for the association from last_stored_index to 0 (most recent added) */
for ( index = ctx - > last_stored_index ; index > = 0 ; index - - ) {
if ( ctx - > sa [ index ] . used ) {
if ( memcmp ( id , & ( ctx - > sa [ index ] . saId ) , sizeof ( AIRPDCAP_SEC_ASSOCIATION_ID ) ) = = 0 ) {
ctx - > index = index ;
return index ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return - 1 ;
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
static INT
AirPDcapStoreSa (
2007-05-20 22:40:35 +00:00
PAIRPDCAP_CONTEXT ctx ,
AIRPDCAP_SEC_ASSOCIATION_ID * id )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
INT last_free ;
if ( ctx - > sa [ ctx - > first_free_index ] . used ) {
/* last addition was in the middle of the array (and the first_free_index was just incremented by 1) */
/* search for a free space from the first_free_index to AIRPDCAP_STA_INFOS_NR (to avoid free blocks in */
/* the middle) */
for ( last_free = ctx - > first_free_index ; last_free < AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR ; last_free + + )
if ( ! ctx - > sa [ last_free ] . used )
break ;
if ( last_free > = AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR ) {
/* there is no empty space available. FAILURE */
return - 1 ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
/* store first free space index */
ctx - > first_free_index = last_free ;
}
/* use this info */
ctx - > index = ctx - > first_free_index ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* reset the info structure */
memset ( ctx - > sa + ctx - > index , 0 , sizeof ( AIRPDCAP_SEC_ASSOCIATION ) ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
ctx - > sa [ ctx - > index ] . used = 1 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* set the info structure */
memcpy ( & ( ctx - > sa [ ctx - > index ] . saId ) , id , sizeof ( AIRPDCAP_SEC_ASSOCIATION_ID ) ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* increment by 1 the first_free_index (heuristic) */
ctx - > first_free_index + + ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* set the last_stored_index if the added index is greater the the last_stored_index */
if ( ctx - > index > ctx - > last_stored_index )
ctx - > last_stored_index = ctx - > index ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return ctx - > index ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
/*
* AirPDcapGetBssidAddress ( ) and AirPDcapGetBssidAddress ( ) are used for
* key caching . In each case , it ' s more important to return a value than
* to return a _correct_ value , so we fudge addresses in some cases , e . g .
* the BSSID in bridged connections .
* FromDS ToDS Sta BSSID
* 0 0 addr2 addr3
* 0 1 addr2 addr1
* 1 0 addr1 addr2
* 1 1 addr2 addr1
*/
2007-04-22 18:26:45 +00:00
static const UCHAR *
2007-01-26 21:54:59 +00:00
AirPDcapGetStaAddress (
2007-05-20 22:40:35 +00:00
const AIRPDCAP_MAC_FRAME_ADDR4 * frame )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
switch ( AIRPDCAP_DS_BITS ( frame - > fc [ 1 ] ) ) { /* Bit 1 = FromDS, bit 0 = ToDS */
case 0 :
case 1 :
case 3 :
return frame - > addr2 ;
case 2 :
return frame - > addr1 ;
default :
return NULL ;
}
2006-12-27 23:05:55 +00:00
}
2007-04-22 18:26:45 +00:00
static const UCHAR *
2007-01-26 21:54:59 +00:00
AirPDcapGetBssidAddress (
2007-05-20 22:40:35 +00:00
const AIRPDCAP_MAC_FRAME_ADDR4 * frame )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
switch ( AIRPDCAP_DS_BITS ( frame - > fc [ 1 ] ) ) { /* Bit 1 = FromDS, bit 0 = ToDS */
case 0 :
return frame - > addr3 ;
case 1 :
case 3 :
return frame - > addr1 ;
case 2 :
return frame - > addr2 ;
default :
return NULL ;
}
2006-12-27 23:05:55 +00:00
}
/* Function used to derive the PTK. Refer to IEEE 802.11I-2004, pag. 74 */
2007-01-26 21:54:59 +00:00
static void
AirPDcapRsnaPrfX (
2007-05-20 22:40:35 +00:00
AIRPDCAP_SEC_ASSOCIATION * sa ,
const UCHAR pmk [ 32 ] ,
const UCHAR snonce [ 32 ] ,
const INT x , /* for TKIP 512, for CCMP 384 */
UCHAR * ptk )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
UINT8 i ;
UCHAR R [ 100 ] ;
INT offset = sizeof ( " Pairwise key expansion " ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
memset ( R , 0 , 100 ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
memcpy ( R , " Pairwise key expansion " , offset ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* Min(AA, SPA) || Max(AA, SPA) */
if ( memcmp ( sa - > saId . sta , sa - > saId . bssid , AIRPDCAP_MAC_LEN ) < 0 )
{
memcpy ( R + offset , sa - > saId . sta , AIRPDCAP_MAC_LEN ) ;
memcpy ( R + offset + AIRPDCAP_MAC_LEN , sa - > saId . bssid , AIRPDCAP_MAC_LEN ) ;
}
else
{
memcpy ( R + offset , sa - > saId . bssid , AIRPDCAP_MAC_LEN ) ;
memcpy ( R + offset + AIRPDCAP_MAC_LEN , sa - > saId . sta , AIRPDCAP_MAC_LEN ) ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
offset + = AIRPDCAP_MAC_LEN * 2 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
/* Min(ANonce,SNonce) || Max(ANonce,SNonce) */
if ( memcmp ( snonce , sa - > wpa . nonce , 32 ) < 0 )
{
memcpy ( R + offset , snonce , 32 ) ;
memcpy ( R + offset + 32 , sa - > wpa . nonce , 32 ) ;
}
else
{
memcpy ( R + offset , sa - > wpa . nonce , 32 ) ;
memcpy ( R + offset + 32 , snonce , 32 ) ;
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
offset + = 32 * 2 ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
for ( i = 0 ; i < ( x + 159 ) / 160 ; i + + )
{
R [ offset ] = i ;
sha1_hmac ( pmk , 32 , R , 100 , ptk + i * 20 ) ;
}
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
static INT
AirPDcapRsnaPwd2PskStep (
2007-06-27 19:02:58 +00:00
const guint8 * ppBytes ,
const guint ppLength ,
2007-05-20 22:40:35 +00:00
const CHAR * ssid ,
const size_t ssidLength ,
const INT iterations ,
const INT count ,
UCHAR * output )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
UCHAR digest [ 36 ] , digest1 [ AIRPDCAP_SHA_DIGEST_LEN ] ;
INT i , j ;
/* U1 = PRF(P, S || INT(i)) */
memcpy ( digest , ssid , ssidLength ) ;
digest [ ssidLength ] = ( UCHAR ) ( ( count > > 24 ) & 0xff ) ;
digest [ ssidLength + 1 ] = ( UCHAR ) ( ( count > > 16 ) & 0xff ) ;
digest [ ssidLength + 2 ] = ( UCHAR ) ( ( count > > 8 ) & 0xff ) ;
digest [ ssidLength + 3 ] = ( UCHAR ) ( count & 0xff ) ;
2007-06-27 19:02:58 +00:00
sha1_hmac ( ppBytes , ppLength , digest , ssidLength + 4 , digest1 ) ;
2007-05-20 22:40:35 +00:00
/* output = U1 */
memcpy ( output , digest1 , AIRPDCAP_SHA_DIGEST_LEN ) ;
for ( i = 1 ; i < iterations ; i + + ) {
/* Un = PRF(P, Un-1) */
2007-06-27 19:02:58 +00:00
sha1_hmac ( ppBytes , ppLength , digest1 , AIRPDCAP_SHA_DIGEST_LEN , digest ) ;
2007-05-20 22:40:35 +00:00
memcpy ( digest1 , digest , AIRPDCAP_SHA_DIGEST_LEN ) ;
/* output = output xor Un */
for ( j = 0 ; j < AIRPDCAP_SHA_DIGEST_LEN ; j + + ) {
output [ j ] ^ = digest [ j ] ;
2006-12-27 23:05:55 +00:00
}
2007-05-20 22:40:35 +00:00
}
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return AIRPDCAP_RET_SUCCESS ;
2006-12-27 23:05:55 +00:00
}
2007-01-26 21:54:59 +00:00
static INT
AirPDcapRsnaPwd2Psk (
2007-06-27 19:02:58 +00:00
const CHAR * passphrase ,
2007-05-20 22:40:35 +00:00
const CHAR * ssid ,
const size_t ssidLength ,
UCHAR * output )
2006-12-27 23:05:55 +00:00
{
2007-05-20 22:40:35 +00:00
UCHAR m_output [ AIRPDCAP_WPA_PSK_LEN ] ;
2007-06-27 19:02:58 +00:00
GByteArray * pp_ba = g_byte_array_new ( ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
memset ( m_output , 0 , AIRPDCAP_WPA_PSK_LEN ) ;
2006-12-27 23:05:55 +00:00
2007-06-27 19:02:58 +00:00
if ( ! uri_str_to_bytes ( passphrase , pp_ba ) ) {
g_byte_array_free ( pp_ba , TRUE ) ;
return 0 ;
}
2006-12-27 23:05:55 +00:00
2007-06-27 19:02:58 +00:00
AirPDcapRsnaPwd2PskStep ( pp_ba - > data , pp_ba - > len , ssid , ssidLength , 4096 , 1 , m_output ) ;
AirPDcapRsnaPwd2PskStep ( pp_ba - > data , pp_ba - > len , ssid , ssidLength , 4096 , 2 , & m_output [ AIRPDCAP_SHA_DIGEST_LEN ] ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
memcpy ( output , m_output , AIRPDCAP_WPA_PSK_LEN ) ;
2007-06-27 19:02:58 +00:00
g_byte_array_free ( pp_ba , TRUE ) ;
2006-12-27 23:05:55 +00:00
2007-05-20 22:40:35 +00:00
return 0 ;
2006-12-27 23:05:55 +00:00
}
2007-01-11 02:42:34 +00:00
/*
* Returns the decryption_key_t struct given a string describing the key .
* Returns NULL if the key_string cannot be parsed .
*/
decryption_key_t *
parse_key_string ( gchar * input_string )
{
gchar * type ;
gchar * key ;
gchar * ssid ;
GString * key_string = NULL ;
2007-06-21 17:49:03 +00:00
GByteArray * ssid_ba = NULL , * key_ba ;
gboolean res ;
2007-01-11 02:42:34 +00:00
gchar * * tokens ;
guint n = 0 ;
decryption_key_t * dk ;
2007-06-21 17:49:03 +00:00
gchar * first_nibble = input_string ;
2007-01-11 02:42:34 +00:00
if ( input_string = = NULL )
2007-05-20 22:40:35 +00:00
return NULL ;
2007-01-11 02:42:34 +00:00
/*
* Parse the input_string . It should be in the form
* < key type > : < key data > [ : < ssid > ]
* XXX - For backward compatibility , the a WEP key can be just a string
* of hexadecimal characters ( if WEP key is wrong , null will be
* returned . . . ) .
*/
2007-06-21 17:49:03 +00:00
/* First, check for a WEP string */
/* XXX - This duplicates code in packet-ieee80211.c */
if ( g_strncasecmp ( input_string , STRING_KEY_TYPE_WEP " : " , 4 ) = = 0 ) {
first_nibble + = 4 ;
2007-01-11 02:42:34 +00:00
}
2007-06-21 17:49:03 +00:00
key_ba = g_byte_array_new ( ) ;
res = hex_str_to_bytes ( first_nibble , key_ba , FALSE ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 20:22:56 +00:00
if ( res & & key_ba - > len > 0 ) {
2007-06-21 17:49:03 +00:00
/* Key is correct! It was probably an 'old style' WEP key */
/* Create the decryption_key_t structure, fill it and return it*/
dk = g_malloc ( sizeof ( decryption_key_t ) ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
dk - > type = AIRPDCAP_KEY_TYPE_WEP ;
2007-06-21 20:22:56 +00:00
/* XXX - The current key handling code in the GUI requires
* no separators and lower case */
dk - > key = g_string_new ( bytes_to_str ( key_ba - > data , key_ba - > len ) ) ;
g_string_down ( dk - > key ) ;
2007-06-21 17:49:03 +00:00
dk - > bits = key_ba - > len * 8 ;
dk - > ssid = NULL ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
g_byte_array_free ( key_ba , TRUE ) ;
return dk ;
2007-05-20 22:40:35 +00:00
}
2007-06-21 17:49:03 +00:00
g_byte_array_free ( key_ba , TRUE ) ;
tokens = g_strsplit ( input_string , " : " , 0 ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
/* Tokens is a null termiated array of strings ... */
while ( tokens [ n ] ! = NULL )
n + + ;
if ( n < 2 )
2007-05-20 22:40:35 +00:00
{
/* Free the array of strings */
g_strfreev ( tokens ) ;
return NULL ;
}
2007-01-11 02:42:34 +00:00
type = g_strdup ( tokens [ 0 ] ) ;
/*
* The second token is the key ( right now it doesn ' t matter
2007-06-21 17:49:03 +00:00
* if it is a passphrase [ + ssid ] or an hexadecimal one )
2007-01-11 02:42:34 +00:00
*/
key = g_strdup ( tokens [ 1 ] ) ;
2007-06-21 17:49:03 +00:00
ssid = NULL ;
2007-01-11 02:42:34 +00:00
/* Maybe there is a third token (an ssid, if everything else is ok) */
if ( n > = 3 )
{
2007-06-21 17:49:03 +00:00
ssid = g_strdup ( tokens [ 2 ] ) ;
2007-01-11 02:42:34 +00:00
}
2007-06-21 17:49:03 +00:00
if ( g_strcasecmp ( type , STRING_KEY_TYPE_WPA_PSK ) = = 0 ) /* WPA key */
2007-01-11 02:42:34 +00:00
{
2007-06-21 17:49:03 +00:00
/* Create a new string */
key_string = g_string_new ( key ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
key_ba = g_byte_array_new ( ) ;
res = hex_str_to_bytes ( key , key_ba , FALSE ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
/* Two tokens means that the user should have entered a WPA-BIN key ... */
2007-06-23 00:00:57 +00:00
if ( ! res | | ( ( key_string - > len ) ! = WPA_PSK_KEY_CHAR_SIZE ) )
2007-05-20 22:40:35 +00:00
{
2007-06-21 17:49:03 +00:00
g_string_free ( key_string , TRUE ) ;
g_byte_array_free ( key_ba , TRUE ) ;
g_free ( type ) ;
g_free ( key ) ;
/* No ssid has been created ... */
/* Free the array of strings */
g_strfreev ( tokens ) ;
return NULL ;
2007-05-20 22:40:35 +00:00
}
2007-06-21 17:49:03 +00:00
/* Key was correct!!! Create the new decryption_key_t ... */
dk = ( decryption_key_t * ) g_malloc ( sizeof ( decryption_key_t ) ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
dk - > type = AIRPDCAP_KEY_TYPE_WPA_PMK ;
dk - > key = g_string_new ( key ) ;
2007-06-23 00:00:57 +00:00
dk - > bits = dk - > key - > len * 4 ;
2007-06-21 17:49:03 +00:00
dk - > ssid = NULL ;
2007-05-20 22:40:35 +00:00
g_string_free ( key_string , TRUE ) ;
2007-06-21 17:49:03 +00:00
g_byte_array_free ( key_ba , TRUE ) ;
2007-05-20 22:40:35 +00:00
g_free ( key ) ;
2007-06-21 17:49:03 +00:00
g_free ( type ) ;
2007-05-20 22:40:35 +00:00
/* Free the array of strings */
g_strfreev ( tokens ) ;
2007-06-21 17:49:03 +00:00
return dk ;
2007-05-20 22:40:35 +00:00
}
2007-06-21 17:49:03 +00:00
else if ( g_strcasecmp ( type , STRING_KEY_TYPE_WPA_PWD ) = = 0 ) /* WPA key */ /* If the number of tokens is more than three, we accept the string... if the first three tokens are correct... */
2007-05-20 22:40:35 +00:00
{
2007-06-21 17:49:03 +00:00
/* Create a new string */
key_string = g_string_new ( key ) ;
ssid_ba = NULL ;
/* Three (or more) tokens mean that the user entered a WPA-PWD key ... */
if ( ( ( key_string - > len ) > WPA_KEY_MAX_CHAR_SIZE ) | | ( ( key_string - > len ) < WPA_KEY_MIN_CHAR_SIZE ) )
2007-05-20 22:40:35 +00:00
{
2007-06-21 17:49:03 +00:00
g_string_free ( key_string , TRUE ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
g_free ( type ) ;
g_free ( key ) ;
g_free ( ssid ) ;
/* Free the array of strings */
g_strfreev ( tokens ) ;
return NULL ;
2007-05-20 22:40:35 +00:00
}
2007-06-21 17:49:03 +00:00
if ( ssid ! = NULL ) /* more than three tokens found, means that the user specified the ssid */
{
ssid_ba = g_byte_array_new ( ) ;
if ( ! uri_str_to_bytes ( ssid , ssid_ba ) ) {
g_string_free ( key_string , TRUE ) ;
g_byte_array_free ( ssid_ba , TRUE ) ;
g_free ( type ) ;
g_free ( key ) ;
g_free ( ssid ) ;
/* Free the array of strings */
g_strfreev ( tokens ) ;
return NULL ;
}
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
if ( ssid_ba - > len > WPA_SSID_MAX_CHAR_SIZE )
{
g_string_free ( key_string , TRUE ) ;
g_byte_array_free ( ssid_ba , TRUE ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
g_free ( type ) ;
g_free ( key ) ;
g_free ( ssid ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
/* Free the array of strings */
g_strfreev ( tokens ) ;
return NULL ;
}
}
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
/* Key was correct!!! Create the new decryption_key_t ... */
dk = ( decryption_key_t * ) g_malloc ( sizeof ( decryption_key_t ) ) ;
2007-05-20 22:40:35 +00:00
2007-06-21 17:49:03 +00:00
dk - > type = AIRPDCAP_KEY_TYPE_WPA_PWD ;
dk - > key = g_string_new ( key ) ;
dk - > bits = 256 ; /* This is the length of the array pf bytes that will be generated using key+ssid ...*/
dk - > ssid = byte_array_dup ( ssid_ba ) ; /* NULL if ssid_ba is NULL */
2007-05-20 22:40:35 +00:00
g_string_free ( key_string , TRUE ) ;
2007-06-21 17:49:03 +00:00
if ( ssid_ba ! = NULL )
g_byte_array_free ( ssid_ba , TRUE ) ;
2007-05-20 22:40:35 +00:00
g_free ( type ) ;
g_free ( key ) ;
2007-06-21 17:49:03 +00:00
if ( ssid ! = NULL )
g_free ( ssid ) ;
2007-05-20 22:40:35 +00:00
/* Free the array of strings */
g_strfreev ( tokens ) ;
2007-06-21 17:49:03 +00:00
return dk ;
2007-01-11 02:42:34 +00:00
}
/* Something was wrong ... free everything */
g_free ( type ) ;
g_free ( key ) ;
2007-01-11 22:12:33 +00:00
if ( ssid ! = NULL )
2007-06-21 17:49:03 +00:00
g_free ( ssid ) ; /* It is not always present */
2007-01-11 22:12:33 +00:00
if ( ssid_ba ! = NULL )
2007-06-21 17:49:03 +00:00
g_byte_array_free ( ssid_ba , TRUE ) ;
2007-01-11 22:12:33 +00:00
2007-01-11 02:42:34 +00:00
/* Free the array of strings */
g_strfreev ( tokens ) ;
return NULL ;
}
/*
* Returns a newly allocated string representing the given decryption_key_t
* struct , or NULL if something is wrong . . .
*/
gchar *
get_key_string ( decryption_key_t * dk )
{
2007-05-20 22:40:35 +00:00
gchar * output_string = NULL ;
2007-06-21 17:49:03 +00:00
if ( dk = = NULL | | dk - > key = = NULL )
2007-05-20 22:40:35 +00:00
return NULL ;
2007-06-21 17:49:03 +00:00
switch ( dk - > type ) {
case AIRPDCAP_KEY_TYPE_WEP :
output_string = g_strdup_printf ( " %s:%s " , STRING_KEY_TYPE_WEP , dk - > key - > str ) ;
break ;
case AIRPDCAP_KEY_TYPE_WPA_PWD :
if ( dk - > ssid = = NULL )
output_string = g_strdup_printf ( " %s:%s " , STRING_KEY_TYPE_WPA_PWD , dk - > key - > str ) ;
else
output_string = g_strdup_printf ( " %s:%s:%s " ,
STRING_KEY_TYPE_WPA_PWD , dk - > key - > str ,
format_uri ( dk - > ssid , " : " ) ) ;
break ;
case AIRPDCAP_KEY_TYPE_WPA_PMK :
output_string = g_strdup_printf ( " %s:%s " , STRING_KEY_TYPE_WPA_PSK , dk - > key - > str ) ;
break ;
default :
2007-05-20 22:40:35 +00:00
return NULL ;
2007-06-21 17:49:03 +00:00
break ;
2007-05-20 22:40:35 +00:00
}
return output_string ;
2007-01-11 02:42:34 +00:00
}
2006-12-05 21:06:09 +00:00
# ifdef __cplusplus
}
# endif
2007-01-01 20:07:23 +00:00
/****************************************************************************/
2007-05-20 22:40:35 +00:00
/*
* Editor modelines
*
* Local Variables :
* c - basic - offset : 4
* tab - width : 8
* set - tabs - mode : nil
* End :
*
* ex : set shiftwidth = 4 tabstop = 8 expandtab
* : indentSize = 4 : tabSize = 8 : noTabs = true :
*/