[PATCH] Fix possible use after free in tls_connection_private_key

Alexander Kabaev kan at freebsd.org
Wed Jul 12 17:59:51 PDT 2017

The code erroneously sets callback on the SSL_CTX, but the code
uses SSL_use_PrivateKey_file, which accepts con->ssl and in turn
invokes PEM_read_bio_PrivateKey as follows:

        pkey = PEM_read_bio_PrivateKey(in, NULL,

So the tls_connection_private_key always fails first time around, and when
it does so, it leaves callback pointer in SSL_CTX set to tls_passwd_cb,
and callback userdata set to strdup-ed and then freed string. So, at the
time of the next iteraction, these callback and dangling data are copied
from SSL_CTX to SSL and callback does get invoked and it accesses the
freed memory as the password string.

To fix the issue, remove the code to set/clear callback in SSL_CTX and
set it only in conn->ssl for the duration of the function.

Signed-off-by: Alexander Kabaev <kan at FreeBSD.org>
 src/crypto/tls_openssl.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 07c61193a..63279f8f1 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2782,7 +2782,6 @@ static int tls_connection_private_key(struct tls_data *data,
 				      const u8 *private_key_blob,
 				      size_t private_key_blob_len)
-	SSL_CTX *ssl_ctx = data->ssl;
 	char *passwd;
 	int ok;
@@ -2796,8 +2795,8 @@ static int tls_connection_private_key(struct tls_data *data,
 	} else
 		passwd = NULL;
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
+	SSL_set_default_passwd_cb(conn->ssl, tls_passwd_cb);
+	SSL_set_default_passwd_cb_userdata(conn->ssl, passwd);
 	ok = 0;
 	while (private_key_blob) {
@@ -2879,15 +2878,14 @@ static int tls_connection_private_key(struct tls_data *data,
+	SSL_set_default_passwd_cb(conn->ssl, NULL);
+	os_free(passwd);
 	if (!ok) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
-		os_free(passwd);
 		return -1;
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
-	os_free(passwd);
 	if (!SSL_check_private_key(conn->ssl)) {
 		tls_show_errors(MSG_INFO, __func__, "Private key failed "

More information about the Hostap mailing list