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