18dbcf02cSchristos /*
28dbcf02cSchristos * EAP-FAST common helper functions (RFC 4851)
38dbcf02cSchristos * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
48dbcf02cSchristos *
562a52023Schristos * This software may be distributed under the terms of the BSD license.
662a52023Schristos * See README for more details.
78dbcf02cSchristos */
88dbcf02cSchristos
98dbcf02cSchristos #include "includes.h"
108dbcf02cSchristos
118dbcf02cSchristos #include "common.h"
128dbcf02cSchristos #include "crypto/sha1.h"
138dbcf02cSchristos #include "crypto/tls.h"
148dbcf02cSchristos #include "eap_defs.h"
158dbcf02cSchristos #include "eap_tlv_common.h"
168dbcf02cSchristos #include "eap_fast_common.h"
178dbcf02cSchristos
188dbcf02cSchristos
eap_fast_put_tlv_hdr(struct wpabuf * buf,u16 type,u16 len)198dbcf02cSchristos void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
208dbcf02cSchristos {
218dbcf02cSchristos struct pac_tlv_hdr hdr;
228dbcf02cSchristos hdr.type = host_to_be16(type);
238dbcf02cSchristos hdr.len = host_to_be16(len);
248dbcf02cSchristos wpabuf_put_data(buf, &hdr, sizeof(hdr));
258dbcf02cSchristos }
268dbcf02cSchristos
278dbcf02cSchristos
eap_fast_put_tlv(struct wpabuf * buf,u16 type,const void * data,u16 len)288dbcf02cSchristos void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
298dbcf02cSchristos u16 len)
308dbcf02cSchristos {
318dbcf02cSchristos eap_fast_put_tlv_hdr(buf, type, len);
328dbcf02cSchristos wpabuf_put_data(buf, data, len);
338dbcf02cSchristos }
348dbcf02cSchristos
358dbcf02cSchristos
eap_fast_put_tlv_buf(struct wpabuf * buf,u16 type,const struct wpabuf * data)368dbcf02cSchristos void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
378dbcf02cSchristos const struct wpabuf *data)
388dbcf02cSchristos {
398dbcf02cSchristos eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
408dbcf02cSchristos wpabuf_put_buf(buf, data);
418dbcf02cSchristos }
428dbcf02cSchristos
438dbcf02cSchristos
eap_fast_tlv_eap_payload(struct wpabuf * buf)448dbcf02cSchristos struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
458dbcf02cSchristos {
468dbcf02cSchristos struct wpabuf *e;
478dbcf02cSchristos
488dbcf02cSchristos if (buf == NULL)
498dbcf02cSchristos return NULL;
508dbcf02cSchristos
518dbcf02cSchristos /* Encapsulate EAP packet in EAP-Payload TLV */
528dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
538dbcf02cSchristos e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
548dbcf02cSchristos if (e == NULL) {
558dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
568dbcf02cSchristos "for TLV encapsulation");
578dbcf02cSchristos wpabuf_free(buf);
588dbcf02cSchristos return NULL;
598dbcf02cSchristos }
608dbcf02cSchristos eap_fast_put_tlv_buf(e,
618dbcf02cSchristos EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
628dbcf02cSchristos buf);
638dbcf02cSchristos wpabuf_free(buf);
648dbcf02cSchristos return e;
658dbcf02cSchristos }
668dbcf02cSchristos
678dbcf02cSchristos
eap_fast_derive_master_secret(const u8 * pac_key,const u8 * server_random,const u8 * client_random,u8 * master_secret)688dbcf02cSchristos void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
698dbcf02cSchristos const u8 *client_random, u8 *master_secret)
708dbcf02cSchristos {
718dbcf02cSchristos #define TLS_RANDOM_LEN 32
728dbcf02cSchristos #define TLS_MASTER_SECRET_LEN 48
738dbcf02cSchristos u8 seed[2 * TLS_RANDOM_LEN];
748dbcf02cSchristos
758dbcf02cSchristos wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
768dbcf02cSchristos client_random, TLS_RANDOM_LEN);
778dbcf02cSchristos wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
788dbcf02cSchristos server_random, TLS_RANDOM_LEN);
798dbcf02cSchristos
808dbcf02cSchristos /*
818dbcf02cSchristos * RFC 4851, Section 5.1:
828dbcf02cSchristos * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
838dbcf02cSchristos * server_random + client_random, 48)
848dbcf02cSchristos */
858dbcf02cSchristos os_memcpy(seed, server_random, TLS_RANDOM_LEN);
868dbcf02cSchristos os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
878dbcf02cSchristos sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
888dbcf02cSchristos "PAC to master secret label hash",
898dbcf02cSchristos seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
908dbcf02cSchristos
918dbcf02cSchristos wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
928dbcf02cSchristos master_secret, TLS_MASTER_SECRET_LEN);
938dbcf02cSchristos }
948dbcf02cSchristos
958dbcf02cSchristos
eap_fast_derive_key(void * ssl_ctx,struct tls_connection * conn,size_t len)96*928750b6Schristos u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, size_t len)
978dbcf02cSchristos {
98*928750b6Schristos u8 *out;
998dbcf02cSchristos
100*928750b6Schristos out = os_malloc(len);
1018dbcf02cSchristos if (out == NULL)
1028dbcf02cSchristos return NULL;
1038dbcf02cSchristos
104*928750b6Schristos if (tls_connection_get_eap_fast_key(ssl_ctx, conn, out, len)) {
1058dbcf02cSchristos os_free(out);
1068dbcf02cSchristos return NULL;
1078dbcf02cSchristos }
1088dbcf02cSchristos
109*928750b6Schristos return out;
110*928750b6Schristos }
1118dbcf02cSchristos
112*928750b6Schristos
eap_fast_derive_eap_msk(const u8 * simck,u8 * msk)113*928750b6Schristos int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
1148dbcf02cSchristos {
1158dbcf02cSchristos /*
1168dbcf02cSchristos * RFC 4851, Section 5.4: EAP Master Session Key Generation
1178dbcf02cSchristos * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
1188dbcf02cSchristos */
1198dbcf02cSchristos
120*928750b6Schristos if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
1218dbcf02cSchristos "Session Key Generating Function", (u8 *) "", 0,
122*928750b6Schristos msk, EAP_FAST_KEY_LEN) < 0)
123*928750b6Schristos return -1;
1248dbcf02cSchristos wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
1258dbcf02cSchristos msk, EAP_FAST_KEY_LEN);
126*928750b6Schristos return 0;
1278dbcf02cSchristos }
1288dbcf02cSchristos
1298dbcf02cSchristos
eap_fast_derive_eap_emsk(const u8 * simck,u8 * emsk)130*928750b6Schristos int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
1318dbcf02cSchristos {
1328dbcf02cSchristos /*
1338dbcf02cSchristos * RFC 4851, Section 5.4: EAP Master Session Key Genreration
1348dbcf02cSchristos * EMSK = T-PRF(S-IMCK[j],
1358dbcf02cSchristos * "Extended Session Key Generating Function", 64)
1368dbcf02cSchristos */
1378dbcf02cSchristos
138*928750b6Schristos if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
1398dbcf02cSchristos "Extended Session Key Generating Function", (u8 *) "", 0,
140*928750b6Schristos emsk, EAP_EMSK_LEN) < 0)
141*928750b6Schristos return -1;
1428dbcf02cSchristos wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
1438dbcf02cSchristos emsk, EAP_EMSK_LEN);
144*928750b6Schristos return 0;
1458dbcf02cSchristos }
1468dbcf02cSchristos
1478dbcf02cSchristos
eap_fast_parse_tlv(struct eap_fast_tlv_parse * tlv,int tlv_type,u8 * pos,size_t len)1488dbcf02cSchristos int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
14936d97821Schristos int tlv_type, u8 *pos, size_t len)
1508dbcf02cSchristos {
1518dbcf02cSchristos switch (tlv_type) {
1528dbcf02cSchristos case EAP_TLV_EAP_PAYLOAD_TLV:
1538dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
1548dbcf02cSchristos pos, len);
1558dbcf02cSchristos if (tlv->eap_payload_tlv) {
1568dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
1578dbcf02cSchristos "EAP-Payload TLV in the message");
1588dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
1598dbcf02cSchristos return -2;
1608dbcf02cSchristos }
1618dbcf02cSchristos tlv->eap_payload_tlv = pos;
1628dbcf02cSchristos tlv->eap_payload_tlv_len = len;
1638dbcf02cSchristos break;
1648dbcf02cSchristos case EAP_TLV_RESULT_TLV:
1658dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
1668dbcf02cSchristos if (tlv->result) {
1678dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
1688dbcf02cSchristos "Result TLV in the message");
1698dbcf02cSchristos tlv->result = EAP_TLV_RESULT_FAILURE;
1708dbcf02cSchristos return -2;
1718dbcf02cSchristos }
1728dbcf02cSchristos if (len < 2) {
1738dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
1748dbcf02cSchristos "Result TLV");
1758dbcf02cSchristos tlv->result = EAP_TLV_RESULT_FAILURE;
1768dbcf02cSchristos break;
1778dbcf02cSchristos }
1788dbcf02cSchristos tlv->result = WPA_GET_BE16(pos);
1798dbcf02cSchristos if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
1808dbcf02cSchristos tlv->result != EAP_TLV_RESULT_FAILURE) {
1818dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
1828dbcf02cSchristos tlv->result);
1838dbcf02cSchristos tlv->result = EAP_TLV_RESULT_FAILURE;
1848dbcf02cSchristos }
1858dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
1868dbcf02cSchristos tlv->result == EAP_TLV_RESULT_SUCCESS ?
1878dbcf02cSchristos "Success" : "Failure");
1888dbcf02cSchristos break;
1898dbcf02cSchristos case EAP_TLV_INTERMEDIATE_RESULT_TLV:
1908dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
1918dbcf02cSchristos pos, len);
1928dbcf02cSchristos if (len < 2) {
1938dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
1948dbcf02cSchristos "Intermediate-Result TLV");
1958dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
1968dbcf02cSchristos break;
1978dbcf02cSchristos }
1988dbcf02cSchristos if (tlv->iresult) {
1998dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2008dbcf02cSchristos "Intermediate-Result TLV in the message");
2018dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
2028dbcf02cSchristos return -2;
2038dbcf02cSchristos }
2048dbcf02cSchristos tlv->iresult = WPA_GET_BE16(pos);
2058dbcf02cSchristos if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
2068dbcf02cSchristos tlv->iresult != EAP_TLV_RESULT_FAILURE) {
2078dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
2088dbcf02cSchristos "Result %d", tlv->iresult);
2098dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
2108dbcf02cSchristos }
2118dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
2128dbcf02cSchristos tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
2138dbcf02cSchristos "Success" : "Failure");
2148dbcf02cSchristos break;
2158dbcf02cSchristos case EAP_TLV_CRYPTO_BINDING_TLV:
2168dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
2178dbcf02cSchristos pos, len);
2188dbcf02cSchristos if (tlv->crypto_binding) {
2198dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2208dbcf02cSchristos "Crypto-Binding TLV in the message");
2218dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
2228dbcf02cSchristos return -2;
2238dbcf02cSchristos }
2248dbcf02cSchristos tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
2258dbcf02cSchristos if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
2268dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
2278dbcf02cSchristos "Crypto-Binding TLV");
2288dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
2298dbcf02cSchristos return -2;
2308dbcf02cSchristos }
2318dbcf02cSchristos tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
2328dbcf02cSchristos (pos - sizeof(struct eap_tlv_hdr));
2338dbcf02cSchristos break;
2348dbcf02cSchristos case EAP_TLV_REQUEST_ACTION_TLV:
2358dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
2368dbcf02cSchristos pos, len);
2378dbcf02cSchristos if (tlv->request_action) {
2388dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2398dbcf02cSchristos "Request-Action TLV in the message");
2408dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
2418dbcf02cSchristos return -2;
2428dbcf02cSchristos }
2438dbcf02cSchristos if (len < 2) {
2448dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
2458dbcf02cSchristos "Request-Action TLV");
2468dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
2478dbcf02cSchristos break;
2488dbcf02cSchristos }
2498dbcf02cSchristos tlv->request_action = WPA_GET_BE16(pos);
2508dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
2518dbcf02cSchristos tlv->request_action);
2528dbcf02cSchristos break;
2538dbcf02cSchristos case EAP_TLV_PAC_TLV:
2548dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
2558dbcf02cSchristos if (tlv->pac) {
2568dbcf02cSchristos wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
2578dbcf02cSchristos "PAC TLV in the message");
2588dbcf02cSchristos tlv->iresult = EAP_TLV_RESULT_FAILURE;
2598dbcf02cSchristos return -2;
2608dbcf02cSchristos }
2618dbcf02cSchristos tlv->pac = pos;
2628dbcf02cSchristos tlv->pac_len = len;
2638dbcf02cSchristos break;
2648dbcf02cSchristos default:
2658dbcf02cSchristos /* Unknown TLV */
2668dbcf02cSchristos return -1;
2678dbcf02cSchristos }
2688dbcf02cSchristos
2698dbcf02cSchristos return 0;
2708dbcf02cSchristos }
271