1 /*
2 * hostapd / EAP-TLS (RFC 2716)
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
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
17 #include "common.h"
18 #include "eap_i.h"
19 #include "eap_tls_common.h"
20 #include "tls.h"
21
22
23 static void eap_tls_reset(struct eap_sm *sm, void *priv);
24
25
26 struct eap_tls_data {
27 struct eap_ssl_data ssl;
28 enum { START, CONTINUE, SUCCESS, FAILURE } state;
29 int established;
30 };
31
32
eap_tls_state_txt(int state)33 static 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
eap_tls_state(struct eap_tls_data * data,int state)50 static 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
eap_tls_init(struct eap_sm * sm)59 static void * eap_tls_init(struct eap_sm *sm)
60 {
61 struct eap_tls_data *data;
62
63 data = os_zalloc(sizeof(*data));
64 if (data == NULL)
65 return NULL;
66 data->state = START;
67
68 if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
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
eap_tls_reset(struct eap_sm * sm,void * priv)78 static void eap_tls_reset(struct eap_sm *sm, void *priv)
79 {
80 struct eap_tls_data *data = priv;
81 if (data == NULL)
82 return;
83 eap_server_tls_ssl_deinit(sm, &data->ssl);
84 os_free(data);
85 }
86
87
eap_tls_build_start(struct eap_sm * sm,struct eap_tls_data * data,u8 id)88 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
89 struct eap_tls_data *data, u8 id)
90 {
91 struct wpabuf *req;
92
93 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
94 id);
95 if (req == NULL) {
96 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
97 "request");
98 eap_tls_state(data, FAILURE);
99 return NULL;
100 }
101
102 wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
103
104 eap_tls_state(data, CONTINUE);
105
106 return req;
107 }
108
109
eap_tls_buildReq(struct eap_sm * sm,void * priv,u8 id)110 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
111 {
112 struct eap_tls_data *data = priv;
113 struct wpabuf *res;
114
115 if (data->ssl.state == FRAG_ACK) {
116 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
117 }
118
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 }
124
125 switch (data->state) {
126 case START:
127 return eap_tls_build_start(sm, data, id);
128 case CONTINUE:
129 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
130 data->established = 1;
131 break;
132 default:
133 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
134 __func__, data->state);
135 return NULL;
136 }
137
138 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
139
140 check_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;
149 }
150
151
eap_tls_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)152 static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
153 struct wpabuf *respData)
154 {
155 const u8 *pos;
156 size_t len;
157
158 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
159 if (pos == NULL || len < 1) {
160 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
161 return TRUE;
162 }
163
164 return FALSE;
165 }
166
167
eap_tls_process_msg(struct eap_sm * sm,void * priv,const struct wpabuf * respData)168 static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
169 const struct wpabuf *respData)
170 {
171 struct eap_tls_data *data = priv;
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");
175 return;
176 }
177 if (eap_server_tls_phase1(sm, &data->ssl) < 0)
178 eap_tls_state(data, FAILURE);
179 }
180
181
eap_tls_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)182 static 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);
190 }
191
192
eap_tls_isDone(struct eap_sm * sm,void * priv)193 static 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
eap_tls_getKey(struct eap_sm * sm,void * priv,size_t * len)200 static 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
208 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
209 "client EAP encryption",
210 EAP_TLS_KEY_LEN);
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
eap_tls_get_emsk(struct eap_sm * sm,void * priv,size_t * len)223 static 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
231 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
232 "client EAP encryption",
233 EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
234 if (eapKeyData) {
235 emsk = os_malloc(EAP_EMSK_LEN);
236 if (emsk)
237 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
238 EAP_EMSK_LEN);
239 os_free(eapKeyData);
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
eap_tls_isSuccess(struct eap_sm * sm,void * priv)255 static 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
eap_server_tls_register(void)262 int 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 }
287