eap_server_tls_common.c revision 252726
1214501Srpaulo/* 2214501Srpaulo * EAP-TLS/PEAP/TTLS/FAST server common functions 3214501Srpaulo * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "crypto/sha1.h" 13214501Srpaulo#include "crypto/tls.h" 14214501Srpaulo#include "eap_i.h" 15214501Srpaulo#include "eap_tls_common.h" 16214501Srpaulo 17214501Srpaulo 18214501Srpaulostatic void eap_server_tls_free_in_buf(struct eap_ssl_data *data); 19214501Srpaulo 20214501Srpaulo 21252726Srpaulostruct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, 22252726Srpaulo u8 code, u8 identifier) 23252726Srpaulo{ 24252726Srpaulo if (type == EAP_UNAUTH_TLS_TYPE) 25252726Srpaulo return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, 26252726Srpaulo EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, 27252726Srpaulo code, identifier); 28252726Srpaulo return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, 29252726Srpaulo identifier); 30252726Srpaulo} 31252726Srpaulo 32252726Srpaulo 33214501Srpauloint eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, 34214501Srpaulo int verify_peer) 35214501Srpaulo{ 36214501Srpaulo data->eap = sm; 37214501Srpaulo data->phase2 = sm->init_phase2; 38214501Srpaulo 39214501Srpaulo data->conn = tls_connection_init(sm->ssl_ctx); 40214501Srpaulo if (data->conn == NULL) { 41214501Srpaulo wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " 42214501Srpaulo "connection"); 43214501Srpaulo return -1; 44214501Srpaulo } 45214501Srpaulo 46214501Srpaulo if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) { 47214501Srpaulo wpa_printf(MSG_INFO, "SSL: Failed to configure verification " 48214501Srpaulo "of TLS peer certificate"); 49214501Srpaulo tls_connection_deinit(sm->ssl_ctx, data->conn); 50214501Srpaulo data->conn = NULL; 51214501Srpaulo return -1; 52214501Srpaulo } 53214501Srpaulo 54252726Srpaulo data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398; 55214501Srpaulo if (data->phase2) { 56214501Srpaulo /* Limit the fragment size in the inner TLS authentication 57214501Srpaulo * since the outer authentication with EAP-PEAP does not yet 58214501Srpaulo * support fragmentation */ 59214501Srpaulo if (data->tls_out_limit > 100) 60214501Srpaulo data->tls_out_limit -= 100; 61214501Srpaulo } 62214501Srpaulo return 0; 63214501Srpaulo} 64214501Srpaulo 65214501Srpaulo 66214501Srpaulovoid eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) 67214501Srpaulo{ 68214501Srpaulo tls_connection_deinit(sm->ssl_ctx, data->conn); 69214501Srpaulo eap_server_tls_free_in_buf(data); 70214501Srpaulo wpabuf_free(data->tls_out); 71214501Srpaulo data->tls_out = NULL; 72214501Srpaulo} 73214501Srpaulo 74214501Srpaulo 75214501Srpaulou8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, 76214501Srpaulo char *label, size_t len) 77214501Srpaulo{ 78214501Srpaulo struct tls_keys keys; 79214501Srpaulo u8 *rnd = NULL, *out; 80214501Srpaulo 81214501Srpaulo out = os_malloc(len); 82214501Srpaulo if (out == NULL) 83214501Srpaulo return NULL; 84214501Srpaulo 85214501Srpaulo if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == 86214501Srpaulo 0) 87214501Srpaulo return out; 88214501Srpaulo 89214501Srpaulo if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) 90214501Srpaulo goto fail; 91214501Srpaulo 92214501Srpaulo if (keys.client_random == NULL || keys.server_random == NULL || 93214501Srpaulo keys.master_key == NULL) 94214501Srpaulo goto fail; 95214501Srpaulo 96214501Srpaulo rnd = os_malloc(keys.client_random_len + keys.server_random_len); 97214501Srpaulo if (rnd == NULL) 98214501Srpaulo goto fail; 99214501Srpaulo os_memcpy(rnd, keys.client_random, keys.client_random_len); 100214501Srpaulo os_memcpy(rnd + keys.client_random_len, keys.server_random, 101214501Srpaulo keys.server_random_len); 102214501Srpaulo 103252726Srpaulo if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, 104252726Srpaulo label, rnd, keys.client_random_len + 105252726Srpaulo keys.server_random_len, out, len)) 106214501Srpaulo goto fail; 107214501Srpaulo 108214501Srpaulo os_free(rnd); 109214501Srpaulo return out; 110214501Srpaulo 111214501Srpaulofail: 112214501Srpaulo os_free(out); 113214501Srpaulo os_free(rnd); 114214501Srpaulo return NULL; 115214501Srpaulo} 116214501Srpaulo 117214501Srpaulo 118214501Srpaulostruct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, 119214501Srpaulo int eap_type, int version, u8 id) 120214501Srpaulo{ 121214501Srpaulo struct wpabuf *req; 122214501Srpaulo u8 flags; 123214501Srpaulo size_t send_len, plen; 124214501Srpaulo 125214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Generating Request"); 126214501Srpaulo if (data->tls_out == NULL) { 127214501Srpaulo wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__); 128214501Srpaulo return NULL; 129214501Srpaulo } 130214501Srpaulo 131214501Srpaulo flags = version; 132214501Srpaulo send_len = wpabuf_len(data->tls_out) - data->tls_out_pos; 133214501Srpaulo if (1 + send_len > data->tls_out_limit) { 134214501Srpaulo send_len = data->tls_out_limit - 1; 135214501Srpaulo flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; 136214501Srpaulo if (data->tls_out_pos == 0) { 137214501Srpaulo flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; 138214501Srpaulo send_len -= 4; 139214501Srpaulo } 140214501Srpaulo } 141214501Srpaulo 142214501Srpaulo plen = 1 + send_len; 143214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 144214501Srpaulo plen += 4; 145214501Srpaulo 146252726Srpaulo req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id); 147214501Srpaulo if (req == NULL) 148214501Srpaulo return NULL; 149214501Srpaulo 150214501Srpaulo wpabuf_put_u8(req, flags); /* Flags */ 151214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) 152214501Srpaulo wpabuf_put_be32(req, wpabuf_len(data->tls_out)); 153214501Srpaulo 154214501Srpaulo wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos, 155214501Srpaulo send_len); 156214501Srpaulo data->tls_out_pos += send_len; 157214501Srpaulo 158214501Srpaulo if (data->tls_out_pos == wpabuf_len(data->tls_out)) { 159214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 160214501Srpaulo "(message sent completely)", 161214501Srpaulo (unsigned long) send_len); 162214501Srpaulo wpabuf_free(data->tls_out); 163214501Srpaulo data->tls_out = NULL; 164214501Srpaulo data->tls_out_pos = 0; 165214501Srpaulo data->state = MSG; 166214501Srpaulo } else { 167214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " 168214501Srpaulo "(%lu more to send)", (unsigned long) send_len, 169214501Srpaulo (unsigned long) wpabuf_len(data->tls_out) - 170214501Srpaulo data->tls_out_pos); 171214501Srpaulo data->state = WAIT_FRAG_ACK; 172214501Srpaulo } 173214501Srpaulo 174214501Srpaulo return req; 175214501Srpaulo} 176214501Srpaulo 177214501Srpaulo 178214501Srpaulostruct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version) 179214501Srpaulo{ 180214501Srpaulo struct wpabuf *req; 181214501Srpaulo 182252726Srpaulo req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id); 183214501Srpaulo if (req == NULL) 184214501Srpaulo return NULL; 185214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Building ACK"); 186214501Srpaulo wpabuf_put_u8(req, version); /* Flags */ 187214501Srpaulo return req; 188214501Srpaulo} 189214501Srpaulo 190214501Srpaulo 191214501Srpaulostatic int eap_server_tls_process_cont(struct eap_ssl_data *data, 192214501Srpaulo const u8 *buf, size_t len) 193214501Srpaulo{ 194214501Srpaulo /* Process continuation of a pending message */ 195214501Srpaulo if (len > wpabuf_tailroom(data->tls_in)) { 196214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Fragment overflow"); 197214501Srpaulo return -1; 198214501Srpaulo } 199214501Srpaulo 200214501Srpaulo wpabuf_put_data(data->tls_in, buf, len); 201214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu " 202214501Srpaulo "bytes more", (unsigned long) len, 203214501Srpaulo (unsigned long) wpabuf_tailroom(data->tls_in)); 204214501Srpaulo 205214501Srpaulo return 0; 206214501Srpaulo} 207214501Srpaulo 208214501Srpaulo 209214501Srpaulostatic int eap_server_tls_process_fragment(struct eap_ssl_data *data, 210214501Srpaulo u8 flags, u32 message_length, 211214501Srpaulo const u8 *buf, size_t len) 212214501Srpaulo{ 213214501Srpaulo /* Process a fragment that is not the last one of the message */ 214214501Srpaulo if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { 215214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a " 216214501Srpaulo "fragmented packet"); 217214501Srpaulo return -1; 218214501Srpaulo } 219214501Srpaulo 220214501Srpaulo if (data->tls_in == NULL) { 221214501Srpaulo /* First fragment of the message */ 222214501Srpaulo 223214501Srpaulo /* Limit length to avoid rogue peers from causing large 224214501Srpaulo * memory allocations. */ 225214501Srpaulo if (message_length > 65536) { 226214501Srpaulo wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size" 227214501Srpaulo " over 64 kB)"); 228214501Srpaulo return -1; 229214501Srpaulo } 230214501Srpaulo 231243419Scperciva if (len > message_length) { 232243419Scperciva wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in " 233243419Scperciva "first fragment of frame (TLS Message " 234243419Scperciva "Length %d bytes)", 235243419Scperciva (int) len, (int) message_length); 236243419Scperciva return -1; 237243419Scperciva } 238243419Scperciva 239214501Srpaulo data->tls_in = wpabuf_alloc(message_length); 240214501Srpaulo if (data->tls_in == NULL) { 241214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: No memory for message"); 242214501Srpaulo return -1; 243214501Srpaulo } 244214501Srpaulo wpabuf_put_data(data->tls_in, buf, len); 245214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first " 246214501Srpaulo "fragment, waiting for %lu bytes more", 247214501Srpaulo (unsigned long) len, 248214501Srpaulo (unsigned long) wpabuf_tailroom(data->tls_in)); 249214501Srpaulo } 250214501Srpaulo 251214501Srpaulo return 0; 252214501Srpaulo} 253214501Srpaulo 254214501Srpaulo 255214501Srpauloint eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) 256214501Srpaulo{ 257214501Srpaulo if (data->tls_out) { 258214501Srpaulo /* This should not happen.. */ 259214501Srpaulo wpa_printf(MSG_INFO, "SSL: pending tls_out data when " 260214501Srpaulo "processing new message"); 261214501Srpaulo wpabuf_free(data->tls_out); 262214501Srpaulo WPA_ASSERT(data->tls_out == NULL); 263214501Srpaulo } 264214501Srpaulo 265214501Srpaulo data->tls_out = tls_connection_server_handshake(sm->ssl_ctx, 266214501Srpaulo data->conn, 267214501Srpaulo data->tls_in, NULL); 268214501Srpaulo if (data->tls_out == NULL) { 269214501Srpaulo wpa_printf(MSG_INFO, "SSL: TLS processing failed"); 270214501Srpaulo return -1; 271214501Srpaulo } 272214501Srpaulo if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { 273214501Srpaulo /* TLS processing has failed - return error */ 274214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " 275214501Srpaulo "report error"); 276214501Srpaulo return -1; 277214501Srpaulo } 278214501Srpaulo 279214501Srpaulo return 0; 280214501Srpaulo} 281214501Srpaulo 282214501Srpaulo 283214501Srpaulostatic int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, 284214501Srpaulo const u8 **pos, size_t *left) 285214501Srpaulo{ 286214501Srpaulo unsigned int tls_msg_len = 0; 287214501Srpaulo const u8 *end = *pos + *left; 288214501Srpaulo 289214501Srpaulo if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { 290214501Srpaulo if (*left < 4) { 291214501Srpaulo wpa_printf(MSG_INFO, "SSL: Short frame with TLS " 292214501Srpaulo "length"); 293214501Srpaulo return -1; 294214501Srpaulo } 295214501Srpaulo tls_msg_len = WPA_GET_BE32(*pos); 296214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", 297214501Srpaulo tls_msg_len); 298214501Srpaulo *pos += 4; 299214501Srpaulo *left -= 4; 300252726Srpaulo 301252726Srpaulo if (*left > tls_msg_len) { 302252726Srpaulo wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d " 303252726Srpaulo "bytes) smaller than this fragment (%d " 304252726Srpaulo "bytes)", (int) tls_msg_len, (int) *left); 305252726Srpaulo return -1; 306252726Srpaulo } 307214501Srpaulo } 308214501Srpaulo 309214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x " 310214501Srpaulo "Message Length %u", flags, tls_msg_len); 311214501Srpaulo 312214501Srpaulo if (data->state == WAIT_FRAG_ACK) { 313214501Srpaulo if (*left != 0) { 314214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in " 315214501Srpaulo "WAIT_FRAG_ACK state"); 316214501Srpaulo return -1; 317214501Srpaulo } 318214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged"); 319214501Srpaulo return 1; 320214501Srpaulo } 321214501Srpaulo 322214501Srpaulo if (data->tls_in && 323214501Srpaulo eap_server_tls_process_cont(data, *pos, end - *pos) < 0) 324214501Srpaulo return -1; 325214501Srpaulo 326214501Srpaulo if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) { 327214501Srpaulo if (eap_server_tls_process_fragment(data, flags, tls_msg_len, 328214501Srpaulo *pos, end - *pos) < 0) 329214501Srpaulo return -1; 330214501Srpaulo 331214501Srpaulo data->state = FRAG_ACK; 332214501Srpaulo return 1; 333214501Srpaulo } 334214501Srpaulo 335214501Srpaulo if (data->state == FRAG_ACK) { 336214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: All fragments received"); 337214501Srpaulo data->state = MSG; 338214501Srpaulo } 339214501Srpaulo 340214501Srpaulo if (data->tls_in == NULL) { 341214501Srpaulo /* Wrap unfragmented messages as wpabuf without extra copy */ 342214501Srpaulo wpabuf_set(&data->tmpbuf, *pos, end - *pos); 343214501Srpaulo data->tls_in = &data->tmpbuf; 344214501Srpaulo } 345214501Srpaulo 346214501Srpaulo return 0; 347214501Srpaulo} 348214501Srpaulo 349214501Srpaulo 350214501Srpaulostatic void eap_server_tls_free_in_buf(struct eap_ssl_data *data) 351214501Srpaulo{ 352214501Srpaulo if (data->tls_in != &data->tmpbuf) 353214501Srpaulo wpabuf_free(data->tls_in); 354214501Srpaulo data->tls_in = NULL; 355214501Srpaulo} 356214501Srpaulo 357214501Srpaulo 358214501Srpaulostruct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, 359214501Srpaulo struct eap_ssl_data *data, 360214501Srpaulo const struct wpabuf *plain) 361214501Srpaulo{ 362214501Srpaulo struct wpabuf *buf; 363214501Srpaulo 364214501Srpaulo buf = tls_connection_encrypt(sm->ssl_ctx, data->conn, 365214501Srpaulo plain); 366214501Srpaulo if (buf == NULL) { 367214501Srpaulo wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); 368214501Srpaulo return NULL; 369214501Srpaulo } 370214501Srpaulo 371214501Srpaulo return buf; 372214501Srpaulo} 373214501Srpaulo 374214501Srpaulo 375214501Srpauloint eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, 376214501Srpaulo struct wpabuf *respData, void *priv, int eap_type, 377214501Srpaulo int (*proc_version)(struct eap_sm *sm, void *priv, 378214501Srpaulo int peer_version), 379214501Srpaulo void (*proc_msg)(struct eap_sm *sm, void *priv, 380214501Srpaulo const struct wpabuf *respData)) 381214501Srpaulo{ 382214501Srpaulo const u8 *pos; 383214501Srpaulo u8 flags; 384214501Srpaulo size_t left; 385214501Srpaulo int ret, res = 0; 386214501Srpaulo 387252726Srpaulo if (eap_type == EAP_UNAUTH_TLS_TYPE) 388252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS, 389252726Srpaulo EAP_VENDOR_TYPE_UNAUTH_TLS, respData, 390252726Srpaulo &left); 391252726Srpaulo else 392252726Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, 393252726Srpaulo &left); 394214501Srpaulo if (pos == NULL || left < 1) 395214501Srpaulo return 0; /* Should not happen - frame already validated */ 396214501Srpaulo flags = *pos++; 397214501Srpaulo left--; 398214501Srpaulo wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x", 399214501Srpaulo (unsigned long) wpabuf_len(respData), flags); 400214501Srpaulo 401214501Srpaulo if (proc_version && 402214501Srpaulo proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0) 403214501Srpaulo return -1; 404214501Srpaulo 405214501Srpaulo ret = eap_server_tls_reassemble(data, flags, &pos, &left); 406214501Srpaulo if (ret < 0) { 407214501Srpaulo res = -1; 408214501Srpaulo goto done; 409214501Srpaulo } else if (ret == 1) 410214501Srpaulo return 0; 411214501Srpaulo 412214501Srpaulo if (proc_msg) 413214501Srpaulo proc_msg(sm, priv, respData); 414214501Srpaulo 415214501Srpaulo if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) { 416214501Srpaulo wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in " 417214501Srpaulo "TLS processing"); 418214501Srpaulo res = -1; 419214501Srpaulo } 420214501Srpaulo 421214501Srpaulodone: 422214501Srpaulo eap_server_tls_free_in_buf(data); 423214501Srpaulo 424214501Srpaulo return res; 425214501Srpaulo} 426