@ -31,6 +31,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv);
# define PAC_OPAQUE_TYPE_PAD 0
# define PAC_OPAQUE_TYPE_KEY 1
# define PAC_OPAQUE_TYPE_LIFETIME 2
# define PAC_OPAQUE_TYPE_IDENTITY 3
/* PAC-Key lifetime in seconds (hard limit) */
# define PAC_KEY_LIFETIME (7 * 24 * 60 * 60)
@ -71,6 +72,8 @@ struct eap_fast_data {
int anon_provisioning ;
int send_new_pac ; /* server triggered re-keying of Tunnel PAC */
struct wpabuf * pending_phase2_resp ;
u8 * identity ; /* from PAC-Opaque */
size_t identity_len ;
} ;
@ -133,6 +136,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
u8 * buf , * pos , * end , * pac_key = NULL ;
os_time_t lifetime = 0 ;
struct os_time now ;
u8 * identity = NULL ;
size_t identity_len = 0 ;
wpa_printf ( MSG_DEBUG , " EAP-FAST: SessionTicket callback " ) ;
wpa_hexdump ( MSG_DEBUG , " EAP-FAST: SessionTicket (PAC-Opaque) " ,
@ -217,6 +222,10 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
}
lifetime = WPA_GET_BE32 ( pos + 2 ) ;
break ;
case PAC_OPAQUE_TYPE_IDENTITY :
identity = pos + 2 ;
identity_len = pos [ 1 ] ;
break ;
}
pos + = 2 + pos [ 1 ] ;
@ -229,6 +238,17 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
return - 1 ;
}
if ( identity ) {
wpa_hexdump_ascii ( MSG_DEBUG , " EAP-FAST: Identity from "
" PAC-Opaque " , identity , identity_len ) ;
os_free ( data - > identity ) ;
data - > identity = os_malloc ( identity_len ) ;
if ( data - > identity ) {
os_memcpy ( data - > identity , identity , identity_len ) ;
data - > identity_len = identity_len ;
}
}
if ( os_get_time ( & now ) < 0 | | lifetime < = 0 | | now . sec > lifetime ) {
wpa_printf ( MSG_DEBUG , " EAP-FAST: PAC-Key not valid anymore "
" (lifetime=%ld now=%ld) " , lifetime , now . sec ) ;
@ -517,6 +537,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv)
os_free ( data - > srv_id ) ;
os_free ( data - > key_block_p ) ;
wpabuf_free ( data - > pending_phase2_resp ) ;
os_free ( data - > identity ) ;
os_free ( data ) ;
}
@ -756,45 +777,80 @@ static struct wpabuf * eap_fast_build_crypto_binding(
static struct wpabuf * eap_fast_build_pac ( struct eap_sm * sm ,
struct eap_fast_data * data )
{
u8 pac_key [ 2 + EAP_FAST_PAC_KEY_LEN + 6 ] ;
u8 pac_opaque [ 8 + EAP_FAST_PAC_KEY_LEN + 8 ] ;
u8 pac_key [ EAP_FAST_PAC_KEY_LEN ] ;
u8 * pac_buf , * pac_opaque ;
struct wpabuf * buf ;
u8 * pos ;
size_t buf_len , srv_id_len ;
size_t buf_len , srv_id_len , pac_len ;
struct eap_tlv_hdr * pac_tlv ;
struct pac_tlv_hdr * hdr , * pac_info ;
struct eap_tlv_result_tlv * result ;
struct os_time now ;
srv_id_len = os_strlen ( data - > srv_id ) ;
pac_key [ 0 ] = PAC_OPAQUE_TYPE_KEY ;
pac_key [ 1 ] = EAP_FAST_PAC_KEY_LEN ;
if ( os_get_random ( pac_key + 2 , EAP_FAST_PAC_KEY_LEN ) < 0 )
return NULL ;
if ( os_get_time ( & now ) < 0 )
if ( os_get_random ( pac_key , EAP_FAST_PAC_KEY_LEN ) < 0 | |
os_get_time ( & now ) < 0 )
return NULL ;
wpa_hexdump_key ( MSG_DEBUG , " EAP-FAST: Generated PAC-Key " ,
pac_key + 2 , EAP_FAST_PAC_KEY_LEN ) ;
pos = pac_key + 2 + EAP_FAST_PAC_KEY_LEN ;
pac_key , EAP_FAST_PAC_KEY_LEN ) ;
pac_len = ( 2 + EAP_FAST_PAC_KEY_LEN ) + ( 2 + 4 ) +
( 2 + sm - > identity_len ) + 8 ;
pac_buf = os_malloc ( pac_len ) ;
if ( pac_buf = = NULL )
return NULL ;
srv_id_len = os_strlen ( data - > srv_id ) ;
pos = pac_buf ;
* pos + + = PAC_OPAQUE_TYPE_KEY ;
* pos + + = EAP_FAST_PAC_KEY_LEN ;
os_memcpy ( pos , pac_key , EAP_FAST_PAC_KEY_LEN ) ;
pos + = EAP_FAST_PAC_KEY_LEN ;
* pos + + = PAC_OPAQUE_TYPE_LIFETIME ;
* pos + + = 4 ;
WPA_PUT_BE32 ( pos , now . sec + PAC_KEY_LIFETIME ) ;
pos + = 4 ;
if ( sm - > identity ) {
* pos + + = PAC_OPAQUE_TYPE_IDENTITY ;
* pos + + = sm - > identity_len ;
os_memcpy ( pos , sm - > identity , sm - > identity_len ) ;
pos + = sm - > identity_len ;
}
if ( aes_wrap ( data - > pac_opaque_encr , sizeof ( pac_key ) / 8 , pac_key ,
pac_opaque ) < 0 )
pac_len = pos - pac_buf ;
if ( pac_len % 8 ) {
* pos + + = PAC_OPAQUE_TYPE_PAD ;
pac_len + + ;
}
pac_opaque = os_malloc ( pac_len + 8 ) ;
if ( pac_opaque = = NULL ) {
os_free ( pac_buf ) ;
return NULL ;
}
if ( aes_wrap ( data - > pac_opaque_encr , pac_len / 8 , pac_buf ,
pac_opaque ) < 0 ) {
os_free ( pac_buf ) ;
os_free ( pac_opaque ) ;
return NULL ;
}
os_free ( pac_buf ) ;
pac_len + = 8 ;
wpa_hexdump ( MSG_DEBUG , " EAP-FAST: PAC-Opaque " ,
pac_opaque , sizeof ( pac_opaque ) ) ;
pac_opaque , pac_len ) ;
buf_len = sizeof ( * pac_tlv ) +
sizeof ( * hdr ) + EAP_FAST_PAC_KEY_LEN +
sizeof ( * hdr ) + sizeof ( pac_opaque ) +
sizeof ( * hdr ) + pac_len +
2 * srv_id_len + 100 + sizeof ( * result ) ;
buf = wpabuf_alloc ( buf_len ) ;
if ( buf = = NULL )
if ( buf = = NULL ) {
os_free ( pac_opaque ) ;
return NULL ;
}
/* PAC TLV */
wpa_printf ( MSG_DEBUG , " EAP-FAST: Add PAC TLV " ) ;
@ -806,13 +862,14 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
hdr = wpabuf_put ( buf , sizeof ( * hdr ) ) ;
hdr - > type = host_to_be16 ( PAC_TYPE_PAC_KEY ) ;
hdr - > len = host_to_be16 ( EAP_FAST_PAC_KEY_LEN ) ;
wpabuf_put_data ( buf , pac_key + 2 , EAP_FAST_PAC_KEY_LEN ) ;
wpabuf_put_data ( buf , pac_key , EAP_FAST_PAC_KEY_LEN ) ;
/* PAC-Opaque */
hdr = wpabuf_put ( buf , sizeof ( * hdr ) ) ;
hdr - > type = host_to_be16 ( PAC_TYPE_PAC_OPAQUE ) ;
hdr - > len = host_to_be16 ( sizeof ( pac_opaque ) ) ;
wpabuf_put_data ( buf , pac_opaque , sizeof ( pac_opaque ) ) ;
hdr - > len = host_to_be16 ( pac_len ) ;
wpabuf_put_data ( buf , pac_opaque , pac_len ) ;
os_free ( pac_opaque ) ;
/* PAC-Info */
pac_info = wpabuf_put ( buf , sizeof ( * pac_info ) ) ;
@ -1524,6 +1581,7 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
size_t left ;
unsigned int tls_msg_len ;
int peer_version ;
u8 next_type ;
pos = eap_hdr_validate ( EAP_VENDOR_IETF , EAP_TYPE_FAST , respData ,
& left ) ;
@ -1594,8 +1652,35 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
/* fall through to PHASE2_START */
case PHASE2_START :
eap_fast_state ( data , PHASE2_ID ) ;
eap_fast_phase2_init ( sm , data , EAP_TYPE_IDENTITY ) ;
if ( data - > identity ) {
os_free ( sm - > identity ) ;
sm - > identity = data - > identity ;
data - > identity = NULL ;
sm - > identity_len = data - > identity_len ;
data - > identity_len = 0 ;
if ( eap_user_get ( sm , sm - > identity , sm - > identity_len , 1 )
! = 0 ) {
wpa_hexdump_ascii ( MSG_DEBUG , " EAP-FAST: "
" Phase2 Identity not found "
" in the user database " ,
sm - > identity ,
sm - > identity_len ) ;
next_type = eap_fast_req_failure ( sm , data ) ;
} else {
wpa_printf ( MSG_DEBUG , " EAP-FAST: Identity "
" already known - skip Phase 2 "
" Identity Request " ) ;
next_type = sm - > user - > methods [ 0 ] . method ;
sm - > user_eap_method_index = 1 ;
}
eap_fast_state ( data , PHASE2_METHOD ) ;
} else {
eap_fast_state ( data , PHASE2_ID ) ;
next_type = EAP_TYPE_IDENTITY ;
}
eap_fast_phase2_init ( sm , data , next_type ) ;
break ;
case PHASE2_ID :
case PHASE2_METHOD :