* EAP-TLS/PEAP/TTLS/FAST server common functions
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
+struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+ u8 code, u8 identifier)
+{
+ if (type == EAP_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
+ code, identifier);
+ else if (type == EAP_WFA_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
+ EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
+ code, identifier);
+ return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
+ identifier);
+}
+
+
+#ifdef CONFIG_TLS_INTERNAL
+static void eap_server_tls_log_cb(void *ctx, const char *msg)
+{
+ struct eap_sm *sm = ctx;
+ eap_log_msg(sm, "TLS: %s", msg);
+}
+#endif /* CONFIG_TLS_INTERNAL */
+
+
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- int verify_peer)
+ int verify_peer, int eap_type)
{
+ u8 session_ctx[8];
+ unsigned int flags = 0;
+
+ if (sm->ssl_ctx == NULL) {
+ wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
+ return -1;
+ }
+
data->eap = sm;
data->phase2 = sm->init_phase2;
return -1;
}
- if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
+#ifdef CONFIG_TLS_INTERNAL
+ tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm);
+#ifdef CONFIG_TESTING_OPTIONS
+ tls_connection_set_test_flags(data->conn, sm->tls_test_flags);
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_TLS_INTERNAL */
+
+ if (eap_type != EAP_TYPE_FAST)
+ flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+ os_memcpy(session_ctx, "hostapd", 7);
+ session_ctx[7] = (u8) eap_type;
+ if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
+ flags, session_ctx,
+ sizeof(session_ctx))) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
tls_connection_deinit(sm->ssl_ctx, data->conn);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
- struct tls_keys keys;
- u8 *rnd = NULL, *out;
+ u8 *out;
out = os_malloc(len);
if (out == NULL)
return NULL;
- if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
- 0)
- return out;
+ if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, out,
+ len)) {
+ os_free(out);
+ return NULL;
+ }
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
- goto fail;
+ return out;
+}
- if (keys.client_random == NULL || keys.server_random == NULL ||
- keys.master_key == NULL)
- goto fail;
- rnd = os_malloc(keys.client_random_len + keys.server_random_len);
- if (rnd == NULL)
- goto fail;
- os_memcpy(rnd, keys.client_random, keys.client_random_len);
- os_memcpy(rnd + keys.client_random_len, keys.server_random,
- keys.server_random_len);
+/**
+ * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len)
+{
+ struct tls_random keys;
+ u8 *out;
+
+ if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
- if (tls_prf(keys.master_key, keys.master_key_len,
- label, rnd, keys.client_random_len +
- keys.server_random_len, out, len))
- goto fail;
+ if (keys.client_random == NULL || keys.server_random == NULL)
+ return NULL;
- os_free(rnd);
- return out;
+ *len = 1 + keys.client_random_len + keys.server_random_len;
+ out = os_malloc(*len);
+ if (out == NULL)
+ return NULL;
-fail:
- os_free(out);
- os_free(rnd);
- return NULL;
+ /* Session-Id = EAP type || client.random || server.random */
+ out[0] = eap_type;
+ os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+ os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ return out;
}
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
plen += 4;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
- EAP_CODE_REQUEST, id);
+ req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
if (req == NULL)
return NULL;
{
struct wpabuf *req;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
- id);
+ req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
if (req == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "SSL: Building ACK");
return -1;
}
+ if (len > message_length) {
+ wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in "
+ "first fragment of frame (TLS Message "
+ "Length %d bytes)",
+ (int) len, (int) message_length);
+ return -1;
+ }
+
data->tls_in = wpabuf_alloc(message_length);
if (data->tls_in == NULL) {
wpa_printf(MSG_DEBUG, "SSL: No memory for message");
tls_msg_len);
*pos += 4;
*left -= 4;
+
+ if (*left > tls_msg_len) {
+ wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
+ "bytes) smaller than this fragment (%d "
+ "bytes)", (int) tls_msg_len, (int) *left);
+ return -1;
+ }
}
wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
size_t left;
int ret, res = 0;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
+ if (eap_type == EAP_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
+ &left);
+ else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
+ EAP_VENDOR_WFA_UNAUTH_TLS, respData,
+ &left);
+ else
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
+ &left);
if (pos == NULL || left < 1)
return 0; /* Should not happen - frame already validated */
flags = *pos++;