Branch data Line data Source code
1 : : /*
2 : : * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
3 : : * Copyright (c) 2004-2013, 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 "crypto/sha1.h"
13 : : #include "crypto/tls.h"
14 : : #include "eap_i.h"
15 : : #include "eap_tls_common.h"
16 : : #include "eap_config.h"
17 : :
18 : :
19 : 706 : static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
20 : : u8 code, u8 identifier)
21 : : {
22 [ - + ]: 706 : if (type == EAP_UNAUTH_TLS_TYPE)
23 : 0 : return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
24 : : EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
25 : : code, identifier);
26 [ + + ]: 706 : if (type == EAP_WFA_UNAUTH_TLS_TYPE)
27 : 4 : return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
28 : : EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
29 : : code, identifier);
30 : 706 : return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
31 : : identifier);
32 : : }
33 : :
34 : :
35 : 464 : static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
36 : : const u8 **data, size_t *data_len)
37 : : {
38 : : const struct wpa_config_blob *blob;
39 : :
40 [ + + ][ + - ]: 464 : if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
41 : 464 : return 0;
42 : :
43 : 0 : blob = eap_get_config_blob(sm, *name + 7);
44 [ # # ]: 0 : if (blob == NULL) {
45 : 0 : wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
46 : 0 : "found", __func__, *name + 7);
47 : 0 : return -1;
48 : : }
49 : :
50 : 0 : *name = NULL;
51 : 0 : *data = blob->data;
52 : 0 : *data_len = blob->len;
53 : :
54 : 464 : return 0;
55 : : }
56 : :
57 : :
58 : 116 : static void eap_tls_params_flags(struct tls_connection_params *params,
59 : : const char *txt)
60 : : {
61 [ + + ]: 116 : if (txt == NULL)
62 : 116 : return;
63 [ - + ]: 13 : if (os_strstr(txt, "tls_allow_md5=1"))
64 : 0 : params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
65 [ + + ]: 13 : if (os_strstr(txt, "tls_disable_time_checks=1"))
66 : 1 : params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
67 [ - + ]: 13 : if (os_strstr(txt, "tls_disable_session_ticket=1"))
68 : 0 : params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
69 [ - + ]: 13 : if (os_strstr(txt, "tls_disable_session_ticket=0"))
70 : 0 : params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
71 [ - + ]: 13 : if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
72 : 0 : params->flags |= TLS_CONN_DISABLE_TLSv1_1;
73 [ - + ]: 13 : if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
74 : 0 : params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
75 [ - + ]: 13 : if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
76 : 0 : params->flags |= TLS_CONN_DISABLE_TLSv1_2;
77 [ - + ]: 13 : if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
78 : 0 : params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
79 : : }
80 : :
81 : :
82 : 115 : static void eap_tls_params_from_conf1(struct tls_connection_params *params,
83 : : struct eap_peer_config *config)
84 : : {
85 : 115 : params->ca_cert = (char *) config->ca_cert;
86 : 115 : params->ca_path = (char *) config->ca_path;
87 : 115 : params->client_cert = (char *) config->client_cert;
88 : 115 : params->private_key = (char *) config->private_key;
89 : 115 : params->private_key_passwd = (char *) config->private_key_passwd;
90 : 115 : params->dh_file = (char *) config->dh_file;
91 : 115 : params->subject_match = (char *) config->subject_match;
92 : 115 : params->altsubject_match = (char *) config->altsubject_match;
93 : 115 : params->suffix_match = config->domain_suffix_match;
94 : 115 : params->engine = config->engine;
95 : 115 : params->engine_id = config->engine_id;
96 : 115 : params->pin = config->pin;
97 : 115 : params->key_id = config->key_id;
98 : 115 : params->cert_id = config->cert_id;
99 : 115 : params->ca_cert_id = config->ca_cert_id;
100 : 115 : eap_tls_params_flags(params, config->phase1);
101 : 115 : }
102 : :
103 : :
104 : 1 : static void eap_tls_params_from_conf2(struct tls_connection_params *params,
105 : : struct eap_peer_config *config)
106 : : {
107 : 1 : params->ca_cert = (char *) config->ca_cert2;
108 : 1 : params->ca_path = (char *) config->ca_path2;
109 : 1 : params->client_cert = (char *) config->client_cert2;
110 : 1 : params->private_key = (char *) config->private_key2;
111 : 1 : params->private_key_passwd = (char *) config->private_key2_passwd;
112 : 1 : params->dh_file = (char *) config->dh_file2;
113 : 1 : params->subject_match = (char *) config->subject_match2;
114 : 1 : params->altsubject_match = (char *) config->altsubject_match2;
115 : 1 : params->suffix_match = config->domain_suffix_match2;
116 : 1 : params->engine = config->engine2;
117 : 1 : params->engine_id = config->engine2_id;
118 : 1 : params->pin = config->pin2;
119 : 1 : params->key_id = config->key2_id;
120 : 1 : params->cert_id = config->cert2_id;
121 : 1 : params->ca_cert_id = config->ca_cert2_id;
122 : 1 : eap_tls_params_flags(params, config->phase2);
123 : 1 : }
124 : :
125 : :
126 : 116 : static int eap_tls_params_from_conf(struct eap_sm *sm,
127 : : struct eap_ssl_data *data,
128 : : struct tls_connection_params *params,
129 : : struct eap_peer_config *config, int phase2)
130 : : {
131 : 116 : os_memset(params, 0, sizeof(*params));
132 [ + - ][ + + ]: 116 : if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
133 : : /*
134 : : * Some deployed authentication servers seem to be unable to
135 : : * handle the TLS Session Ticket extension (they are supposed
136 : : * to ignore unrecognized TLS extensions, but end up rejecting
137 : : * the ClientHello instead). As a workaround, disable use of
138 : : * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
139 : : * EAP-TTLS (EAP-FAST uses session ticket, so any server that
140 : : * supports EAP-FAST does not need this workaround).
141 : : */
142 : 109 : params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
143 : : }
144 [ + + ]: 116 : if (phase2) {
145 : 1 : wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
146 : 1 : eap_tls_params_from_conf2(params, config);
147 : : } else {
148 : 115 : wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
149 : 115 : eap_tls_params_from_conf1(params, config);
150 : : }
151 : :
152 : : /*
153 : : * Use blob data, if available. Otherwise, leave reference to external
154 : : * file as-is.
155 : : */
156 [ + - ]: 116 : if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob,
157 [ + - ]: 116 : ¶ms->ca_cert_blob_len) ||
158 : 116 : eap_tls_check_blob(sm, ¶ms->client_cert,
159 : : ¶ms->client_cert_blob,
160 [ + - ]: 116 : ¶ms->client_cert_blob_len) ||
161 : 116 : eap_tls_check_blob(sm, ¶ms->private_key,
162 : : ¶ms->private_key_blob,
163 [ - + ]: 116 : ¶ms->private_key_blob_len) ||
164 : 116 : eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob,
165 : : ¶ms->dh_blob_len)) {
166 : 0 : wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
167 : 0 : return -1;
168 : : }
169 : :
170 : 116 : return 0;
171 : : }
172 : :
173 : :
174 : 116 : static int eap_tls_init_connection(struct eap_sm *sm,
175 : : struct eap_ssl_data *data,
176 : : struct eap_peer_config *config,
177 : : struct tls_connection_params *params)
178 : : {
179 : : int res;
180 : :
181 [ + + ]: 116 : if (config->ocsp)
182 : 2 : params->flags |= TLS_CONN_REQUEST_OCSP;
183 [ + + ]: 116 : if (config->ocsp == 2)
184 : 2 : params->flags |= TLS_CONN_REQUIRE_OCSP;
185 : 116 : data->conn = tls_connection_init(data->ssl_ctx);
186 [ - + ]: 116 : if (data->conn == NULL) {
187 : 0 : wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
188 : : "connection");
189 : 0 : return -1;
190 : : }
191 : :
192 : 116 : res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
193 [ - + ]: 116 : if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
194 : : /*
195 : : * At this point with the pkcs11 engine the PIN might be wrong.
196 : : * We reset the PIN in the configuration to be sure to not use
197 : : * it again and the calling function must request a new one.
198 : : */
199 : 0 : os_free(config->pin);
200 : 0 : config->pin = NULL;
201 [ - + ]: 116 : } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
202 : 0 : wpa_printf(MSG_INFO, "TLS: Failed to load private key");
203 : : /*
204 : : * We do not know exactly but maybe the PIN was wrong,
205 : : * so ask for a new one.
206 : : */
207 : 0 : os_free(config->pin);
208 : 0 : config->pin = NULL;
209 : 0 : eap_sm_request_pin(sm);
210 : 0 : sm->ignore = TRUE;
211 : 0 : tls_connection_deinit(data->ssl_ctx, data->conn);
212 : 0 : data->conn = NULL;
213 : 0 : return -1;
214 [ + + ]: 116 : } else if (res) {
215 : 1 : wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
216 : : "parameters");
217 : 1 : tls_connection_deinit(data->ssl_ctx, data->conn);
218 : 1 : data->conn = NULL;
219 : 1 : return -1;
220 : : }
221 : :
222 : 116 : return 0;
223 : : }
224 : :
225 : :
226 : : /**
227 : : * eap_peer_tls_ssl_init - Initialize shared TLS functionality
228 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
229 : : * @data: Data for TLS processing
230 : : * @config: Pointer to the network configuration
231 : : * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
232 : : * Returns: 0 on success, -1 on failure
233 : : *
234 : : * This function is used to initialize shared TLS functionality for EAP-TLS,
235 : : * EAP-PEAP, EAP-TTLS, and EAP-FAST.
236 : : */
237 : 116 : int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
238 : : struct eap_peer_config *config, u8 eap_type)
239 : : {
240 : : struct tls_connection_params params;
241 : :
242 [ - + ]: 116 : if (config == NULL)
243 : 0 : return -1;
244 : :
245 : 116 : data->eap = sm;
246 : 116 : data->eap_type = eap_type;
247 : 116 : data->phase2 = sm->init_phase2;
248 [ + + ][ + - ]: 116 : data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
249 : : sm->ssl_ctx;
250 [ - + ]: 116 : if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) <
251 : : 0)
252 : 0 : return -1;
253 : :
254 [ + + ]: 116 : if (eap_tls_init_connection(sm, data, config, ¶ms) < 0)
255 : 1 : return -1;
256 : :
257 : 115 : data->tls_out_limit = config->fragment_size;
258 [ + + ]: 115 : if (data->phase2) {
259 : : /* Limit the fragment size in the inner TLS authentication
260 : : * since the outer authentication with EAP-PEAP does not yet
261 : : * support fragmentation */
262 [ + - ]: 1 : if (data->tls_out_limit > 100)
263 : 1 : data->tls_out_limit -= 100;
264 : : }
265 : :
266 [ + + ][ - + ]: 115 : if (config->phase1 &&
267 : 12 : os_strstr(config->phase1, "include_tls_length=1")) {
268 : 0 : wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
269 : : "unfragmented packets");
270 : 0 : data->include_tls_length = 1;
271 : : }
272 : :
273 : 116 : return 0;
274 : : }
275 : :
276 : :
277 : : /**
278 : : * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality
279 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
280 : : * @data: Data for TLS processing
281 : : *
282 : : * This function deinitializes shared TLS functionality that was initialized
283 : : * with eap_peer_tls_ssl_init().
284 : : */
285 : 116 : void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
286 : : {
287 : 116 : tls_connection_deinit(data->ssl_ctx, data->conn);
288 : 116 : eap_peer_tls_reset_input(data);
289 : 116 : eap_peer_tls_reset_output(data);
290 : 116 : }
291 : :
292 : :
293 : : /**
294 : : * eap_peer_tls_derive_key - Derive a key based on TLS session data
295 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
296 : : * @data: Data for TLS processing
297 : : * @label: Label string for deriving the keys, e.g., "client EAP encryption"
298 : : * @len: Length of the key material to generate (usually 64 for MSK)
299 : : * Returns: Pointer to allocated key on success or %NULL on failure
300 : : *
301 : : * This function uses TLS-PRF to generate pseudo-random data based on the TLS
302 : : * session data (client/server random and master key). Each key type may use a
303 : : * different label to bind the key usage into the generated material.
304 : : *
305 : : * The caller is responsible for freeing the returned buffer.
306 : : */
307 : 179 : u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
308 : : const char *label, size_t len)
309 : : {
310 : : #ifndef CONFIG_FIPS
311 : : struct tls_keys keys;
312 : : #endif /* CONFIG_FIPS */
313 : 179 : u8 *rnd = NULL, *out;
314 : :
315 : 179 : out = os_malloc(len);
316 [ - + ]: 179 : if (out == NULL)
317 : 0 : return NULL;
318 : :
319 : : /* First, try to use TLS library function for PRF, if available. */
320 [ + - ]: 179 : if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
321 : : == 0)
322 : 179 : return out;
323 : :
324 : : #ifndef CONFIG_FIPS
325 : : /*
326 : : * TLS library did not support key generation, so get the needed TLS
327 : : * session parameters and use an internal implementation of TLS PRF to
328 : : * derive the key.
329 : : */
330 [ # # ]: 0 : if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
331 : 0 : goto fail;
332 : :
333 [ # # ][ # # ]: 0 : if (keys.client_random == NULL || keys.server_random == NULL ||
[ # # ]
334 : 0 : keys.master_key == NULL)
335 : : goto fail;
336 : :
337 : 0 : rnd = os_malloc(keys.client_random_len + keys.server_random_len);
338 [ # # ]: 0 : if (rnd == NULL)
339 : 0 : goto fail;
340 : 0 : os_memcpy(rnd, keys.client_random, keys.client_random_len);
341 : 0 : os_memcpy(rnd + keys.client_random_len, keys.server_random,
342 : : keys.server_random_len);
343 : :
344 [ # # ]: 0 : if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
345 : 0 : label, rnd, keys.client_random_len +
346 : 0 : keys.server_random_len, out, len))
347 : 0 : goto fail;
348 : :
349 : 0 : os_free(rnd);
350 : 0 : return out;
351 : :
352 : : fail:
353 : : #endif /* CONFIG_FIPS */
354 : 0 : os_free(out);
355 : 0 : os_free(rnd);
356 : 179 : return NULL;
357 : : }
358 : :
359 : :
360 : : /**
361 : : * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
362 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
363 : : * @data: Data for TLS processing
364 : : * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
365 : : * @len: Pointer to length of the session ID generated
366 : : * Returns: Pointer to allocated Session-Id on success or %NULL on failure
367 : : *
368 : : * This function derive the Session-Id based on the TLS session data
369 : : * (client/server random and method type).
370 : : *
371 : : * The caller is responsible for freeing the returned buffer.
372 : : */
373 : 119 : u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
374 : : struct eap_ssl_data *data, u8 eap_type,
375 : : size_t *len)
376 : : {
377 : : struct tls_keys keys;
378 : : u8 *out;
379 : :
380 : : /*
381 : : * TLS library did not support session ID generation,
382 : : * so get the needed TLS session parameters
383 : : */
384 [ - + ]: 119 : if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
385 : 0 : return NULL;
386 : :
387 [ + - ][ + - ]: 119 : if (keys.client_random == NULL || keys.server_random == NULL ||
[ - + ]
388 : 119 : keys.master_key == NULL)
389 : 0 : return NULL;
390 : :
391 : 119 : *len = 1 + keys.client_random_len + keys.server_random_len;
392 : 119 : out = os_malloc(*len);
393 [ - + ]: 119 : if (out == NULL)
394 : 0 : return NULL;
395 : :
396 : : /* Session-Id = EAP type || client.random || server.random */
397 : 119 : out[0] = eap_type;
398 : 119 : os_memcpy(out + 1, keys.client_random, keys.client_random_len);
399 : 119 : os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
400 : : keys.server_random_len);
401 : :
402 : 119 : return out;
403 : : }
404 : :
405 : :
406 : : /**
407 : : * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
408 : : * @data: Data for TLS processing
409 : : * @in_data: Next incoming TLS segment
410 : : * Returns: 0 on success, 1 if more data is needed for the full message, or
411 : : * -1 on error
412 : : */
413 : 240 : static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
414 : : const struct wpabuf *in_data)
415 : : {
416 : : size_t tls_in_len, in_len;
417 : :
418 [ + + ]: 240 : tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0;
419 [ + - ]: 240 : in_len = in_data ? wpabuf_len(in_data) : 0;
420 : :
421 [ - + ]: 240 : if (tls_in_len + in_len == 0) {
422 : : /* No message data received?! */
423 : 0 : wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "
424 : : "tls_in_left=%lu tls_in_len=%lu in_len=%lu",
425 : : (unsigned long) data->tls_in_left,
426 : : (unsigned long) tls_in_len,
427 : : (unsigned long) in_len);
428 : 0 : eap_peer_tls_reset_input(data);
429 : 0 : return -1;
430 : : }
431 : :
432 [ - + ]: 240 : if (tls_in_len + in_len > 65536) {
433 : : /*
434 : : * Limit length to avoid rogue servers from causing large
435 : : * memory allocations.
436 : : */
437 : 0 : wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "
438 : : "64 kB)");
439 : 0 : eap_peer_tls_reset_input(data);
440 : 0 : return -1;
441 : : }
442 : :
443 [ - + ]: 240 : if (in_len > data->tls_in_left) {
444 : : /* Sender is doing something odd - reject message */
445 : 0 : wpa_printf(MSG_INFO, "SSL: more data than TLS message length "
446 : : "indicated");
447 : 0 : eap_peer_tls_reset_input(data);
448 : 0 : return -1;
449 : : }
450 : :
451 [ - + ]: 240 : if (wpabuf_resize(&data->tls_in, in_len) < 0) {
452 : 0 : wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "
453 : : "data");
454 : 0 : eap_peer_tls_reset_input(data);
455 : 0 : return -1;
456 : : }
457 [ + - ]: 240 : if (in_data)
458 : 240 : wpabuf_put_buf(data->tls_in, in_data);
459 : 240 : data->tls_in_left -= in_len;
460 : :
461 [ + + ]: 240 : if (data->tls_in_left > 0) {
462 : 120 : wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
463 : : "data", (unsigned long) data->tls_in_left);
464 : 120 : return 1;
465 : : }
466 : :
467 : 240 : return 0;
468 : : }
469 : :
470 : :
471 : : /**
472 : : * eap_peer_tls_data_reassemble - Reassemble TLS data
473 : : * @data: Data for TLS processing
474 : : * @in_data: Next incoming TLS segment
475 : : * @need_more_input: Variable for returning whether more input data is needed
476 : : * to reassemble this TLS packet
477 : : * Returns: Pointer to output data, %NULL on error or when more data is needed
478 : : * for the full message (in which case, *need_more_input is also set to 1).
479 : : *
480 : : * This function reassembles TLS fragments. Caller must not free the returned
481 : : * data buffer since an internal pointer to it is maintained.
482 : : */
483 : 694 : static const struct wpabuf * eap_peer_tls_data_reassemble(
484 : : struct eap_ssl_data *data, const struct wpabuf *in_data,
485 : : int *need_more_input)
486 : : {
487 : 694 : *need_more_input = 0;
488 : :
489 [ + + ][ + + ]: 814 : if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) {
490 : : /* Message has fragments */
491 : 240 : int res = eap_peer_tls_reassemble_fragment(data, in_data);
492 [ + + ]: 240 : if (res) {
493 [ + - ]: 120 : if (res == 1)
494 : 120 : *need_more_input = 1;
495 : 120 : return NULL;
496 : : }
497 : :
498 : : /* Message is now fully reassembled. */
499 : : } else {
500 : : /* No fragments in this message, so just make a copy of it. */
501 : 454 : data->tls_in_left = 0;
502 : 454 : data->tls_in = wpabuf_dup(in_data);
503 [ - + ]: 454 : if (data->tls_in == NULL)
504 : 0 : return NULL;
505 : : }
506 : :
507 : 694 : return data->tls_in;
508 : : }
509 : :
510 : :
511 : : /**
512 : : * eap_tls_process_input - Process incoming TLS message
513 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
514 : : * @data: Data for TLS processing
515 : : * @in_data: Message received from the server
516 : : * @in_len: Length of in_data
517 : : * @out_data: Buffer for returning a pointer to application data (if available)
518 : : * Returns: 0 on success, 1 if more input data is needed, 2 if application data
519 : : * is available, -1 on failure
520 : : */
521 : 499 : static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
522 : : const u8 *in_data, size_t in_len,
523 : : struct wpabuf **out_data)
524 : : {
525 : : const struct wpabuf *msg;
526 : : int need_more_input;
527 : : struct wpabuf *appl_data;
528 : : struct wpabuf buf;
529 : :
530 : 499 : wpabuf_set(&buf, in_data, in_len);
531 : 499 : msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input);
532 [ + + ]: 499 : if (msg == NULL)
533 [ + - ]: 120 : return need_more_input ? 1 : -1;
534 : :
535 : : /* Full TLS message reassembled - continue handshake processing */
536 [ - + ]: 379 : if (data->tls_out) {
537 : : /* This should not happen.. */
538 : 0 : wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "
539 : : "tls_out data even though tls_out_len = 0");
540 : 0 : wpabuf_free(data->tls_out);
541 : : WPA_ASSERT(data->tls_out == NULL);
542 : : }
543 : 379 : appl_data = NULL;
544 : 379 : data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
545 : : msg, &appl_data);
546 : :
547 : 379 : eap_peer_tls_reset_input(data);
548 : :
549 [ + + + - ]: 383 : if (appl_data &&
550 [ + - ]: 8 : tls_connection_established(data->ssl_ctx, data->conn) &&
551 : 4 : !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
552 : 4 : wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
553 : : appl_data);
554 : 4 : *out_data = appl_data;
555 : 4 : return 2;
556 : : }
557 : :
558 : 375 : wpabuf_free(appl_data);
559 : :
560 : 499 : return 0;
561 : : }
562 : :
563 : :
564 : : /**
565 : : * eap_tls_process_output - Process outgoing TLS message
566 : : * @data: Data for TLS processing
567 : : * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
568 : : * @peap_version: Version number for EAP-PEAP/TTLS
569 : : * @id: EAP identifier for the response
570 : : * @ret: Return value to use on success
571 : : * @out_data: Buffer for returning the allocated output buffer
572 : : * Returns: ret (0 or 1) on success, -1 on failure
573 : : */
574 : 480 : static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
575 : : int peap_version, u8 id, int ret,
576 : : struct wpabuf **out_data)
577 : : {
578 : : size_t len;
579 : : u8 *flags;
580 : : int more_fragments, length_included;
581 : :
582 [ - + ]: 480 : if (data->tls_out == NULL)
583 : 0 : return -1;
584 : 480 : len = wpabuf_len(data->tls_out) - data->tls_out_pos;
585 : 480 : wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
586 : : "%lu bytes)",
587 : : (unsigned long) len,
588 : 480 : (unsigned long) wpabuf_len(data->tls_out));
589 : :
590 : : /*
591 : : * Limit outgoing message to the configured maximum size. Fragment
592 : : * message if needed.
593 : : */
594 [ + + ]: 480 : if (len > data->tls_out_limit) {
595 : 12 : more_fragments = 1;
596 : 12 : len = data->tls_out_limit;
597 : 12 : wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
598 : : "will follow", (unsigned long) len);
599 : : } else
600 : 468 : more_fragments = 0;
601 : :
602 [ + + + + ]: 1404 : length_included = data->tls_out_pos == 0 &&
603 [ - + ]: 924 : (wpabuf_len(data->tls_out) > data->tls_out_limit ||
604 : 456 : data->include_tls_length);
605 [ + + ][ + + ]: 480 : if (!length_included &&
606 [ + + + + ]: 126 : eap_type == EAP_TYPE_PEAP && peap_version == 0 &&
607 : 12 : !tls_connection_established(data->eap->ssl_ctx, data->conn)) {
608 : : /*
609 : : * Windows Server 2008 NPS really wants to have the TLS Message
610 : : * length included in phase 0 even for unfragmented frames or
611 : : * it will get very confused with Compound MAC calculation and
612 : : * Outer TLVs.
613 : : */
614 : 4 : length_included = 1;
615 : : }
616 : :
617 : 480 : *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
618 : : EAP_CODE_RESPONSE, id);
619 [ - + ]: 480 : if (*out_data == NULL)
620 : 0 : return -1;
621 : :
622 : 480 : flags = wpabuf_put(*out_data, 1);
623 : 480 : *flags = peap_version;
624 [ + + ]: 480 : if (more_fragments)
625 : 12 : *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
626 [ + + ]: 480 : if (length_included) {
627 : 16 : *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
628 : 16 : wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out));
629 : : }
630 : :
631 : 480 : wpabuf_put_data(*out_data,
632 : 480 : wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
633 : : len);
634 : 480 : data->tls_out_pos += len;
635 : :
636 [ + + ]: 480 : if (!more_fragments)
637 : 468 : eap_peer_tls_reset_output(data);
638 : :
639 : 480 : return ret;
640 : : }
641 : :
642 : :
643 : : /**
644 : : * eap_peer_tls_process_helper - Process TLS handshake message
645 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
646 : : * @data: Data for TLS processing
647 : : * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
648 : : * @peap_version: Version number for EAP-PEAP/TTLS
649 : : * @id: EAP identifier for the response
650 : : * @in_data: Message received from the server
651 : : * @in_len: Length of in_data
652 : : * @out_data: Buffer for returning a pointer to the response message
653 : : * Returns: 0 on success, 1 if more input data is needed, 2 if application data
654 : : * is available, or -1 on failure
655 : : *
656 : : * This function can be used to process TLS handshake messages. It reassembles
657 : : * the received fragments and uses a TLS library to process the messages. The
658 : : * response data from the TLS library is fragmented to suitable output messages
659 : : * that the caller can send out.
660 : : *
661 : : * out_data is used to return the response message if the return value of this
662 : : * function is 0, 2, or -1. In case of failure, the message is likely a TLS
663 : : * alarm message. The caller is responsible for freeing the allocated buffer if
664 : : * *out_data is not %NULL.
665 : : *
666 : : * This function is called for each received TLS message during the TLS
667 : : * handshake after eap_peer_tls_process_init() call and possible processing of
668 : : * TLS Flags field. Once the handshake has been completed, i.e., when
669 : : * tls_connection_established() returns 1, EAP method specific decrypting of
670 : : * the tunneled data is used.
671 : : */
672 : 511 : int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
673 : : EapType eap_type, int peap_version,
674 : : u8 id, const u8 *in_data, size_t in_len,
675 : : struct wpabuf **out_data)
676 : : {
677 : 511 : int ret = 0;
678 : :
679 : 511 : *out_data = NULL;
680 : :
681 [ + + ][ + - ]: 511 : if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) {
[ - + ]
682 : 0 : wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output "
683 : : "fragments are waiting to be sent out");
684 : 0 : return -1;
685 : : }
686 : :
687 [ + + ][ - + ]: 511 : if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
688 : : /*
689 : : * No more data to send out - expect to receive more data from
690 : : * the AS.
691 : : */
692 : 499 : int res = eap_tls_process_input(sm, data, in_data, in_len,
693 : : out_data);
694 [ + + ]: 499 : if (res) {
695 : : /*
696 : : * Input processing failed (res = -1) or more data is
697 : : * needed (res = 1).
698 : : */
699 : 124 : return res;
700 : : }
701 : :
702 : : /*
703 : : * The incoming message has been reassembled and processed. The
704 : : * response was allocated into data->tls_out buffer.
705 : : */
706 : : }
707 : :
708 [ - + ]: 387 : if (data->tls_out == NULL) {
709 : : /*
710 : : * No outgoing fragments remaining from the previous message
711 : : * and no new message generated. This indicates an error in TLS
712 : : * processing.
713 : : */
714 : 0 : eap_peer_tls_reset_output(data);
715 : 0 : return -1;
716 : : }
717 : :
718 [ + + ]: 387 : if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
719 : : /* TLS processing has failed - return error */
720 : 11 : wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
721 : : "report error");
722 : 11 : ret = -1;
723 : : /* TODO: clean pin if engine used? */
724 : : }
725 : :
726 [ + - ][ + + ]: 387 : if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
727 : : /*
728 : : * TLS negotiation should now be complete since all other cases
729 : : * needing more data should have been caught above based on
730 : : * the TLS Message Length field.
731 : : */
732 : 113 : wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
733 : 113 : wpabuf_free(data->tls_out);
734 : 113 : data->tls_out = NULL;
735 : 113 : return 1;
736 : : }
737 : :
738 : : /* Send the pending message (in fragments, if needed). */
739 : 511 : return eap_tls_process_output(data, eap_type, peap_version, id, ret,
740 : : out_data);
741 : : }
742 : :
743 : :
744 : : /**
745 : : * eap_peer_tls_build_ack - Build a TLS ACK frame
746 : : * @id: EAP identifier for the response
747 : : * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
748 : : * @peap_version: Version number for EAP-PEAP/TTLS
749 : : * Returns: Pointer to the allocated ACK frame or %NULL on failure
750 : : */
751 : 226 : struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
752 : : int peap_version)
753 : : {
754 : : struct wpabuf *resp;
755 : :
756 : 226 : resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
757 [ - + ]: 226 : if (resp == NULL)
758 : 0 : return NULL;
759 : 226 : wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
760 : : (int) eap_type, id, peap_version);
761 : 226 : wpabuf_put_u8(resp, peap_version); /* Flags */
762 : 226 : return resp;
763 : : }
764 : :
765 : :
766 : : /**
767 : : * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption
768 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
769 : : * @data: Data for TLS processing
770 : : * Returns: 0 on success, -1 on failure
771 : : */
772 : 16 : int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
773 : : {
774 : 16 : eap_peer_tls_reset_input(data);
775 : 16 : eap_peer_tls_reset_output(data);
776 : 16 : return tls_connection_shutdown(data->ssl_ctx, data->conn);
777 : : }
778 : :
779 : :
780 : : /**
781 : : * eap_peer_tls_status - Get TLS status
782 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
783 : : * @data: Data for TLS processing
784 : : * @buf: Buffer for status information
785 : : * @buflen: Maximum buffer length
786 : : * @verbose: Whether to include verbose status information
787 : : * Returns: Number of bytes written to buf.
788 : : */
789 : 71 : int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
790 : : char *buf, size_t buflen, int verbose)
791 : : {
792 : : char name[128];
793 : 71 : int len = 0, ret;
794 : :
795 [ + - ]: 71 : if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
796 : : {
797 : 71 : ret = os_snprintf(buf + len, buflen - len,
798 : : "EAP TLS cipher=%s\n", name);
799 [ + - ][ - + ]: 71 : if (ret < 0 || (size_t) ret >= buflen - len)
800 : 0 : return len;
801 : 71 : len += ret;
802 : : }
803 : :
804 : 71 : return len;
805 : : }
806 : :
807 : :
808 : : /**
809 : : * eap_peer_tls_process_init - Initial validation/processing of EAP requests
810 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
811 : : * @data: Data for TLS processing
812 : : * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
813 : : * @ret: Return values from EAP request validation and processing
814 : : * @reqData: EAP request to be processed (eapReqData)
815 : : * @len: Buffer for returning length of the remaining payload
816 : : * @flags: Buffer for returning TLS flags
817 : : * Returns: Pointer to payload after TLS flags and length or %NULL on failure
818 : : *
819 : : * This function validates the EAP header and processes the optional TLS
820 : : * Message Length field. If this is the first fragment of a TLS message, the
821 : : * TLS reassembly code is initialized to receive the indicated number of bytes.
822 : : *
823 : : * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this
824 : : * function as the first step in processing received messages. They will need
825 : : * to process the flags (apart from Message Length Included) that are returned
826 : : * through the flags pointer and the message payload that will be returned (and
827 : : * the length is returned through the len pointer). Return values (ret) are set
828 : : * for continuation of EAP method processing. The caller is responsible for
829 : : * setting these to indicate completion (either success or failure) based on
830 : : * the authentication result.
831 : : */
832 : 713 : const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
833 : : struct eap_ssl_data *data,
834 : : EapType eap_type,
835 : : struct eap_method_ret *ret,
836 : : const struct wpabuf *reqData,
837 : : size_t *len, u8 *flags)
838 : : {
839 : : const u8 *pos;
840 : : size_t left;
841 : : unsigned int tls_msg_len;
842 : :
843 [ - + ]: 713 : if (tls_get_errors(data->ssl_ctx)) {
844 : 0 : wpa_printf(MSG_INFO, "SSL: TLS errors detected");
845 : 0 : ret->ignore = TRUE;
846 : 0 : return NULL;
847 : : }
848 : :
849 [ - + ]: 713 : if (eap_type == EAP_UNAUTH_TLS_TYPE)
850 : 0 : pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
851 : : EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
852 : : &left);
853 [ + + ]: 713 : else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
854 : 4 : pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
855 : : EAP_VENDOR_WFA_UNAUTH_TLS, reqData,
856 : : &left);
857 : : else
858 : 709 : pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
859 : : &left);
860 [ - + ]: 713 : if (pos == NULL) {
861 : 0 : ret->ignore = TRUE;
862 : 0 : return NULL;
863 : : }
864 [ - + ]: 713 : if (left == 0) {
865 : 0 : wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
866 : : "octet included");
867 [ # # ]: 0 : if (!sm->workaround) {
868 : 0 : ret->ignore = TRUE;
869 : 0 : return NULL;
870 : : }
871 : :
872 : 0 : wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags "
873 : : "indicates ACK frame");
874 : 0 : *flags = 0;
875 : : } else {
876 : 713 : *flags = *pos++;
877 : 713 : left--;
878 : : }
879 : 713 : wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
880 : : "Flags 0x%02x", (unsigned long) wpabuf_len(reqData),
881 : 713 : *flags);
882 [ + + ]: 713 : if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
883 [ - + ]: 120 : if (left < 4) {
884 : 0 : wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
885 : : "length");
886 : 0 : ret->ignore = TRUE;
887 : 0 : return NULL;
888 : : }
889 : 120 : tls_msg_len = WPA_GET_BE32(pos);
890 : 120 : wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
891 : : tls_msg_len);
892 [ + - ]: 120 : if (data->tls_in_left == 0) {
893 : 120 : data->tls_in_total = tls_msg_len;
894 : 120 : data->tls_in_left = tls_msg_len;
895 : 120 : wpabuf_free(data->tls_in);
896 : 120 : data->tls_in = NULL;
897 : : }
898 : 120 : pos += 4;
899 : 120 : left -= 4;
900 : :
901 [ - + ]: 120 : if (left > tls_msg_len) {
902 : 0 : wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
903 : : "bytes) smaller than this fragment (%d "
904 : : "bytes)", (int) tls_msg_len, (int) left);
905 : 0 : ret->ignore = TRUE;
906 : 0 : return NULL;
907 : : }
908 : : }
909 : :
910 : 713 : ret->ignore = FALSE;
911 : 713 : ret->methodState = METHOD_MAY_CONT;
912 : 713 : ret->decision = DECISION_FAIL;
913 : 713 : ret->allowNotifications = TRUE;
914 : :
915 : 713 : *len = left;
916 : 713 : return pos;
917 : : }
918 : :
919 : :
920 : : /**
921 : : * eap_peer_tls_reset_input - Reset input buffers
922 : : * @data: Data for TLS processing
923 : : *
924 : : * This function frees any allocated memory for input buffers and resets input
925 : : * state.
926 : : */
927 : 717 : void eap_peer_tls_reset_input(struct eap_ssl_data *data)
928 : : {
929 : 717 : data->tls_in_left = data->tls_in_total = 0;
930 : 717 : wpabuf_free(data->tls_in);
931 : 717 : data->tls_in = NULL;
932 : 717 : }
933 : :
934 : :
935 : : /**
936 : : * eap_peer_tls_reset_output - Reset output buffers
937 : : * @data: Data for TLS processing
938 : : *
939 : : * This function frees any allocated memory for output buffers and resets
940 : : * output state.
941 : : */
942 : 806 : void eap_peer_tls_reset_output(struct eap_ssl_data *data)
943 : : {
944 : 806 : data->tls_out_pos = 0;
945 : 806 : wpabuf_free(data->tls_out);
946 : 806 : data->tls_out = NULL;
947 : 806 : }
948 : :
949 : :
950 : : /**
951 : : * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message
952 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
953 : : * @data: Data for TLS processing
954 : : * @in_data: Message received from the server
955 : : * @in_decrypted: Buffer for returning a pointer to the decrypted message
956 : : * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
957 : : */
958 : 195 : int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
959 : : const struct wpabuf *in_data,
960 : : struct wpabuf **in_decrypted)
961 : : {
962 : : const struct wpabuf *msg;
963 : : int need_more_input;
964 : :
965 : 195 : msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
966 [ - + ]: 195 : if (msg == NULL)
967 [ # # ]: 0 : return need_more_input ? 1 : -1;
968 : :
969 : 195 : *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
970 : 195 : eap_peer_tls_reset_input(data);
971 [ - + ]: 195 : if (*in_decrypted == NULL) {
972 : 0 : wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
973 : 0 : return -1;
974 : : }
975 : 195 : return 0;
976 : : }
977 : :
978 : :
979 : : /**
980 : : * eap_peer_tls_encrypt - Encrypt phase 2 TLS message
981 : : * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
982 : : * @data: Data for TLS processing
983 : : * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
984 : : * @peap_version: Version number for EAP-PEAP/TTLS
985 : : * @id: EAP identifier for the response
986 : : * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments
987 : : * @out_data: Buffer for returning a pointer to the encrypted response message
988 : : * Returns: 0 on success, -1 on failure
989 : : */
990 : 206 : int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
991 : : EapType eap_type, int peap_version, u8 id,
992 : : const struct wpabuf *in_data,
993 : : struct wpabuf **out_data)
994 : : {
995 [ + - ]: 206 : if (in_data) {
996 : 206 : eap_peer_tls_reset_output(data);
997 : 206 : data->tls_out = tls_connection_encrypt(data->ssl_ctx,
998 : : data->conn, in_data);
999 [ - + ]: 206 : if (data->tls_out == NULL) {
1000 : 0 : wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
1001 : : "data (in_len=%lu)",
1002 : : (unsigned long) wpabuf_len(in_data));
1003 : 0 : eap_peer_tls_reset_output(data);
1004 : 0 : return -1;
1005 : : }
1006 : : }
1007 : :
1008 : 206 : return eap_tls_process_output(data, eap_type, peap_version, id, 0,
1009 : : out_data);
1010 : : }
1011 : :
1012 : :
1013 : : /**
1014 : : * eap_peer_select_phase2_methods - Select phase 2 EAP method
1015 : : * @config: Pointer to the network configuration
1016 : : * @prefix: 'phase2' configuration prefix, e.g., "auth="
1017 : : * @types: Buffer for returning allocated list of allowed EAP methods
1018 : : * @num_types: Buffer for returning number of allocated EAP methods
1019 : : * Returns: 0 on success, -1 on failure
1020 : : *
1021 : : * This function is used to parse EAP method list and select allowed methods
1022 : : * for Phase2 authentication.
1023 : : */
1024 : 34 : int eap_peer_select_phase2_methods(struct eap_peer_config *config,
1025 : : const char *prefix,
1026 : : struct eap_method_type **types,
1027 : : size_t *num_types)
1028 : : {
1029 : : char *start, *pos, *buf;
1030 : 34 : struct eap_method_type *methods = NULL, *_methods;
1031 : : u8 method;
1032 : 34 : size_t num_methods = 0, prefix_len;
1033 : :
1034 [ + - ][ + + ]: 34 : if (config == NULL || config->phase2 == NULL)
1035 : : goto get_defaults;
1036 : :
1037 : 29 : start = buf = os_strdup(config->phase2);
1038 [ - + ]: 29 : if (buf == NULL)
1039 : 0 : return -1;
1040 : :
1041 : 29 : prefix_len = os_strlen(prefix);
1042 : :
1043 [ + + ][ + - ]: 58 : while (start && *start != '\0') {
1044 : : int vendor;
1045 : 29 : pos = os_strstr(start, prefix);
1046 [ - + ]: 29 : if (pos == NULL)
1047 : 0 : break;
1048 [ - + ][ # # ]: 29 : if (start != pos && *(pos - 1) != ' ') {
1049 : 0 : start = pos + prefix_len;
1050 : 0 : continue;
1051 : : }
1052 : :
1053 : 29 : start = pos + prefix_len;
1054 : 29 : pos = os_strchr(start, ' ');
1055 [ - + ]: 29 : if (pos)
1056 : 0 : *pos++ = '\0';
1057 : 29 : method = eap_get_phase2_type(start, &vendor);
1058 [ + - ][ - + ]: 29 : if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) {
1059 : 0 : wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP "
1060 : : "method '%s'", start);
1061 : : } else {
1062 : 29 : num_methods++;
1063 : 29 : _methods = os_realloc_array(methods, num_methods,
1064 : : sizeof(*methods));
1065 [ - + ]: 29 : if (_methods == NULL) {
1066 : 0 : os_free(methods);
1067 : 0 : os_free(buf);
1068 : 0 : return -1;
1069 : : }
1070 : 29 : methods = _methods;
1071 : 29 : methods[num_methods - 1].vendor = vendor;
1072 : 29 : methods[num_methods - 1].method = method;
1073 : : }
1074 : :
1075 : 29 : start = pos;
1076 : : }
1077 : :
1078 : 29 : os_free(buf);
1079 : :
1080 : : get_defaults:
1081 [ + + ]: 34 : if (methods == NULL)
1082 : 5 : methods = eap_get_phase2_types(config, &num_methods);
1083 : :
1084 [ - + ]: 34 : if (methods == NULL) {
1085 : 0 : wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available");
1086 : 0 : return -1;
1087 : : }
1088 : 34 : wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types",
1089 : : (u8 *) methods,
1090 : : num_methods * sizeof(struct eap_method_type));
1091 : :
1092 : 34 : *types = methods;
1093 : 34 : *num_types = num_methods;
1094 : :
1095 : 34 : return 0;
1096 : : }
1097 : :
1098 : :
1099 : : /**
1100 : : * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2
1101 : : * @types: Buffer for returning allocated list of allowed EAP methods
1102 : : * @num_types: Buffer for returning number of allocated EAP methods
1103 : : * @hdr: EAP-Request header (and the following EAP type octet)
1104 : : * @resp: Buffer for returning the EAP-Nak message
1105 : : * Returns: 0 on success, -1 on failure
1106 : : */
1107 : 10 : int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
1108 : : struct eap_hdr *hdr, struct wpabuf **resp)
1109 : : {
1110 : 10 : u8 *pos = (u8 *) (hdr + 1);
1111 : : size_t i;
1112 : :
1113 : : /* TODO: add support for expanded Nak */
1114 : 10 : wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos);
1115 : 10 : wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types",
1116 : : (u8 *) types, num_types * sizeof(struct eap_method_type));
1117 : 10 : *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types,
1118 : 10 : EAP_CODE_RESPONSE, hdr->identifier);
1119 [ - + ]: 10 : if (*resp == NULL)
1120 : 0 : return -1;
1121 : :
1122 [ + + ]: 20 : for (i = 0; i < num_types; i++) {
1123 [ + - ][ + - ]: 10 : if (types[i].vendor == EAP_VENDOR_IETF &&
1124 : 10 : types[i].method < 256)
1125 : 10 : wpabuf_put_u8(*resp, types[i].method);
1126 : : }
1127 : :
1128 : 10 : eap_update_len(*resp);
1129 : :
1130 : 10 : return 0;
1131 : : }
|