2 * WPA Supplicant / EAP-TLS/PEAP/TTLS/FAST common functions
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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.
21 #include "eap_tls_common.h"
22 #include "wpa_supplicant.h"
23 #include "config_ssid.h"
30 static int eap_tls_check_blob(struct eap_sm
*sm
, const char **name
,
31 const u8
**data
, size_t *data_len
)
33 const struct wpa_config_blob
*blob
;
35 if (*name
== NULL
|| strncmp(*name
, "blob://", 7) != 0)
38 blob
= eap_get_config_blob(sm
, *name
+ 7);
40 wpa_printf(MSG_ERROR
, "%s: Named configuration blob '%s' not "
41 "found", __func__
, *name
+ 7);
47 *data_len
= blob
->len
;
53 int eap_tls_ssl_init(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
54 struct wpa_ssid
*config
)
57 struct tls_connection_params params
;
63 data
->phase2
= sm
->init_phase2
;
64 memset(¶ms
, 0, sizeof(params
));
65 params
.engine
= config
->engine
;
67 params
.ca_cert
= (char *) config
->ca_cert2
;
68 params
.ca_path
= (char *) config
->ca_path2
;
69 params
.client_cert
= (char *) config
->client_cert2
;
70 params
.private_key
= (char *) config
->private_key2
;
71 params
.private_key_passwd
=
72 (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
;
77 params
.ca_cert
= (char *) config
->ca_cert
;
78 params
.ca_path
= (char *) config
->ca_path
;
79 params
.client_cert
= (char *) config
->client_cert
;
80 params
.private_key
= (char *) config
->private_key
;
81 params
.private_key_passwd
=
82 (char *) config
->private_key_passwd
;
83 params
.dh_file
= (char *) config
->dh_file
;
84 params
.subject_match
= (char *) config
->subject_match
;
85 params
.altsubject_match
= (char *) config
->altsubject_match
;
86 params
.engine_id
= config
->engine_id
;
87 params
.pin
= config
->pin
;
88 params
.key_id
= config
->key_id
;
91 if (eap_tls_check_blob(sm
, ¶ms
.ca_cert
, ¶ms
.ca_cert_blob
,
92 ¶ms
.ca_cert_blob_len
) ||
93 eap_tls_check_blob(sm
, ¶ms
.client_cert
,
94 ¶ms
.client_cert_blob
,
95 ¶ms
.client_cert_blob_len
) ||
96 eap_tls_check_blob(sm
, ¶ms
.private_key
,
97 ¶ms
.private_key_blob
,
98 ¶ms
.private_key_blob_len
) ||
99 eap_tls_check_blob(sm
, ¶ms
.dh_file
, ¶ms
.dh_blob
,
100 ¶ms
.dh_blob_len
)) {
101 wpa_printf(MSG_INFO
, "SSL: Failed to get configuration blobs");
105 data
->conn
= tls_connection_init(sm
->ssl_ctx
);
106 if (data
->conn
== NULL
) {
107 wpa_printf(MSG_INFO
, "SSL: Failed to initialize new TLS "
112 res
= tls_connection_set_params(sm
->ssl_ctx
, data
->conn
, ¶ms
);
113 if (res
== TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED
) {
114 /* At this point with the pkcs11 engine the PIN might be wrong.
115 * We reset the PIN in the configuration to be sure to not use
116 * it again and the calling function must request a new one */
119 } else if (res
== TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED
) {
120 wpa_printf(MSG_INFO
,"TLS: Failed to load private key");
121 /* We don't know exactly but maybe the PIN was wrong,
122 * so ask for a new one. */
125 eap_sm_request_pin(sm
, config
);
129 wpa_printf(MSG_INFO
, "TLS: Failed to set TLS connection "
134 /* TODO: make this configurable */
135 data
->tls_out_limit
= 1398;
137 /* Limit the fragment size in the inner TLS authentication
138 * since the outer authentication with EAP-PEAP does not yet
139 * support fragmentation */
140 if (data
->tls_out_limit
> 100)
141 data
->tls_out_limit
-= 100;
144 if (config
->phase1
&&
145 strstr(config
->phase1
, "include_tls_length=1")) {
146 wpa_printf(MSG_DEBUG
, "TLS: Include TLS Message Length in "
147 "unfragmented packets");
148 data
->include_tls_length
= 1;
158 void eap_tls_ssl_deinit(struct eap_sm
*sm
, struct eap_ssl_data
*data
)
160 tls_connection_deinit(sm
->ssl_ctx
, data
->conn
);
166 u8
* eap_tls_derive_key(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
167 char *label
, size_t len
)
169 struct tls_keys keys
;
173 if (tls_connection_get_keys(sm
->ssl_ctx
, data
->conn
, &keys
))
176 if (keys
.eap_tls_prf
&& strcmp(label
, "client EAP encryption") == 0) {
177 if (len
> keys
.eap_tls_prf_len
)
182 memcpy(out
, keys
.eap_tls_prf
, len
);
186 if (keys
.client_random
== NULL
|| keys
.server_random
== NULL
||
187 keys
.master_key
== NULL
)
191 rnd
= malloc(keys
.client_random_len
+ keys
.server_random_len
);
192 if (out
== NULL
|| rnd
== NULL
) {
197 memcpy(rnd
, keys
.client_random
, keys
.client_random_len
);
198 memcpy(rnd
+ keys
.client_random_len
, keys
.server_random
,
199 keys
.server_random_len
);
201 if (tls_prf(keys
.master_key
, keys
.master_key_len
,
202 label
, rnd
, keys
.client_random_len
+
203 keys
.server_random_len
, out
, len
)) {
214 * eap_tls_data_reassemble - Reassemble TLS data
215 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
216 * @data: Data for TLS processing
217 * @in_data: Next incoming TLS segment
218 * @in_len: Length of in_data
219 * @out_len: Variable for returning output data length
220 * @need_more_input: Variable for returning whether more input data is needed
221 * to reassemble this TLS packet
222 * Returns: Pointer to output data or %NULL on error
224 * This function reassembles TLS fragments.
226 const u8
* eap_tls_data_reassemble(
227 struct eap_sm
*sm
, struct eap_ssl_data
*data
, const u8
*in_data
,
228 size_t in_len
, size_t *out_len
, int *need_more_input
)
232 *need_more_input
= 0;
234 if (data
->tls_in_left
> in_len
|| data
->tls_in
) {
235 if (data
->tls_in_len
+ in_len
== 0) {
238 data
->tls_in_len
= 0;
239 wpa_printf(MSG_WARNING
, "SSL: Invalid reassembly "
240 "state: tls_in_left=%lu tls_in_len=%lu "
242 (unsigned long) data
->tls_in_left
,
243 (unsigned long) data
->tls_in_len
,
244 (unsigned long) in_len
);
247 buf
= realloc(data
->tls_in
, data
->tls_in_len
+ in_len
);
251 data
->tls_in_len
= 0;
252 wpa_printf(MSG_INFO
, "SSL: Could not allocate memory "
256 memcpy(buf
+ data
->tls_in_len
, in_data
, in_len
);
258 data
->tls_in_len
+= in_len
;
259 if (in_len
> data
->tls_in_left
) {
260 wpa_printf(MSG_INFO
, "SSL: more data than TLS message "
262 data
->tls_in_left
= 0;
265 data
->tls_in_left
-= in_len
;
266 if (data
->tls_in_left
> 0) {
267 wpa_printf(MSG_DEBUG
, "SSL: Need %lu bytes more input "
268 "data", (unsigned long) data
->tls_in_left
);
269 *need_more_input
= 1;
273 data
->tls_in_left
= 0;
274 data
->tls_in
= malloc(in_len
);
275 if (data
->tls_in
== NULL
)
277 memcpy(data
->tls_in
, in_data
, in_len
);
278 data
->tls_in_len
= in_len
;
281 *out_len
= data
->tls_in_len
;
286 int eap_tls_process_helper(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
287 int eap_type
, int peap_version
,
288 u8 id
, const u8
*in_data
, size_t in_len
,
289 u8
**out_data
, size_t *out_len
)
293 struct eap_hdr
*resp
;
296 WPA_ASSERT(data
->tls_out_len
== 0 || in_len
== 0);
299 if (data
->tls_out_len
== 0) {
300 /* No more data to send out - expect to receive more data from
306 msg
= eap_tls_data_reassemble(sm
, data
, in_data
, in_len
,
307 &msg_len
, &need_more_input
);
309 return need_more_input
? 1 : -1;
311 /* Full TLS message reassembled - continue handshake processing
314 /* This should not happen.. */
315 wpa_printf(MSG_INFO
, "SSL: eap_tls_process_helper - "
316 "pending tls_out data even though "
319 WPA_ASSERT(data
->tls_out
== NULL
);
321 data
->tls_out
= tls_connection_handshake(sm
->ssl_ctx
,
326 /* Clear reassembled input data (if the buffer was needed). */
327 data
->tls_in_left
= data
->tls_in_total
= data
->tls_in_len
= 0;
332 if (data
->tls_out
== NULL
) {
333 data
->tls_out_len
= 0;
336 if (tls_connection_get_failed(sm
->ssl_ctx
, data
->conn
)) {
337 wpa_printf(MSG_DEBUG
, "SSL: Failed - tls_out available to "
340 /* TODO: clean pin if engine used? */
343 if (data
->tls_out_len
== 0) {
344 /* TLS negotiation should now be complete since all other cases
345 * needing more that should have been catched above based on
346 * the TLS Message Length field. */
347 wpa_printf(MSG_DEBUG
, "SSL: No data to be sent out");
349 data
->tls_out
= NULL
;
353 wpa_printf(MSG_DEBUG
, "SSL: %lu bytes left to be sent out (of total "
355 (unsigned long) data
->tls_out_len
- data
->tls_out_pos
,
356 (unsigned long) data
->tls_out_len
);
357 resp
= malloc(sizeof(struct eap_hdr
) + 2 + 4 + data
->tls_out_limit
);
362 resp
->code
= EAP_CODE_RESPONSE
;
363 resp
->identifier
= id
;
364 pos
= (u8
*) (resp
+ 1);
367 *flags
= peap_version
;
368 if (data
->tls_out_pos
== 0 &&
369 (data
->tls_out_len
> data
->tls_out_limit
||
370 data
->include_tls_length
)) {
371 *flags
|= EAP_TLS_FLAGS_LENGTH_INCLUDED
;
372 *pos
++ = (data
->tls_out_len
>> 24) & 0xff;
373 *pos
++ = (data
->tls_out_len
>> 16) & 0xff;
374 *pos
++ = (data
->tls_out_len
>> 8) & 0xff;
375 *pos
++ = data
->tls_out_len
& 0xff;
378 len
= data
->tls_out_len
- data
->tls_out_pos
;
379 if (len
> data
->tls_out_limit
) {
380 *flags
|= EAP_TLS_FLAGS_MORE_FRAGMENTS
;
381 len
= data
->tls_out_limit
;
382 wpa_printf(MSG_DEBUG
, "SSL: sending %lu bytes, more fragments "
383 "will follow", (unsigned long) len
);
385 memcpy(pos
, &data
->tls_out
[data
->tls_out_pos
], len
);
386 data
->tls_out_pos
+= len
;
387 *out_len
= (pos
- (u8
*) resp
) + len
;
388 resp
->length
= host_to_be16(*out_len
);
389 *out_data
= (u8
*) resp
;
391 if (!(*flags
& EAP_TLS_FLAGS_MORE_FRAGMENTS
)) {
392 data
->tls_out_len
= 0;
393 data
->tls_out_pos
= 0;
395 data
->tls_out
= NULL
;
402 u8
* eap_tls_build_ack(struct eap_ssl_data
*data
, size_t *respDataLen
, u8 id
,
403 int eap_type
, int peap_version
)
405 struct eap_hdr
*resp
;
408 *respDataLen
= sizeof(struct eap_hdr
) + 2;
409 resp
= malloc(*respDataLen
);
412 wpa_printf(MSG_DEBUG
, "SSL: Building ACK");
413 resp
->code
= EAP_CODE_RESPONSE
;
414 resp
->identifier
= id
;
415 resp
->length
= host_to_be16(*respDataLen
);
416 pos
= (u8
*) (resp
+ 1);
417 *pos
++ = eap_type
; /* Type */
418 *pos
= peap_version
; /* Flags */
423 int eap_tls_reauth_init(struct eap_sm
*sm
, struct eap_ssl_data
*data
)
427 data
->tls_in_len
= data
->tls_in_left
= data
->tls_in_total
= 0;
429 data
->tls_out
= NULL
;
430 data
->tls_out_len
= data
->tls_out_pos
= 0;
432 return tls_connection_shutdown(sm
->ssl_ctx
, data
->conn
);
436 int eap_tls_status(struct eap_sm
*sm
, struct eap_ssl_data
*data
, char *buf
,
437 size_t buflen
, int verbose
)
442 if (tls_get_cipher(sm
->ssl_ctx
, data
->conn
, name
, sizeof(name
)) == 0) {
443 len
+= snprintf(buf
+ len
, buflen
- len
,
444 "EAP TLS cipher=%s\n", name
);
451 const u8
* eap_tls_process_init(struct eap_sm
*sm
, struct eap_ssl_data
*data
,
452 EapType eap_type
, struct eap_method_ret
*ret
,
453 const u8
*reqData
, size_t reqDataLen
,
454 size_t *len
, u8
*flags
)
456 const struct eap_hdr
*req
;
459 unsigned int tls_msg_len
;
461 if (tls_get_errors(sm
->ssl_ctx
)) {
462 wpa_printf(MSG_INFO
, "SSL: TLS errors detected");
467 pos
= eap_hdr_validate(eap_type
, reqData
, reqDataLen
, &left
);
472 req
= (const struct eap_hdr
*) reqData
;
475 wpa_printf(MSG_DEBUG
, "SSL: Received packet(len=%lu) - "
476 "Flags 0x%02x", (unsigned long) reqDataLen
, *flags
);
477 if (*flags
& EAP_TLS_FLAGS_LENGTH_INCLUDED
) {
479 wpa_printf(MSG_INFO
, "SSL: Short frame with TLS "
484 tls_msg_len
= (pos
[0] << 24) | (pos
[1] << 16) | (pos
[2] << 8) |
486 wpa_printf(MSG_DEBUG
, "SSL: TLS Message Length: %d",
488 if (data
->tls_in_left
== 0) {
489 data
->tls_in_total
= tls_msg_len
;
490 data
->tls_in_left
= tls_msg_len
;
493 data
->tls_in_len
= 0;
500 ret
->methodState
= METHOD_MAY_CONT
;
501 ret
->decision
= DECISION_FAIL
;
502 ret
->allowNotifications
= TRUE
;
504 *len
= (size_t) left
;