Tidying up the OpenSSL private key password logic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi folks,

I've attached two patches that I think tidy up the logic around
OpenSSL private key loading and passwords.

The first just removes an unnecessary strdup. That parameter isn't
mutated or anything, it's just a generic data argument to the same
callback that you pass in.

The second avoids using the SSL(_CTX) default password callback
altogether. Since you all use it for one-off calls anyway, it ends up
being a little cumbersome as you must set and unset them. Further, you
end up mutating the SSL_CTX after SSLs have been created, which isn't
generally safe. Rather, I think it's cleaner to just pass the password
into the PEM_read_bio_PrivateKey call yourself. The SSL-level
functions are merely convenience routines on top of this. This also
allows abstracting away the DER/PEM fallback code. (It also avoids a
mess of OpenSSL version variability.)

Note: you probably want to run tests on this. I wasn't sure how to do
that, but I have checked that they compile on my system.

Thoughts?

David
From b80a2911d0a5d9719e3566f2a487012ddd5eaa45 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben@xxxxxxxxxx>
Date: Mon, 18 Sep 2017 00:33:43 -0400
Subject: [PATCH 1/2] OpenSSL: Remove unnecessary os_strdup.

There's no need to make an extra copy of private_key_passwd.

Signed-Off-By: David Benjamin <davidben@xxxxxxxxxx>
---
 src/crypto/tls_openssl.c | 38 +++++++++++---------------------------
 1 file changed, 11 insertions(+), 27 deletions(-)

diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index ada88a9d3..df2ce07d2 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -3039,19 +3039,11 @@ static int tls_connection_private_key(struct tls_data *data,
 				      size_t private_key_blob_len)
 {
 	SSL_CTX *ssl_ctx = data->ssl;
-	char *passwd;
 	int ok;
 
 	if (private_key == NULL && private_key_blob == NULL)
 		return 0;
 
-	if (private_key_passwd) {
-		passwd = os_strdup(private_key_passwd);
-		if (passwd == NULL)
-			return -1;
-	} else
-		passwd = NULL;
-
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
 #ifndef LIBRESSL_VERSION_NUMBER
 #ifndef OPENSSL_IS_BORINGSSL
@@ -3060,13 +3052,15 @@ static int tls_connection_private_key(struct tls_data *data,
 	 * from the SSL object. See OpenSSL commit d61461a75253.
 	 */
 	SSL_set_default_passwd_cb(conn->ssl, tls_passwd_cb);
-	SSL_set_default_passwd_cb_userdata(conn->ssl, passwd);
+	SSL_set_default_passwd_cb_userdata(conn->ssl,
+					   (void *)private_key_passwd);
 #endif /* !BoringSSL */
 #endif /* !LibreSSL */
 #endif /* >= 1.1.0f && */
 	/* Keep these for OpenSSL < 1.1.0f */
 	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
+	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,
+					       (void *)private_key_passwd);
 
 	ok = 0;
 	while (private_key_blob) {
@@ -3098,7 +3092,8 @@ static int tls_connection_private_key(struct tls_data *data,
 		}
 
 		if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
-					 private_key_blob_len, passwd) == 0) {
+					 private_key_blob_len,
+					 private_key_passwd) == 0) {
 			wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
 				   "OK");
 			ok = 1;
@@ -3130,8 +3125,8 @@ static int tls_connection_private_key(struct tls_data *data,
 			   __func__);
 #endif /* OPENSSL_NO_STDIO */
 
-		if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
-		    == 0) {
+		if (tls_read_pkcs12(data, conn->ssl, private_key,
+				    private_key_passwd) == 0) {
 			wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
 				   "--> OK");
 			ok = 1;
@@ -3152,12 +3147,10 @@ static int tls_connection_private_key(struct tls_data *data,
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
 		tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
-		os_free(passwd);
 		return -1;
 	}
 	ERR_clear_error();
 	tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
-	os_free(passwd);
 
 	if (!SSL_check_private_key(conn->ssl)) {
 		tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -3175,20 +3168,13 @@ static int tls_global_private_key(struct tls_data *data,
 				  const char *private_key_passwd)
 {
 	SSL_CTX *ssl_ctx = data->ssl;
-	char *passwd;
 
 	if (private_key == NULL)
 		return 0;
 
-	if (private_key_passwd) {
-		passwd = os_strdup(private_key_passwd);
-		if (passwd == NULL)
-			return -1;
-	} 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_CTX_set_default_passwd_cb_userdata(ssl_ctx,
+					       (void *)private_key_passwd);
 	if (
 #ifndef OPENSSL_NO_STDIO
 	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
@@ -3196,16 +3182,14 @@ static int tls_global_private_key(struct tls_data *data,
 	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
 					SSL_FILETYPE_PEM) != 1 &&
 #endif /* OPENSSL_NO_STDIO */
-	    tls_read_pkcs12(data, NULL, private_key, passwd)) {
+	    tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
 		tls_clear_default_passwd_cb(ssl_ctx, NULL);
-		os_free(passwd);
 		ERR_clear_error();
 		return -1;
 	}
 	tls_clear_default_passwd_cb(ssl_ctx, NULL);
-	os_free(passwd);
 	ERR_clear_error();
 
 	if (!SSL_CTX_check_private_key(ssl_ctx)) {
-- 
2.15.0.531.g2ccb3012c9-goog

From 821e2b131340a959bdb52a5079eac4932640509a Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben@xxxxxxxxxx>
Date: Mon, 18 Sep 2017 11:47:47 -0400
Subject: [PATCH 2/2] OpenSSL: Avoid SSL*_use_default_passwd_cb.

These functions are a bit awkward to use for one-off file loads, as
suggested by the tls_clear_default_passwd_cb logic. There was also some
historical mess with OpenSSL versions and either not having per-SSL
settings, having per-SSL settings but ignoring them, and requiring the
per-SSL settings.

Instead, loading the key with the lower-level functions seems a bit
tidier and also allows abstracting away trying both formats, one after
another.

Signed-off-by: David Benjamin <davidben@xxxxxxxxxx>
---
 src/crypto/tls_openssl.c | 121 ++++++++++++++++++++++-------------------------
 1 file changed, 56 insertions(+), 65 deletions(-)

diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index df2ce07d2..3d32fc1f7 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2686,16 +2686,6 @@ static int tls_global_client_cert(struct tls_data *data,
 }
 
 
-static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
-{
-	if (password == NULL) {
-		return 0;
-	}
-	os_strlcpy(buf, (char *) password, size);
-	return os_strlen(buf);
-}
-
-
 #ifdef PKCS12_FUNCS
 static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
 			    const char *passwd)
@@ -3014,21 +3004,60 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
 }
 
 
-static void tls_clear_default_passwd_cb(SSL_CTX *ssl_ctx, SSL *ssl)
+#ifndef OPENSSL_NO_STDIO
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
 {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-#ifndef LIBRESSL_VERSION_NUMBER
-#ifndef OPENSSL_IS_BORINGSSL
-	if (ssl) {
-		SSL_set_default_passwd_cb(ssl, NULL);
-		SSL_set_default_passwd_cb_userdata(ssl, NULL);
-	}
-#endif /* !BoringSSL */
-#endif /* !LibreSSL */
-#endif /* >= 1.1.0f */
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL);
+	if (password == NULL) {
+		return 0;
+	}
+	os_strlcpy(buf, (const char *) password, size);
+	return os_strlen(buf);
+}
+
+
+static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
+				    const char *private_key,
+				    const char *private_key_passwd) {
+	BIO *bio;
+	EVP_PKEY *pkey;
+	int ret;
+
+	/* First try ASN.1. */
+	bio = BIO_new_file(private_key, "r");
+	if (bio == NULL)
+		return -1;
+	pkey = d2i_PrivateKey_bio(bio, NULL);
+	BIO_free(bio);
+
+	if (pkey != NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: "
+			   "tls_use_private_key_file (DER) --> loaded");
+	} else {
+		/* Try PEM with the provided password. */
+		bio = BIO_new_file(private_key, "r");
+		if (bio == NULL)
+			return -1;
+		pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
+					       (void *)private_key_passwd);
+		BIO_free(bio);
+		if (pkey == NULL)
+			return -1;
+		wpa_printf(MSG_DEBUG, "OpenSSL: "
+			   "tls_use_private_key_file (PEM) --> loaded");
+		/* Clear errors from the previous failed load. */
+		ERR_clear_error();
+	}
+
+	if (ssl != NULL) {
+		ret = SSL_use_PrivateKey(ssl, pkey);
+	} else {
+		ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
+	}
+
+	EVP_PKEY_free(pkey);
+	return ret == 1 ? 0 : -1;
 }
+#endif /* OPENSSL_NO_STDIO */
 
 
 static int tls_connection_private_key(struct tls_data *data,
@@ -3038,30 +3067,11 @@ 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;
 	int ok;
 
 	if (private_key == NULL && private_key_blob == NULL)
 		return 0;
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-#ifndef LIBRESSL_VERSION_NUMBER
-#ifndef OPENSSL_IS_BORINGSSL
-	/*
-	 * In OpenSSL >= 1.1.0f SSL_use_PrivateKey_file() uses the callback
-	 * from the SSL object. See OpenSSL commit d61461a75253.
-	 */
-	SSL_set_default_passwd_cb(conn->ssl, tls_passwd_cb);
-	SSL_set_default_passwd_cb_userdata(conn->ssl,
-					   (void *)private_key_passwd);
-#endif /* !BoringSSL */
-#endif /* !LibreSSL */
-#endif /* >= 1.1.0f && */
-	/* Keep these for OpenSSL < 1.1.0f */
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,
-					       (void *)private_key_passwd);
-
 	ok = 0;
 	while (private_key_blob) {
 		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
@@ -3105,18 +3115,8 @@ static int tls_connection_private_key(struct tls_data *data,
 
 	while (!ok && private_key) {
 #ifndef OPENSSL_NO_STDIO
-		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
-					    SSL_FILETYPE_ASN1) == 1) {
-			wpa_printf(MSG_DEBUG, "OpenSSL: "
-				   "SSL_use_PrivateKey_File (DER) --> OK");
-			ok = 1;
-			break;
-		}
-
-		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
-					    SSL_FILETYPE_PEM) == 1) {
-			wpa_printf(MSG_DEBUG, "OpenSSL: "
-				   "SSL_use_PrivateKey_File (PEM) --> OK");
+		if (tls_use_private_key_file(data, conn->ssl, private_key,
+					     private_key_passwd) == 0) {
 			ok = 1;
 			break;
 		}
@@ -3146,11 +3146,9 @@ static int tls_connection_private_key(struct tls_data *data,
 	if (!ok) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
-		tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
 		return -1;
 	}
 	ERR_clear_error();
-	tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
 
 	if (!SSL_check_private_key(conn->ssl)) {
 		tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -3172,24 +3170,17 @@ static int tls_global_private_key(struct tls_data *data,
 	if (private_key == NULL)
 		return 0;
 
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx,
-					       (void *)private_key_passwd);
 	if (
 #ifndef OPENSSL_NO_STDIO
-	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
-					SSL_FILETYPE_ASN1) != 1 &&
-	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
-					SSL_FILETYPE_PEM) != 1 &&
+	    tls_use_private_key_file(data, NULL, private_key,
+				     private_key_passwd) &&
 #endif /* OPENSSL_NO_STDIO */
 	    tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
-		tls_clear_default_passwd_cb(ssl_ctx, NULL);
 		ERR_clear_error();
 		return -1;
 	}
-	tls_clear_default_passwd_cb(ssl_ctx, NULL);
 	ERR_clear_error();
 
 	if (!SSL_CTX_check_private_key(ssl_ctx)) {
-- 
2.15.0.531.g2ccb3012c9-goog

_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap

[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux