EAP peer: Add Session-Id derivation

This adds a new getSessionId() callback for EAP peer methods to allow
EAP Session-Id to be derived. This commits implements this for EAP-FAST,
EAP-GPSK, EAP-IKEv2, EAP-PEAP, EAP-TLS, and EAP-TTLS.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Stevent Li 2013-02-06 18:52:33 +02:00 committed by Jouni Malinen
parent 9288e6625b
commit 950c563076
13 changed files with 457 additions and 2 deletions

View file

@ -340,6 +340,141 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
} }
static int eap_gpsk_derive_mid_helper(u32 csuite_specifier,
u8 *kdf_out, size_t kdf_out_len,
const u8 *psk, const u8 *seed,
size_t seed_len, u8 method_type)
{
u8 *pos, *data;
size_t data_len;
int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
u8 *buf, size_t len);
gkdf = NULL;
switch (csuite_specifier) {
case EAP_GPSK_CIPHER_AES:
gkdf = eap_gpsk_gkdf_cmac;
break;
#ifdef EAP_GPSK_SHA256
case EAP_GPSK_CIPHER_SHA256:
gkdf = eap_gpsk_gkdf_sha256;
break;
#endif /* EAP_GPSK_SHA256 */
default:
wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in "
"Session-Id derivation", csuite_specifier);
return -1;
}
#define SID_LABEL "Method ID"
/* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */
data_len = strlen(SID_LABEL) + 1 + 6 + seed_len;
data = os_malloc(data_len);
if (data == NULL)
return -1;
pos = data;
os_memcpy(pos, SID_LABEL, strlen(SID_LABEL));
pos += strlen(SID_LABEL);
#undef SID_LABEL
os_memcpy(pos, &method_type, 1);
pos += 1;
WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
pos += 4;
WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
pos += 2;
os_memcpy(pos, seed, seed_len); /* inputString */
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation",
data, data_len);
if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) {
os_free(data);
return -1;
}
os_free(data);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len);
return 0;
}
/**
* eap_gpsk_session_id - Derive EAP-GPSK Session ID
* @psk: Pre-shared key
* @psk_len: Length of psk in bytes
* @vendor: CSuite/Vendor
* @specifier: CSuite/Specifier
* @rand_peer: 32-byte RAND_Peer
* @rand_server: 32-byte RAND_Server
* @id_peer: ID_Peer
* @id_peer_len: Length of ID_Peer
* @id_server: ID_Server
* @id_server_len: Length of ID_Server
* @method_type: EAP Authentication Method Type
* @sid: Buffer for 17-byte Session ID
* @sid_len: Buffer for returning length of Session ID
* Returns: 0 on success, -1 on failure
*/
int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
int specifier,
const u8 *rand_peer, const u8 *rand_server,
const u8 *id_peer, size_t id_peer_len,
const u8 *id_server, size_t id_server_len,
u8 method_type, u8 *sid, size_t *sid_len)
{
u8 *seed, *pos;
u8 kdf_out[16];
size_t seed_len;
int ret;
wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)",
vendor, specifier);
if (vendor != EAP_GPSK_VENDOR_IETF)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
/*
* inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
* (= seed)
* KS = 16, CSuite_Sel = 0x00000000 0x0001
* Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
* CSuite_Sel || inputString)
*/
seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
seed = os_malloc(seed_len);
if (seed == NULL) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
"for Session-Id derivation");
return -1;
}
pos = seed;
os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
pos += EAP_GPSK_RAND_LEN;
os_memcpy(pos, id_peer, id_peer_len);
pos += id_peer_len;
os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
pos += EAP_GPSK_RAND_LEN;
os_memcpy(pos, id_server, id_server_len);
pos += id_server_len;
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
ret = eap_gpsk_derive_mid_helper(specifier,
kdf_out, sizeof(kdf_out),
psk, seed, seed_len,
method_type);
sid[0] = method_type;
os_memcpy(sid + 1, kdf_out, sizeof(kdf_out));
*sid_len = 1 + sizeof(kdf_out);
os_free(seed);
return ret;
}
/** /**
* eap_gpsk_mic_len - Get the length of the MIC * eap_gpsk_mic_len - Get the length of the MIC
* @vendor: CSuite/Vendor * @vendor: CSuite/Vendor

View file

@ -53,6 +53,12 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
const u8 *id_server, size_t id_server_len, const u8 *id_server, size_t id_server_len,
u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
u8 *pk, size_t *pk_len); u8 *pk, size_t *pk_len);
int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
int specifier,
const u8 *rand_peer, const u8 *rand_server,
const u8 *id_peer, size_t id_peer_len,
const u8 *id_server, size_t id_server_len,
u8 method_type, u8 *sid, size_t *sid_len);
size_t eap_gpsk_mic_len(int vendor, int specifier); size_t eap_gpsk_mic_len(int vendor, int specifier);
int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
int specifier, const u8 *data, size_t len, u8 *mic); int specifier, const u8 *data, size_t len, u8 *mic);

View file

@ -161,6 +161,8 @@ SM_STATE(EAP, INITIALIZE)
eapol_set_bool(sm, EAPOL_eapFail, FALSE); eapol_set_bool(sm, EAPOL_eapFail, FALSE);
os_free(sm->eapKeyData); os_free(sm->eapKeyData);
sm->eapKeyData = NULL; sm->eapKeyData = NULL;
os_free(sm->eapSessionId);
sm->eapSessionId = NULL;
sm->eapKeyAvailable = FALSE; sm->eapKeyAvailable = FALSE;
eapol_set_bool(sm, EAPOL_eapRestart, FALSE); eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
sm->lastId = -1; /* new session - make sure this does not match with sm->lastId = -1; /* new session - make sure this does not match with
@ -403,6 +405,13 @@ SM_STATE(EAP, METHOD)
os_free(sm->eapKeyData); os_free(sm->eapKeyData);
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
&sm->eapKeyDataLen); &sm->eapKeyDataLen);
os_free(sm->eapSessionId);
sm->eapSessionId = sm->m->getSessionId(sm, sm->eap_method_priv,
&sm->eapSessionIdLen);
if (sm->eapSessionId) {
wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
sm->eapSessionId, sm->eapSessionIdLen);
}
} }
} }
@ -1462,6 +1471,8 @@ void eap_sm_abort(struct eap_sm *sm)
sm->eapRespData = NULL; sm->eapRespData = NULL;
os_free(sm->eapKeyData); os_free(sm->eapKeyData);
sm->eapKeyData = NULL; sm->eapKeyData = NULL;
os_free(sm->eapSessionId);
sm->eapSessionId = NULL;
/* This is not clearly specified in the EAP statemachines draft, but /* This is not clearly specified in the EAP statemachines draft, but
* it seems necessary to make sure that some of the EAPOL variables get * it seems necessary to make sure that some of the EAPOL variables get
@ -2158,6 +2169,28 @@ void eap_notify_lower_layer_success(struct eap_sm *sm)
} }
/**
* eap_get_eapSessionId - Get Session-Id from EAP state machine
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @len: Pointer to variable that will be set to number of bytes in the session
* Returns: Pointer to the EAP Session-Id or %NULL on failure
*
* Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
* only after a successful authentication. EAP state machine continues to manage
* the Session-Id and the caller must not change or free the returned data.
*/
const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
{
if (sm == NULL || sm->eapSessionId == NULL) {
*len = 0;
return NULL;
}
*len = sm->eapSessionIdLen;
return sm->eapSessionId;
}
/** /**
* eap_get_eapKeyData - Get master session key (MSK) from EAP state machine * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()

View file

@ -306,6 +306,7 @@ void eap_set_force_disabled(struct eap_sm *sm, int disabled);
int eap_key_available(struct eap_sm *sm); int eap_key_available(struct eap_sm *sm);
void eap_notify_success(struct eap_sm *sm); void eap_notify_success(struct eap_sm *sm);
void eap_notify_lower_layer_success(struct eap_sm *sm); void eap_notify_lower_layer_success(struct eap_sm *sm);
const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
struct wpabuf * eap_get_eapRespData(struct eap_sm *sm); struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx); void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);

View file

@ -53,6 +53,8 @@ struct eap_fast_data {
int session_ticket_used; int session_ticket_used;
u8 key_data[EAP_FAST_KEY_LEN]; u8 key_data[EAP_FAST_KEY_LEN];
u8 *session_id;
size_t id_len;
u8 emsk[EAP_EMSK_LEN]; u8 emsk[EAP_EMSK_LEN];
int success; int success;
@ -238,6 +240,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
pac = pac->next; pac = pac->next;
eap_fast_free_pac(prev); eap_fast_free_pac(prev);
} }
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req); wpabuf_free(data->pending_phase2_req);
os_free(data); os_free(data);
} }
@ -785,6 +788,21 @@ static struct wpabuf * eap_fast_process_crypto_binding(
return NULL; return NULL;
} }
if (!data->anon_provisioning && data->phase2_success) {
os_free(data->session_id);
data->session_id = eap_peer_tls_derive_session_id(
sm, &data->ssl, EAP_TYPE_FAST, &data->id_len);
if (data->session_id) {
wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id",
data->session_id, data->id_len);
} else {
wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
"Session-Id");
wpabuf_free(resp);
return NULL;
}
}
pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv)); pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *) eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
pos, _bind, cmk); pos, _bind, cmk);
@ -1604,6 +1622,8 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
os_free(data); os_free(data);
return NULL; return NULL;
} }
os_free(data->session_id);
data->session_id = NULL;
if (data->phase2_priv && data->phase2_method && if (data->phase2_priv && data->phase2_method &&
data->phase2_method->init_for_reauth) data->phase2_method->init_for_reauth)
data->phase2_method->init_for_reauth(sm, data->phase2_priv); data->phase2_method->init_for_reauth(sm, data->phase2_priv);
@ -1662,6 +1682,25 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
} }
static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_fast_data *data = priv;
u8 *id;
if (!data->success)
return NULL;
id = os_malloc(data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
os_memcpy(id, data->session_id, data->id_len);
return id;
}
static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len) static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{ {
struct eap_fast_data *data = priv; struct eap_fast_data *data = priv;
@ -1696,6 +1735,7 @@ int eap_peer_fast_register(void)
eap->process = eap_fast_process; eap->process = eap_fast_process;
eap->isKeyAvailable = eap_fast_isKeyAvailable; eap->isKeyAvailable = eap_fast_isKeyAvailable;
eap->getKey = eap_fast_getKey; eap->getKey = eap_fast_getKey;
eap->getSessionId = eap_fast_get_session_id;
eap->get_status = eap_fast_get_status; eap->get_status = eap_fast_get_status;
#if 0 #if 0
eap->has_reauth_data = eap_fast_has_reauth_data; eap->has_reauth_data = eap_fast_has_reauth_data;

View file

@ -23,8 +23,8 @@ struct eap_gpsk_data {
size_t sk_len; size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN]; u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len; size_t pk_len;
u8 session_id; u8 session_id[128];
int session_id_set; size_t id_len;
u8 *id_peer; u8 *id_peer;
size_t id_peer_len; size_t id_peer_len;
u8 *id_server; u8 *id_server;
@ -354,6 +354,21 @@ static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
return NULL; return NULL;
} }
if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
data->id_server, data->id_server_len,
EAP_TYPE_GPSK,
data->session_id, &data->id_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
eap_gpsk_state(data, FAILURE);
wpabuf_free(resp);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
data->session_id, data->id_len);
/* No PD_Payload_1 */ /* No PD_Payload_1 */
wpabuf_put_be16(resp, 0); wpabuf_put_be16(resp, 0);
@ -708,6 +723,24 @@ static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
} }
static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_gpsk_data *data = priv;
u8 *sid;
if (data->state != SUCCESS)
return NULL;
sid = os_malloc(data->id_len);
if (sid == NULL)
return NULL;
os_memcpy(sid, data->session_id, data->id_len);
*len = data->id_len;
return sid;
}
int eap_peer_gpsk_register(void) int eap_peer_gpsk_register(void)
{ {
struct eap_method *eap; struct eap_method *eap;
@ -724,6 +757,7 @@ int eap_peer_gpsk_register(void)
eap->isKeyAvailable = eap_gpsk_isKeyAvailable; eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
eap->getKey = eap_gpsk_getKey; eap->getKey = eap_gpsk_getKey;
eap->get_emsk = eap_gpsk_get_emsk; eap->get_emsk = eap_gpsk_get_emsk;
eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_peer_method_register(eap); ret = eap_peer_method_register(eap);
if (ret) if (ret)

View file

@ -261,6 +261,19 @@ struct eap_method {
* private data or this function may derive the key. * private data or this function may derive the key.
*/ */
u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
/**
* getSessionId - Get EAP method specific Session-Id
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
* @len: Pointer to a variable to store Session-Id length
* Returns: Session-Id or %NULL if not available
*
* This function can be used to get the Session-Id from the EAP method.
* The Session-Id may already be stored in the method-specific private
* data or this function may derive the Session-Id.
*/
u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
}; };
@ -298,6 +311,8 @@ struct eap_sm {
Boolean eapKeyAvailable; /* peer to lower layer */ Boolean eapKeyAvailable; /* peer to lower layer */
u8 *eapKeyData; /* peer to lower layer */ u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */ size_t eapKeyDataLen; /* peer to lower layer */
u8 *eapSessionId; /* peer to lower layer */
size_t eapSessionIdLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */ const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */ /* not defined in RFC 4137 */
Boolean changed; Boolean changed;

View file

@ -475,6 +475,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
} }
static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ikev2_data *data = priv;
u8 *sid;
size_t sid_len;
size_t offset;
if (data->state != DONE || !data->keymat_ok)
return NULL;
sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
sid = os_malloc(sid_len);
if (sid) {
offset = 0;
sid[offset] = EAP_TYPE_IKEV2;
offset++;
os_memcpy(sid + offset, data->ikev2.i_nonce,
data->ikev2.i_nonce_len);
offset += data->ikev2.i_nonce_len;
os_memcpy(sid + offset, data->ikev2.r_nonce,
data->ikev2.r_nonce_len);
*len = sid_len;
wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
sid, sid_len);
}
return sid;
}
int eap_peer_ikev2_register(void) int eap_peer_ikev2_register(void)
{ {
struct eap_method *eap; struct eap_method *eap;
@ -492,6 +522,7 @@ int eap_peer_ikev2_register(void)
eap->isKeyAvailable = eap_ikev2_isKeyAvailable; eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
eap->getKey = eap_ikev2_getKey; eap->getKey = eap_ikev2_getKey;
eap->get_emsk = eap_ikev2_get_emsk; eap->get_emsk = eap_ikev2_get_emsk;
eap->getSessionId = eap_ikev2_get_session_id;
ret = eap_peer_method_register(eap); ret = eap_peer_method_register(eap);
if (ret) if (ret)

View file

@ -56,6 +56,8 @@ struct eap_peap_data {
int resuming; /* starting a resumed session */ int resuming; /* starting a resumed session */
int reauth; /* reauthentication */ int reauth; /* reauthentication */
u8 *key_data; u8 *key_data;
u8 *session_id;
size_t id_len;
struct wpabuf *pending_phase2_req; struct wpabuf *pending_phase2_req;
enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
@ -179,6 +181,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
os_free(data->phase2_types); os_free(data->phase2_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl); eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data); os_free(data->key_data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req); wpabuf_free(data->pending_phase2_req);
os_free(data); os_free(data);
} }
@ -1107,6 +1110,20 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
"derive key"); "derive key");
} }
os_free(data->session_id);
data->session_id =
eap_peer_tls_derive_session_id(sm, &data->ssl,
EAP_TYPE_PEAP,
&data->id_len);
if (data->session_id) {
wpa_hexdump(MSG_DEBUG,
"EAP-PEAP: Derived Session-Id",
data->session_id, data->id_len);
} else {
wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
"derive Session-Id");
}
if (sm->workaround && data->resuming) { if (sm->workaround && data->resuming) {
/* /*
* At least few RADIUS servers (Aegis v1.1.6; * At least few RADIUS servers (Aegis v1.1.6;
@ -1178,6 +1195,8 @@ static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
struct eap_peap_data *data = priv; struct eap_peap_data *data = priv;
os_free(data->key_data); os_free(data->key_data);
data->key_data = NULL; data->key_data = NULL;
os_free(data->session_id);
data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) { if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data); os_free(data);
return NULL; return NULL;
@ -1260,6 +1279,25 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
} }
static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
u8 *id;
if (data->session_id == NULL || !data->phase2_success)
return NULL;
id = os_malloc(data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
os_memcpy(id, data->session_id, data->id_len);
return id;
}
int eap_peer_peap_register(void) int eap_peer_peap_register(void)
{ {
struct eap_method *eap; struct eap_method *eap;
@ -1279,6 +1317,7 @@ int eap_peer_peap_register(void)
eap->has_reauth_data = eap_peap_has_reauth_data; eap->has_reauth_data = eap_peap_has_reauth_data;
eap->deinit_for_reauth = eap_peap_deinit_for_reauth; eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
eap->init_for_reauth = eap_peap_init_for_reauth; eap->init_for_reauth = eap_peap_init_for_reauth;
eap->getSessionId = eap_peap_get_session_id;
ret = eap_peer_method_register(eap); ret = eap_peer_method_register(eap);
if (ret) if (ret)

View file

@ -21,6 +21,8 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv);
struct eap_tls_data { struct eap_tls_data {
struct eap_ssl_data ssl; struct eap_ssl_data ssl;
u8 *key_data; u8 *key_data;
u8 *session_id;
size_t id_len;
void *ssl_ctx; void *ssl_ctx;
u8 eap_type; u8 eap_type;
}; };
@ -103,6 +105,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
return; return;
eap_peer_tls_ssl_deinit(sm, &data->ssl); eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data); os_free(data->key_data);
os_free(data->session_id);
os_free(data); os_free(data);
} }
@ -165,6 +168,17 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
} else { } else {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key"); wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
} }
os_free(data->session_id);
data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
EAP_TYPE_TLS,
&data->id_len);
if (data->session_id) {
wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
data->session_id, data->id_len);
} else {
wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
}
} }
@ -228,6 +242,8 @@ static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
struct eap_tls_data *data = priv; struct eap_tls_data *data = priv;
os_free(data->key_data); os_free(data->key_data);
data->key_data = NULL; data->key_data = NULL;
os_free(data->session_id);
data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) { if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data); os_free(data);
return NULL; return NULL;
@ -289,6 +305,25 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
} }
static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_tls_data *data = priv;
u8 *id;
if (data->session_id == NULL)
return NULL;
id = os_malloc(data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
os_memcpy(id, data->session_id, data->id_len);
return id;
}
int eap_peer_tls_register(void) int eap_peer_tls_register(void)
{ {
struct eap_method *eap; struct eap_method *eap;
@ -304,6 +339,7 @@ int eap_peer_tls_register(void)
eap->process = eap_tls_process; eap->process = eap_tls_process;
eap->isKeyAvailable = eap_tls_isKeyAvailable; eap->isKeyAvailable = eap_tls_isKeyAvailable;
eap->getKey = eap_tls_getKey; eap->getKey = eap_tls_getKey;
eap->getSessionId = eap_tls_get_session_id;
eap->get_status = eap_tls_get_status; eap->get_status = eap_tls_get_status;
eap->has_reauth_data = eap_tls_has_reauth_data; eap->has_reauth_data = eap_tls_has_reauth_data;
eap->deinit_for_reauth = eap_tls_deinit_for_reauth; eap->deinit_for_reauth = eap_tls_deinit_for_reauth;

View file

@ -339,6 +339,52 @@ fail:
} }
/**
* eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @data: Data for TLS processing
* @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
* @len: Pointer to length of the session ID generated
* Returns: Pointer to allocated Session-Id on success or %NULL on failure
*
* This function derive the Session-Id based on the TLS session data
* (client/server random and method type).
*
* The caller is responsible for freeing the returned buffer.
*/
u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len)
{
struct tls_keys keys;
u8 *out;
/*
* TLS library did not support session ID generation,
* so get the needed TLS session parameters
*/
if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
return NULL;
if (keys.client_random == NULL || keys.server_random == NULL ||
keys.master_key == NULL)
return NULL;
*len = 1 + keys.client_random_len + keys.server_random_len;
out = os_malloc(*len);
if (out == NULL)
return NULL;
/* Session-Id = EAP type || client.random || server.random */
out[0] = eap_type;
os_memcpy(out + 1, keys.client_random, keys.client_random_len);
os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
keys.server_random_len);
return out;
}
/** /**
* eap_peer_tls_reassemble_fragment - Reassemble a received fragment * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
* @data: Data for TLS processing * @data: Data for TLS processing

View file

@ -94,6 +94,9 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len); const char *label, size_t len);
u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
EapType eap_type, int peap_version, EapType eap_type, int peap_version,
u8 id, const u8 *in_data, size_t in_len, u8 id, const u8 *in_data, size_t in_len,

View file

@ -54,6 +54,8 @@ struct eap_ttls_data {
int resuming; /* starting a resumed session */ int resuming; /* starting a resumed session */
int reauth; /* reauthentication */ int reauth; /* reauthentication */
u8 *key_data; u8 *key_data;
u8 *session_id;
size_t id_len;
struct wpabuf *pending_phase2_req; struct wpabuf *pending_phase2_req;
@ -140,6 +142,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
os_free(data->phase2_eap_types); os_free(data->phase2_eap_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl); eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data); os_free(data->key_data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req); wpabuf_free(data->pending_phase2_req);
os_free(data); os_free(data);
} }
@ -222,6 +225,17 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
data->key_data, EAP_TLS_KEY_LEN); data->key_data, EAP_TLS_KEY_LEN);
os_free(data->session_id);
data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
EAP_TYPE_TTLS,
&data->id_len);
if (data->session_id) {
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
data->session_id, data->id_len);
} else {
wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
}
return 0; return 0;
} }
@ -1528,6 +1542,8 @@ static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
struct eap_ttls_data *data = priv; struct eap_ttls_data *data = priv;
os_free(data->key_data); os_free(data->key_data);
data->key_data = NULL; data->key_data = NULL;
os_free(data->session_id);
data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) { if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data); os_free(data);
return NULL; return NULL;
@ -1612,6 +1628,25 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
} }
static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
u8 *id;
if (data->session_id == NULL || !data->phase2_success)
return NULL;
id = os_malloc(data->id_len);
if (id == NULL)
return NULL;
*len = data->id_len;
os_memcpy(id, data->session_id, data->id_len);
return id;
}
int eap_peer_ttls_register(void) int eap_peer_ttls_register(void)
{ {
struct eap_method *eap; struct eap_method *eap;
@ -1627,6 +1662,7 @@ int eap_peer_ttls_register(void)
eap->process = eap_ttls_process; eap->process = eap_ttls_process;
eap->isKeyAvailable = eap_ttls_isKeyAvailable; eap->isKeyAvailable = eap_ttls_isKeyAvailable;
eap->getKey = eap_ttls_getKey; eap->getKey = eap_ttls_getKey;
eap->getSessionId = eap_ttls_get_session_id;
eap->get_status = eap_ttls_get_status; eap->get_status = eap_ttls_get_status;
eap->has_reauth_data = eap_ttls_has_reauth_data; eap->has_reauth_data = eap_ttls_has_reauth_data;
eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;