]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OpenSSL: Add support for TPM2-wrapped keys
authorDaniel Kobras <kobras@puzzle-itc.de>
Tue, 2 Jul 2019 14:19:38 +0000 (16:19 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 29 Dec 2019 09:28:19 +0000 (11:28 +0200)
If the header of a PEM-formatted certificate or key in private_key file
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.

This functionality needs
https://git.kernel.org/pub/scm/linux/kernel/git/jejb/openssl_tpm2_engine.git
to be installed as an OpenSSL engine.

Signed-off-by: Daniel Kobras <kobras@puzzle-itc.de>
src/crypto/tls_openssl.c

index 29115bc60c0f2d9507bf9192a0e2c77795e92708..a4a647eee0f00f01af22cc1e935ad1b5b5a47d65 100644 (file)
@@ -4908,6 +4908,76 @@ static int ocsp_status_cb(SSL *s, void *arg)
 #endif /* HAVE_OCSP */
 
 
+static size_t max_str_len(const char **lines)
+{
+       const char **p;
+       size_t max_len = 0;
+
+       for (p = lines; *p; p++) {
+               size_t len = os_strlen(*p);
+
+               if (len > max_len)
+                       max_len = len;
+       }
+
+       return max_len;
+}
+
+
+static int match_lines_in_file(const char *path, const char **lines)
+{
+       FILE *f;
+       char *buf;
+       size_t bufsize;
+       int found = 0, is_linestart = 1;
+
+       bufsize = max_str_len(lines) + sizeof("\r\n");
+       buf = os_malloc(bufsize);
+       if (!buf)
+               return 0;
+
+       f = fopen(path, "r");
+       if (!f) {
+               os_free(buf);
+               return 0;
+       }
+
+       while (!found && fgets(buf, bufsize, f)) {
+               int is_lineend;
+               size_t len;
+               const char **p;
+
+               len = strcspn(buf, "\r\n");
+               is_lineend = buf[len] != '\0';
+               buf[len] = '\0';
+
+               if (is_linestart && is_lineend) {
+                       for (p = lines; !found && *p; p++)
+                               found = os_strcmp(buf, *p) == 0;
+               }
+               is_linestart = is_lineend;
+       }
+
+       fclose(f);
+       bin_clear_free(buf, bufsize);
+
+       return found;
+}
+
+
+static int is_tpm2_key(const char *path)
+{
+       /* Check both new and old format of TPM2 PEM guard tag */
+       static 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)
 {
@@ -4960,6 +5030,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 (params->private_key &&
+           (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
+           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) {
@@ -4991,7 +5072,8 @@ 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)