hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / src / eap_server / eap_tls.c
CommitLineData
ebfa2275
SZ
1/*
2 * hostapd / EAP-TLS (RFC 2716)
a875087d 3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
ebfa2275
SZ
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
ebfa2275
SZ
17#include "common.h"
18#include "eap_i.h"
19#include "eap_tls_common.h"
20#include "tls.h"
21
22
23static void eap_tls_reset(struct eap_sm *sm, void *priv);
24
25
26struct eap_tls_data {
27 struct eap_ssl_data ssl;
28 enum { START, CONTINUE, SUCCESS, FAILURE } state;
a875087d 29 int established;
ebfa2275
SZ
30};
31
32
a875087d
JL
33static const char * eap_tls_state_txt(int state)
34{
35 switch (state) {
36 case START:
37 return "START";
38 case CONTINUE:
39 return "CONTINUE";
40 case SUCCESS:
41 return "SUCCESS";
42 case FAILURE:
43 return "FAILURE";
44 default:
45 return "Unknown?!";
46 }
47}
48
49
50static void eap_tls_state(struct eap_tls_data *data, int state)
51{
52 wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
53 eap_tls_state_txt(data->state),
54 eap_tls_state_txt(state));
55 data->state = state;
56}
57
58
ebfa2275
SZ
59static void * eap_tls_init(struct eap_sm *sm)
60{
61 struct eap_tls_data *data;
62
a875087d 63 data = os_zalloc(sizeof(*data));
ebfa2275
SZ
64 if (data == NULL)
65 return NULL;
66 data->state = START;
67
a875087d 68 if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
ebfa2275
SZ
69 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
70 eap_tls_reset(sm, data);
71 return NULL;
72 }
73
74 return data;
75}
76
77
78static void eap_tls_reset(struct eap_sm *sm, void *priv)
79{
80 struct eap_tls_data *data = priv;
81 if (data == NULL)
82 return;
a875087d
JL
83 eap_server_tls_ssl_deinit(sm, &data->ssl);
84 os_free(data);
ebfa2275
SZ
85}
86
87
a875087d
JL
88static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
89 struct eap_tls_data *data, u8 id)
ebfa2275 90{
a875087d 91 struct wpabuf *req;
ebfa2275 92
a875087d
JL
93 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
94 id);
ebfa2275
SZ
95 if (req == NULL) {
96 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
97 "request");
a875087d 98 eap_tls_state(data, FAILURE);
ebfa2275
SZ
99 return NULL;
100 }
101
a875087d 102 wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
ebfa2275 103
a875087d 104 eap_tls_state(data, CONTINUE);
ebfa2275 105
a875087d 106 return req;
ebfa2275
SZ
107}
108
109
a875087d 110static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
ebfa2275 111{
a875087d
JL
112 struct eap_tls_data *data = priv;
113 struct wpabuf *res;
ebfa2275 114
a875087d
JL
115 if (data->ssl.state == FRAG_ACK) {
116 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
ebfa2275
SZ
117 }
118
a875087d
JL
119 if (data->ssl.state == WAIT_FRAG_ACK) {
120 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
121 id);
122 goto check_established;
123 }
ebfa2275
SZ
124
125 switch (data->state) {
126 case START:
a875087d 127 return eap_tls_build_start(sm, data, id);
ebfa2275 128 case CONTINUE:
a875087d
JL
129 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
130 data->established = 1;
131 break;
ebfa2275
SZ
132 default:
133 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
134 __func__, data->state);
135 return NULL;
136 }
a875087d
JL
137
138 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
139
140check_established:
141 if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
142 /* TLS handshake has been completed and there are no more
143 * fragments waiting to be sent out. */
144 wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
145 eap_tls_state(data, SUCCESS);
146 }
147
148 return res;
ebfa2275
SZ
149}
150
151
152static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
a875087d 153 struct wpabuf *respData)
ebfa2275 154{
a875087d
JL
155 const u8 *pos;
156 size_t len;
ebfa2275 157
a875087d
JL
158 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
159 if (pos == NULL || len < 1) {
ebfa2275
SZ
160 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
161 return TRUE;
162 }
163
164 return FALSE;
165}
166
167
a875087d
JL
168static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
169 const struct wpabuf *respData)
ebfa2275
SZ
170{
171 struct eap_tls_data *data = priv;
a875087d
JL
172 if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) {
173 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
174 "handshake message");
ebfa2275
SZ
175 return;
176 }
a875087d
JL
177 if (eap_server_tls_phase1(sm, &data->ssl) < 0)
178 eap_tls_state(data, FAILURE);
179}
ebfa2275 180
a875087d
JL
181
182static void eap_tls_process(struct eap_sm *sm, void *priv,
183 struct wpabuf *respData)
184{
185 struct eap_tls_data *data = priv;
186 if (eap_server_tls_process(sm, &data->ssl, respData, data,
187 EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
188 0)
189 eap_tls_state(data, FAILURE);
ebfa2275
SZ
190}
191
192
193static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
194{
195 struct eap_tls_data *data = priv;
196 return data->state == SUCCESS || data->state == FAILURE;
197}
198
199
200static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
201{
202 struct eap_tls_data *data = priv;
203 u8 *eapKeyData;
204
205 if (data->state != SUCCESS)
206 return NULL;
207
a875087d
JL
208 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
209 "client EAP encryption",
210 EAP_TLS_KEY_LEN);
ebfa2275
SZ
211 if (eapKeyData) {
212 *len = EAP_TLS_KEY_LEN;
213 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
214 eapKeyData, EAP_TLS_KEY_LEN);
215 } else {
216 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
217 }
218
219 return eapKeyData;
220}
221
222
223static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
224{
225 struct eap_tls_data *data = priv;
226 u8 *eapKeyData, *emsk;
227
228 if (data->state != SUCCESS)
229 return NULL;
230
a875087d
JL
231 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
232 "client EAP encryption",
233 EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
ebfa2275 234 if (eapKeyData) {
a875087d 235 emsk = os_malloc(EAP_EMSK_LEN);
ebfa2275 236 if (emsk)
a875087d
JL
237 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
238 EAP_EMSK_LEN);
239 os_free(eapKeyData);
ebfa2275
SZ
240 } else
241 emsk = NULL;
242
243 if (emsk) {
244 *len = EAP_EMSK_LEN;
245 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
246 emsk, EAP_EMSK_LEN);
247 } else {
248 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
249 }
250
251 return emsk;
252}
253
254
255static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
256{
257 struct eap_tls_data *data = priv;
258 return data->state == SUCCESS;
259}
260
261
262int eap_server_tls_register(void)
263{
264 struct eap_method *eap;
265 int ret;
266
267 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
268 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
269 if (eap == NULL)
270 return -1;
271
272 eap->init = eap_tls_init;
273 eap->reset = eap_tls_reset;
274 eap->buildReq = eap_tls_buildReq;
275 eap->check = eap_tls_check;
276 eap->process = eap_tls_process;
277 eap->isDone = eap_tls_isDone;
278 eap->getKey = eap_tls_getKey;
279 eap->isSuccess = eap_tls_isSuccess;
280 eap->get_emsk = eap_tls_get_emsk;
281
282 ret = eap_server_method_register(eap);
283 if (ret)
284 eap_server_method_free(eap);
285 return ret;
286}