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