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;
60 data->phase2 = sm->init_phase2;
61 memset(¶ms, 0, sizeof(params));
62 params.engine = config->engine;
64 } else if (data->phase2) {
65 params.ca_cert = (char *) config->ca_cert2;
66 params.ca_path = (char *) config->ca_path2;
67 params.client_cert = (char *) config->client_cert2;
68 params.private_key = (char *) config->private_key2;
69 params.private_key_passwd =
70 (char *) config->private_key2_passwd;
71 params.dh_file = (char *) config->dh_file2;
72 params.subject_match = (char *) config->subject_match2;
73 params.altsubject_match = (char *) config->altsubject_match2;
75 params.ca_cert = (char *) config->ca_cert;
76 params.ca_path = (char *) config->ca_path;
77 params.client_cert = (char *) config->client_cert;
78 params.private_key = (char *) config->private_key;
79 params.private_key_passwd =
80 (char *) config->private_key_passwd;
81 params.dh_file = (char *) config->dh_file;
82 params.subject_match = (char *) config->subject_match;
83 params.altsubject_match = (char *) config->altsubject_match;
84 params.engine_id = config->engine_id;
85 params.pin = config->pin;
86 params.key_id = config->key_id;
89 if (eap_tls_check_blob(sm, ¶ms.ca_cert, ¶ms.ca_cert_blob,
90 ¶ms.ca_cert_blob_len) ||
91 eap_tls_check_blob(sm, ¶ms.client_cert,
92 ¶ms.client_cert_blob,
93 ¶ms.client_cert_blob_len) ||
94 eap_tls_check_blob(sm, ¶ms.private_key,
95 ¶ms.private_key_blob,
96 ¶ms.private_key_blob_len) ||
97 eap_tls_check_blob(sm, ¶ms.dh_file, ¶ms.dh_blob,
98 ¶ms.dh_blob_len)) {
99 wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
103 data->conn = tls_connection_init(sm->ssl_ctx);
104 if (data->conn == NULL) {
105 wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
110 res = tls_connection_set_params(sm->ssl_ctx, data->conn, ¶ms);
111 if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
112 /* At this point with the pkcs11 engine the PIN might be wrong.
113 * We reset the PIN in the configuration to be sure to not use
114 * it again and the calling function must request a new one */
117 } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
118 wpa_printf(MSG_INFO,"TLS: Failed to load private key");
119 /* We don't know exactly but maybe the PIN was wrong,
120 * so ask for a new one. */
123 eap_sm_request_pin(sm, config);
127 wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
132 /* TODO: make this configurable */
133 data->tls_out_limit = 1398;
135 /* Limit the fragment size in the inner TLS authentication
136 * since the outer authentication with EAP-PEAP does not yet
137 * support fragmentation */
138 if (data->tls_out_limit > 100)
139 data->tls_out_limit -= 100;
142 if (config && config->phase1 &&
143 strstr(config->phase1, "include_tls_length=1")) {
144 wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
145 "unfragmented packets");
146 data->include_tls_length = 1;
156 void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
158 tls_connection_deinit(sm->ssl_ctx, data->conn);
164 u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
165 char *label, size_t len)
167 struct tls_keys keys;
171 if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
174 if (keys.eap_tls_prf && strcmp(label, "client EAP encryption") == 0) {
175 if (len > keys.eap_tls_prf_len)
180 memcpy(out, keys.eap_tls_prf, len);
184 if (keys.client_random == NULL || keys.server_random == NULL ||
185 keys.master_key == NULL)
189 rnd = malloc(keys.client_random_len + keys.server_random_len);
190 if (out == NULL || rnd == NULL) {
195 memcpy(rnd, keys.client_random, keys.client_random_len);
196 memcpy(rnd + keys.client_random_len, keys.server_random,
197 keys.server_random_len);
199 if (tls_prf(keys.master_key, keys.master_key_len,
200 label, rnd, keys.client_random_len +
201 keys.server_random_len, out, len)) {
212 * eap_tls_data_reassemble - Reassemble TLS data
213 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
214 * @data: Data for TLS processing
215 * @in_data: Next incoming TLS segment
216 * @in_len: Length of in_data
217 * @out_len: Variable for returning output data length
218 * @need_more_input: Variable for returning whether more input data is needed
219 * to reassemble this TLS packet
220 * Returns: Pointer to output data or %NULL on error
222 * This function reassembles TLS fragments.
224 const u8 * eap_tls_data_reassemble(
225 struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data,
226 size_t in_len, size_t *out_len, int *need_more_input)
230 *need_more_input = 0;
232 if (data->tls_in_left > in_len || data->tls_in) {
233 if (data->tls_in_len + in_len == 0) {
236 data->tls_in_len = 0;
237 wpa_printf(MSG_WARNING, "SSL: Invalid reassembly "
238 "state: tls_in_left=%lu tls_in_len=%lu "
240 (unsigned long) data->tls_in_left,
241 (unsigned long) data->tls_in_len,
242 (unsigned long) in_len);
245 buf = realloc(data->tls_in, data->tls_in_len + in_len);
249 data->tls_in_len = 0;
250 wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
254 memcpy(buf + data->tls_in_len, in_data, in_len);
256 data->tls_in_len += in_len;
257 if (in_len > data->tls_in_left) {
258 wpa_printf(MSG_INFO, "SSL: more data than TLS message "
260 data->tls_in_left = 0;
263 data->tls_in_left -= in_len;
264 if (data->tls_in_left > 0) {
265 wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
266 "data", (unsigned long) data->tls_in_left);
267 *need_more_input = 1;
271 data->tls_in_left = 0;
272 data->tls_in = malloc(in_len);
273 if (data->tls_in == NULL)
275 memcpy(data->tls_in, in_data, in_len);
276 data->tls_in_len = in_len;
279 *out_len = data->tls_in_len;
284 int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
285 int eap_type, int peap_version,
286 u8 id, const u8 *in_data, size_t in_len,
287 u8 **out_data, size_t *out_len)
291 struct eap_hdr *resp;
294 WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
297 if (data->tls_out_len == 0) {
298 /* No more data to send out - expect to receive more data from
304 msg = eap_tls_data_reassemble(sm, data, in_data, in_len,
305 &msg_len, &need_more_input);
307 return need_more_input ? 1 : -1;
309 /* Full TLS message reassembled - continue handshake processing
312 /* This should not happen.. */
313 wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - "
314 "pending tls_out data even though "
317 WPA_ASSERT(data->tls_out == NULL);
319 data->tls_out = tls_connection_handshake(sm->ssl_ctx,
324 /* Clear reassembled input data (if the buffer was needed). */
325 data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
330 if (data->tls_out == NULL) {
331 data->tls_out_len = 0;
334 if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
335 wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
338 /* TODO: clean pin if engine used? */
341 if (data->tls_out_len == 0) {
342 /* TLS negotiation should now be complete since all other cases
343 * needing more that should have been catched above based on
344 * the TLS Message Length field. */
345 wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
347 data->tls_out = NULL;
351 wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
353 (unsigned long) data->tls_out_len - data->tls_out_pos,
354 (unsigned long) data->tls_out_len);
355 resp = malloc(sizeof(struct eap_hdr) + 2 + 4 + data->tls_out_limit);
360 resp->code = EAP_CODE_RESPONSE;
361 resp->identifier = id;
362 pos = (u8 *) (resp + 1);
365 *flags = peap_version;
366 if (data->tls_out_pos == 0 &&
367 (data->tls_out_len > data->tls_out_limit ||
368 data->include_tls_length)) {
369 *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
370 *pos++ = (data->tls_out_len >> 24) & 0xff;
371 *pos++ = (data->tls_out_len >> 16) & 0xff;
372 *pos++ = (data->tls_out_len >> 8) & 0xff;
373 *pos++ = data->tls_out_len & 0xff;
376 len = data->tls_out_len - data->tls_out_pos;
377 if (len > data->tls_out_limit) {
378 *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
379 len = data->tls_out_limit;
380 wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
381 "will follow", (unsigned long) len);
383 memcpy(pos, &data->tls_out[data->tls_out_pos], len);
384 data->tls_out_pos += len;
385 *out_len = (pos - (u8 *) resp) + len;
386 resp->length = host_to_be16(*out_len);
387 *out_data = (u8 *) resp;
389 if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
390 data->tls_out_len = 0;
391 data->tls_out_pos = 0;
393 data->tls_out = NULL;
400 u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
401 int eap_type, int peap_version)
403 struct eap_hdr *resp;
406 *respDataLen = sizeof(struct eap_hdr) + 2;
407 resp = malloc(*respDataLen);
410 wpa_printf(MSG_DEBUG, "SSL: Building ACK");
411 resp->code = EAP_CODE_RESPONSE;
412 resp->identifier = id;
413 resp->length = host_to_be16(*respDataLen);
414 pos = (u8 *) (resp + 1);
415 *pos++ = eap_type; /* Type */
416 *pos = peap_version; /* Flags */
421 int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
425 data->tls_in_len = data->tls_in_left = data->tls_in_total = 0;
427 data->tls_out = NULL;
428 data->tls_out_len = data->tls_out_pos = 0;
430 return tls_connection_shutdown(sm->ssl_ctx, data->conn);
434 int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
435 size_t buflen, int verbose)
440 if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
441 len += snprintf(buf + len, buflen - len,
442 "EAP TLS cipher=%s\n", name);
449 const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
450 EapType eap_type, struct eap_method_ret *ret,
451 const u8 *reqData, size_t reqDataLen,
452 size_t *len, u8 *flags)
454 const struct eap_hdr *req;
457 unsigned int tls_msg_len;
459 if (tls_get_errors(sm->ssl_ctx)) {
460 wpa_printf(MSG_INFO, "SSL: TLS errors detected");
465 pos = eap_hdr_validate(eap_type, reqData, reqDataLen, &left);
470 req = (const struct eap_hdr *) reqData;
473 wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
474 "Flags 0x%02x", (unsigned long) reqDataLen, *flags);
475 if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
477 wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
482 tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
484 wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
486 if (data->tls_in_left == 0) {
487 data->tls_in_total = tls_msg_len;
488 data->tls_in_left = tls_msg_len;
491 data->tls_in_len = 0;
498 ret->methodState = METHOD_MAY_CONT;
499 ret->decision = DECISION_FAIL;
500 ret->allowNotifications = TRUE;
502 *len = (size_t) left;