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;