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