Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / eap_server / eap_server_tls_common.c
index e149ee3..05677b7 100644 (file)
@@ -2,14 +2,8 @@
  * 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;
 
@@ -37,7 +64,20 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
                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);
@@ -69,43 +109,60 @@ void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 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_prf(sm->ssl_ctx, data->conn, label, 0, 0,
+                              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;
 }
 
 
@@ -137,8 +194,7 @@ struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
        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;
 
@@ -174,8 +230,7 @@ struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
 {
        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");
@@ -224,6 +279,14 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
                        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");
@@ -285,6 +348,13 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
                           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 "
@@ -365,7 +435,17 @@ int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
        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++;