2 * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include "eap_tls_common.h"
20 #include "config_ssid.h"
27 static int eap_tls_check_blob(struct eap_sm
*sm
, const char **name
,
28 const u8
**data
, size_t *data_len
)
30 const struct wpa_config_blob
*blob
;
32 if (*name
== NULL
|| os_strncmp(*name
, "blob://", 7) != 0)
35 blob
= eap_get_config_blob(sm
, *name
+ 7);
37 wpa_printf(MSG_ERROR
, "%s: Named configuration blob '%s' not "
38 "found", __func__
, *name
+ 7);
44 *data_len
= blob
->len
;
50 static void eap_tls_params_from_conf1(struct tls_connection_params
*params
,
51 struct wpa_ssid
*config
)
53 params
->ca_cert
= (char *) config
->ca_cert
;
54 params
->ca_path
= (char *) config
->ca_path
;
55 params
->client_cert
= (char *) config
->client_cert
;
56 params
->private_key
= (char *) config
->private_key
;
57 params
->private_key_passwd
= (char *) config
->private_key_passwd
;
58 params
->dh_file
= (char *) config
->dh_file
;
59 params
->subject_match
= (char *) config
->subject_match
;
60 params
->altsubject_match
= (char *) config
->altsubject_match
;
61 params
->engine_id
= config
->engine_id
;
62 params
->pin
= config
->pin
;
63 params
->key_id
= config
->key_id
;
67 static void eap_tls_params_from_conf2(struct tls_connection_params
*params
,
68 struct wpa_ssid
*config
)
70 params
->ca_cert
= (char *) config
->ca_cert2
;
71 params
->ca_path
= (char *) config
->ca_path2
;
72 params
->client_cert
= (char *) config
->client_cert2
;
73 params
->private_key
= (char *) config
->private_key2
;
74 params
->private_key_passwd
= (char *) config
->private_key2_passwd
;
75 params
->dh_file
= (char *) config
->dh_file2
;
76 params
->subject_match
= (char *) config
->subject_match2
;
77 params
->altsubject_match
= (char *) config
->altsubject_match2
;
81 static int eap_tls_params_from_conf(struct eap_sm
*sm
,
82 struct eap_ssl_data
*data
,
83 struct tls_connection_params
*params
,
84 struct wpa_ssid
*config
, int phase2
)
86 os_memset(params
, 0, sizeof(*params
));
87 params
->engine
= config
->engine
;
89 eap_tls_params_from_conf2(params
, config
);
91 eap_tls_params_from_conf1(params
, config
);
92 params
->tls_ia
= data
->tls_ia
;
95 if (eap_tls_check_blob(sm
, ¶ms
->ca_cert
, ¶ms
->ca_cert_blob
,
96 ¶ms
->ca_cert_blob_len
) ||
97 eap_tls_check_blob(sm
, ¶ms
->client_cert
,
98 ¶ms
->client_cert_blob
,
99 ¶ms
->client_cert_blob_len
) ||
100 eap_tls_check_blob(sm
, ¶ms
->private_key
,
101 ¶ms
->private_key_blob
,
102 ¶ms
->private_key_blob_len
) ||
103 eap_tls_check_blob(sm
, ¶ms
->dh_file
, ¶ms
->dh_blob
,
104 ¶ms
->dh_blob_len
)) {
105 wpa_printf(MSG_INFO
, "SSL: Failed to get configuration blobs");
113 static int eap_tls_init_connection(struct eap_sm
*sm
,
114 struct eap_ssl_data
*data
,
115 struct wpa_ssid
*config
,
116 struct tls_connection_params
*params
)
120 data
->conn
= tls_connection_init(sm
->ssl_ctx
);
121 if (data
->conn
== NULL
) {
122 wpa_printf(MSG_INFO
, "SSL: Failed to initialize new TLS "
127 res
= tls_connection_set_params(sm
->ssl_ctx
, data
->conn
, params
);
128 if (res
== TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED
) {
129 /* At this point with the pkcs11 engine the PIN might be wrong.
130 * We reset the PIN in the configuration to be sure to not use
131 * it again and the calling function must request a new one */
132 os_free(config
->pin
);
134 } else if (res
== TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED
) {
135 wpa_printf(MSG_INFO
, "TLS: Failed to load private key");
136 /* We don't know exactly but maybe the PIN was wrong,
137 * so ask for a new one. */
138 os_free(config
->pin
);
140 eap_sm_request_pin(sm
);
144 wpa_printf(MSG_INFO
, "TLS: Failed to set TLS connection "
154 * eap_tls_ssl_init - Initialize shared TLS functionality
155 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
156 * @data: Data for TLS processing
157 * @config: Pointer to the network configuration
158 * Returns: 0 on success, -1 on failure
160 * This function is used to initialize shared TLS functionality for EAP-TLS,
161 * EAP-PEAP, EAP-TTLS, and EAP-FAST.
163 int eap_tls_ssl_init(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
164 struct wpa_ssid
*config
)
167 struct tls_connection_params params
;
173 data
->phase2
= sm
->init_phase2
;
174 if (eap_tls_params_from_conf(sm
, data
, ¶ms
, config
, data
->phase2
) <
178 if (eap_tls_init_connection(sm
, data
, config
, ¶ms
) < 0)
181 data
->tls_out_limit
= config
->fragment_size
;
183 /* Limit the fragment size in the inner TLS authentication
184 * since the outer authentication with EAP-PEAP does not yet
185 * support fragmentation */
186 if (data
->tls_out_limit
> 100)
187 data
->tls_out_limit
-= 100;
190 if (config
->phase1
&&
191 os_strstr(config
->phase1
, "include_tls_length=1")) {
192 wpa_printf(MSG_DEBUG
, "TLS: Include TLS Message Length in "
193 "unfragmented packets");
194 data
->include_tls_length
= 1;
205 * eap_tls_ssl_deinit - Deinitialize shared TLS functionality
206 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
207 * @data: Data for TLS processing
209 * This function deinitializes shared TLS functionality that was initialized
210 * with eap_tls_ssl_init().
212 void eap_tls_ssl_deinit(struct eap_sm
*sm
, struct eap_ssl_data
*data
)
214 tls_connection_deinit(sm
->ssl_ctx
, data
->conn
);
215 os_free(data
->tls_in
);
216 os_free(data
->tls_out
);
221 * eap_tls_derive_key - Derive a key based on TLS session data
222 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
223 * @data: Data for TLS processing
224 * @label: Label string for deriving the keys, e.g., "client EAP encryption"
225 * @len: Length of the key material to generate (usually 64 for MSK)
226 * Returns: Pointer to allocated key on success or %NULL on failure
228 * This function uses TLS-PRF to generate pseudo-random data based on the TLS
229 * session data (client/server random and master key). Each key type may use a
230 * different label to bind the key usage into the generated material.
232 * The caller is responsible for freeing the returned buffer.
234 u8
* eap_tls_derive_key(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
235 const char *label
, size_t len
)
237 struct tls_keys keys
;
238 u8
*rnd
= NULL
, *out
;
240 out
= os_malloc(len
);
244 /* First, try to use TLS library function for PRF, if available. */
245 if (tls_connection_prf(sm
->ssl_ctx
, data
->conn
, label
, 0, out
, len
) ==
250 * TLS library did not support key generation, so get the needed TLS
251 * session parameters and use an internal implementation of TLS PRF to
254 if (tls_connection_get_keys(sm
->ssl_ctx
, data
->conn
, &keys
))
257 if (keys
.client_random
== NULL
|| keys
.server_random
== NULL
||
258 keys
.master_key
== NULL
)
261 rnd
= os_malloc(keys
.client_random_len
+ keys
.server_random_len
);
264 os_memcpy(rnd
, keys
.client_random
, keys
.client_random_len
);
265 os_memcpy(rnd
+ keys
.client_random_len
, keys
.server_random
,
266 keys
.server_random_len
);
268 if (tls_prf(keys
.master_key
, keys
.master_key_len
,
269 label
, rnd
, keys
.client_random_len
+
270 keys
.server_random_len
, out
, len
))
284 * eap_tls_data_reassemble - Reassemble TLS data
285 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
286 * @data: Data for TLS processing
287 * @in_data: Next incoming TLS segment
288 * @in_len: Length of in_data
289 * @out_len: Variable for returning output data length
290 * @need_more_input: Variable for returning whether more input data is needed
291 * to reassemble this TLS packet
292 * Returns: Pointer to output data, %NULL on error or when more data is needed
293 * for the full message (in which case, *need_more_input is also set to 1).
295 * This function reassembles TLS fragments. Caller must not free the returned
296 * data buffer since an internal pointer to it is maintained.
298 const u8
* eap_tls_data_reassemble(
299 struct eap_sm
*sm
, struct eap_ssl_data
*data
, const u8
*in_data
,
300 size_t in_len
, size_t *out_len
, int *need_more_input
)
304 *need_more_input
= 0;
306 if (data
->tls_in_left
> in_len
|| data
->tls_in
) {
307 if (data
->tls_in_len
+ in_len
== 0) {
308 os_free(data
->tls_in
);
310 data
->tls_in_len
= 0;
311 wpa_printf(MSG_WARNING
, "SSL: Invalid reassembly "
312 "state: tls_in_left=%lu tls_in_len=%lu "
314 (unsigned long) data
->tls_in_left
,
315 (unsigned long) data
->tls_in_len
,
316 (unsigned long) in_len
);
319 if (data
->tls_in_len
+ in_len
> 65536) {
320 /* Limit length to avoid rogue servers from causing
321 * large memory allocations. */
322 os_free(data
->tls_in
);
324 data
->tls_in_len
= 0;
325 wpa_printf(MSG_INFO
, "SSL: Too long TLS fragment (size"
329 buf
= os_realloc(data
->tls_in
, data
->tls_in_len
+ in_len
);
331 os_free(data
->tls_in
);
333 data
->tls_in_len
= 0;
334 wpa_printf(MSG_INFO
, "SSL: Could not allocate memory "
338 os_memcpy(buf
+ data
->tls_in_len
, in_data
, in_len
);
340 data
->tls_in_len
+= in_len
;
341 if (in_len
> data
->tls_in_left
) {
342 wpa_printf(MSG_INFO
, "SSL: more data than TLS message "
344 data
->tls_in_left
= 0;
347 data
->tls_in_left
-= in_len
;
348 if (data
->tls_in_left
> 0) {
349 wpa_printf(MSG_DEBUG
, "SSL: Need %lu bytes more input "
350 "data", (unsigned long) data
->tls_in_left
);
351 *need_more_input
= 1;
355 data
->tls_in_left
= 0;
356 data
->tls_in
= os_malloc(in_len
? in_len
: 1);
357 if (data
->tls_in
== NULL
)
359 os_memcpy(data
->tls_in
, in_data
, in_len
);
360 data
->tls_in_len
= in_len
;
363 *out_len
= data
->tls_in_len
;
368 static int eap_tls_process_input(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
369 const u8
*in_data
, size_t in_len
,
370 u8
**out_data
, size_t *out_len
)
376 size_t appl_data_len
;
378 msg
= eap_tls_data_reassemble(sm
, data
, in_data
, in_len
,
379 &msg_len
, &need_more_input
);
381 return need_more_input
? 1 : -1;
383 /* Full TLS message reassembled - continue handshake processing */
385 /* This should not happen.. */
386 wpa_printf(MSG_INFO
, "SSL: eap_tls_process_helper - pending "
387 "tls_out data even though tls_out_len = 0");
388 os_free(data
->tls_out
);
389 WPA_ASSERT(data
->tls_out
== NULL
);
392 data
->tls_out
= tls_connection_handshake(sm
->ssl_ctx
, data
->conn
,
395 &appl_data
, &appl_data_len
);
397 /* Clear reassembled input data (if the buffer was needed). */
398 data
->tls_in_left
= data
->tls_in_total
= data
->tls_in_len
= 0;
399 os_free(data
->tls_in
);
403 tls_connection_established(sm
->ssl_ctx
, data
->conn
) &&
404 !tls_connection_get_failed(sm
->ssl_ctx
, data
->conn
)) {
405 wpa_hexdump_key(MSG_MSGDUMP
, "SSL: Application data",
406 appl_data
, appl_data_len
);
407 *out_data
= appl_data
;
408 *out_len
= appl_data_len
;
418 static int eap_tls_process_output(struct eap_ssl_data
*data
, EapType eap_type
,
419 int peap_version
, u8 id
, int ret
,
420 u8
**out_data
, size_t *out_len
)
424 int more_fragments
, length_included
;
426 wpa_printf(MSG_DEBUG
, "SSL: %lu bytes left to be sent out (of total "
428 (unsigned long) data
->tls_out_len
- data
->tls_out_pos
,
429 (unsigned long) data
->tls_out_len
);
431 len
= data
->tls_out_len
- data
->tls_out_pos
;
432 if (len
> data
->tls_out_limit
) {
434 len
= data
->tls_out_limit
;
435 wpa_printf(MSG_DEBUG
, "SSL: sending %lu bytes, more fragments "
436 "will follow", (unsigned long) len
);
440 length_included
= data
->tls_out_pos
== 0 &&
441 (data
->tls_out_len
> data
->tls_out_limit
||
442 data
->include_tls_length
);
445 eap_msg_alloc(EAP_VENDOR_IETF
, eap_type
, out_len
,
446 1 + length_included
* 4 + len
, EAP_CODE_RESPONSE
,
448 if (*out_data
== NULL
)
452 *flags
= peap_version
;
454 *flags
|= EAP_TLS_FLAGS_MORE_FRAGMENTS
;
455 if (length_included
) {
456 *flags
|= EAP_TLS_FLAGS_LENGTH_INCLUDED
;
457 WPA_PUT_BE32(pos
, data
->tls_out_len
);
461 os_memcpy(pos
, &data
->tls_out
[data
->tls_out_pos
], len
);
462 data
->tls_out_pos
+= len
;
464 if (!more_fragments
) {
465 data
->tls_out_len
= 0;
466 data
->tls_out_pos
= 0;
467 os_free(data
->tls_out
);
468 data
->tls_out
= NULL
;
476 * eap_tls_process_helper - Process TLS handshake message
477 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
478 * @data: Data for TLS processing
479 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
480 * @peap_version: Version number for EAP-PEAP/TTLS
481 * @id: EAP identifier for the response
482 * @in_data: Message received from the server
483 * @in_len: Length of in_data
484 * @out_data: Buffer for returning a pointer to the response message
485 * @out_len: Buffer for returning the length of the response message
486 * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
488 * This function can be used to process TLS handshake messages. It reassembles
489 * the received fragments and uses a TLS library to process the messages. The
490 * response data from the TLS library is fragmented to suitable output messages
491 * that the caller can send out.
493 * out_data is used to return the response message if the return value of this
494 * function is 0 or -1. In case of failure, the message is likely a TLS alarm
495 * message. The caller is responsible for freeing the allocated buffer if
496 * *out_data is not %NULL.
498 int eap_tls_process_helper(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
499 EapType eap_type
, int peap_version
,
500 u8 id
, const u8
*in_data
, size_t in_len
,
501 u8
**out_data
, size_t *out_len
)
505 WPA_ASSERT(data
->tls_out_len
== 0 || in_len
== 0);
509 if (data
->tls_out_len
== 0) {
510 /* No more data to send out - expect to receive more data from
512 int res
= eap_tls_process_input(sm
, data
, in_data
, in_len
,
518 if (data
->tls_out
== NULL
) {
519 data
->tls_out_len
= 0;
523 if (tls_connection_get_failed(sm
->ssl_ctx
, data
->conn
)) {
524 wpa_printf(MSG_DEBUG
, "SSL: Failed - tls_out available to "
527 /* TODO: clean pin if engine used? */
530 if (data
->tls_out_len
== 0) {
531 /* TLS negotiation should now be complete since all other cases
532 * needing more data should have been caught above based on
533 * the TLS Message Length field. */
534 wpa_printf(MSG_DEBUG
, "SSL: No data to be sent out");
535 os_free(data
->tls_out
);
536 data
->tls_out
= NULL
;
540 return eap_tls_process_output(data
, eap_type
, peap_version
, id
, ret
,
546 * eap_tls_build_ack - Build a TLS ACK frames
547 * @data: Data for TLS processing
548 * @respDataLen: Buffer for returning the length of the response message
549 * @id: EAP identifier for the response
550 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
551 * @peap_version: Version number for EAP-PEAP/TTLS
552 * Returns: Pointer to allocated ACK frames or %NULL on failure
554 u8
* eap_tls_build_ack(struct eap_ssl_data
*data
, size_t *respDataLen
, u8 id
,
555 EapType eap_type
, int peap_version
)
557 struct eap_hdr
*resp
;
560 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, eap_type
, respDataLen
,
561 1, EAP_CODE_RESPONSE
, id
, &pos
);
564 wpa_printf(MSG_DEBUG
, "SSL: Building ACK");
565 *pos
= peap_version
; /* Flags */
571 * eap_tls_reauth_init - Re-initialize shared TLS for session resumption
572 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
573 * @data: Data for TLS processing
574 * Returns: 0 on success, -1 on failure
576 int eap_tls_reauth_init(struct eap_sm
*sm
, struct eap_ssl_data
*data
)
578 os_free(data
->tls_in
);
580 data
->tls_in_len
= data
->tls_in_left
= data
->tls_in_total
= 0;
581 os_free(data
->tls_out
);
582 data
->tls_out
= NULL
;
583 data
->tls_out_len
= data
->tls_out_pos
= 0;
585 return tls_connection_shutdown(sm
->ssl_ctx
, data
->conn
);
590 * eap_tls_status - Get TLS status
591 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
592 * @data: Data for TLS processing
593 * @buf: Buffer for status information
594 * @buflen: Maximum buffer length
595 * @verbose: Whether to include verbose status information
596 * Returns: Number of bytes written to buf.
598 int eap_tls_status(struct eap_sm
*sm
, struct eap_ssl_data
*data
, char *buf
,
599 size_t buflen
, int verbose
)
604 if (tls_get_cipher(sm
->ssl_ctx
, data
->conn
, name
, sizeof(name
)) == 0) {
605 ret
= os_snprintf(buf
+ len
, buflen
- len
,
606 "EAP TLS cipher=%s\n", name
);
607 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
617 * eap_tls_process_init - Initial validation and processing of EAP requests
618 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
619 * @data: Data for TLS processing
620 * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
621 * @ret: Return values from EAP request validation and processing
622 * @reqData: EAP request to be processed (eapReqData)
623 * @reqDataLen: Length of the EAP request
624 * @len: Buffer for returning length of the remaining payload
625 * @flags: Buffer for returning TLS flags
626 * Returns: Buffer to payload after TLS flags and length or %NULL on failure
628 const u8
* eap_tls_process_init(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
629 EapType eap_type
, struct eap_method_ret
*ret
,
630 const u8
*reqData
, size_t reqDataLen
,
631 size_t *len
, u8
*flags
)
635 unsigned int tls_msg_len
;
637 if (tls_get_errors(sm
->ssl_ctx
)) {
638 wpa_printf(MSG_INFO
, "SSL: TLS errors detected");
643 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, eap_type
, reqData
, reqDataLen
,
651 wpa_printf(MSG_DEBUG
, "SSL: Received packet(len=%lu) - "
652 "Flags 0x%02x", (unsigned long) reqDataLen
, *flags
);
653 if (*flags
& EAP_TLS_FLAGS_LENGTH_INCLUDED
) {
655 wpa_printf(MSG_INFO
, "SSL: Short frame with TLS "
660 tls_msg_len
= WPA_GET_BE32(pos
);
661 wpa_printf(MSG_DEBUG
, "SSL: TLS Message Length: %d",
663 if (data
->tls_in_left
== 0) {
664 data
->tls_in_total
= tls_msg_len
;
665 data
->tls_in_left
= tls_msg_len
;
666 os_free(data
->tls_in
);
668 data
->tls_in_len
= 0;
675 ret
->methodState
= METHOD_MAY_CONT
;
676 ret
->decision
= DECISION_FAIL
;
677 ret
->allowNotifications
= TRUE
;
679 *len
= (size_t) left
;