From fa0e715100b0e6fd956b6de67c3cdf908437436a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 31 Mar 2015 15:47:32 +0300 Subject: [PATCH] Use tls_connection_prf() for all EAP TLS-based key derivation tls_openssl.c is the only remaining TLS/crypto wrapper that needs the internal PRF implementation for EAP-FAST (since SSL_export_keying_material() is not available in older versions and does not support server-random-before-client case). As such, it is cleaner to assume that TLS libraries support tls_connection_prf() and move the additional support code for the otherwise unsupported cases into tls_openssl.c. Signed-off-by: Jouni Malinen --- src/crypto/tls_openssl.c | 61 +++++++++++++++++++++++++- src/eap_common/eap_fast_common.c | 35 +++------------ src/eap_peer/eap_tls_common.c | 45 +++---------------- src/eap_server/eap_server_tls_common.c | 35 +++------------ 4 files changed, 75 insertions(+), 101 deletions(-) diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 52db8fc07..8f9bea6a1 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -26,6 +26,7 @@ #include "common.h" #include "crypto.h" +#include "sha1.h" #include "tls.h" #if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data) @@ -2644,6 +2645,60 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, } +static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn, + const char *label, int server_random_first, + u8 *out, size_t out_len) +{ +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS " + "mode"); + return -1; +#else /* CONFIG_FIPS */ + SSL *ssl; + u8 *rnd; + int ret = -1; + + /* + * TLS library did not support key generation, so get the needed TLS + * session parameters and use an internal implementation of TLS PRF to + * derive the key. + */ + + if (conn == NULL) + return -1; + ssl = conn->ssl; + if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL || + ssl->s3->client_random == NULL || ssl->s3->server_random == NULL || + ssl->session->master_key == NULL) + return -1; + + rnd = os_malloc(2 * SSL3_RANDOM_SIZE); + if (rnd == NULL) + return -1; + if (server_random_first) { + os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random, + SSL3_RANDOM_SIZE); + } else { + os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random, + SSL3_RANDOM_SIZE); + } + + /* TODO: TLSv1.2 may need another PRF. This could use something closer + * to SSL_export_keying_material() design. */ + if (tls_prf_sha1_md5(ssl->session->master_key, + ssl->session->master_key_length, + label, rnd, 2 * SSL3_RANDOM_SIZE, + out, out_len) == 0) + ret = 0; + os_free(rnd); + + return ret; +#endif /* CONFIG_FIPS */ +} + + int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, u8 *out, size_t out_len) @@ -2653,7 +2708,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, if (conn == NULL) return -1; if (server_random_first) - return -1; + return openssl_tls_prf(tls_ctx, conn, label, + server_random_first, out, out_len); ssl = conn->ssl; if (SSL_export_keying_material(ssl, out, out_len, label, os_strlen(label), NULL, 0, 0) == 1) { @@ -2661,7 +2717,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, return 0; } #endif - return -1; + return openssl_tls_prf(tls_ctx, conn, label, server_random_first, + out, out_len); } diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c index fceb1b0ad..5b4118935 100644 --- a/src/eap_common/eap_fast_common.c +++ b/src/eap_common/eap_fast_common.c @@ -96,8 +96,7 @@ void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, const char *label, size_t len) { - struct tls_keys keys; - u8 *rnd = NULL, *out; + u8 *out; int block_size; block_size = tls_connection_get_keyblock_size(ssl_ctx, conn); @@ -108,37 +107,15 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, if (out == NULL) return NULL; - if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len) - == 0) { - os_memmove(out, out + block_size, len); - return out; + if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)) + { + os_free(out); + return NULL; } - if (tls_connection_get_keys(ssl_ctx, conn, &keys)) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - - os_memcpy(rnd, keys.server_random, keys.server_random_len); - os_memcpy(rnd + keys.server_random_len, keys.client_random, - keys.client_random_len); - - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key " - "expansion", keys.master_key, keys.master_key_len); - if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, block_size + len)) - goto fail; - os_free(rnd); os_memmove(out, out + block_size, len); + os_memset(out + len, 0, block_size); return out; - -fail: - os_free(rnd); - os_free(out); - return NULL; } diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 871078161..e5a6ee5e4 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -313,53 +313,18 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, const char *label, size_t len) { -#ifndef CONFIG_FIPS - struct tls_keys keys; -#endif /* CONFIG_FIPS */ - u8 *rnd = NULL, *out; + u8 *out; out = os_malloc(len); if (out == NULL) return NULL; - /* First, try to use TLS library function for PRF, if available. */ - if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len) - == 0) - return out; + if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)) { + os_free(out); + return NULL; + } -#ifndef CONFIG_FIPS - /* - * TLS library did not support key generation, so get the needed TLS - * session parameters and use an internal implementation of TLS PRF to - * derive the key. - */ - if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys)) - goto fail; - - if (keys.client_random == NULL || keys.server_random == NULL || - keys.master_key == NULL) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); - - if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, len)) - goto fail; - - os_free(rnd); return out; - -fail: -#endif /* CONFIG_FIPS */ - os_free(out); - os_free(rnd); - return NULL; } diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c index 56916c45a..09f2a82d0 100644 --- a/src/eap_server/eap_server_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -100,43 +100,18 @@ void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, char *label, size_t len) { - struct tls_keys keys; - u8 *rnd = NULL, *out; + u8 *out; out = os_malloc(len); if (out == NULL) return NULL; - if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == - 0) - return out; + if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len)) { + os_free(out); + return NULL; + } - 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) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); - - if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, len)) - goto fail; - - os_free(rnd); return out; - -fail: - os_free(out); - os_free(rnd); - return NULL; }