|
@@ -15,6 +15,7 @@
|
|
|
#include "includes.h"
|
|
|
|
|
|
#include "common.h"
|
|
|
+#include "sha1.h"
|
|
|
#include "eap_i.h"
|
|
|
#include "eap_tls_common.h"
|
|
|
#include "eap_common/eap_tlv_common.h"
|
|
@@ -41,11 +42,20 @@ struct eap_peap_data {
|
|
|
} state;
|
|
|
|
|
|
int peap_version;
|
|
|
+ int recv_version;
|
|
|
const struct eap_method *phase2_method;
|
|
|
void *phase2_priv;
|
|
|
int force_version;
|
|
|
struct wpabuf *pending_phase2_resp;
|
|
|
enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
|
|
|
+ int crypto_binding_sent;
|
|
|
+ int crypto_binding_used;
|
|
|
+ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
|
|
|
+ u8 binding_nonce[32];
|
|
|
+ u8 ipmk[40];
|
|
|
+ u8 cmk[20];
|
|
|
+ u8 *phase2_key;
|
|
|
+ size_t phase2_key_len;
|
|
|
};
|
|
|
|
|
|
|
|
@@ -167,6 +177,7 @@ static void * eap_peap_init(struct eap_sm *sm)
|
|
|
data->peap_version = data->force_version;
|
|
|
}
|
|
|
data->state = START;
|
|
|
+ data->crypto_binding = NO_BINDING;
|
|
|
|
|
|
if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
|
|
|
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
|
|
@@ -187,6 +198,7 @@ static void eap_peap_reset(struct eap_sm *sm, void *priv)
|
|
|
data->phase2_method->reset(sm, data->phase2_priv);
|
|
|
eap_server_tls_ssl_deinit(sm, &data->ssl);
|
|
|
wpabuf_free(data->pending_phase2_resp);
|
|
|
+ os_free(data->phase2_key);
|
|
|
os_free(data);
|
|
|
}
|
|
|
|
|
@@ -303,13 +315,147 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
|
|
|
}
|
|
|
|
|
|
|
|
|
+static void eap_peap_get_isk(struct eap_peap_data *data,
|
|
|
+ u8 *isk, size_t isk_len)
|
|
|
+{
|
|
|
+ size_t key_len;
|
|
|
+
|
|
|
+ os_memset(isk, 0, isk_len);
|
|
|
+ if (data->phase2_key == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+ key_len = data->phase2_key_len;
|
|
|
+ if (key_len > isk_len)
|
|
|
+ key_len = isk_len;
|
|
|
+ os_memcpy(isk, data->phase2_key, key_len);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void peap_prfplus(int version, const u8 *key, size_t key_len,
|
|
|
+ const char *label, const u8 *seed, size_t seed_len,
|
|
|
+ u8 *buf, size_t buf_len)
|
|
|
+{
|
|
|
+ unsigned char counter = 0;
|
|
|
+ size_t pos, plen;
|
|
|
+ u8 hash[SHA1_MAC_LEN];
|
|
|
+ size_t label_len = os_strlen(label);
|
|
|
+ u8 extra[2];
|
|
|
+ const unsigned char *addr[5];
|
|
|
+ size_t len[5];
|
|
|
+
|
|
|
+ addr[0] = hash;
|
|
|
+ len[0] = 0;
|
|
|
+ addr[1] = (unsigned char *) label;
|
|
|
+ len[1] = label_len;
|
|
|
+ addr[2] = seed;
|
|
|
+ len[2] = seed_len;
|
|
|
+
|
|
|
+ if (version == 0) {
|
|
|
+
|
|
|
+ * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
|
|
|
+ * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
|
|
|
+ * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
|
|
|
+ * ...
|
|
|
+ * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
|
|
|
+ */
|
|
|
+
|
|
|
+ extra[0] = 0;
|
|
|
+ extra[1] = 0;
|
|
|
+
|
|
|
+ addr[3] = &counter;
|
|
|
+ len[3] = 1;
|
|
|
+ addr[4] = extra;
|
|
|
+ len[4] = 2;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
|
|
|
+ * T1 = HMAC-SHA1(K, S | LEN | 0x01)
|
|
|
+ * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
|
|
|
+ * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
|
|
|
+ * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
|
|
|
+ * ...
|
|
|
+ */
|
|
|
+
|
|
|
+ extra[0] = buf_len & 0xff;
|
|
|
+
|
|
|
+ addr[3] = extra;
|
|
|
+ len[3] = 1;
|
|
|
+ addr[4] = &counter;
|
|
|
+ len[4] = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ pos = 0;
|
|
|
+ while (pos < buf_len) {
|
|
|
+ counter++;
|
|
|
+ plen = buf_len - pos;
|
|
|
+ hmac_sha1_vector(key, key_len, 5, addr, len, hash);
|
|
|
+ if (plen >= SHA1_MAC_LEN) {
|
|
|
+ os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
|
|
|
+ pos += SHA1_MAC_LEN;
|
|
|
+ } else {
|
|
|
+ os_memcpy(&buf[pos], hash, plen);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ len[0] = SHA1_MAC_LEN;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
|
|
|
+{
|
|
|
+ u8 *tk;
|
|
|
+ u8 isk[32], imck[60];
|
|
|
+
|
|
|
+
|
|
|
+ * Tunnel key (TK) is the first 60 octets of the key generated by
|
|
|
+ * phase 1 of PEAP (based on TLS).
|
|
|
+ */
|
|
|
+ tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
|
|
|
+ EAP_TLS_KEY_LEN);
|
|
|
+ if (tk == NULL)
|
|
|
+ return -1;
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
|
|
|
+
|
|
|
+ eap_peap_get_isk(data, isk, sizeof(isk));
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
|
|
|
+
|
|
|
+
|
|
|
+ * IPMK Seed = "Inner Methods Compound Keys" | ISK
|
|
|
+ * TempKey = First 40 octets of TK
|
|
|
+ * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
|
|
|
+ * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
|
|
|
+ * in the end of the label just before ISK; is that just a typo?)
|
|
|
+ */
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
|
|
|
+ peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
|
|
|
+ isk, sizeof(isk), imck, sizeof(imck));
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
|
|
|
+ imck, sizeof(imck));
|
|
|
+
|
|
|
+ os_free(tk);
|
|
|
+
|
|
|
+
|
|
|
+ os_memcpy(data->ipmk, imck, 40);
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
|
|
|
+ os_memcpy(data->cmk, imck + 40, 20);
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
|
|
|
struct eap_peap_data *data,
|
|
|
u8 id)
|
|
|
{
|
|
|
struct wpabuf *buf, *encr_req;
|
|
|
+ size_t len;
|
|
|
+
|
|
|
+ len = 6;
|
|
|
+ if (data->crypto_binding != NO_BINDING)
|
|
|
+ len += 60;
|
|
|
|
|
|
- buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 6,
|
|
|
+ buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
|
|
|
EAP_CODE_REQUEST, id);
|
|
|
if (buf == NULL)
|
|
|
return NULL;
|
|
@@ -322,6 +468,50 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
|
|
|
wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
|
|
|
EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
|
|
|
|
|
|
+ if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
|
|
|
+ data->crypto_binding != NO_BINDING) {
|
|
|
+ u8 *mac;
|
|
|
+ u8 eap_type = EAP_TYPE_PEAP;
|
|
|
+ const u8 *addr[2];
|
|
|
+ size_t len[2];
|
|
|
+ u16 tlv_type;
|
|
|
+
|
|
|
+ if (eap_peap_derive_cmk(sm, data) < 0 ||
|
|
|
+ os_get_random(data->binding_nonce, 32)) {
|
|
|
+ wpabuf_free(buf);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ addr[0] = wpabuf_put(buf, 0);
|
|
|
+ len[0] = 60;
|
|
|
+ addr[1] = &eap_type;
|
|
|
+ len[1] = 1;
|
|
|
+
|
|
|
+ tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
|
|
|
+ if (data->peap_version >= 2)
|
|
|
+ tlv_type |= EAP_TLV_TYPE_MANDATORY;
|
|
|
+ wpabuf_put_be16(buf, tlv_type);
|
|
|
+ wpabuf_put_be16(buf, 56);
|
|
|
+
|
|
|
+ wpabuf_put_u8(buf, 0);
|
|
|
+ wpabuf_put_u8(buf, data->peap_version);
|
|
|
+ wpabuf_put_u8(buf, data->recv_version);
|
|
|
+ wpabuf_put_u8(buf, 0);
|
|
|
+ wpabuf_put_data(buf, data->binding_nonce, 32);
|
|
|
+ mac = wpabuf_put(buf, 20);
|
|
|
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
|
|
|
+ data->cmk, 20);
|
|
|
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
|
|
|
+ addr[0], len[0]);
|
|
|
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
|
|
|
+ addr[1], len[1]);
|
|
|
+ hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
|
|
|
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
|
|
|
+ mac, SHA1_MAC_LEN);
|
|
|
+ data->crypto_binding_sent = 1;
|
|
|
+ }
|
|
|
+
|
|
|
wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
|
|
|
buf);
|
|
|
|
|
@@ -423,14 +613,66 @@ static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
|
|
|
}
|
|
|
|
|
|
|
|
|
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
|
|
|
+ struct eap_peap_data *data,
|
|
|
+ const u8 *crypto_tlv,
|
|
|
+ size_t crypto_tlv_len)
|
|
|
+{
|
|
|
+ u8 buf[61], mac[SHA1_MAC_LEN];
|
|
|
+ const u8 *pos;
|
|
|
+
|
|
|
+ if (crypto_tlv_len != 4 + 56) {
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
|
|
|
+ "length %d", (int) crypto_tlv_len);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ pos = crypto_tlv;
|
|
|
+ pos += 4;
|
|
|
+ if (pos[1] != data->peap_version) {
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
|
|
|
+ "mismatch (was %d; expected %d)",
|
|
|
+ pos[1], data->peap_version);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pos[3] != 1) {
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
|
|
|
+ "SubType %d", pos[3]);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ pos += 4;
|
|
|
+ pos += 32;
|
|
|
+
|
|
|
+
|
|
|
+ os_memcpy(buf, crypto_tlv, 60);
|
|
|
+ os_memset(buf + 4 + 4 + 32, 0, 20);
|
|
|
+ buf[60] = EAP_TYPE_PEAP;
|
|
|
+ hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
|
|
|
+
|
|
|
+ if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
|
|
|
+ "cryptobinding TLV");
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
|
|
|
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
|
|
|
+ buf, 61);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
|
|
|
struct eap_peap_data *data,
|
|
|
struct wpabuf *in_data)
|
|
|
{
|
|
|
const u8 *pos;
|
|
|
size_t left;
|
|
|
- const u8 *result_tlv = NULL;
|
|
|
- size_t result_tlv_len = 0;
|
|
|
+ const u8 *result_tlv = NULL, *crypto_tlv = NULL;
|
|
|
+ size_t result_tlv_len = 0, crypto_tlv_len = 0;
|
|
|
int tlv_type, mandatory, tlv_len;
|
|
|
|
|
|
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
|
|
@@ -440,7 +682,7 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
|
|
|
}
|
|
|
|
|
|
|
|
|
- wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
|
|
|
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
|
|
|
while (left >= 4) {
|
|
|
mandatory = !!(pos[0] & 0x80);
|
|
|
tlv_type = pos[0] & 0x3f;
|
|
@@ -449,7 +691,7 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
|
|
|
pos += 4;
|
|
|
left -= 4;
|
|
|
if ((size_t) tlv_len > left) {
|
|
|
- wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
|
|
|
"(tlv_len=%d left=%lu)", tlv_len,
|
|
|
(unsigned long) left);
|
|
|
eap_peap_state(data, FAILURE);
|
|
@@ -460,8 +702,12 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
|
|
|
result_tlv = pos;
|
|
|
result_tlv_len = tlv_len;
|
|
|
break;
|
|
|
+ case EAP_TLV_CRYPTO_BINDING_TLV:
|
|
|
+ crypto_tlv = pos;
|
|
|
+ crypto_tlv_len = tlv_len;
|
|
|
+ break;
|
|
|
default:
|
|
|
- wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
|
|
|
"%d%s", tlv_type,
|
|
|
mandatory ? " (mandatory)" : "");
|
|
|
if (mandatory) {
|
|
@@ -476,21 +722,37 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
|
|
|
left -= tlv_len;
|
|
|
}
|
|
|
if (left) {
|
|
|
- wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
|
|
|
"Request (left=%lu)", (unsigned long) left);
|
|
|
eap_peap_state(data, FAILURE);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
+ if (crypto_tlv && data->crypto_binding_sent) {
|
|
|
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
|
|
|
+ crypto_tlv, crypto_tlv_len);
|
|
|
+ if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
|
|
|
+ crypto_tlv_len + 4) < 0) {
|
|
|
+ eap_peap_state(data, FAILURE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ data->crypto_binding_used = 1;
|
|
|
+ } else if (!crypto_tlv && data->crypto_binding_sent &&
|
|
|
+ data->crypto_binding == REQUIRE_BINDING) {
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
|
|
|
+ eap_peap_state(data, FAILURE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (result_tlv) {
|
|
|
int status;
|
|
|
const char *requested;
|
|
|
|
|
|
- wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
|
|
|
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
|
|
|
result_tlv, result_tlv_len);
|
|
|
if (result_tlv_len < 2) {
|
|
|
- wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
|
|
|
+ wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
|
|
|
"(len=%lu)",
|
|
|
(unsigned long) result_tlv_len);
|
|
|
eap_peap_state(data, FAILURE);
|
|
@@ -500,7 +762,7 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
|
|
|
"Failure";
|
|
|
status = WPA_GET_BE16(result_tlv);
|
|
|
if (status == EAP_TLV_RESULT_SUCCESS) {
|
|
|
- wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
|
|
|
+ wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
|
|
|
"- requested %s", requested);
|
|
|
if (data->tlv_request == TLV_REQ_SUCCESS)
|
|
|
eap_peap_state(data, SUCCESS);
|
|
@@ -508,11 +770,11 @@ static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
|
|
|
eap_peap_state(data, FAILURE);
|
|
|
|
|
|
} else if (status == EAP_TLV_RESULT_FAILURE) {
|
|
|
- wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure - "
|
|
|
- "requested %s", requested);
|
|
|
+ wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
|
|
|
+ "- requested %s", requested);
|
|
|
eap_peap_state(data, FAILURE);
|
|
|
} else {
|
|
|
- wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
|
|
|
+ wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
|
|
|
"Status %d", status);
|
|
|
eap_peap_state(data, FAILURE);
|
|
|
}
|
|
@@ -589,6 +851,19 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ os_free(data->phase2_key);
|
|
|
+ if (data->phase2_method->getKey) {
|
|
|
+ data->phase2_key = data->phase2_method->getKey(
|
|
|
+ sm, data->phase2_priv, &data->phase2_key_len);
|
|
|
+ if (data->phase2_key == NULL) {
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
|
|
|
+ "failed");
|
|
|
+ eap_peap_req_failure(sm, data);
|
|
|
+ eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
switch (data->state) {
|
|
|
case PHASE1_ID2:
|
|
|
case PHASE2_ID:
|
|
@@ -881,7 +1156,7 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
|
|
|
wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
|
|
|
"Flags 0x%02x", (unsigned long) wpabuf_len(respData),
|
|
|
flags);
|
|
|
- peer_version = flags & EAP_PEAP_VERSION_MASK;
|
|
|
+ data->recv_version = peer_version = flags & EAP_PEAP_VERSION_MASK;
|
|
|
if (data->force_version >= 0 && peer_version != data->force_version) {
|
|
|
wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
|
|
|
" version (forced=%d peer=%d) - reject",
|
|
@@ -979,6 +1254,26 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
|
|
if (data->state != SUCCESS)
|
|
|
return NULL;
|
|
|
|
|
|
+ if (data->crypto_binding_used) {
|
|
|
+ u8 csk[128];
|
|
|
+ peap_prfplus(data->peap_version, data->ipmk, 40,
|
|
|
+ "Session Key Generating Function",
|
|
|
+ (u8 *) "", 0, csk, sizeof(csk));
|
|
|
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
|
|
|
+ eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
|
|
|
+ if (eapKeyData) {
|
|
|
+ os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
|
|
|
+ *len = EAP_TLS_KEY_LEN;
|
|
|
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
|
|
|
+ eapKeyData, EAP_TLS_KEY_LEN);
|
|
|
+ } else {
|
|
|
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
|
|
|
+ "key");
|
|
|
+ }
|
|
|
+
|
|
|
+ return eapKeyData;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
|
|
|
"client EAP encryption",
|