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