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 */ }