1*39beb93cSSam Leffler /* 2*39beb93cSSam Leffler * EAP-FAST common helper functions (RFC 4851) 3*39beb93cSSam Leffler * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4*39beb93cSSam Leffler * 5*39beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 6*39beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 7*39beb93cSSam Leffler * published by the Free Software Foundation. 8*39beb93cSSam Leffler * 9*39beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 10*39beb93cSSam Leffler * license. 11*39beb93cSSam Leffler * 12*39beb93cSSam Leffler * See README and COPYING for more details. 13*39beb93cSSam Leffler */ 14*39beb93cSSam Leffler 15*39beb93cSSam Leffler #include "includes.h" 16*39beb93cSSam Leffler 17*39beb93cSSam Leffler #include "common.h" 18*39beb93cSSam Leffler #include "sha1.h" 19*39beb93cSSam Leffler #include "tls.h" 20*39beb93cSSam Leffler #include "eap_defs.h" 21*39beb93cSSam Leffler #include "eap_tlv_common.h" 22*39beb93cSSam Leffler #include "eap_fast_common.h" 23*39beb93cSSam Leffler 24*39beb93cSSam Leffler 25*39beb93cSSam Leffler void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len) 26*39beb93cSSam Leffler { 27*39beb93cSSam Leffler struct pac_tlv_hdr hdr; 28*39beb93cSSam Leffler hdr.type = host_to_be16(type); 29*39beb93cSSam Leffler hdr.len = host_to_be16(len); 30*39beb93cSSam Leffler wpabuf_put_data(buf, &hdr, sizeof(hdr)); 31*39beb93cSSam Leffler } 32*39beb93cSSam Leffler 33*39beb93cSSam Leffler 34*39beb93cSSam Leffler void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, 35*39beb93cSSam Leffler u16 len) 36*39beb93cSSam Leffler { 37*39beb93cSSam Leffler eap_fast_put_tlv_hdr(buf, type, len); 38*39beb93cSSam Leffler wpabuf_put_data(buf, data, len); 39*39beb93cSSam Leffler } 40*39beb93cSSam Leffler 41*39beb93cSSam Leffler 42*39beb93cSSam Leffler void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, 43*39beb93cSSam Leffler const struct wpabuf *data) 44*39beb93cSSam Leffler { 45*39beb93cSSam Leffler eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data)); 46*39beb93cSSam Leffler wpabuf_put_buf(buf, data); 47*39beb93cSSam Leffler } 48*39beb93cSSam Leffler 49*39beb93cSSam Leffler 50*39beb93cSSam Leffler struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf) 51*39beb93cSSam Leffler { 52*39beb93cSSam Leffler struct wpabuf *e; 53*39beb93cSSam Leffler 54*39beb93cSSam Leffler if (buf == NULL) 55*39beb93cSSam Leffler return NULL; 56*39beb93cSSam Leffler 57*39beb93cSSam Leffler /* Encapsulate EAP packet in EAP-Payload TLV */ 58*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV"); 59*39beb93cSSam Leffler e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf)); 60*39beb93cSSam Leffler if (e == NULL) { 61*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory " 62*39beb93cSSam Leffler "for TLV encapsulation"); 63*39beb93cSSam Leffler wpabuf_free(buf); 64*39beb93cSSam Leffler return NULL; 65*39beb93cSSam Leffler } 66*39beb93cSSam Leffler eap_fast_put_tlv_buf(e, 67*39beb93cSSam Leffler EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV, 68*39beb93cSSam Leffler buf); 69*39beb93cSSam Leffler wpabuf_free(buf); 70*39beb93cSSam Leffler return e; 71*39beb93cSSam Leffler } 72*39beb93cSSam Leffler 73*39beb93cSSam Leffler 74*39beb93cSSam Leffler void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, 75*39beb93cSSam Leffler const u8 *client_random, u8 *master_secret) 76*39beb93cSSam Leffler { 77*39beb93cSSam Leffler #define TLS_RANDOM_LEN 32 78*39beb93cSSam Leffler #define TLS_MASTER_SECRET_LEN 48 79*39beb93cSSam Leffler u8 seed[2 * TLS_RANDOM_LEN]; 80*39beb93cSSam Leffler 81*39beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random", 82*39beb93cSSam Leffler client_random, TLS_RANDOM_LEN); 83*39beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random", 84*39beb93cSSam Leffler server_random, TLS_RANDOM_LEN); 85*39beb93cSSam Leffler 86*39beb93cSSam Leffler /* 87*39beb93cSSam Leffler * RFC 4851, Section 5.1: 88*39beb93cSSam Leffler * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 89*39beb93cSSam Leffler * server_random + client_random, 48) 90*39beb93cSSam Leffler */ 91*39beb93cSSam Leffler os_memcpy(seed, server_random, TLS_RANDOM_LEN); 92*39beb93cSSam Leffler os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN); 93*39beb93cSSam Leffler sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN, 94*39beb93cSSam Leffler "PAC to master secret label hash", 95*39beb93cSSam Leffler seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN); 96*39beb93cSSam Leffler 97*39beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret", 98*39beb93cSSam Leffler master_secret, TLS_MASTER_SECRET_LEN); 99*39beb93cSSam Leffler } 100*39beb93cSSam Leffler 101*39beb93cSSam Leffler 102*39beb93cSSam Leffler u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, 103*39beb93cSSam Leffler const char *label, size_t len) 104*39beb93cSSam Leffler { 105*39beb93cSSam Leffler struct tls_keys keys; 106*39beb93cSSam Leffler u8 *rnd = NULL, *out; 107*39beb93cSSam Leffler int block_size; 108*39beb93cSSam Leffler 109*39beb93cSSam Leffler block_size = tls_connection_get_keyblock_size(ssl_ctx, conn); 110*39beb93cSSam Leffler if (block_size < 0) 111*39beb93cSSam Leffler return NULL; 112*39beb93cSSam Leffler 113*39beb93cSSam Leffler out = os_malloc(block_size + len); 114*39beb93cSSam Leffler if (out == NULL) 115*39beb93cSSam Leffler return NULL; 116*39beb93cSSam Leffler 117*39beb93cSSam Leffler if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len) 118*39beb93cSSam Leffler == 0) { 119*39beb93cSSam Leffler os_memmove(out, out + block_size, len); 120*39beb93cSSam Leffler return out; 121*39beb93cSSam Leffler } 122*39beb93cSSam Leffler 123*39beb93cSSam Leffler if (tls_connection_get_keys(ssl_ctx, conn, &keys)) 124*39beb93cSSam Leffler goto fail; 125*39beb93cSSam Leffler 126*39beb93cSSam Leffler rnd = os_malloc(keys.client_random_len + keys.server_random_len); 127*39beb93cSSam Leffler if (rnd == NULL) 128*39beb93cSSam Leffler goto fail; 129*39beb93cSSam Leffler 130*39beb93cSSam Leffler os_memcpy(rnd, keys.server_random, keys.server_random_len); 131*39beb93cSSam Leffler os_memcpy(rnd + keys.server_random_len, keys.client_random, 132*39beb93cSSam Leffler keys.client_random_len); 133*39beb93cSSam Leffler 134*39beb93cSSam Leffler wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key " 135*39beb93cSSam Leffler "expansion", keys.master_key, keys.master_key_len); 136*39beb93cSSam Leffler if (tls_prf(keys.master_key, keys.master_key_len, 137*39beb93cSSam Leffler label, rnd, keys.client_random_len + 138*39beb93cSSam Leffler keys.server_random_len, out, block_size + len)) 139*39beb93cSSam Leffler goto fail; 140*39beb93cSSam Leffler os_free(rnd); 141*39beb93cSSam Leffler os_memmove(out, out + block_size, len); 142*39beb93cSSam Leffler return out; 143*39beb93cSSam Leffler 144*39beb93cSSam Leffler fail: 145*39beb93cSSam Leffler os_free(rnd); 146*39beb93cSSam Leffler os_free(out); 147*39beb93cSSam Leffler return NULL; 148*39beb93cSSam Leffler } 149*39beb93cSSam Leffler 150*39beb93cSSam Leffler 151*39beb93cSSam Leffler void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk) 152*39beb93cSSam Leffler { 153*39beb93cSSam Leffler /* 154*39beb93cSSam Leffler * RFC 4851, Section 5.4: EAP Master Session Key Generation 155*39beb93cSSam Leffler * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64) 156*39beb93cSSam Leffler */ 157*39beb93cSSam Leffler 158*39beb93cSSam Leffler sha1_t_prf(simck, EAP_FAST_SIMCK_LEN, 159*39beb93cSSam Leffler "Session Key Generating Function", (u8 *) "", 0, 160*39beb93cSSam Leffler msk, EAP_FAST_KEY_LEN); 161*39beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)", 162*39beb93cSSam Leffler msk, EAP_FAST_KEY_LEN); 163*39beb93cSSam Leffler } 164*39beb93cSSam Leffler 165*39beb93cSSam Leffler 166*39beb93cSSam Leffler void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk) 167*39beb93cSSam Leffler { 168*39beb93cSSam Leffler /* 169*39beb93cSSam Leffler * RFC 4851, Section 5.4: EAP Master Session Key Genreration 170*39beb93cSSam Leffler * EMSK = T-PRF(S-IMCK[j], 171*39beb93cSSam Leffler * "Extended Session Key Generating Function", 64) 172*39beb93cSSam Leffler */ 173*39beb93cSSam Leffler 174*39beb93cSSam Leffler sha1_t_prf(simck, EAP_FAST_SIMCK_LEN, 175*39beb93cSSam Leffler "Extended Session Key Generating Function", (u8 *) "", 0, 176*39beb93cSSam Leffler emsk, EAP_EMSK_LEN); 177*39beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)", 178*39beb93cSSam Leffler emsk, EAP_EMSK_LEN); 179*39beb93cSSam Leffler } 180*39beb93cSSam Leffler 181*39beb93cSSam Leffler 182*39beb93cSSam Leffler int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, 183*39beb93cSSam Leffler int tlv_type, u8 *pos, int len) 184*39beb93cSSam Leffler { 185*39beb93cSSam Leffler switch (tlv_type) { 186*39beb93cSSam Leffler case EAP_TLV_EAP_PAYLOAD_TLV: 187*39beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV", 188*39beb93cSSam Leffler pos, len); 189*39beb93cSSam Leffler if (tlv->eap_payload_tlv) { 190*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " 191*39beb93cSSam Leffler "EAP-Payload TLV in the message"); 192*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 193*39beb93cSSam Leffler return -2; 194*39beb93cSSam Leffler } 195*39beb93cSSam Leffler tlv->eap_payload_tlv = pos; 196*39beb93cSSam Leffler tlv->eap_payload_tlv_len = len; 197*39beb93cSSam Leffler break; 198*39beb93cSSam Leffler case EAP_TLV_RESULT_TLV: 199*39beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len); 200*39beb93cSSam Leffler if (tlv->result) { 201*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " 202*39beb93cSSam Leffler "Result TLV in the message"); 203*39beb93cSSam Leffler tlv->result = EAP_TLV_RESULT_FAILURE; 204*39beb93cSSam Leffler return -2; 205*39beb93cSSam Leffler } 206*39beb93cSSam Leffler if (len < 2) { 207*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " 208*39beb93cSSam Leffler "Result TLV"); 209*39beb93cSSam Leffler tlv->result = EAP_TLV_RESULT_FAILURE; 210*39beb93cSSam Leffler break; 211*39beb93cSSam Leffler } 212*39beb93cSSam Leffler tlv->result = WPA_GET_BE16(pos); 213*39beb93cSSam Leffler if (tlv->result != EAP_TLV_RESULT_SUCCESS && 214*39beb93cSSam Leffler tlv->result != EAP_TLV_RESULT_FAILURE) { 215*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d", 216*39beb93cSSam Leffler tlv->result); 217*39beb93cSSam Leffler tlv->result = EAP_TLV_RESULT_FAILURE; 218*39beb93cSSam Leffler } 219*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s", 220*39beb93cSSam Leffler tlv->result == EAP_TLV_RESULT_SUCCESS ? 221*39beb93cSSam Leffler "Success" : "Failure"); 222*39beb93cSSam Leffler break; 223*39beb93cSSam Leffler case EAP_TLV_INTERMEDIATE_RESULT_TLV: 224*39beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV", 225*39beb93cSSam Leffler pos, len); 226*39beb93cSSam Leffler if (len < 2) { 227*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " 228*39beb93cSSam Leffler "Intermediate-Result TLV"); 229*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 230*39beb93cSSam Leffler break; 231*39beb93cSSam Leffler } 232*39beb93cSSam Leffler if (tlv->iresult) { 233*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " 234*39beb93cSSam Leffler "Intermediate-Result TLV in the message"); 235*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 236*39beb93cSSam Leffler return -2; 237*39beb93cSSam Leffler } 238*39beb93cSSam Leffler tlv->iresult = WPA_GET_BE16(pos); 239*39beb93cSSam Leffler if (tlv->iresult != EAP_TLV_RESULT_SUCCESS && 240*39beb93cSSam Leffler tlv->iresult != EAP_TLV_RESULT_FAILURE) { 241*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate " 242*39beb93cSSam Leffler "Result %d", tlv->iresult); 243*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 244*39beb93cSSam Leffler } 245*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s", 246*39beb93cSSam Leffler tlv->iresult == EAP_TLV_RESULT_SUCCESS ? 247*39beb93cSSam Leffler "Success" : "Failure"); 248*39beb93cSSam Leffler break; 249*39beb93cSSam Leffler case EAP_TLV_CRYPTO_BINDING_TLV: 250*39beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV", 251*39beb93cSSam Leffler pos, len); 252*39beb93cSSam Leffler if (tlv->crypto_binding) { 253*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " 254*39beb93cSSam Leffler "Crypto-Binding TLV in the message"); 255*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 256*39beb93cSSam Leffler return -2; 257*39beb93cSSam Leffler } 258*39beb93cSSam Leffler tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len; 259*39beb93cSSam Leffler if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) { 260*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " 261*39beb93cSSam Leffler "Crypto-Binding TLV"); 262*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 263*39beb93cSSam Leffler return -2; 264*39beb93cSSam Leffler } 265*39beb93cSSam Leffler tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *) 266*39beb93cSSam Leffler (pos - sizeof(struct eap_tlv_hdr)); 267*39beb93cSSam Leffler break; 268*39beb93cSSam Leffler case EAP_TLV_REQUEST_ACTION_TLV: 269*39beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV", 270*39beb93cSSam Leffler pos, len); 271*39beb93cSSam Leffler if (tlv->request_action) { 272*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " 273*39beb93cSSam Leffler "Request-Action TLV in the message"); 274*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 275*39beb93cSSam Leffler return -2; 276*39beb93cSSam Leffler } 277*39beb93cSSam Leffler if (len < 2) { 278*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " 279*39beb93cSSam Leffler "Request-Action TLV"); 280*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 281*39beb93cSSam Leffler break; 282*39beb93cSSam Leffler } 283*39beb93cSSam Leffler tlv->request_action = WPA_GET_BE16(pos); 284*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d", 285*39beb93cSSam Leffler tlv->request_action); 286*39beb93cSSam Leffler break; 287*39beb93cSSam Leffler case EAP_TLV_PAC_TLV: 288*39beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len); 289*39beb93cSSam Leffler if (tlv->pac) { 290*39beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " 291*39beb93cSSam Leffler "PAC TLV in the message"); 292*39beb93cSSam Leffler tlv->iresult = EAP_TLV_RESULT_FAILURE; 293*39beb93cSSam Leffler return -2; 294*39beb93cSSam Leffler } 295*39beb93cSSam Leffler tlv->pac = pos; 296*39beb93cSSam Leffler tlv->pac_len = len; 297*39beb93cSSam Leffler break; 298*39beb93cSSam Leffler default: 299*39beb93cSSam Leffler /* Unknown TLV */ 300*39beb93cSSam Leffler return -1; 301*39beb93cSSam Leffler } 302*39beb93cSSam Leffler 303*39beb93cSSam Leffler return 0; 304*39beb93cSSam Leffler } 305