1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* |
---|
4 | * EAP peer method: EAP-TLS (RFC 2716) |
---|
5 | * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi> |
---|
6 | * |
---|
7 | * This software may be distributed under the terms of the BSD license. |
---|
8 | * See README for more details. |
---|
9 | */ |
---|
10 | |
---|
11 | #include "includes.h" |
---|
12 | |
---|
13 | #include "common.h" |
---|
14 | #include "crypto/tls.h" |
---|
15 | #include "eap_i.h" |
---|
16 | #include "eap_tls_common.h" |
---|
17 | #include "eap_config.h" |
---|
18 | |
---|
19 | |
---|
20 | static void eap_tls_deinit(struct eap_sm *sm, void *priv); |
---|
21 | |
---|
22 | |
---|
23 | struct eap_tls_data { |
---|
24 | struct eap_ssl_data ssl; |
---|
25 | u8 *key_data; |
---|
26 | u8 *session_id; |
---|
27 | size_t id_len; |
---|
28 | void *ssl_ctx; |
---|
29 | u8 eap_type; |
---|
30 | }; |
---|
31 | |
---|
32 | |
---|
33 | static void * eap_tls_init(struct eap_sm *sm) |
---|
34 | { |
---|
35 | struct eap_tls_data *data; |
---|
36 | struct eap_peer_config *config = eap_get_config(sm); |
---|
37 | if (config == NULL || |
---|
38 | ((sm->init_phase2 ? config->private_key2 : config->private_key) |
---|
39 | == NULL && |
---|
40 | (sm->init_phase2 ? config->engine2 : config->engine) == 0)) { |
---|
41 | wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured"); |
---|
42 | return NULL; |
---|
43 | } |
---|
44 | |
---|
45 | data = os_zalloc(sizeof(*data)); |
---|
46 | if (data == NULL) |
---|
47 | return NULL; |
---|
48 | |
---|
49 | data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : |
---|
50 | sm->ssl_ctx; |
---|
51 | |
---|
52 | if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) { |
---|
53 | wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); |
---|
54 | eap_tls_deinit(sm, data); |
---|
55 | if (config->engine) { |
---|
56 | wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard " |
---|
57 | "PIN"); |
---|
58 | eap_sm_request_pin(sm); |
---|
59 | sm->ignore = TRUE; |
---|
60 | } else if (config->private_key && !config->private_key_passwd) |
---|
61 | { |
---|
62 | wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private " |
---|
63 | "key passphrase"); |
---|
64 | eap_sm_request_passphrase(sm); |
---|
65 | sm->ignore = TRUE; |
---|
66 | } |
---|
67 | return NULL; |
---|
68 | } |
---|
69 | |
---|
70 | data->eap_type = EAP_TYPE_TLS; |
---|
71 | |
---|
72 | return data; |
---|
73 | } |
---|
74 | |
---|
75 | |
---|
76 | #ifdef EAP_UNAUTH_TLS |
---|
77 | static void * eap_unauth_tls_init(struct eap_sm *sm) |
---|
78 | { |
---|
79 | struct eap_tls_data *data; |
---|
80 | struct eap_peer_config *config = eap_get_config(sm); |
---|
81 | |
---|
82 | data = os_zalloc(sizeof(*data)); |
---|
83 | if (data == NULL) |
---|
84 | return NULL; |
---|
85 | |
---|
86 | data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : |
---|
87 | sm->ssl_ctx; |
---|
88 | |
---|
89 | if (eap_peer_tls_ssl_init(sm, &data->ssl, config, |
---|
90 | EAP_UNAUTH_TLS_TYPE)) { |
---|
91 | wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); |
---|
92 | eap_tls_deinit(sm, data); |
---|
93 | return NULL; |
---|
94 | } |
---|
95 | |
---|
96 | data->eap_type = EAP_UNAUTH_TLS_TYPE; |
---|
97 | |
---|
98 | return data; |
---|
99 | } |
---|
100 | #endif /* EAP_UNAUTH_TLS */ |
---|
101 | |
---|
102 | |
---|
103 | #ifdef CONFIG_HS20 |
---|
104 | static void * eap_wfa_unauth_tls_init(struct eap_sm *sm) |
---|
105 | { |
---|
106 | struct eap_tls_data *data; |
---|
107 | struct eap_peer_config *config = eap_get_config(sm); |
---|
108 | |
---|
109 | data = os_zalloc(sizeof(*data)); |
---|
110 | if (data == NULL) |
---|
111 | return NULL; |
---|
112 | |
---|
113 | data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 : |
---|
114 | sm->ssl_ctx; |
---|
115 | |
---|
116 | if (eap_peer_tls_ssl_init(sm, &data->ssl, config, |
---|
117 | EAP_WFA_UNAUTH_TLS_TYPE)) { |
---|
118 | wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); |
---|
119 | eap_tls_deinit(sm, data); |
---|
120 | return NULL; |
---|
121 | } |
---|
122 | |
---|
123 | data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE; |
---|
124 | |
---|
125 | return data; |
---|
126 | } |
---|
127 | #endif /* CONFIG_HS20 */ |
---|
128 | |
---|
129 | |
---|
130 | static void eap_tls_free_key(struct eap_tls_data *data) |
---|
131 | { |
---|
132 | if (data->key_data) { |
---|
133 | bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); |
---|
134 | data->key_data = NULL; |
---|
135 | } |
---|
136 | } |
---|
137 | |
---|
138 | |
---|
139 | static void eap_tls_deinit(struct eap_sm *sm, void *priv) |
---|
140 | { |
---|
141 | struct eap_tls_data *data = priv; |
---|
142 | if (data == NULL) |
---|
143 | return; |
---|
144 | eap_peer_tls_ssl_deinit(sm, &data->ssl); |
---|
145 | eap_tls_free_key(data); |
---|
146 | os_free(data->session_id); |
---|
147 | os_free(data); |
---|
148 | } |
---|
149 | |
---|
150 | |
---|
151 | static struct wpabuf * eap_tls_failure(struct eap_sm *sm, |
---|
152 | struct eap_tls_data *data, |
---|
153 | struct eap_method_ret *ret, int res, |
---|
154 | struct wpabuf *resp, u8 id) |
---|
155 | { |
---|
156 | wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed"); |
---|
157 | |
---|
158 | ret->methodState = METHOD_DONE; |
---|
159 | ret->decision = DECISION_FAIL; |
---|
160 | |
---|
161 | if (resp) { |
---|
162 | /* |
---|
163 | * This is likely an alert message, so send it instead of just |
---|
164 | * ACKing the error. |
---|
165 | */ |
---|
166 | return resp; |
---|
167 | } |
---|
168 | |
---|
169 | return eap_peer_tls_build_ack(id, data->eap_type, 0); |
---|
170 | } |
---|
171 | |
---|
172 | |
---|
173 | static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, |
---|
174 | struct eap_method_ret *ret) |
---|
175 | { |
---|
176 | wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); |
---|
177 | |
---|
178 | ret->methodState = METHOD_DONE; |
---|
179 | ret->decision = DECISION_UNCOND_SUCC; |
---|
180 | |
---|
181 | eap_tls_free_key(data); |
---|
182 | data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, |
---|
183 | "client EAP encryption", |
---|
184 | EAP_TLS_KEY_LEN + |
---|
185 | EAP_EMSK_LEN); |
---|
186 | if (data->key_data) { |
---|
187 | wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key", |
---|
188 | data->key_data, EAP_TLS_KEY_LEN); |
---|
189 | wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK", |
---|
190 | data->key_data + EAP_TLS_KEY_LEN, |
---|
191 | EAP_EMSK_LEN); |
---|
192 | } else { |
---|
193 | wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key"); |
---|
194 | } |
---|
195 | |
---|
196 | os_free(data->session_id); |
---|
197 | data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, |
---|
198 | EAP_TYPE_TLS, |
---|
199 | &data->id_len); |
---|
200 | if (data->session_id) { |
---|
201 | wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id", |
---|
202 | data->session_id, data->id_len); |
---|
203 | } else { |
---|
204 | wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id"); |
---|
205 | } |
---|
206 | } |
---|
207 | |
---|
208 | |
---|
209 | static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, |
---|
210 | struct eap_method_ret *ret, |
---|
211 | const struct wpabuf *reqData) |
---|
212 | { |
---|
213 | size_t left; |
---|
214 | int res; |
---|
215 | struct wpabuf *resp; |
---|
216 | u8 flags, id; |
---|
217 | const u8 *pos; |
---|
218 | struct eap_tls_data *data = priv; |
---|
219 | struct wpabuf msg; |
---|
220 | |
---|
221 | pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret, |
---|
222 | reqData, &left, &flags); |
---|
223 | if (pos == NULL) |
---|
224 | return NULL; |
---|
225 | id = eap_get_id(reqData); |
---|
226 | |
---|
227 | if (flags & EAP_TLS_FLAGS_START) { |
---|
228 | wpa_printf(MSG_DEBUG, "EAP-TLS: Start"); |
---|
229 | left = 0; /* make sure that this frame is empty, even though it |
---|
230 | * should always be, anyway */ |
---|
231 | } |
---|
232 | |
---|
233 | resp = NULL; |
---|
234 | wpabuf_set(&msg, pos, left); |
---|
235 | res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0, |
---|
236 | id, &msg, &resp); |
---|
237 | |
---|
238 | if (res < 0) { |
---|
239 | return eap_tls_failure(sm, data, ret, res, resp, id); |
---|
240 | } |
---|
241 | |
---|
242 | if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) |
---|
243 | eap_tls_success(sm, data, ret); |
---|
244 | |
---|
245 | if (res == 1) { |
---|
246 | wpabuf_free(resp); |
---|
247 | return eap_peer_tls_build_ack(id, data->eap_type, 0); |
---|
248 | } |
---|
249 | |
---|
250 | return resp; |
---|
251 | } |
---|
252 | |
---|
253 | |
---|
254 | static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv) |
---|
255 | { |
---|
256 | struct eap_tls_data *data = priv; |
---|
257 | return tls_connection_established(data->ssl_ctx, data->ssl.conn); |
---|
258 | } |
---|
259 | |
---|
260 | |
---|
261 | static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) |
---|
262 | { |
---|
263 | } |
---|
264 | |
---|
265 | |
---|
266 | static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) |
---|
267 | { |
---|
268 | struct eap_tls_data *data = priv; |
---|
269 | eap_tls_free_key(data); |
---|
270 | os_free(data->session_id); |
---|
271 | data->session_id = NULL; |
---|
272 | if (eap_peer_tls_reauth_init(sm, &data->ssl)) { |
---|
273 | os_free(data); |
---|
274 | return NULL; |
---|
275 | } |
---|
276 | return priv; |
---|
277 | } |
---|
278 | |
---|
279 | |
---|
280 | static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf, |
---|
281 | size_t buflen, int verbose) |
---|
282 | { |
---|
283 | struct eap_tls_data *data = priv; |
---|
284 | return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); |
---|
285 | } |
---|
286 | |
---|
287 | |
---|
288 | static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv) |
---|
289 | { |
---|
290 | struct eap_tls_data *data = priv; |
---|
291 | return data->key_data != NULL; |
---|
292 | } |
---|
293 | |
---|
294 | |
---|
295 | static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) |
---|
296 | { |
---|
297 | struct eap_tls_data *data = priv; |
---|
298 | u8 *key; |
---|
299 | |
---|
300 | if (data->key_data == NULL) |
---|
301 | return NULL; |
---|
302 | |
---|
303 | key = os_malloc(EAP_TLS_KEY_LEN); |
---|
304 | if (key == NULL) |
---|
305 | return NULL; |
---|
306 | |
---|
307 | *len = EAP_TLS_KEY_LEN; |
---|
308 | os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); |
---|
309 | |
---|
310 | return key; |
---|
311 | } |
---|
312 | |
---|
313 | |
---|
314 | static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) |
---|
315 | { |
---|
316 | struct eap_tls_data *data = priv; |
---|
317 | u8 *key; |
---|
318 | |
---|
319 | if (data->key_data == NULL) |
---|
320 | return NULL; |
---|
321 | |
---|
322 | key = os_malloc(EAP_EMSK_LEN); |
---|
323 | if (key == NULL) |
---|
324 | return NULL; |
---|
325 | |
---|
326 | *len = EAP_EMSK_LEN; |
---|
327 | os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); |
---|
328 | |
---|
329 | return key; |
---|
330 | } |
---|
331 | |
---|
332 | |
---|
333 | static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) |
---|
334 | { |
---|
335 | struct eap_tls_data *data = priv; |
---|
336 | u8 *id; |
---|
337 | |
---|
338 | if (data->session_id == NULL) |
---|
339 | return NULL; |
---|
340 | |
---|
341 | id = os_malloc(data->id_len); |
---|
342 | if (id == NULL) |
---|
343 | return NULL; |
---|
344 | |
---|
345 | *len = data->id_len; |
---|
346 | os_memcpy(id, data->session_id, data->id_len); |
---|
347 | |
---|
348 | return id; |
---|
349 | } |
---|
350 | |
---|
351 | |
---|
352 | int eap_peer_tls_register(void) |
---|
353 | { |
---|
354 | struct eap_method *eap; |
---|
355 | int ret; |
---|
356 | |
---|
357 | eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, |
---|
358 | EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); |
---|
359 | if (eap == NULL) |
---|
360 | return -1; |
---|
361 | |
---|
362 | eap->init = eap_tls_init; |
---|
363 | eap->deinit = eap_tls_deinit; |
---|
364 | eap->process = eap_tls_process; |
---|
365 | eap->isKeyAvailable = eap_tls_isKeyAvailable; |
---|
366 | eap->getKey = eap_tls_getKey; |
---|
367 | eap->getSessionId = eap_tls_get_session_id; |
---|
368 | eap->get_status = eap_tls_get_status; |
---|
369 | eap->has_reauth_data = eap_tls_has_reauth_data; |
---|
370 | eap->deinit_for_reauth = eap_tls_deinit_for_reauth; |
---|
371 | eap->init_for_reauth = eap_tls_init_for_reauth; |
---|
372 | eap->get_emsk = eap_tls_get_emsk; |
---|
373 | |
---|
374 | ret = eap_peer_method_register(eap); |
---|
375 | if (ret) |
---|
376 | eap_peer_method_free(eap); |
---|
377 | return ret; |
---|
378 | } |
---|
379 | |
---|
380 | |
---|
381 | #ifdef EAP_UNAUTH_TLS |
---|
382 | int eap_peer_unauth_tls_register(void) |
---|
383 | { |
---|
384 | struct eap_method *eap; |
---|
385 | int ret; |
---|
386 | |
---|
387 | eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, |
---|
388 | EAP_VENDOR_UNAUTH_TLS, |
---|
389 | EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS"); |
---|
390 | if (eap == NULL) |
---|
391 | return -1; |
---|
392 | |
---|
393 | eap->init = eap_unauth_tls_init; |
---|
394 | eap->deinit = eap_tls_deinit; |
---|
395 | eap->process = eap_tls_process; |
---|
396 | eap->isKeyAvailable = eap_tls_isKeyAvailable; |
---|
397 | eap->getKey = eap_tls_getKey; |
---|
398 | eap->get_status = eap_tls_get_status; |
---|
399 | eap->has_reauth_data = eap_tls_has_reauth_data; |
---|
400 | eap->deinit_for_reauth = eap_tls_deinit_for_reauth; |
---|
401 | eap->init_for_reauth = eap_tls_init_for_reauth; |
---|
402 | eap->get_emsk = eap_tls_get_emsk; |
---|
403 | |
---|
404 | ret = eap_peer_method_register(eap); |
---|
405 | if (ret) |
---|
406 | eap_peer_method_free(eap); |
---|
407 | return ret; |
---|
408 | } |
---|
409 | #endif /* EAP_UNAUTH_TLS */ |
---|
410 | |
---|
411 | |
---|
412 | #ifdef CONFIG_HS20 |
---|
413 | int eap_peer_wfa_unauth_tls_register(void) |
---|
414 | { |
---|
415 | struct eap_method *eap; |
---|
416 | int ret; |
---|
417 | |
---|
418 | eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, |
---|
419 | EAP_VENDOR_WFA_NEW, |
---|
420 | EAP_VENDOR_WFA_UNAUTH_TLS, |
---|
421 | "WFA-UNAUTH-TLS"); |
---|
422 | if (eap == NULL) |
---|
423 | return -1; |
---|
424 | |
---|
425 | eap->init = eap_wfa_unauth_tls_init; |
---|
426 | eap->deinit = eap_tls_deinit; |
---|
427 | eap->process = eap_tls_process; |
---|
428 | eap->isKeyAvailable = eap_tls_isKeyAvailable; |
---|
429 | eap->getKey = eap_tls_getKey; |
---|
430 | eap->get_status = eap_tls_get_status; |
---|
431 | eap->has_reauth_data = eap_tls_has_reauth_data; |
---|
432 | eap->deinit_for_reauth = eap_tls_deinit_for_reauth; |
---|
433 | eap->init_for_reauth = eap_tls_init_for_reauth; |
---|
434 | eap->get_emsk = eap_tls_get_emsk; |
---|
435 | |
---|
436 | ret = eap_peer_method_register(eap); |
---|
437 | if (ret) |
---|
438 | eap_peer_method_free(eap); |
---|
439 | return ret; |
---|
440 | } |
---|
441 | #endif /* CONFIG_HS20 */ |
---|