aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2005-12-16 03:49:45 (GMT)
committerJouni Malinen <j@w1.fi>2005-12-16 03:49:45 (GMT)
commit80bd47ff434abe5a4dab04efc1d2f9b6c431f750 (patch)
tree99c0584062eacede1b7ddf841ce659dbd909da33
parent88711969fc7fb0457cbc08b0ca823264703aa71c (diff)
downloadhostap-history-80bd47ff434abe5a4dab04efc1d2f9b6c431f750.zip
hostap-history-80bd47ff434abe5a4dab04efc1d2f9b6c431f750.tar.gz
hostap-history-80bd47ff434abe5a4dab04efc1d2f9b6c431f750.tar.bz2
Replaced eap_tls_prf in struct tls_keys with a clearned design for
handling TLS libraries that do not export master secret: - new function, tls_connection_prf(), can be used to implement TLS key derivation using TLS library functions; this means that tls_connection_get_keys() is not needed in such a case - implemented tls_connection_prf() for GnuTLS v1.3.2 and newer; this means that the ugly workaround of using internal structures is not needed anymore - moved tls_schannel.c to use tls_connection_prf() instead of previously used eap_tls_prf workaround
-rw-r--r--wpa_supplicant/eap_fast.c40
-rw-r--r--wpa_supplicant/eap_tls_common.c42
-rw-r--r--wpa_supplicant/tls.h35
-rw-r--r--wpa_supplicant/tls_gnutls.c47
-rw-r--r--wpa_supplicant/tls_openssl.c8
-rw-r--r--wpa_supplicant/tls_schannel.c19
6 files changed, 135 insertions, 56 deletions
diff --git a/wpa_supplicant/eap_fast.c b/wpa_supplicant/eap_fast.c
index f432f40..9bce9dc 100644
--- a/wpa_supplicant/eap_fast.c
+++ b/wpa_supplicant/eap_fast.c
@@ -820,7 +820,8 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
size_t seed_len, server_random_len;
if (data->tls_master_secret_set || !data->current_pac ||
- tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys)) {
+ tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
+ keys.client_random == NULL) {
return 0;
}
@@ -854,7 +855,6 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
server_random, server_random_len);
-
seed_len = keys.client_random_len + server_random_len;
seed = malloc(seed_len);
if (seed == NULL)
@@ -887,22 +887,28 @@ static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
struct tls_keys keys;
- u8 *rnd;
- u8 *out;
+ u8 *rnd = NULL, *out;
int block_size;
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
- return NULL;
block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
if (block_size < 0)
return NULL;
+
out = malloc(block_size + len);
- rnd = malloc(keys.client_random_len + keys.server_random_len);
- if (out == NULL || rnd == NULL) {
- free(out);
- free(rnd);
+ if (out == NULL)
return NULL;
- }
+
+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out, len) ==
+ 0)
+ return out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ goto fail;
+
+ rnd = malloc(keys.client_random_len + keys.server_random_len);
+ if (rnd == NULL)
+ goto fail;
+
memcpy(rnd, keys.server_random, keys.server_random_len);
memcpy(rnd + keys.server_random_len, keys.client_random,
keys.client_random_len);
@@ -911,14 +917,16 @@ static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
"expansion", keys.master_key, keys.master_key_len);
if (tls_prf(keys.master_key, keys.master_key_len,
label, rnd, keys.client_random_len +
- keys.server_random_len, out, block_size + len)) {
- free(rnd);
- free(out);
- return NULL;
- }
+ keys.server_random_len, out, block_size + len))
+ goto fail;
free(rnd);
memmove(out, out + block_size, len);
return out;
+
+fail:
+ free(rnd);
+ free(out);
+ return NULL;
}
diff --git a/wpa_supplicant/eap_tls_common.c b/wpa_supplicant/eap_tls_common.c
index 91fbe6e..9c92892 100644
--- a/wpa_supplicant/eap_tls_common.c
+++ b/wpa_supplicant/eap_tls_common.c
@@ -163,46 +163,42 @@ u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
struct tls_keys keys;
- u8 *rnd;
- u8 *out;
+ u8 *rnd = NULL, *out;
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ out = malloc(len);
+ if (out == NULL)
return NULL;
- if (keys.eap_tls_prf && strcmp(label, "client EAP encryption") == 0) {
- if (len > keys.eap_tls_prf_len)
- return NULL;
- out = malloc(len);
- if (out == NULL)
- return NULL;
- memcpy(out, keys.eap_tls_prf, len);
+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
+ 0)
return out;
- }
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ goto fail;
if (keys.client_random == NULL || keys.server_random == NULL ||
keys.master_key == NULL)
- return NULL;
+ goto fail;
- out = malloc(len);
rnd = malloc(keys.client_random_len + keys.server_random_len);
- if (out == NULL || rnd == NULL) {
- free(out);
- free(rnd);
- return NULL;
- }
+ if (rnd == NULL)
+ goto fail;
memcpy(rnd, keys.client_random, keys.client_random_len);
memcpy(rnd + keys.client_random_len, keys.server_random,
keys.server_random_len);
if (tls_prf(keys.master_key, keys.master_key_len,
label, rnd, keys.client_random_len +
- keys.server_random_len, out, len)) {
- free(rnd);
- free(out);
- return NULL;
- }
+ keys.server_random_len, out, len))
+ goto fail;
+
free(rnd);
return out;
+
+fail:
+ free(out);
+ free(rnd);
+ return NULL;
}
diff --git a/wpa_supplicant/tls.h b/wpa_supplicant/tls.h
index 08dc42e..b38b686 100644
--- a/wpa_supplicant/tls.h
+++ b/wpa_supplicant/tls.h
@@ -18,21 +18,12 @@
struct tls_connection;
struct tls_keys {
- const u8 *master_key;
+ const u8 *master_key; /* TLS master secret */
size_t master_key_len;
const u8 *client_random;
size_t client_random_len;
const u8 *server_random;
size_t server_random_len;
-
- /*
- * If TLS library does not provide access to master_key, but only to
- * EAP key block, this pointer can be set to point to the result of
- * PRF(master_secret, "client EAP encryption",
- * client_random + server_random).
- */
- const u8 *eap_tls_prf;
- size_t eap_tls_prf_len;
};
struct tls_config {
@@ -256,6 +247,30 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys);
/**
+ * tls_connection_prf - Use TLS-PRF to derive keying material
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is optional to implement if tls_connection_get_keys() provides
+ * access to master secret and server/client random values. If these values are
+ * not exported from the TLS library, tls_connection_prf() is required so that
+ * further keying material can be derived from the master secret. If not
+ * implemented, the function will still need to be defined, but it can just
+ * return -1. Example implementation of this function is in tls_prf() function
+ * when it is called with seed set to client_random|server_random (or
+ * server_random|client_random).
+ */
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len);
+
+/**
* tls_connection_handshake - Process TLS handshake (client side)
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
diff --git a/wpa_supplicant/tls_gnutls.c b/wpa_supplicant/tls_gnutls.c
index ff10a11..b669caf 100644
--- a/wpa_supplicant/tls_gnutls.c
+++ b/wpa_supplicant/tls_gnutls.c
@@ -20,6 +20,18 @@
#include "tls.h"
+#define TLS_RANDOM_SIZE 32
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x010302
+/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
+ * use of internal structures to get the master_secret and
+ * {server,client}_random.
+ */
+#define GNUTLS_INTERNAL_STRUCTURE_HACK
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
/*
* It looks like gnutls does not provide access to client/server_random and
* master_key. This is somewhat unfortunate since these are needed for key
@@ -29,7 +41,6 @@
*/
typedef u8 uint8;
-#define TLS_RANDOM_SIZE 32
#define TLS_MASTER_SIZE 48
typedef unsigned char opaque;
typedef struct {
@@ -56,6 +67,7 @@ struct gnutls_session_int {
security_parameters_st security_parameters;
/* followed by things we are not interested in */
};
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
struct tls_connection {
@@ -105,18 +117,22 @@ extern int wpa_debug_show_keys;
void * tls_init(const struct tls_config *conf)
{
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
/* Because of the horrible hack to get master_secret and client/server
* random, we need to make sure that the gnutls version is something
* that is expected to have same structure definition for the session
* data.. */
const char *ver;
const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
+ "1.3.2",
NULL };
int i;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
if (gnutls_global_init() < 0)
return NULL;
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
ver = gnutls_check_version(NULL);
if (ver == NULL)
return NULL;
@@ -130,6 +146,7 @@ void * tls_init(const struct tls_config *conf)
"to be tested and enabled in tls_gnutls.c", ver);
return NULL;
}
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
gnutls_global_set_log_function(tls_log_func);
if (wpa_debug_show_keys)
@@ -488,24 +505,50 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
security_parameters_st *sec;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
if (conn == NULL || conn->session == NULL || keys == NULL)
return -1;
memset(keys, 0, sizeof(*keys));
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
sec = &conn->session->security_parameters;
keys->master_key = sec->master_secret;
keys->master_key_len = TLS_MASTER_SIZE;
keys->client_random = sec->client_random;
- keys->client_random_len = TLS_RANDOM_SIZE;
keys->server_random = sec->server_random;
+#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+ keys->client_random = gnutls_session_get_client_random(conn->session);
+ keys->server_random = gnutls_session_get_server_random(conn->session);
+ /* No access to master_secret */
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+ keys->client_random_len = TLS_RANDOM_SIZE;
keys->server_random_len = TLS_RANDOM_SIZE;
return 0;
}
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
+{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+ if (conn == NULL || conn->session == NULL)
+ return -1;
+
+ return gnutls_prf(conn->session, strlen(label), label,
+ server_random_first, 0, NULL, out_len, out);
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+ return -1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+}
+
+
static int tls_connection_verify_peer(struct tls_connection *conn)
{
unsigned int status, num_certs, i;
diff --git a/wpa_supplicant/tls_openssl.c b/wpa_supplicant/tls_openssl.c
index bbba85f..2211d53 100644
--- a/wpa_supplicant/tls_openssl.c
+++ b/wpa_supplicant/tls_openssl.c
@@ -1654,6 +1654,14 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
}
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
+{
+ return -1;
+}
+
+
u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
const u8 *in_data, size_t in_len,
size_t *out_len)
diff --git a/wpa_supplicant/tls_schannel.c b/wpa_supplicant/tls_schannel.c
index 2671e44..78f7f82 100644
--- a/wpa_supplicant/tls_schannel.c
+++ b/wpa_supplicant/tls_schannel.c
@@ -200,11 +200,15 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
- if (conn == NULL || keys == NULL || !conn->eap_tls_prf_set)
- return -1;
+ /* Schannel does not export master secret or client/server random. */
+ return -1;
+}
- memset(keys, 0, sizeof(*keys));
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
+{
/*
* Cannot get master_key from Schannel, but EapKeyBlock can be used to
* generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
@@ -213,8 +217,13 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
* and just use Schannel or CryptoAPI for low-level crypto
* functionality..
*/
- keys->eap_tls_prf = conn->eap_tls_prf;
- keys->eap_tls_prf_len = sizeof(conn->eap_tls_prf);
+
+ if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
+ strcmp(label, "client EAP encryption") != 0 ||
+ out_len > sizeof(conn->eap_tls_prf))
+ return -1;
+
+ memcpy(out, conn->eap_tls_prf, out_len);
return 0;
}