diff mbox series

OpenSSL: add support for TPM2-wrapped keys

Message ID 8fd6383f-74f5-64d0-c023-e59823a4d138@puzzle-itc.de
State Accepted
Headers show
Series OpenSSL: add support for TPM2-wrapped keys | expand

Commit Message

Daniel Kobras July 2, 2019, 2:19 p.m. UTC
If the header of a PEM-formatted cert or key indicates that it is
wrapped with a TPM2 key, try to autoload the appropriate OpenSSL engine
that can transparently unwrap the key. This enables systems to use
TPM2-wrapped keys as drop-in replacements to ordinary SSL keys.

Signed-off-by: Daniel Kobras <kobras@puzzle-itc.de>
---
Hi!

This patch adds support for TPM2-wrapped keys, similar to what David
Woodhouse did in openconnect, and suggested earlier on this list for
wpa_supplicant as well. It requires
https://git.kernel.org/pub/scm/linux/kernel/git/jejb/openssl_tpm2_engine.git/
to be installed as an openssl engine.

The match_line_in_file() helper function is rather generic. If there's a
better place to put it, please let me know.

Kind regards,

Daniel
---
 src/crypto/tls_openssl.c | 74 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 73 insertions(+), 1 deletion(-)

 #if OPENSSL_VERSION_NUMBER < 0x10100000L ||
defined(LIBRESSL_VERSION_NUMBER)
 	if (params->flags & TLS_CONN_EAP_FAST) {
@@ -4903,7 +4975,7 @@ int tls_connection_set_params(void *tls_ctx,
struct tls_connection *conn,
 	}

 	if (engine_id) {
-		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s", engine_id);
 		ret = tls_engine_init(conn, engine_id, params->pin,
 				      key_id, cert_id, ca_cert_id);
 		if (ret)

Comments

Daniel Kobras Aug. 7, 2019, 2:26 p.m. UTC | #1
Hi!

Am 02.07.19 um 16:19 schrieb Daniel Kobras:
> If the header of a PEM-formatted cert or key indicates that it is
> wrapped with a TPM2 key, try to autoload the appropriate OpenSSL engine
> that can transparently unwrap the key. This enables systems to use
> TPM2-wrapped keys as drop-in replacements to ordinary SSL keys.
> 
> Signed-off-by: Daniel Kobras <kobras@puzzle-itc.de>
> ---

Any thoughts on the TPM2 below? NetworkManager has just release version
1.20 that includes a patch to pass through TPM2-wrapped PEM key files.
Corresponding support in wpa_supplicant now is the missing piece of the
puzzle to enable transparent support for TPM2-pinned keys with 802.1x
for desktop users. If there's anything else you want me to provide
regarding this patch, please let me know.

Kind regards,

Daniel

> Hi!
> 
> This patch adds support for TPM2-wrapped keys, similar to what David
> Woodhouse did in openconnect, and suggested earlier on this list for
> wpa_supplicant as well. It requires
> https://git.kernel.org/pub/scm/linux/kernel/git/jejb/openssl_tpm2_engine.git/
> to be installed as an openssl engine.
> 
> The match_line_in_file() helper function is rather generic. If there's a
> better place to put it, please let me know.
> 
> Kind regards,
> 
> Daniel
> ---
>  src/crypto/tls_openssl.c | 74 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 73 insertions(+), 1 deletion(-)
> 
> diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
> index 1073f6450..7f61f7560 100644
> --- a/src/crypto/tls_openssl.c
> +++ b/src/crypto/tls_openssl.c
> @@ -4819,6 +4819,67 @@ static int ocsp_status_cb(SSL *s, void *arg)
> 
>  #endif /* HAVE_OCSP */
> 
> +static int match_lines_in_file(const char *path, const char **lines)
> +{
> +	FILE *f = NULL;
> +	const char **p;
> +	char *buf;
> +	size_t bufsize = 0;
> +	int found, is_linestart;
> +
> +	if (!path || !lines || !*lines)
> +		return 0;
> +
> +	for (p = lines; *p; p++) {
> +		size_t size = strlen(*p) + sizeof("\r\n");
> +		bufsize = (size > bufsize) ? size : bufsize;
> +	}
> +
> +	buf = os_malloc(bufsize);
> +	if (!buf)
> +		return 0;
> +
> +	f = fopen(path, "r");
> +	if (!f) {
> +		os_free(buf);
> +		return 0;
> +	}
> +
> +	found = 0;
> +	is_linestart = 1;
> +
> +	while (!found && fgets(buf, bufsize, f)) {
> +		int is_lineend;
> +		size_t buflen = strlen(buf);
> +
> +		buf[strcspn(buf, "\r\n")] = '\0';
> +		is_lineend = strlen(buf) < buflen;
> +
> +		if (is_linestart && is_lineend) {
> +			for (p = lines; !found && *p; p++) {
> +				found = !os_strcmp(buf, *p);
> +			}
> +		}
> +		is_linestart = is_lineend;
> +	}
> +
> +	fclose(f);
> +	os_free(buf);
> +
> +	return found;
> +}
> +
> +static int is_tpm2_key(const char *path)
> +{
> +	/* Check both new and old format of TPM2 PEM guard tag */
> +	const char *tpm2_tags[] = {
> +		"-----BEGIN TSS2 PRIVATE KEY-----",
> +		"-----BEGIN TSS2 KEY BLOB-----",
> +		NULL
> +	};
> +
> +	return match_lines_in_file(path, tpm2_tags);
> +}
> 
>  int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
>  			      const struct tls_connection_params *params)
> @@ -4872,6 +4933,17 @@ int tls_connection_set_params(void *tls_ctx,
> struct tls_connection *conn,
>  	if (can_pkcs11 == 2 && !engine_id)
>  		engine_id = "pkcs11";
> 
> +	/* If private_key points to a TPM2-wrapped key, automatically enable
> +	 * tpm2 engine and use it to unwrap the key. */
> +	if (!engine_id || os_strcmp(engine_id, "tpm2")) {
> +		if (is_tpm2_key(params->private_key)) {
> +			wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
> +			           params->private_key);
> +			key_id = key_id ? key_id : params->private_key;
> +			engine_id = engine_id ? engine_id : "tpm2";
> +		}
> +	}
> +
>  #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||
> defined(EAP_SERVER_FAST)
>  #if OPENSSL_VERSION_NUMBER < 0x10100000L ||
> defined(LIBRESSL_VERSION_NUMBER)
>  	if (params->flags & TLS_CONN_EAP_FAST) {
> @@ -4903,7 +4975,7 @@ int tls_connection_set_params(void *tls_ctx,
> struct tls_connection *conn,
>  	}
> 
>  	if (engine_id) {
> -		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
> +		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s", engine_id);
>  		ret = tls_engine_init(conn, engine_id, params->pin,
>  				      key_id, cert_id, ca_cert_id);
>  		if (ret)
>
Jouni Malinen Dec. 29, 2019, 9:55 a.m. UTC | #2
On Tue, Jul 02, 2019 at 04:19:38PM +0200, Daniel Kobras wrote:
> If the header of a PEM-formatted cert or key indicates that it is
> wrapped with a TPM2 key, try to autoload the appropriate OpenSSL engine
> that can transparently unwrap the key. This enables systems to use
> TPM2-wrapped keys as drop-in replacements to ordinary SSL keys.

Thanks, applied.
David Woodhouse Dec. 29, 2019, 11:42 a.m. UTC | #3
On 29 December 2019 09:55:41 GMT, Jouni Malinen <j@w1.fi> wrote:
>On Tue, Jul 02, 2019 at 04:19:38PM +0200, Daniel Kobras wrote:
>> If the header of a PEM-formatted cert or key indicates that it is
>> wrapped with a TPM2 key, try to autoload the appropriate OpenSSL
>engine
>> that can transparently unwrap the key. This enables systems to use
>> TPM2-wrapped keys as drop-in replacements to ordinary SSL keys.
>
>Thanks, applied.
>

cf. https://github.com/tpm2-software/tpm2-tss-engine/issues/28
diff mbox series

Patch

diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 1073f6450..7f61f7560 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -4819,6 +4819,67 @@  static int ocsp_status_cb(SSL *s, void *arg)

 #endif /* HAVE_OCSP */

+static int match_lines_in_file(const char *path, const char **lines)
+{
+	FILE *f = NULL;
+	const char **p;
+	char *buf;
+	size_t bufsize = 0;
+	int found, is_linestart;
+
+	if (!path || !lines || !*lines)
+		return 0;
+
+	for (p = lines; *p; p++) {
+		size_t size = strlen(*p) + sizeof("\r\n");
+		bufsize = (size > bufsize) ? size : bufsize;
+	}
+
+	buf = os_malloc(bufsize);
+	if (!buf)
+		return 0;
+
+	f = fopen(path, "r");
+	if (!f) {
+		os_free(buf);
+		return 0;
+	}
+
+	found = 0;
+	is_linestart = 1;
+
+	while (!found && fgets(buf, bufsize, f)) {
+		int is_lineend;
+		size_t buflen = strlen(buf);
+
+		buf[strcspn(buf, "\r\n")] = '\0';
+		is_lineend = strlen(buf) < buflen;
+
+		if (is_linestart && is_lineend) {
+			for (p = lines; !found && *p; p++) {
+				found = !os_strcmp(buf, *p);
+			}
+		}
+		is_linestart = is_lineend;
+	}
+
+	fclose(f);
+	os_free(buf);
+
+	return found;
+}
+
+static int is_tpm2_key(const char *path)
+{
+	/* Check both new and old format of TPM2 PEM guard tag */
+	const char *tpm2_tags[] = {
+		"-----BEGIN TSS2 PRIVATE KEY-----",
+		"-----BEGIN TSS2 KEY BLOB-----",
+		NULL
+	};
+
+	return match_lines_in_file(path, tpm2_tags);
+}

 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 			      const struct tls_connection_params *params)
@@ -4872,6 +4933,17 @@  int tls_connection_set_params(void *tls_ctx,
struct tls_connection *conn,
 	if (can_pkcs11 == 2 && !engine_id)
 		engine_id = "pkcs11";

+	/* If private_key points to a TPM2-wrapped key, automatically enable
+	 * tpm2 engine and use it to unwrap the key. */
+	if (!engine_id || os_strcmp(engine_id, "tpm2")) {
+		if (is_tpm2_key(params->private_key)) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
+			           params->private_key);
+			key_id = key_id ? key_id : params->private_key;
+			engine_id = engine_id ? engine_id : "tpm2";
+		}
+	}
+
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||
defined(EAP_SERVER_FAST)