1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * hostapd / EAP-TLS (RFC 2716)
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_i.h"
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eap_tls_common.h"
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "tls.h"
21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_tls_reset(struct eap_sm *sm, void *priv);
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct eap_tls_data {
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_ssl_data ssl;
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	enum { START, CONTINUE, SUCCESS, FAILURE } state;
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int established;
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic const char * eap_tls_state_txt(int state)
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (state) {
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case START:
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "START";
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case CONTINUE:
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "CONTINUE";
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case SUCCESS:
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "SUCCESS";
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case FAILURE:
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "FAILURE";
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return "Unknown?!";
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_tls_state(struct eap_tls_data *data, int state)
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   eap_tls_state_txt(data->state),
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   eap_tls_state_txt(state));
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = state;
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void * eap_tls_init(struct eap_sm *sm)
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data;
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data = os_zalloc(sizeof(*data));
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = START;
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_tls_reset(sm, data);
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data;
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_tls_reset(struct eap_sm *sm, void *priv)
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data == NULL)
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_server_tls_ssl_deinit(sm, &data->ssl);
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data);
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   struct eap_tls_data *data, u8 id)
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *req;
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    id);
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (req == NULL) {
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "request");
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_tls_state(data, FAILURE);
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap_tls_state(data, CONTINUE);
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return req;
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *res;
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->ssl.state == FRAG_ACK) {
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->ssl.state == WAIT_FRAG_ACK) {
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       id);
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		goto check_established;
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (data->state) {
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case START:
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return eap_tls_build_start(sm, data, id);
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case CONTINUE:
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->established = 1;
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   __func__, data->state);
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtcheck_established:
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* TLS handshake has been completed and there are no more
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * fragments waiting to be sent out. */
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_tls_state(data, SUCCESS);
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return res;
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic Boolean eap_tls_check(struct eap_sm *sm, void *priv,
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     struct wpabuf *respData)
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos;
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len;
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos == NULL || len < 1) {
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return TRUE;
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return FALSE;
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_tls_process_msg(struct eap_sm *sm, void *priv,
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				const struct wpabuf *respData)
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) {
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "handshake message");
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_server_tls_phase1(sm, &data->ssl) < 0)
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_tls_state(data, FAILURE);
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void eap_tls_process(struct eap_sm *sm, void *priv,
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    struct wpabuf *respData)
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap_server_tls_process(sm, &data->ssl, respData, data,
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    0)
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_tls_state(data, FAILURE);
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->state == SUCCESS || data->state == FAILURE;
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *eapKeyData;
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != SUCCESS)
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       "client EAP encryption",
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       EAP_TLS_KEY_LEN);
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eapKeyData) {
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		*len = EAP_TLS_KEY_LEN;
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    eapKeyData, EAP_TLS_KEY_LEN);
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return eapKeyData;
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *eapKeyData, *emsk;
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != SUCCESS)
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       "client EAP encryption",
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eapKeyData) {
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		emsk = os_malloc(EAP_EMSK_LEN);
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (emsk)
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  EAP_EMSK_LEN);
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(eapKeyData);
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		emsk = NULL;
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (emsk) {
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		*len = EAP_EMSK_LEN;
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    emsk, EAP_EMSK_LEN);
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return emsk;
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_tls_data *data = priv;
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return data->state == SUCCESS;
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint eap_server_tls_register(void)
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct eap_method *eap;
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret;
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				      EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (eap == NULL)
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->init = eap_tls_init;
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->reset = eap_tls_reset;
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->buildReq = eap_tls_buildReq;
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->check = eap_tls_check;
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->process = eap_tls_process;
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->isDone = eap_tls_isDone;
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->getKey = eap_tls_getKey;
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->isSuccess = eap_tls_isSuccess;
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	eap->get_emsk = eap_tls_get_emsk;
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = eap_server_method_register(eap);
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ret)
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		eap_server_method_free(eap);
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
287