Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * WPA Supplicant / SSL/TLS interface functions for openssl
      3  * Copyright (c) 2004-2007, Jouni Malinen <j (at) 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 #include <gnutls/gnutls.h>
     17 #include <gnutls/x509.h>
     18 #ifdef PKCS12_FUNCS
     19 #include <gnutls/pkcs12.h>
     20 #endif /* PKCS12_FUNCS */
     21 
     22 #ifdef CONFIG_GNUTLS_EXTRA
     23 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
     24 #define GNUTLS_IA
     25 #include <gnutls/extra.h>
     26 #if LIBGNUTLS_VERSION_NUMBER == 0x010302
     27 /* This function is not included in the current gnutls/extra.h even though it
     28  * should be, so define it here as a workaround for the time being. */
     29 int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
     30 #endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
     31 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
     32 #endif /* CONFIG_GNUTLS_EXTRA */
     33 
     34 #include "common.h"
     35 #include "tls.h"
     36 
     37 
     38 #define TLS_RANDOM_SIZE 32
     39 #define TLS_MASTER_SIZE 48
     40 
     41 
     42 #if LIBGNUTLS_VERSION_NUMBER < 0x010302
     43 /* GnuTLS 1.3.2 added functions for using master secret. Older versions require
     44  * use of internal structures to get the master_secret and
     45  * {server,client}_random.
     46  */
     47 #define GNUTLS_INTERNAL_STRUCTURE_HACK
     48 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
     49 
     50 
     51 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
     52 /*
     53  * It looks like gnutls does not provide access to client/server_random and
     54  * master_key. This is somewhat unfortunate since these are needed for key
     55  * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
     56  * hack that copies the gnutls_session_int definition from gnutls_int.h so that
     57  * we can get the needed information.
     58  */
     59 
     60 typedef u8 uint8;
     61 typedef unsigned char opaque;
     62 typedef struct {
     63     uint8 suite[2];
     64 } cipher_suite_st;
     65 
     66 typedef struct {
     67 	gnutls_connection_end_t entity;
     68 	gnutls_kx_algorithm_t kx_algorithm;
     69 	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
     70 	gnutls_mac_algorithm_t read_mac_algorithm;
     71 	gnutls_compression_method_t read_compression_algorithm;
     72 	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
     73 	gnutls_mac_algorithm_t write_mac_algorithm;
     74 	gnutls_compression_method_t write_compression_algorithm;
     75 	cipher_suite_st current_cipher_suite;
     76 	opaque master_secret[TLS_MASTER_SIZE];
     77 	opaque client_random[TLS_RANDOM_SIZE];
     78 	opaque server_random[TLS_RANDOM_SIZE];
     79 	/* followed by stuff we are not interested in */
     80 } security_parameters_st;
     81 
     82 struct gnutls_session_int {
     83 	security_parameters_st security_parameters;
     84 	/* followed by things we are not interested in */
     85 };
     86 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
     87 
     88 static int tls_gnutls_ref_count = 0;
     89 
     90 struct tls_global {
     91 	/* Data for session resumption */
     92 	void *session_data;
     93 	size_t session_data_size;
     94 
     95 	int server;
     96 
     97 	int params_set;
     98 	gnutls_certificate_credentials_t xcred;
     99 };
    100 
    101 struct tls_connection {
    102 	gnutls_session session;
    103 	char *subject_match, *altsubject_match;
    104 	int read_alerts, write_alerts, failed;
    105 
    106 	u8 *pre_shared_secret;
    107 	size_t pre_shared_secret_len;
    108 	int established;
    109 	int verify_peer;
    110 
    111 	u8 *push_buf, *pull_buf, *pull_buf_offset;
    112 	size_t push_buf_len, pull_buf_len;
    113 
    114 	int params_set;
    115 	gnutls_certificate_credentials_t xcred;
    116 
    117 	int tls_ia;
    118 	int final_phase_finished;
    119 
    120 #ifdef GNUTLS_IA
    121 	gnutls_ia_server_credentials_t iacred_srv;
    122 	gnutls_ia_client_credentials_t iacred_cli;
    123 
    124 	/* Session keys generated in the current phase for inner secret
    125 	 * permutation before generating/verifying PhaseFinished. */
    126 	u8 *session_keys;
    127 	size_t session_keys_len;
    128 
    129 	u8 inner_secret[TLS_MASTER_SIZE];
    130 #endif /* GNUTLS_IA */
    131 };
    132 
    133 
    134 static void tls_log_func(int level, const char *msg)
    135 {
    136 	char *s, *pos;
    137 	if (level == 6 || level == 7) {
    138 		/* These levels seem to be mostly I/O debug and msg dumps */
    139 		return;
    140 	}
    141 
    142 	s = os_strdup(msg);
    143 	if (s == NULL)
    144 		return;
    145 
    146 	pos = s;
    147 	while (*pos != '\0') {
    148 		if (*pos == '\n') {
    149 			*pos = '\0';
    150 			break;
    151 		}
    152 		pos++;
    153 	}
    154 	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
    155 		   "gnutls<%d> %s", level, s);
    156 	os_free(s);
    157 }
    158 
    159 
    160 extern int wpa_debug_show_keys;
    161 
    162 void * tls_init(const struct tls_config *conf)
    163 {
    164 	struct tls_global *global;
    165 
    166 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
    167 	/* Because of the horrible hack to get master_secret and client/server
    168 	 * random, we need to make sure that the gnutls version is something
    169 	 * that is expected to have same structure definition for the session
    170 	 * data.. */
    171 	const char *ver;
    172 	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
    173 				 "1.3.2",
    174 				 NULL };
    175 	int i;
    176 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
    177 
    178 	global = os_zalloc(sizeof(*global));
    179 	if (global == NULL)
    180 		return NULL;
    181 
    182 	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
    183 		os_free(global);
    184 		return NULL;
    185 	}
    186 	tls_gnutls_ref_count++;
    187 
    188 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
    189 	ver = gnutls_check_version(NULL);
    190 	if (ver == NULL) {
    191 		tls_deinit(global);
    192 		return NULL;
    193 	}
    194 	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
    195 	for (i = 0; ok_ver[i]; i++) {
    196 		if (strcmp(ok_ver[i], ver) == 0)
    197 			break;
    198 	}
    199 	if (ok_ver[i] == NULL) {
    200 		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
    201 			   "to be tested and enabled in tls_gnutls.c", ver);
    202 		tls_deinit(global);
    203 		return NULL;
    204 	}
    205 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
    206 
    207 	gnutls_global_set_log_function(tls_log_func);
    208 	if (wpa_debug_show_keys)
    209 		gnutls_global_set_log_level(11);
    210 	return global;
    211 }
    212 
    213 
    214 void tls_deinit(void *ssl_ctx)
    215 {
    216 	struct tls_global *global = ssl_ctx;
    217 	if (global) {
    218 		if (global->params_set)
    219 			gnutls_certificate_free_credentials(global->xcred);
    220 		os_free(global->session_data);
    221 		os_free(global);
    222 	}
    223 
    224 	tls_gnutls_ref_count--;
    225 	if (tls_gnutls_ref_count == 0)
    226 		gnutls_global_deinit();
    227 }
    228 
    229 
    230 int tls_get_errors(void *ssl_ctx)
    231 {
    232 	return 0;
    233 }
    234 
    235 
    236 static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
    237 			     size_t len)
    238 {
    239 	struct tls_connection *conn = (struct tls_connection *) ptr;
    240 	u8 *end;
    241 	if (conn->pull_buf == NULL) {
    242 		errno = EWOULDBLOCK;
    243 		return -1;
    244 	}
    245 
    246 	end = conn->pull_buf + conn->pull_buf_len;
    247 	if ((size_t) (end - conn->pull_buf_offset) < len)
    248 		len = end - conn->pull_buf_offset;
    249 	os_memcpy(buf, conn->pull_buf_offset, len);
    250 	conn->pull_buf_offset += len;
    251 	if (conn->pull_buf_offset == end) {
    252 		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
    253 		os_free(conn->pull_buf);
    254 		conn->pull_buf = conn->pull_buf_offset = NULL;
    255 		conn->pull_buf_len = 0;
    256 	} else {
    257 		wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in pull_buf",
    258 			   __func__, end - conn->pull_buf_offset);
    259 	}
    260 	return len;
    261 }
    262 
    263 
    264 static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
    265 			     size_t len)
    266 {
    267 	struct tls_connection *conn = (struct tls_connection *) ptr;
    268 	u8 *nbuf;
    269 
    270 	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len);
    271 	if (nbuf == NULL) {
    272 		errno = ENOMEM;
    273 		return -1;
    274 	}
    275 	os_memcpy(nbuf + conn->push_buf_len, buf, len);
    276 	conn->push_buf = nbuf;
    277 	conn->push_buf_len += len;
    278 
    279 	return len;
    280 }
    281 
    282 
    283 static int tls_gnutls_init_session(struct tls_global *global,
    284 				   struct tls_connection *conn)
    285 {
    286 	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
    287 	const int protos[2] = { GNUTLS_TLS1, 0 };
    288 	int ret;
    289 
    290 	ret = gnutls_init(&conn->session,
    291 			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
    292 	if (ret < 0) {
    293 		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
    294 			   "connection: %s", gnutls_strerror(ret));
    295 		return -1;
    296 	}
    297 
    298 	ret = gnutls_set_default_priority(conn->session);
    299 	if (ret < 0)
    300 		goto fail;
    301 
    302 	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
    303 	if (ret < 0)
    304 		goto fail;
    305 
    306 	ret = gnutls_protocol_set_priority(conn->session, protos);
    307 	if (ret < 0)
    308 		goto fail;
    309 
    310 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
    311 	gnutls_transport_set_push_function(conn->session, tls_push_func);
    312 	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
    313 
    314 	return 0;
    315 
    316 fail:
    317 	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
    318 		   gnutls_strerror(ret));
    319 	gnutls_deinit(conn->session);
    320 	return -1;
    321 }
    322 
    323 
    324 struct tls_connection * tls_connection_init(void *ssl_ctx)
    325 {
    326 	struct tls_global *global = ssl_ctx;
    327 	struct tls_connection *conn;
    328 	int ret;
    329 
    330 	conn = os_zalloc(sizeof(*conn));
    331 	if (conn == NULL)
    332 		return NULL;
    333 
    334 	if (tls_gnutls_init_session(global, conn)) {
    335 		os_free(conn);
    336 		return NULL;
    337 	}
    338 
    339 	if (global->params_set) {
    340 		ret = gnutls_credentials_set(conn->session,
    341 					     GNUTLS_CRD_CERTIFICATE,
    342 					     global->xcred);
    343 		if (ret < 0) {
    344 			wpa_printf(MSG_INFO, "Failed to configure "
    345 				   "credentials: %s", gnutls_strerror(ret));
    346 			os_free(conn);
    347 			return NULL;
    348 		}
    349 	}
    350 
    351 	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
    352 		os_free(conn);
    353 		return NULL;
    354 	}
    355 
    356 	return conn;
    357 }
    358 
    359 
    360 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
    361 {
    362 	if (conn == NULL)
    363 		return;
    364 
    365 #ifdef GNUTLS_IA
    366 	if (conn->iacred_srv)
    367 		gnutls_ia_free_server_credentials(conn->iacred_srv);
    368 	if (conn->iacred_cli)
    369 		gnutls_ia_free_client_credentials(conn->iacred_cli);
    370 	if (conn->session_keys) {
    371 		os_memset(conn->session_keys, 0, conn->session_keys_len);
    372 		os_free(conn->session_keys);
    373 	}
    374 #endif /* GNUTLS_IA */
    375 
    376 	gnutls_certificate_free_credentials(conn->xcred);
    377 	gnutls_deinit(conn->session);
    378 	os_free(conn->pre_shared_secret);
    379 	os_free(conn->subject_match);
    380 	os_free(conn->altsubject_match);
    381 	os_free(conn->push_buf);
    382 	os_free(conn->pull_buf);
    383 	os_free(conn);
    384 }
    385 
    386 
    387 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
    388 {
    389 	return conn ? conn->established : 0;
    390 }
    391 
    392 
    393 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
    394 {
    395 	struct tls_global *global = ssl_ctx;
    396 	int ret;
    397 
    398 	if (conn == NULL)
    399 		return -1;
    400 
    401 	/* Shutdown previous TLS connection without notifying the peer
    402 	 * because the connection was already terminated in practice
    403 	 * and "close notify" shutdown alert would confuse AS. */
    404 	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
    405 	os_free(conn->push_buf);
    406 	conn->push_buf = NULL;
    407 	conn->push_buf_len = 0;
    408 	conn->established = 0;
    409 	conn->final_phase_finished = 0;
    410 #ifdef GNUTLS_IA
    411 	if (conn->session_keys) {
    412 		os_memset(conn->session_keys, 0, conn->session_keys_len);
    413 		os_free(conn->session_keys);
    414 	}
    415 	conn->session_keys_len = 0;
    416 #endif /* GNUTLS_IA */
    417 
    418 	gnutls_deinit(conn->session);
    419 	if (tls_gnutls_init_session(global, conn)) {
    420 		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
    421 			   "for session resumption use");
    422 		return -1;
    423 	}
    424 
    425 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
    426 				     conn->params_set ? conn->xcred :
    427 				     global->xcred);
    428 	if (ret < 0) {
    429 		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
    430 			   "for session resumption: %s", gnutls_strerror(ret));
    431 		return -1;
    432 	}
    433 
    434 	if (global->session_data) {
    435 		ret = gnutls_session_set_data(conn->session,
    436 					      global->session_data,
    437 					      global->session_data_size);
    438 		if (ret < 0) {
    439 			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
    440 				   "data: %s", gnutls_strerror(ret));
    441 			return -1;
    442 		}
    443 	}
    444 
    445 	return 0;
    446 }
    447 
    448 
    449 #if 0
    450 static int tls_match_altsubject(X509 *cert, const char *match)
    451 {
    452 	GENERAL_NAME *gen;
    453 	char *field, *tmp;
    454 	void *ext;
    455 	int i, found = 0;
    456 	size_t len;
    457 
    458 	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
    459 
    460 	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
    461 		gen = sk_GENERAL_NAME_value(ext, i);
    462 		switch (gen->type) {
    463 		case GEN_EMAIL:
    464 			field = "EMAIL";
    465 			break;
    466 		case GEN_DNS:
    467 			field = "DNS";
    468 			break;
    469 		case GEN_URI:
    470 			field = "URI";
    471 			break;
    472 		default:
    473 			field = NULL;
    474 			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
    475 				   "unsupported type=%d", gen->type);
    476 			break;
    477 		}
    478 
    479 		if (!field)
    480 			continue;
    481 
    482 		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
    483 			   field, gen->d.ia5->data);
    484 		len = os_strlen(field) + 1 +
    485 			strlen((char *) gen->d.ia5->data) + 1;
    486 		tmp = os_malloc(len);
    487 		if (tmp == NULL)
    488 			continue;
    489 		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
    490 		if (strstr(tmp, match))
    491 			found++;
    492 		os_free(tmp);
    493 	}
    494 
    495 	return found;
    496 }
    497 #endif
    498 
    499 
    500 #if 0
    501 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
    502 {
    503 	char buf[256];
    504 	X509 *err_cert;
    505 	int err, depth;
    506 	SSL *ssl;
    507 	struct tls_connection *conn;
    508 	char *match, *altmatch;
    509 
    510 	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
    511 	err = X509_STORE_CTX_get_error(x509_ctx);
    512 	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
    513 	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
    514 					 SSL_get_ex_data_X509_STORE_CTX_idx());
    515 	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
    516 
    517 	conn = SSL_get_app_data(ssl);
    518 	match = conn ? conn->subject_match : NULL;
    519 	altmatch = conn ? conn->altsubject_match : NULL;
    520 
    521 	if (!preverify_ok) {
    522 		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
    523 			   " error %d (%s) depth %d for '%s'", err,
    524 			   X509_verify_cert_error_string(err), depth, buf);
    525 	} else {
    526 		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
    527 			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
    528 			   preverify_ok, err,
    529 			   X509_verify_cert_error_string(err), depth, buf);
    530 		if (depth == 0 && match && strstr(buf, match) == NULL) {
    531 			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
    532 				   "match with '%s'", buf, match);
    533 			preverify_ok = 0;
    534 		} else if (depth == 0 && altmatch &&
    535 			   !tls_match_altsubject(err_cert, altmatch)) {
    536 			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
    537 				   "'%s' not found", altmatch);
    538 			preverify_ok = 0;
    539 		}
    540 	}
    541 
    542 	return preverify_ok;
    543 }
    544 #endif
    545 
    546 
    547 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
    548 			      const struct tls_connection_params *params)
    549 {
    550 	int ret;
    551 
    552 	if (conn == NULL || params == NULL)
    553 		return -1;
    554 
    555 	os_free(conn->subject_match);
    556 	conn->subject_match = NULL;
    557 	if (params->subject_match) {
    558 		conn->subject_match = os_strdup(params->subject_match);
    559 		if (conn->subject_match == NULL)
    560 			return -1;
    561 	}
    562 
    563 	os_free(conn->altsubject_match);
    564 	conn->altsubject_match = NULL;
    565 	if (params->altsubject_match) {
    566 		conn->altsubject_match = os_strdup(params->altsubject_match);
    567 		if (conn->altsubject_match == NULL)
    568 			return -1;
    569 	}
    570 
    571 	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
    572 	 * to force peer validation(?) */
    573 
    574 	if (params->ca_cert) {
    575 		conn->verify_peer = 1;
    576 		ret = gnutls_certificate_set_x509_trust_file(
    577 			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
    578 		if (ret < 0) {
    579 			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
    580 				   "in PEM format: %s", params->ca_cert,
    581 				   gnutls_strerror(ret));
    582 			ret = gnutls_certificate_set_x509_trust_file(
    583 				conn->xcred, params->ca_cert,
    584 				GNUTLS_X509_FMT_DER);
    585 			if (ret < 0) {
    586 				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
    587 					   "'%s' in DER format: %s",
    588 					   params->ca_cert,
    589 					   gnutls_strerror(ret));
    590 				return -1;
    591 			}
    592 		}
    593 	}
    594 
    595 	if (params->client_cert && params->private_key) {
    596 		/* TODO: private_key_passwd? */
    597 		ret = gnutls_certificate_set_x509_key_file(
    598 			conn->xcred, params->client_cert, params->private_key,
    599 			GNUTLS_X509_FMT_PEM);
    600 		if (ret < 0) {
    601 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
    602 				   "in PEM format: %s", gnutls_strerror(ret));
    603 			ret = gnutls_certificate_set_x509_key_file(
    604 				conn->xcred, params->client_cert,
    605 				params->private_key, GNUTLS_X509_FMT_DER);
    606 			if (ret < 0) {
    607 				wpa_printf(MSG_DEBUG, "Failed to read client "
    608 					   "cert/key in DER format: %s",
    609 					   gnutls_strerror(ret));
    610 				return ret;
    611 			}
    612 		}
    613 	} else if (params->private_key) {
    614 		int pkcs12_ok = 0;
    615 #ifdef PKCS12_FUNCS
    616 		/* Try to load in PKCS#12 format */
    617 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
    618 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
    619 			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
    620 			params->private_key_passwd);
    621 		if (ret != 0) {
    622 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
    623 				   "PKCS#12 format: %s", gnutls_strerror(ret));
    624 			return -1;
    625 		} else
    626 			pkcs12_ok = 1;
    627 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
    628 #endif /* PKCS12_FUNCS */
    629 
    630 		if (!pkcs12_ok) {
    631 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
    632 				   "included");
    633 			return -1;
    634 		}
    635 	}
    636 
    637 	conn->tls_ia = params->tls_ia;
    638 	conn->params_set = 1;
    639 
    640 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
    641 				     conn->xcred);
    642 	if (ret < 0) {
    643 		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
    644 			   gnutls_strerror(ret));
    645 	}
    646 
    647 #ifdef GNUTLS_IA
    648 	if (conn->iacred_cli)
    649 		gnutls_ia_free_client_credentials(conn->iacred_cli);
    650 
    651 	ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
    652 	if (ret) {
    653 		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
    654 			   gnutls_strerror(ret));
    655 		return -1;
    656 	}
    657 
    658 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
    659 				     conn->iacred_cli);
    660 	if (ret) {
    661 		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
    662 			   gnutls_strerror(ret));
    663 		gnutls_ia_free_client_credentials(conn->iacred_cli);
    664 		conn->iacred_cli = NULL;
    665 		return -1;
    666 	}
    667 #endif /* GNUTLS_IE */
    668 
    669 	return ret;
    670 }
    671 
    672 
    673 int tls_global_set_params(void *tls_ctx,
    674 			  const struct tls_connection_params *params)
    675 {
    676 	struct tls_global *global = tls_ctx;
    677 	int ret;
    678 
    679 	/* Currently, global parameters are only set when running in server
    680 	 * mode. */
    681 	global->server = 1;
    682 
    683 	if (global->params_set) {
    684 		gnutls_certificate_free_credentials(global->xcred);
    685 		global->params_set = 0;
    686 	}
    687 
    688 	ret = gnutls_certificate_allocate_credentials(&global->xcred);
    689 	if (ret) {
    690 		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
    691 			   "%s", gnutls_strerror(ret));
    692 		return -1;
    693 	}
    694 
    695 	if (params->ca_cert) {
    696 		ret = gnutls_certificate_set_x509_trust_file(
    697 			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
    698 		if (ret < 0) {
    699 			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
    700 				   "in PEM format: %s", params->ca_cert,
    701 				   gnutls_strerror(ret));
    702 			ret = gnutls_certificate_set_x509_trust_file(
    703 				global->xcred, params->ca_cert,
    704 				GNUTLS_X509_FMT_DER);
    705 			if (ret < 0) {
    706 				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
    707 					   "'%s' in DER format: %s",
    708 					   params->ca_cert,
    709 					   gnutls_strerror(ret));
    710 				goto fail;
    711 			}
    712 		}
    713 	}
    714 
    715 	if (params->client_cert && params->private_key) {
    716 		/* TODO: private_key_passwd? */
    717 		ret = gnutls_certificate_set_x509_key_file(
    718 			global->xcred, params->client_cert,
    719 			params->private_key, GNUTLS_X509_FMT_PEM);
    720 		if (ret < 0) {
    721 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
    722 				   "in PEM format: %s", gnutls_strerror(ret));
    723 			ret = gnutls_certificate_set_x509_key_file(
    724 				global->xcred, params->client_cert,
    725 				params->private_key, GNUTLS_X509_FMT_DER);
    726 			if (ret < 0) {
    727 				wpa_printf(MSG_DEBUG, "Failed to read client "
    728 					   "cert/key in DER format: %s",
    729 					   gnutls_strerror(ret));
    730 				goto fail;
    731 			}
    732 		}
    733 	} else if (params->private_key) {
    734 		int pkcs12_ok = 0;
    735 #ifdef PKCS12_FUNCS
    736 		/* Try to load in PKCS#12 format */
    737 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
    738 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
    739 			global->xcred, params->private_key,
    740 			GNUTLS_X509_FMT_DER, params->private_key_passwd);
    741 		if (ret != 0) {
    742 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
    743 				   "PKCS#12 format: %s", gnutls_strerror(ret));
    744 			goto fail;
    745 		} else
    746 			pkcs12_ok = 1;
    747 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
    748 #endif /* PKCS12_FUNCS */
    749 
    750 		if (!pkcs12_ok) {
    751 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
    752 				   "included");
    753 			goto fail;
    754 		}
    755 	}
    756 
    757 	global->params_set = 1;
    758 
    759 	return 0;
    760 
    761 fail:
    762 	gnutls_certificate_free_credentials(global->xcred);
    763 	return -1;
    764 }
    765 
    766 
    767 int tls_global_set_verify(void *ssl_ctx, int check_crl)
    768 {
    769 	/* TODO */
    770 	return 0;
    771 }
    772 
    773 
    774 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
    775 			      int verify_peer)
    776 {
    777 	if (conn == NULL || conn->session == NULL)
    778 		return -1;
    779 
    780 	conn->verify_peer = verify_peer;
    781 	gnutls_certificate_server_set_request(conn->session,
    782 					      verify_peer ? GNUTLS_CERT_REQUIRE
    783 					      : GNUTLS_CERT_REQUEST);
    784 
    785 	return 0;
    786 }
    787 
    788 
    789 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
    790 			    struct tls_keys *keys)
    791 {
    792 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
    793 	security_parameters_st *sec;
    794 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
    795 
    796 	if (conn == NULL || conn->session == NULL || keys == NULL)
    797 		return -1;
    798 
    799 	os_memset(keys, 0, sizeof(*keys));
    800 
    801 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
    802 	sec = &conn->session->security_parameters;
    803 	keys->master_key = sec->master_secret;
    804 	keys->master_key_len = TLS_MASTER_SIZE;
    805 	keys->client_random = sec->client_random;
    806 	keys->server_random = sec->server_random;
    807 #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
    808 	keys->client_random =
    809 		(u8 *) gnutls_session_get_client_random(conn->session);
    810 	keys->server_random =
    811 		(u8 *) gnutls_session_get_server_random(conn->session);
    812 	/* No access to master_secret */
    813 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
    814 
    815 #ifdef GNUTLS_IA
    816 	gnutls_ia_extract_inner_secret(conn->session,
    817 				       (char *) conn->inner_secret);
    818 	keys->inner_secret = conn->inner_secret;
    819 	keys->inner_secret_len = TLS_MASTER_SIZE;
    820 #endif /* GNUTLS_IA */
    821 
    822 	keys->client_random_len = TLS_RANDOM_SIZE;
    823 	keys->server_random_len = TLS_RANDOM_SIZE;
    824 
    825 	return 0;
    826 }
    827 
    828 
    829 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
    830 		       const char *label, int server_random_first,
    831 		       u8 *out, size_t out_len)
    832 {
    833 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
    834 	if (conn == NULL || conn->session == NULL)
    835 		return -1;
    836 
    837 	return gnutls_prf(conn->session, os_strlen(label), label,
    838 			  server_random_first, 0, NULL, out_len, (char *) out);
    839 #else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
    840 	return -1;
    841 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
    842 }
    843 
    844 
    845 static int tls_connection_verify_peer(struct tls_connection *conn)
    846 {
    847 	unsigned int status, num_certs, i;
    848 	struct os_time now;
    849 	const gnutls_datum_t *certs;
    850 	gnutls_x509_crt_t cert;
    851 
    852 	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
    853 		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
    854 			   "certificate chain");
    855 		return -1;
    856 	}
    857 
    858 	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
    859 		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
    860 		return -1;
    861 	}
    862 
    863 	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
    864 		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
    865 			   "known issuer");
    866 		return -1;
    867 	}
    868 
    869 	if (status & GNUTLS_CERT_REVOKED) {
    870 		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
    871 		return -1;
    872 	}
    873 
    874 	os_get_time(&now);
    875 
    876 	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
    877 	if (certs == NULL) {
    878 		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
    879 			   "received");
    880 		return -1;
    881 	}
    882 
    883 	for (i = 0; i < num_certs; i++) {
    884 		char *buf;
    885 		size_t len;
    886 		if (gnutls_x509_crt_init(&cert) < 0) {
    887 			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
    888 				   "failed");
    889 			return -1;
    890 		}
    891 
    892 		if (gnutls_x509_crt_import(cert, &certs[i],
    893 					   GNUTLS_X509_FMT_DER) < 0) {
    894 			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
    895 				   "certificate %d/%d", i + 1, num_certs);
    896 			gnutls_x509_crt_deinit(cert);
    897 			return -1;
    898 		}
    899 
    900 		gnutls_x509_crt_get_dn(cert, NULL, &len);
    901 		len++;
    902 		buf = os_malloc(len + 1);
    903 		if (buf) {
    904 			buf[0] = buf[len] = '\0';
    905 			gnutls_x509_crt_get_dn(cert, buf, &len);
    906 		}
    907 		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
    908 			   i + 1, num_certs, buf);
    909 
    910 		if (i == 0) {
    911 			/* TODO: validate subject_match and altsubject_match */
    912 		}
    913 
    914 		os_free(buf);
    915 
    916 		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
    917 		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
    918 			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
    919 				   "not valid at this time",
    920 				   i + 1, num_certs);
    921 			gnutls_x509_crt_deinit(cert);
    922 			return -1;
    923 		}
    924 
    925 		gnutls_x509_crt_deinit(cert);
    926 	}
    927 
    928 	return 0;
    929 }
    930 
    931 
    932 u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
    933 			      const u8 *in_data, size_t in_len,
    934 			      size_t *out_len, u8 **appl_data,
    935 			      size_t *appl_data_len)
    936 {
    937 	struct tls_global *global = ssl_ctx;
    938 	u8 *out_data;
    939 	int ret;
    940 
    941 	if (appl_data)
    942 		*appl_data = NULL;
    943 
    944 	if (in_data && in_len) {
    945 		if (conn->pull_buf) {
    946 			wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
    947 				   "pull_buf", __func__, conn->pull_buf_len);
    948 			os_free(conn->pull_buf);
    949 		}
    950 		conn->pull_buf = os_malloc(in_len);
    951 		if (conn->pull_buf == NULL)
    952 			return NULL;
    953 		os_memcpy(conn->pull_buf, in_data, in_len);
    954 		conn->pull_buf_offset = conn->pull_buf;
    955 		conn->pull_buf_len = in_len;
    956 	}
    957 
    958 	ret = gnutls_handshake(conn->session);
    959 	if (ret < 0) {
    960 		switch (ret) {
    961 		case GNUTLS_E_AGAIN:
    962 			if (global->server && conn->established &&
    963 			    conn->push_buf == NULL) {
    964 				/* Need to return something to trigger
    965 				 * completion of EAP-TLS. */
    966 				conn->push_buf = os_malloc(1);
    967 			}
    968 			break;
    969 		case GNUTLS_E_FATAL_ALERT_RECEIVED:
    970 			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
    971 				   __func__, gnutls_alert_get_name(
    972 					   gnutls_alert_get(conn->session)));
    973 			conn->read_alerts++;
    974 			/* continue */
    975 		default:
    976 			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
    977 				   "-> %s", __func__, gnutls_strerror(ret));
    978 			conn->failed++;
    979 		}
    980 	} else {
    981 		size_t size;
    982 
    983 		if (conn->verify_peer && tls_connection_verify_peer(conn)) {
    984 			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
    985 				   "failed validation");
    986 			conn->failed++;
    987 			return NULL;
    988 		}
    989 
    990 		if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
    991 			wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
    992 			conn->failed++;
    993 			return NULL;
    994 		}
    995 
    996 		if (conn->tls_ia)
    997 			wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
    998 		else {
    999 			wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
   1000 				   "successfully");
   1001 		}
   1002 		conn->established = 1;
   1003 		if (conn->push_buf == NULL) {
   1004 			/* Need to return something to get final TLS ACK. */
   1005 			conn->push_buf = os_malloc(1);
   1006 		}
   1007 
   1008 		gnutls_session_get_data(conn->session, NULL, &size);
   1009 		if (global->session_data == NULL ||
   1010 		    global->session_data_size < size) {
   1011 			os_free(global->session_data);
   1012 			global->session_data = os_malloc(size);
   1013 		}
   1014 		if (global->session_data) {
   1015 			global->session_data_size = size;
   1016 			gnutls_session_get_data(conn->session,
   1017 						global->session_data,
   1018 						&global->session_data_size);
   1019 		}
   1020 	}
   1021 
   1022 	out_data = conn->push_buf;
   1023 	*out_len = conn->push_buf_len;
   1024 	conn->push_buf = NULL;
   1025 	conn->push_buf_len = 0;
   1026 	return out_data;
   1027 }
   1028 
   1029 
   1030 u8 * tls_connection_server_handshake(void *ssl_ctx,
   1031 				     struct tls_connection *conn,
   1032 				     const u8 *in_data, size_t in_len,
   1033 				     size_t *out_len)
   1034 {
   1035 	return tls_connection_handshake(ssl_ctx, conn, in_data, in_len,
   1036 					out_len, NULL, NULL);
   1037 }
   1038 
   1039 
   1040 int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
   1041 			   const u8 *in_data, size_t in_len,
   1042 			   u8 *out_data, size_t out_len)
   1043 {
   1044 	ssize_t res;
   1045 
   1046 #ifdef GNUTLS_IA
   1047 	if (conn->tls_ia)
   1048 		res = gnutls_ia_send(conn->session, (char *) in_data, in_len);
   1049 	else
   1050 #endif /* GNUTLS_IA */
   1051 	res = gnutls_record_send(conn->session, in_data, in_len);
   1052 	if (res < 0) {
   1053 		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
   1054 			   __func__, gnutls_strerror(res));
   1055 		return -1;
   1056 	}
   1057 	if (conn->push_buf == NULL)
   1058 		return -1;
   1059 	if (conn->push_buf_len < out_len)
   1060 		out_len = conn->push_buf_len;
   1061 	os_memcpy(out_data, conn->push_buf, out_len);
   1062 	os_free(conn->push_buf);
   1063 	conn->push_buf = NULL;
   1064 	conn->push_buf_len = 0;
   1065 	return out_len;
   1066 }
   1067 
   1068 
   1069 int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
   1070 			   const u8 *in_data, size_t in_len,
   1071 			   u8 *out_data, size_t out_len)
   1072 {
   1073 	ssize_t res;
   1074 
   1075 	if (conn->pull_buf) {
   1076 		wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
   1077 			   "pull_buf", __func__, conn->pull_buf_len);
   1078 		os_free(conn->pull_buf);
   1079 	}
   1080 	conn->pull_buf = os_malloc(in_len);
   1081 	if (conn->pull_buf == NULL)
   1082 		return -1;
   1083 	os_memcpy(conn->pull_buf, in_data, in_len);
   1084 	conn->pull_buf_offset = conn->pull_buf;
   1085 	conn->pull_buf_len = in_len;
   1086 
   1087 #ifdef GNUTLS_IA
   1088 	if (conn->tls_ia) {
   1089 		res = gnutls_ia_recv(conn->session, (char *) out_data,
   1090 				     out_len);
   1091 		if (out_len >= 12 &&
   1092 		    (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
   1093 		     res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) {
   1094 			int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
   1095 			wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
   1096 				   __func__, final ? "Final" : "Intermediate");
   1097 
   1098 			res = gnutls_ia_permute_inner_secret(
   1099 				conn->session, conn->session_keys_len,
   1100 				(char *) conn->session_keys);
   1101 			if (conn->session_keys) {
   1102 				os_memset(conn->session_keys, 0,
   1103 					  conn->session_keys_len);
   1104 				os_free(conn->session_keys);
   1105 			}
   1106 			conn->session_keys = NULL;
   1107 			conn->session_keys_len = 0;
   1108 			if (res) {
   1109 				wpa_printf(MSG_DEBUG, "%s: Failed to permute "
   1110 					   "inner secret: %s",
   1111 					   __func__, gnutls_strerror(res));
   1112 				return -1;
   1113 			}
   1114 
   1115 			res = gnutls_ia_verify_endphase(conn->session,
   1116 							(char *) out_data);
   1117 			if (res == 0) {
   1118 				wpa_printf(MSG_DEBUG, "%s: Correct endphase "
   1119 					   "checksum", __func__);
   1120 			} else {
   1121 				wpa_printf(MSG_INFO, "%s: Endphase "
   1122 					   "verification failed: %s",
   1123 					   __func__, gnutls_strerror(res));
   1124 				return -1;
   1125 			}
   1126 
   1127 			if (final)
   1128 				conn->final_phase_finished = 1;
   1129 
   1130 			return 0;
   1131 		}
   1132 
   1133 		if (res < 0) {
   1134 			wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
   1135 				   "(%s)", __func__, res,
   1136 				   gnutls_strerror(res));
   1137 		}
   1138 		return res;
   1139 	}
   1140 #endif /* GNUTLS_IA */
   1141 
   1142 	res = gnutls_record_recv(conn->session, out_data, out_len);
   1143 	if (res < 0) {
   1144 		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
   1145 			   "(%s)", __func__, res, gnutls_strerror(res));
   1146 	}
   1147 
   1148 	return res;
   1149 }
   1150 
   1151 
   1152 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
   1153 {
   1154 	if (conn == NULL)
   1155 		return 0;
   1156 	return gnutls_session_is_resumed(conn->session);
   1157 }
   1158 
   1159 
   1160 int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
   1161 				  const u8 *key, size_t key_len)
   1162 {
   1163 	/* TODO */
   1164 	return -1;
   1165 }
   1166 
   1167 
   1168 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
   1169 				   u8 *ciphers)
   1170 {
   1171 	/* TODO */
   1172 	return -1;
   1173 }
   1174 
   1175 
   1176 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
   1177 		   char *buf, size_t buflen)
   1178 {
   1179 	/* TODO */
   1180 	buf[0] = '\0';
   1181 	return 0;
   1182 }
   1183 
   1184 
   1185 int tls_connection_enable_workaround(void *ssl_ctx,
   1186 				     struct tls_connection *conn)
   1187 {
   1188 	/* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
   1189 	return 0;
   1190 }
   1191 
   1192 
   1193 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
   1194 				    int ext_type, const u8 *data,
   1195 				    size_t data_len)
   1196 {
   1197 	/* TODO */
   1198 	return -1;
   1199 }
   1200 
   1201 
   1202 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
   1203 {
   1204 	if (conn == NULL)
   1205 		return -1;
   1206 	return conn->failed;
   1207 }
   1208 
   1209 
   1210 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
   1211 {
   1212 	if (conn == NULL)
   1213 		return -1;
   1214 	return conn->read_alerts;
   1215 }
   1216 
   1217 
   1218 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
   1219 {
   1220 	if (conn == NULL)
   1221 		return -1;
   1222 	return conn->write_alerts;
   1223 }
   1224 
   1225 
   1226 int tls_connection_get_keyblock_size(void *tls_ctx,
   1227 				     struct tls_connection *conn)
   1228 {
   1229 	/* TODO */
   1230 	return -1;
   1231 }
   1232 
   1233 
   1234 unsigned int tls_capabilities(void *tls_ctx)
   1235 {
   1236 	unsigned int capa = 0;
   1237 
   1238 #ifdef GNUTLS_IA
   1239 	capa |= TLS_CAPABILITY_IA;
   1240 #endif /* GNUTLS_IA */
   1241 
   1242 	return capa;
   1243 }
   1244 
   1245 
   1246 int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
   1247 			  int tls_ia)
   1248 {
   1249 #ifdef GNUTLS_IA
   1250 	int ret;
   1251 
   1252 	if (conn == NULL)
   1253 		return -1;
   1254 
   1255 	conn->tls_ia = tls_ia;
   1256 	if (!tls_ia)
   1257 		return 0;
   1258 
   1259 	ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
   1260 	if (ret) {
   1261 		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
   1262 			   gnutls_strerror(ret));
   1263 		return -1;
   1264 	}
   1265 
   1266 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
   1267 				     conn->iacred_srv);
   1268 	if (ret) {
   1269 		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
   1270 			   gnutls_strerror(ret));
   1271 		gnutls_ia_free_server_credentials(conn->iacred_srv);
   1272 		conn->iacred_srv = NULL;
   1273 		return -1;
   1274 	}
   1275 
   1276 	return 0;
   1277 #else /* GNUTLS_IA */
   1278 	return -1;
   1279 #endif /* GNUTLS_IA */
   1280 }
   1281 
   1282 
   1283 int tls_connection_ia_send_phase_finished(void *tls_ctx,
   1284 					  struct tls_connection *conn,
   1285 					  int final,
   1286 					  u8 *out_data, size_t out_len)
   1287 {
   1288 #ifdef GNUTLS_IA
   1289 	int ret;
   1290 
   1291 	if (conn == NULL || conn->session == NULL || !conn->tls_ia)
   1292 		return -1;
   1293 
   1294 	ret = gnutls_ia_permute_inner_secret(conn->session,
   1295 					     conn->session_keys_len,
   1296 					     (char *) conn->session_keys);
   1297 	if (conn->session_keys) {
   1298 		os_memset(conn->session_keys, 0, conn->session_keys_len);
   1299 		os_free(conn->session_keys);
   1300 	}
   1301 	conn->session_keys = NULL;
   1302 	conn->session_keys_len = 0;
   1303 	if (ret) {
   1304 		wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
   1305 			   __func__, gnutls_strerror(ret));
   1306 		return -1;
   1307 	}
   1308 
   1309 	ret = gnutls_ia_endphase_send(conn->session, final);
   1310 	if (ret) {
   1311 		wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
   1312 			   __func__, gnutls_strerror(ret));
   1313 		return -1;
   1314 	}
   1315 
   1316 	if (conn->push_buf == NULL)
   1317 		return -1;
   1318 	if (conn->push_buf_len < out_len)
   1319 		out_len = conn->push_buf_len;
   1320 	os_memcpy(out_data, conn->push_buf, out_len);
   1321 	os_free(conn->push_buf);
   1322 	conn->push_buf = NULL;
   1323 	conn->push_buf_len = 0;
   1324 	return out_len;
   1325 #else /* GNUTLS_IA */
   1326 	return -1;
   1327 #endif /* GNUTLS_IA */
   1328 }
   1329 
   1330 
   1331 int tls_connection_ia_final_phase_finished(void *tls_ctx,
   1332 					   struct tls_connection *conn)
   1333 {
   1334 	if (conn == NULL)
   1335 		return -1;
   1336 
   1337 	return conn->final_phase_finished;
   1338 }
   1339 
   1340 
   1341 int tls_connection_ia_permute_inner_secret(void *tls_ctx,
   1342 					   struct tls_connection *conn,
   1343 					   const u8 *key, size_t key_len)
   1344 {
   1345 #ifdef GNUTLS_IA
   1346 	if (conn == NULL || !conn->tls_ia)
   1347 		return -1;
   1348 
   1349 	if (conn->session_keys) {
   1350 		os_memset(conn->session_keys, 0, conn->session_keys_len);
   1351 		os_free(conn->session_keys);
   1352 	}
   1353 	conn->session_keys_len = 0;
   1354 
   1355 	if (key) {
   1356 		conn->session_keys = os_malloc(key_len);
   1357 		if (conn->session_keys == NULL)
   1358 			return -1;
   1359 		os_memcpy(conn->session_keys, key, key_len);
   1360 		conn->session_keys_len = key_len;
   1361 	} else {
   1362 		conn->session_keys = NULL;
   1363 		conn->session_keys_len = 0;
   1364 	}
   1365 
   1366 	return 0;
   1367 #else /* GNUTLS_IA */
   1368 	return -1;
   1369 #endif /* GNUTLS_IA */
   1370 }
   1371