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