• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
3  * Copyright (c) 2004-2006, 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 "config_ssid.h"
21 #include "md5.h"
22 #include "sha1.h"
23 #include "tls.h"
24 #include "config.h"
25 
eap_tls_check_blob(struct eap_sm * sm,const char ** name,const u8 ** data,size_t * data_len)26 static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
27 			      const u8 **data, size_t *data_len)
28 {
29 	const struct wpa_config_blob *blob;
30 
31 	if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
32 		return 0;
33 
34 	blob = eap_get_config_blob(sm, *name + 7);
35 	if (blob == NULL) {
36 		wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
37 			   "found", __func__, *name + 7);
38 		return -1;
39 	}
40 	*name = NULL;
41 	*data = blob->data;
42 	*data_len = blob->len;
43 
44 	return 0;
45 }
46 
47 
eap_tls_params_from_conf1(struct tls_connection_params * params,struct wpa_ssid * config)48 static void eap_tls_params_from_conf1(struct tls_connection_params *params,
49 				      struct wpa_ssid *config)
50 {
51 	params->ca_cert = (char *) config->ca_cert;
52 	params->ca_path = (char *) config->ca_path;
53 	params->client_cert = (char *) config->client_cert;
54 	params->private_key = (char *) config->private_key;
55 	params->private_key_passwd = (char *) config->private_key_passwd;
56 	params->dh_file = (char *) config->dh_file;
57 	params->subject_match = (char *) config->subject_match;
58 	params->altsubject_match = (char *) config->altsubject_match;
59 	params->engine_id = config->engine_id;
60 	params->pin = config->pin;
61 	params->key_id = config->key_id;
62 }
63 
64 
eap_tls_params_from_conf2(struct tls_connection_params * params,struct wpa_ssid * config)65 static void eap_tls_params_from_conf2(struct tls_connection_params *params,
66 				      struct wpa_ssid *config)
67 {
68 	params->ca_cert = (char *) config->ca_cert2;
69 	params->ca_path = (char *) config->ca_path2;
70 	params->client_cert = (char *) config->client_cert2;
71 	params->private_key = (char *) config->private_key2;
72 	params->private_key_passwd = (char *) config->private_key2_passwd;
73 	params->dh_file = (char *) config->dh_file2;
74 	params->subject_match = (char *) config->subject_match2;
75 	params->altsubject_match = (char *) config->altsubject_match2;
76 }
77 
78 
eap_tls_params_from_conf(struct eap_sm * sm,struct eap_ssl_data * data,struct tls_connection_params * params,struct wpa_ssid * config,int phase2)79 static int eap_tls_params_from_conf(struct eap_sm *sm,
80 				    struct eap_ssl_data *data,
81 				    struct tls_connection_params *params,
82 				    struct wpa_ssid *config, int phase2)
83 {
84 	os_memset(params, 0, sizeof(*params));
85 	params->engine = config->engine;
86 	if (phase2)
87 		eap_tls_params_from_conf2(params, config);
88 	else
89 		eap_tls_params_from_conf1(params, config);
90 	params->tls_ia = data->tls_ia;
91 
92 
93 	if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
94 			       &params->ca_cert_blob_len) ||
95 	    eap_tls_check_blob(sm, &params->client_cert,
96 			       &params->client_cert_blob,
97 			       &params->client_cert_blob_len) ||
98 	    eap_tls_check_blob(sm, &params->private_key,
99 			       &params->private_key_blob,
100 			       &params->private_key_blob_len) ||
101 	    eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,
102 			       &params->dh_blob_len)) {
103 		wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
104 		return -1;
105 	}
106 
107 	return 0;
108 }
109 
110 
eap_tls_init_connection(struct eap_sm * sm,struct eap_ssl_data * data,struct wpa_ssid * config,struct tls_connection_params * params)111 static int eap_tls_init_connection(struct eap_sm *sm,
112 				   struct eap_ssl_data *data,
113 				   struct wpa_ssid *config,
114 				   struct tls_connection_params *params)
115 {
116 	int res;
117 
118 	data->conn = tls_connection_init(sm->ssl_ctx);
119 	if (data->conn == NULL) {
120 		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
121 			   "connection");
122 		return -1;
123 	}
124 
125 	res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
126 	if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
127 		/* At this point with the pkcs11 engine the PIN might be wrong.
128 		 * We reset the PIN in the configuration to be sure to not use
129 		 * it again and the calling function must request a new one */
130 		os_free(config->pin);
131 		config->pin = NULL;
132 	} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
133 		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
134 		/* We don't know exactly but maybe the PIN was wrong,
135 		 * so ask for a new one. */
136 		os_free(config->pin);
137 		config->pin = NULL;
138 		eap_sm_request_pin(sm);
139 		sm->ignore = TRUE;
140 		return -1;
141 	} else if (res) {
142 		wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
143 			   "parameters");
144 		return -1;
145 	}
146 
147 	return 0;
148 }
149 
150 
151 /**
152  * eap_tls_ssl_init - Initialize shared TLS functionality
153  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
154  * @data: Data for TLS processing
155  * @config: Pointer to the network configuration
156  * Returns: 0 on success, -1 on failure
157  *
158  * This function is used to initialize shared TLS functionality for EAP-TLS,
159  * EAP-PEAP, EAP-TTLS, and EAP-FAST.
160  */
eap_tls_ssl_init(struct eap_sm * sm,struct eap_ssl_data * data,struct wpa_ssid * config)161 int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
162 		     struct wpa_ssid *config)
163 {
164 	int ret = -1;
165 	struct tls_connection_params params;
166 
167 	if (config == NULL)
168 		return -1;
169 
170 	data->eap = sm;
171 	data->phase2 = sm->init_phase2;
172 	if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
173 	    0)
174 		goto done;
175 
176 	if (eap_tls_init_connection(sm, data, config, &params) < 0)
177 		goto done;
178 
179 	data->tls_out_limit = config->fragment_size;
180 	if (data->phase2) {
181 		/* Limit the fragment size in the inner TLS authentication
182 		 * since the outer authentication with EAP-PEAP does not yet
183 		 * support fragmentation */
184 		if (data->tls_out_limit > 100)
185 			data->tls_out_limit -= 100;
186 	}
187 
188 	if (config->phase1 &&
189 	    os_strstr(config->phase1, "include_tls_length=1")) {
190 		wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
191 			   "unfragmented packets");
192 		data->include_tls_length = 1;
193 	}
194 
195 	ret = 0;
196 
197 done:
198 	return ret;
199 }
200 
201 
202 /**
203  * eap_tls_ssl_deinit - Deinitialize shared TLS functionality
204  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
205  * @data: Data for TLS processing
206  *
207  * This function deinitializes shared TLS functionality that was initialized
208  * with eap_tls_ssl_init().
209  */
eap_tls_ssl_deinit(struct eap_sm * sm,struct eap_ssl_data * data)210 void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
211 {
212 	tls_connection_deinit(sm->ssl_ctx, data->conn);
213 	os_free(data->tls_in);
214 	os_free(data->tls_out);
215 }
216 
217 
218 /**
219  * eap_tls_derive_key - Derive a key based on TLS session data
220  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
221  * @data: Data for TLS processing
222  * @label: Label string for deriving the keys, e.g., "client EAP encryption"
223  * @len: Length of the key material to generate (usually 64 for MSK)
224  * Returns: Pointer to allocated key on success or %NULL on failure
225  *
226  * This function uses TLS-PRF to generate pseudo-random data based on the TLS
227  * session data (client/server random and master key). Each key type may use a
228  * different label to bind the key usage into the generated material.
229  *
230  * The caller is responsible for freeing the returned buffer.
231  */
eap_tls_derive_key(struct eap_sm * sm,struct eap_ssl_data * data,const char * label,size_t len)232 u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
233 			const char *label, size_t len)
234 {
235 	struct tls_keys keys;
236 	u8 *rnd = NULL, *out;
237 
238 	out = os_malloc(len);
239 	if (out == NULL)
240 		return NULL;
241 
242 	/* First, try to use TLS library function for PRF, if available. */
243 	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
244 	    0)
245 		return out;
246 
247 	/*
248 	 * TLS library did not support key generation, so get the needed TLS
249 	 * session parameters and use an internal implementation of TLS PRF to
250 	 * derive the key.
251 	 */
252 	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
253 		goto fail;
254 
255 	if (keys.client_random == NULL || keys.server_random == NULL ||
256 	    keys.master_key == NULL)
257 		goto fail;
258 
259 	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
260 	if (rnd == NULL)
261 		goto fail;
262 	os_memcpy(rnd, keys.client_random, keys.client_random_len);
263 	os_memcpy(rnd + keys.client_random_len, keys.server_random,
264 		  keys.server_random_len);
265 
266 	if (tls_prf(keys.master_key, keys.master_key_len,
267 		    label, rnd, keys.client_random_len +
268 		    keys.server_random_len, out, len))
269 		goto fail;
270 
271 	os_free(rnd);
272 	return out;
273 
274 fail:
275 	os_free(out);
276 	os_free(rnd);
277 	return NULL;
278 }
279 
280 
281 /**
282  * eap_tls_data_reassemble - Reassemble TLS data
283  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
284  * @data: Data for TLS processing
285  * @in_data: Next incoming TLS segment
286  * @in_len: Length of in_data
287  * @out_len: Variable for returning output data length
288  * @need_more_input: Variable for returning whether more input data is needed
289  * to reassemble this TLS packet
290  * Returns: Pointer to output data, %NULL on error or when more data is needed
291  * for the full message (in which case, *need_more_input is also set to 1).
292  *
293  * This function reassembles TLS fragments. Caller must not free the returned
294  * data buffer since an internal pointer to it is maintained.
295  */
eap_tls_data_reassemble(struct eap_sm * sm,struct eap_ssl_data * data,const u8 * in_data,size_t in_len,size_t * out_len,int * need_more_input)296 const u8 * eap_tls_data_reassemble(
297 	struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data,
298 	size_t in_len, size_t *out_len, int *need_more_input)
299 {
300 	u8 *buf;
301 
302 	*need_more_input = 0;
303 
304 	if (data->tls_in_left > in_len || data->tls_in) {
305 		if (data->tls_in_len + in_len == 0) {
306 			os_free(data->tls_in);
307 			data->tls_in = NULL;
308 			data->tls_in_len = 0;
309 			wpa_printf(MSG_WARNING, "SSL: Invalid reassembly "
310 				   "state: tls_in_left=%lu tls_in_len=%lu "
311 				   "in_len=%lu",
312 				   (unsigned long) data->tls_in_left,
313 				   (unsigned long) data->tls_in_len,
314 				   (unsigned long) in_len);
315 			return NULL;
316 		}
317 		if (data->tls_in_len + in_len > 65536) {
318 			/* Limit length to avoid rogue servers from causing
319 			 * large memory allocations. */
320 			os_free(data->tls_in);
321 			data->tls_in = NULL;
322 			data->tls_in_len = 0;
323 			wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
324 				   " over 64 kB)");
325 			return NULL;
326 		}
327 		buf = os_realloc(data->tls_in, data->tls_in_len + in_len);
328 		if (buf == NULL) {
329 			os_free(data->tls_in);
330 			data->tls_in = NULL;
331 			data->tls_in_len = 0;
332 			wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
333 				   "for TLS data");
334 			return NULL;
335 		}
336 		os_memcpy(buf + data->tls_in_len, in_data, in_len);
337 		data->tls_in = buf;
338 		data->tls_in_len += in_len;
339 		if (in_len > data->tls_in_left) {
340 			wpa_printf(MSG_INFO, "SSL: more data than TLS message "
341 				   "length indicated");
342 			data->tls_in_left = 0;
343 			return NULL;
344 		}
345 		data->tls_in_left -= in_len;
346 		if (data->tls_in_left > 0) {
347 			wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
348 				   "data", (unsigned long) data->tls_in_left);
349 			*need_more_input = 1;
350 			return NULL;
351 		}
352 	} else {
353 		data->tls_in_left = 0;
354 		data->tls_in = os_malloc(in_len ? in_len : 1);
355 		if (data->tls_in == NULL)
356 			return NULL;
357 		os_memcpy(data->tls_in, in_data, in_len);
358 		data->tls_in_len = in_len;
359 	}
360 
361 	*out_len = data->tls_in_len;
362 	return data->tls_in;
363 }
364 
365 
eap_tls_process_input(struct eap_sm * sm,struct eap_ssl_data * data,const u8 * in_data,size_t in_len,u8 ** out_data,size_t * out_len)366 static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
367 				 const u8 *in_data, size_t in_len,
368 				 u8 **out_data, size_t *out_len)
369 {
370 	const u8 *msg;
371 	size_t msg_len;
372 	int need_more_input;
373 	u8 *appl_data;
374 	size_t appl_data_len;
375 
376 	msg = eap_tls_data_reassemble(sm, data, in_data, in_len,
377 				      &msg_len, &need_more_input);
378 	if (msg == NULL)
379 		return need_more_input ? 1 : -1;
380 
381 	/* Full TLS message reassembled - continue handshake processing */
382 	if (data->tls_out) {
383 		/* This should not happen.. */
384 		wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - pending "
385 			   "tls_out data even though tls_out_len = 0");
386 		os_free(data->tls_out);
387 		WPA_ASSERT(data->tls_out == NULL);
388 	}
389 	appl_data = NULL;
390 	data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
391 						 msg, msg_len,
392 						 &data->tls_out_len,
393 						 &appl_data, &appl_data_len);
394 
395 	/* Clear reassembled input data (if the buffer was needed). */
396 	data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
397 	os_free(data->tls_in);
398 	data->tls_in = NULL;
399 
400 	if (appl_data &&
401 	    tls_connection_established(sm->ssl_ctx, data->conn) &&
402 	    !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
403 		wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data",
404 				appl_data, appl_data_len);
405 		*out_data = appl_data;
406 		*out_len = appl_data_len;
407 		return 2;
408 	}
409 
410 	os_free(appl_data);
411 
412 	return 0;
413 }
414 
415 
eap_tls_process_output(struct eap_ssl_data * data,EapType eap_type,int peap_version,u8 id,int ret,u8 ** out_data,size_t * out_len)416 static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
417 				  int peap_version, u8 id, int ret,
418 				  u8 **out_data, size_t *out_len)
419 {
420 	size_t len;
421 	u8 *pos, *flags;
422 	int more_fragments, length_included;
423 
424 	wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
425 		   "%lu bytes)",
426 		   (unsigned long) data->tls_out_len - data->tls_out_pos,
427 		   (unsigned long) data->tls_out_len);
428 
429 	len = data->tls_out_len - data->tls_out_pos;
430 	if (len > data->tls_out_limit) {
431 		more_fragments = 1;
432 		len = data->tls_out_limit;
433 		wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
434 			   "will follow", (unsigned long) len);
435 	} else
436 		more_fragments = 0;
437 
438 	length_included = data->tls_out_pos == 0 &&
439 		(data->tls_out_len > data->tls_out_limit ||
440 		 data->include_tls_length);
441 
442 	*out_data = (u8 *)
443 		eap_msg_alloc(EAP_VENDOR_IETF, eap_type, out_len,
444 			      1 + length_included * 4 + len, EAP_CODE_RESPONSE,
445 			      id, &pos);
446 	if (*out_data == NULL)
447 		return -1;
448 
449 	flags = pos++;
450 	*flags = peap_version;
451 	if (more_fragments)
452 		*flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
453 	if (length_included) {
454 		*flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
455 		WPA_PUT_BE32(pos, data->tls_out_len);
456 		pos += 4;
457 	}
458 
459 	os_memcpy(pos, &data->tls_out[data->tls_out_pos], len);
460 	data->tls_out_pos += len;
461 
462 	if (!more_fragments) {
463 		data->tls_out_len = 0;
464 		data->tls_out_pos = 0;
465 		os_free(data->tls_out);
466 		data->tls_out = NULL;
467 	}
468 
469 	return ret;
470 }
471 
472 
473 /**
474  * eap_tls_process_helper - Process TLS handshake message
475  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
476  * @data: Data for TLS processing
477  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
478  * @peap_version: Version number for EAP-PEAP/TTLS
479  * @id: EAP identifier for the response
480  * @in_data: Message received from the server
481  * @in_len: Length of in_data
482  * @out_data: Buffer for returning a pointer to the response message
483  * @out_len: Buffer for returning the length of the response message
484  * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
485  *
486  * This function can be used to process TLS handshake messages. It reassembles
487  * the received fragments and uses a TLS library to process the messages. The
488  * response data from the TLS library is fragmented to suitable output messages
489  * that the caller can send out.
490  *
491  * out_data is used to return the response message if the return value of this
492  * function is 0 or -1. In case of failure, the message is likely a TLS alarm
493  * message. The caller is responsible for freeing the allocated buffer if
494  * *out_data is not %NULL.
495  */
eap_tls_process_helper(struct eap_sm * sm,struct eap_ssl_data * data,EapType eap_type,int peap_version,u8 id,const u8 * in_data,size_t in_len,u8 ** out_data,size_t * out_len)496 int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
497 			   EapType eap_type, int peap_version,
498 			   u8 id, const u8 *in_data, size_t in_len,
499 			   u8 **out_data, size_t *out_len)
500 {
501 	int ret = 0;
502 
503 	WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
504 	*out_len = 0;
505 	*out_data = NULL;
506 
507 	if (data->tls_out_len == 0) {
508 		/* No more data to send out - expect to receive more data from
509 		 * the AS. */
510 		int res = eap_tls_process_input(sm, data, in_data, in_len,
511 						out_data, out_len);
512 		if (res)
513 			return res;
514 	}
515 
516 	if (data->tls_out == NULL) {
517 		data->tls_out_len = 0;
518 		return -1;
519 	}
520 
521 	if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
522 		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
523 			   "report error");
524 		ret = -1;
525 		/* TODO: clean pin if engine used? */
526 	}
527 
528 	if (data->tls_out_len == 0) {
529 		/* TLS negotiation should now be complete since all other cases
530 		 * needing more data should have been caught above based on
531 		 * the TLS Message Length field. */
532 		wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
533 		os_free(data->tls_out);
534 		data->tls_out = NULL;
535 		return 1;
536 	}
537 
538 	return eap_tls_process_output(data, eap_type, peap_version, id, ret,
539 				      out_data, out_len);
540 }
541 
542 
543 /**
544  * eap_tls_build_ack - Build a TLS ACK frames
545  * @data: Data for TLS processing
546  * @respDataLen: Buffer for returning the length of the response message
547  * @id: EAP identifier for the response
548  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
549  * @peap_version: Version number for EAP-PEAP/TTLS
550  * Returns: Pointer to allocated ACK frames or %NULL on failure
551  */
eap_tls_build_ack(struct eap_ssl_data * data,size_t * respDataLen,u8 id,EapType eap_type,int peap_version)552 u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
553 		       EapType eap_type, int peap_version)
554 {
555 	struct eap_hdr *resp;
556 	u8 *pos;
557 
558 	resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, respDataLen,
559 			     1, EAP_CODE_RESPONSE, id, &pos);
560 	if (resp == NULL)
561 		return NULL;
562 	wpa_printf(MSG_DEBUG, "SSL: Building ACK");
563 	*pos = peap_version; /* Flags */
564 	return (u8 *) resp;
565 }
566 
567 
568 /**
569  * eap_tls_reauth_init - Re-initialize shared TLS for session resumption
570  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
571  * @data: Data for TLS processing
572  * Returns: 0 on success, -1 on failure
573  */
eap_tls_reauth_init(struct eap_sm * sm,struct eap_ssl_data * data)574 int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
575 {
576 	os_free(data->tls_in);
577 	data->tls_in = NULL;
578 	data->tls_in_len = data->tls_in_left = data->tls_in_total = 0;
579 	os_free(data->tls_out);
580 	data->tls_out = NULL;
581 	data->tls_out_len = data->tls_out_pos = 0;
582 
583 	return tls_connection_shutdown(sm->ssl_ctx, data->conn);
584 }
585 
586 
587 /**
588  * eap_tls_status - Get TLS status
589  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
590  * @data: Data for TLS processing
591  * @buf: Buffer for status information
592  * @buflen: Maximum buffer length
593  * @verbose: Whether to include verbose status information
594  * Returns: Number of bytes written to buf.
595  */
eap_tls_status(struct eap_sm * sm,struct eap_ssl_data * data,char * buf,size_t buflen,int verbose)596 int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
597 		   size_t buflen, int verbose)
598 {
599 	char name[128];
600 	int len = 0, ret;
601 
602 	if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
603 		ret = os_snprintf(buf + len, buflen - len,
604 				  "EAP TLS cipher=%s\n", name);
605 		if (ret < 0 || (size_t) ret >= buflen - len)
606 			return len;
607 		len += ret;
608 	}
609 
610 	return len;
611 }
612 
613 
614 /**
615  * eap_tls_process_init - Initial validation and processing of EAP requests
616  * @sm: Pointer to EAP state machine allocated with eap_sm_init()
617  * @data: Data for TLS processing
618  * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
619  * @ret: Return values from EAP request validation and processing
620  * @reqData: EAP request to be processed (eapReqData)
621  * @reqDataLen: Length of the EAP request
622  * @len: Buffer for returning length of the remaining payload
623  * @flags: Buffer for returning TLS flags
624  * Returns: Buffer to payload after TLS flags and length or %NULL on failure
625  */
eap_tls_process_init(struct eap_sm * sm,struct eap_ssl_data * data,EapType eap_type,struct eap_method_ret * ret,const u8 * reqData,size_t reqDataLen,size_t * len,u8 * flags)626 const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
627 				EapType eap_type, struct eap_method_ret *ret,
628 				const u8 *reqData, size_t reqDataLen,
629 				size_t *len, u8 *flags)
630 {
631 	const u8 *pos;
632 	size_t left;
633 	unsigned int tls_msg_len;
634 
635 	if (tls_get_errors(sm->ssl_ctx)) {
636 		wpa_printf(MSG_INFO, "SSL: TLS errors detected");
637 		ret->ignore = TRUE;
638 		return NULL;
639 	}
640 
641 	pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, reqDataLen,
642 			       &left);
643 	if (pos == NULL) {
644 		ret->ignore = TRUE;
645 		return NULL;
646 	}
647 	*flags = *pos++;
648 	left--;
649 	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
650 		   "Flags 0x%02x", (unsigned long) reqDataLen, *flags);
651 	if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
652 		if (left < 4) {
653 			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
654 				   "length");
655 			ret->ignore = TRUE;
656 			return NULL;
657 		}
658 		tls_msg_len = WPA_GET_BE32(pos);
659 		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
660 			   tls_msg_len);
661 		if (data->tls_in_left == 0) {
662 			data->tls_in_total = tls_msg_len;
663 			data->tls_in_left = tls_msg_len;
664 			os_free(data->tls_in);
665 			data->tls_in = NULL;
666 			data->tls_in_len = 0;
667 		}
668 		pos += 4;
669 		left -= 4;
670 	}
671 
672 	ret->ignore = FALSE;
673 	ret->methodState = METHOD_MAY_CONT;
674 	ret->decision = DECISION_FAIL;
675 	ret->allowNotifications = TRUE;
676 
677 	*len = (size_t) left;
678 	return pos;
679 }
680