From 3de28506d2fe1a5530dd91a369044d3ec025fb8f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 28 Jul 2015 10:48:05 +0300 Subject: [PATCH] OpenSSL: Implement openssl_tls_prf() for OpenSSL 1.1.0 This needs to use the new accessor functions since the SSL session details are not directly accessible anymore and there is now sufficient helper functions to get to the needed information. Signed-off-by: Jouni Malinen --- src/crypto/tls_openssl.c | 102 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 902374c9e..31b02523e 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -2680,6 +2680,7 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, static int openssl_get_keyblock_size(SSL *ssl) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L const EVP_CIPHER *c; const EVP_MD *h; int md_size; @@ -2709,6 +2710,33 @@ static int openssl_get_keyblock_size(SSL *ssl) return 2 * (EVP_CIPHER_key_length(c) + md_size + EVP_CIPHER_iv_length(c)); +#else + const SSL_CIPHER *ssl_cipher; + int cipher, digest; + const EVP_CIPHER *c; + const EVP_MD *h; + + ssl_cipher = SSL_get_current_cipher(ssl); + if (!ssl_cipher) + return -1; + cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher); + digest = SSL_CIPHER_get_digest_nid(ssl_cipher); + wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d", + cipher, digest); + if (cipher < 0 || digest < 0) + return -1; + c = EVP_get_cipherbynid(cipher); + h = EVP_get_digestbynid(digest); + if (!c || !h) + return -1; + + wpa_printf(MSG_DEBUG, + "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d", + EVP_CIPHER_key_length(c), EVP_MD_size(h), + EVP_CIPHER_iv_length(c)); + return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) + + EVP_CIPHER_iv_length(c)); +#endif } @@ -2721,6 +2749,7 @@ static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn, "mode"); return -1; #else /* CONFIG_FIPS */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL *ssl; u8 *rnd; int ret = -1; @@ -2780,6 +2809,79 @@ static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn, bin_clear_free(tmp_out, skip); return ret; +#else + SSL *ssl; + SSL_SESSION *sess; + u8 *rnd; + int ret = -1; + int skip = 0; + u8 *tmp_out = NULL; + u8 *_out = out; + unsigned char client_random[SSL3_RANDOM_SIZE]; + unsigned char server_random[SSL3_RANDOM_SIZE]; + unsigned char master_key[64]; + size_t master_key_len; + + /* + * 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) + return -1; + sess = SSL_get_session(ssl); + if (!sess) + return -1; + + if (skip_keyblock) { + skip = openssl_get_keyblock_size(ssl); + if (skip < 0) + return -1; + tmp_out = os_malloc(skip + out_len); + if (!tmp_out) + return -1; + _out = tmp_out; + } + + rnd = os_malloc(2 * SSL3_RANDOM_SIZE); + if (!rnd) { + os_free(tmp_out); + return -1; + } + + SSL_get_client_random(ssl, client_random, sizeof(client_random)); + SSL_get_server_random(ssl, server_random, sizeof(server_random)); + master_key_len = SSL_SESSION_get_master_key(sess, master_key, + sizeof(master_key)); + + if (server_random_first) { + os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, + SSL3_RANDOM_SIZE); + } else { + os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, 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(master_key, master_key_len, + label, rnd, 2 * SSL3_RANDOM_SIZE, + _out, skip + out_len) == 0) + ret = 0; + os_memset(master_key, 0, sizeof(master_key)); + os_free(rnd); + if (ret == 0 && skip_keyblock) + os_memcpy(out, _out + skip, out_len); + bin_clear_free(tmp_out, skip); + + return ret; +#endif #endif /* CONFIG_FIPS */ }