]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
libtpmtss: Establish session with TPM 2.0
authorAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 8 Nov 2021 08:02:40 +0000 (09:02 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 11 Dec 2021 15:21:59 +0000 (16:21 +0100)
Using the trusted RSA or ECC Endorsement Key of the TPM 2.0 a
secure session is established via RSA public key encryption or
an ephemeral ECDH key exchange, respectively.

The session allows HMAC-based authenticated communication with
the TPM 2.0 and the exchanged parameters can be encrypted where
necessary to guarantee confidentiality.

conf/plugins/tpm.opt
src/libtpmtss/Makefile.am
src/libtpmtss/tpm_tss_tss2_session.c [new file with mode: 0644]
src/libtpmtss/tpm_tss_tss2_session.h [new file with mode: 0644]
src/libtpmtss/tpm_tss_tss2_v2.c

index 06c88861ea704e7ce14f1a29647c2ad2a56f2124..cb1ab36e426eef22190a2b91199e91724733e1e6 100644 (file)
@@ -1,5 +1,6 @@
 charon.plugins.tpm.use_rng = no
-       Whether the TPM should be used as RNG.
+       Whether the TPM should be used as RNG. For security reasons enable only if
+       an authenticated session can be set up (see _ek_handle_ option).
 
 charon.plugins.tpm.fips_186_4 = no
        Is the TPM 2.0 FIPS-186-4 compliant, forcing e.g. the use of the default
@@ -14,3 +15,7 @@ charon.plugins.tpm.tcti.name = device|tabrmd
 charon.plugins.tpm.tcti.opts = /dev/tpmrm0|<none>
        Options for the TPM 2.0 TCTI library. Defaults are _/dev/tpmrm0_ if the
        TCTI library name is _device_ and no options otherwise.
+
+charon.plugins.tpm.ek_handle =
+       Handle of the RSA or ECC Endorsement Key (EK) to be used to set up an
+       authenticated session with a TPM 2.0 (e.g. 0x81010001).
index d192fc126746386316b52b31606d6981d3c5c296..a9ce63036c11df2e572ddcd5d9954f589fecde41 100644 (file)
@@ -25,7 +25,8 @@ libtpmtss_la_SOURCES = \
        tpm_tss_quote_info.h tpm_tss_quote_info.c \
        tpm_tss_trousers.h tpm_tss_trousers.c \
        tpm_tss_tss2.h tpm_tss_tss2_v1.c tpm_tss_tss2_v2.c \
-       tpm_tss_tss2_names.h tpm_tss_tss2_names_v1.c tpm_tss_tss2_names_v2.c
+       tpm_tss_tss2_names.h tpm_tss_tss2_names_v1.c tpm_tss_tss2_names_v2.c \
+       tpm_tss_tss2_session.h tpm_tss_tss2_session.c
 
 if MONOLITHIC
 SUBDIRS =
diff --git a/src/libtpmtss/tpm_tss_tss2_session.c b/src/libtpmtss/tpm_tss_tss2_session.c
new file mode 100644 (file)
index 0000000..05e5b3b
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2021 Andreas Steffen, strongSec GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifdef TSS_TSS2_V2
+
+#include "tpm_tss_tss2_session.h"
+
+#define LABEL  "TPM 2.0 - "
+
+typedef struct private_tpm_tss_tss2_session_t private_tpm_tss_tss2_session_t;
+
+/**
+ * Private data of an tpm_tss_tss2_session_t object.
+ */
+struct private_tpm_tss_tss2_session_t {
+
+       /**
+        * Public tpm_tss_tss2_session_t interface.
+        */
+       tpm_tss_tss2_session_t public;
+
+       /**
+        * Session handle for protected communication with TPM 2.0
+        */
+       uint32_t session_handle;
+
+       /**
+        * Session key for protected communication with TPM 2.0
+        */
+       chunk_t session_key;
+
+       /**
+        * Hash algorithm to be used for protected communication with TPM 2.0
+        */
+       TPM2_ALG_ID hash_alg;
+
+       /**
+        * nonceCaller used for protected communication with TPM 2.0
+        */
+       TPM2B_NONCE nonceCaller;
+
+       /**
+        * nonceTPM used for protected communication with TPM 2.0
+        */
+       TPM2B_NONCE nonceTPM;
+
+       /**
+        * AES-CFB encryption of protected communication with TPM 2.0
+        */
+       crypter_t *crypter;
+
+       /**
+        * SYS context
+        */
+       TSS2_SYS_CONTEXT  *sys_context;
+
+};
+
+/**
+ * Two functions shared with tpm_tss_tss2_v2.c
+ */
+
+hash_algorithm_t hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg);
+
+size_t hash_len_from_tpm_alg_id(TPM2_ALG_ID alg);
+
+
+/**
+ * Convert TPM2_ALG_ID to PRF algorithm
+ */
+pseudo_random_function_t prf_alg_from_tpm_alg_id(TPM2_ALG_ID alg)
+{
+       switch (alg)
+       {
+               case TPM2_ALG_SHA1:
+                       return PRF_HMAC_SHA1;
+               case TPM2_ALG_SHA256:
+                       return PRF_HMAC_SHA2_256;
+               case TPM2_ALG_SHA384:
+                       return PRF_HMAC_SHA2_384;
+               case TPM2_ALG_SHA512:
+                       return PRF_HMAC_SHA2_512;
+               default:
+                       return PRF_UNDEFINED;
+       }
+}
+
+static bool generate_nonce(size_t size, TPM2B_NONCE *nonce)
+{
+       nonce_gen_t *nonce_gen;
+       bool success;
+
+       nonce_gen = lib->crypto->create_nonce_gen(lib->crypto);
+       if (!nonce_gen)
+       {
+               DBG1(DBG_PTS, "no nonce generator available");
+               return FALSE;
+       }
+       nonce->size = size;
+       success = nonce_gen->get_nonce(nonce_gen, nonce->size, nonce->buffer);
+       nonce_gen->destroy(nonce_gen);
+
+       if (!success)
+       {
+               DBG1(DBG_PTS, "generation of nonce failed");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+METHOD(tpm_tss_tss2_session_t, set_cmd_auths, bool,
+       private_tpm_tss_tss2_session_t *this)
+{
+       size_t hash_len, param_size, cp_size;
+       const uint8_t *param_buffer, *cp_buffer;
+       uint8_t cc_buffer[4];
+       hash_algorithm_t hash_algorithm;
+       hasher_t *hasher;
+       pseudo_random_function_t prf_alg;
+       prf_t *prf;
+       chunk_t data, cp_hash, cp_hmac, nonce_caller, nonce_tpm, session_attributes;
+       bool success;
+       uint32_t rval;
+
+       TSS2L_SYS_AUTH_COMMAND cmd;
+       TPM2B_DIGEST cpHash;
+
+       cmd.count = 1;
+       cmd.auths[0].sessionHandle = this->session_handle;
+       cmd.auths[0].sessionAttributes = TPMA_SESSION_CONTINUESESSION |
+                                                                        TPMA_SESSION_ENCRYPT;
+       session_attributes = chunk_create(&cmd.auths[0].sessionAttributes, 1);
+
+       hash_len = hash_len_from_tpm_alg_id(this->hash_alg);
+
+       if (!generate_nonce(hash_len, &this->nonceCaller))
+       {
+               return FALSE;
+       }
+       cmd.auths[0].nonce.size = this->nonceCaller.size;
+       memcpy(cmd.auths[0].nonce.buffer, this->nonceCaller.buffer,
+                                                                         this->nonceCaller.size);
+
+       rval = Tss2_Sys_GetEncryptParam(this->sys_context, &param_size,
+                                                                                                          &param_buffer);
+       if (rval == TSS2_SYS_RC_NO_ENCRYPT_PARAM)
+       {
+               DBG2(DBG_PTS, LABEL "parameter encryption not possible");
+               return FALSE;
+       }
+
+       rval = Tss2_Sys_GetCommandCode(this->sys_context, cc_buffer);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_GetCommandCode failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       rval = Tss2_Sys_GetCpBuffer(this->sys_context, &cp_size, &cp_buffer);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_GetCpBuffer failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       /* compute cpHash */
+       hash_algorithm = hash_alg_from_tpm_alg_id(this->hash_alg);
+       hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
+       if (!hasher)
+       {
+               DBG1(DBG_PTS, "hasher could not be created");
+               return FALSE;
+       }
+
+       data = chunk_alloc(4 + cp_size);
+       memcpy(data.ptr, cc_buffer, 4);
+       memcpy(data.ptr + 4, cp_buffer, cp_size);
+
+       success = hasher->get_hash(hasher, data, cpHash.buffer);
+       cpHash.size = hasher->get_hash_size(hasher);
+       hasher->destroy(hasher);
+       chunk_free(&data);
+
+       if (!success)
+       {
+               DBG1(DBG_PTS, "computation of cpHash failed");
+               return FALSE;
+       }
+       cp_hash = chunk_create(cpHash.buffer, cpHash.size);
+
+       /* compute cp HMAC */
+       prf_alg = prf_alg_from_tpm_alg_id(this->hash_alg);
+       prf = lib->crypto->create_prf(lib->crypto, prf_alg);
+       if (!prf)
+       {
+               DBG1(DBG_PTS, "could not create PRF");
+               return FALSE;
+       }
+       if (!prf->set_key(prf, this->session_key))
+       {
+               DBG1(DBG_PTS, "could not set PRF key");
+               prf->destroy(prf);
+               return FALSE;
+       }
+
+       nonce_caller = chunk_create(this->nonceCaller.buffer, this->nonceCaller.size);
+       nonce_tpm = chunk_create(this->nonceTPM.buffer, this->nonceTPM.size);
+
+       success = prf->get_bytes(prf, cp_hash, NULL)       &&
+                         prf->get_bytes(prf, nonce_caller, NULL)  &&
+                         prf->get_bytes(prf, nonce_tpm, NULL)     &&
+                         prf->get_bytes(prf, session_attributes, cmd.auths[0].hmac.buffer);
+       cmd.auths[0].hmac.size = prf->get_block_size(prf);
+       prf->destroy(prf);
+
+       if (!success)
+       {
+               DBG1(DBG_PTS, "cpHmac computation failed");
+               return FALSE;
+       }
+       cp_hmac = chunk_create(cmd.auths[0].hmac.buffer, cmd.auths[0].hmac.size);
+       DBG2(DBG_PTS, LABEL "cpHmac: %B", &cp_hmac);
+
+       rval = Tss2_Sys_SetCmdAuths(this->sys_context, &cmd);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_SetCmdAuths failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/**
+ * Key Derivation Function using Counter Mode as defined by NIST SP800-108
+ * - the label is expected to be NUL terminated
+ */
+static bool kdf_a(TPMI_ALG_HASH hash_alg, chunk_t key, chunk_t label,
+                                 chunk_t context_u, chunk_t context_v, uint32_t bytes,
+                                 chunk_t *key_mat)
+{
+       pseudo_random_function_t prf_alg;
+       chunk_t count_chunk, bits_chunk;
+       uint32_t iterations, counter, count, bits;
+       uint8_t *pos;
+       size_t hlen;
+       prf_t *prf;
+
+       bits = htonl(8 * bytes);
+       bits_chunk = chunk_create((uint8_t*)&bits, sizeof(bits));
+
+       prf_alg = prf_alg_from_tpm_alg_id(hash_alg);
+       prf = lib->crypto->create_prf(lib->crypto, prf_alg);
+       if (!prf)
+       {
+               DBG1(DBG_PTS, "could not create PRF");
+               return FALSE;
+       }
+       if (!prf->set_key(prf, key))
+       {
+               DBG1(DBG_PTS, "could not set PRF key");
+               prf->destroy(prf);
+               return FALSE;
+       }
+
+       hlen = prf->get_block_size(prf);
+       iterations = (bytes + hlen - 1) / hlen;
+       *key_mat = chunk_alloc(iterations * hlen);
+       pos = key_mat->ptr;
+
+       for (counter = 1; counter <= iterations; counter++)
+       {
+               count = htonl(counter);
+               count_chunk = chunk_create((uint8_t*)&count, sizeof(count));
+
+               if (!prf->get_bytes(prf, count_chunk, NULL) ||
+                       !prf->get_bytes(prf, label, NULL)       ||
+                       !prf->get_bytes(prf, context_u, NULL)   ||
+                       !prf->get_bytes(prf, context_v, NULL)   ||
+                       !prf->get_bytes(prf, bits_chunk, pos))
+               {
+                       DBG1(DBG_PTS, "KDFa computation failed");
+                       chunk_free(key_mat);
+                       prf->destroy(prf);
+                       return FALSE;
+               }
+               pos += hlen;
+       }
+       prf->destroy(prf);
+
+       return TRUE;
+}
+
+METHOD(tpm_tss_tss2_session_t, get_rsp_auths, bool,
+       private_tpm_tss_tss2_session_t *this)
+{
+       size_t param_size, rp_size, key_len, iv_len;
+       const uint8_t *param_buffer, *rp_buffer;
+       uint8_t rc_buffer[4] = { 0 };
+       uint8_t cc_buffer[4];
+       hash_algorithm_t hash_algorithm;
+       hasher_t *hasher;
+       pseudo_random_function_t prf_alg;
+       prf_t *prf;
+       chunk_t kdf_label = chunk_from_chars('C','F','B', 0x00);
+       chunk_t data, rp_hash, rp_hmac, nonce_caller, nonce_tpm, session_attributes;
+       chunk_t key_mat, aes_key, aes_iv;
+       bool success;
+       uint32_t rval;
+
+       TSS2L_SYS_AUTH_RESPONSE rsp;
+       TPM2B_DIGEST rpHash, rpHmac;
+
+       rval = Tss2_Sys_GetRspAuths(this->sys_context, &rsp);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_GetRspAuths failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       /* update nonceTPM */
+       memcpy(this->nonceTPM.buffer, rsp.auths[0].nonce.buffer,
+                                                                 rsp.auths[0].nonce.size);
+       this->nonceTPM.size = rsp.auths[0].nonce.size;
+
+       rval = Tss2_Sys_GetRpBuffer(this->sys_context, &rp_size, &rp_buffer);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_GetRpBuffer failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       rval = Tss2_Sys_GetCommandCode(this->sys_context, cc_buffer);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_GetCommandCode failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       /* compute rpHash */
+       hash_algorithm = hash_alg_from_tpm_alg_id(this->hash_alg);
+       hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
+       if (!hasher)
+       {
+               DBG1(DBG_PTS, "hasher could not be created");
+               return FALSE;
+       }
+
+       data = chunk_alloc(4 + 4 + rp_size);
+       memcpy(data.ptr, rc_buffer, 4);
+       memcpy(data.ptr + 4, cc_buffer, 4);
+       memcpy(data.ptr + 8, rp_buffer, rp_size);
+
+       success = hasher->get_hash(hasher, data, rpHash.buffer);
+       rpHash.size = hasher->get_hash_size(hasher);
+       hasher->destroy(hasher);
+       chunk_free(&data);
+
+       if (!success)
+       {
+               DBG1(DBG_PTS, "computation of rpHash failed");
+               return FALSE;
+       }
+       rp_hash = chunk_create(rpHash.buffer, rpHash.size);
+
+       /* compute rpHmac */
+       prf_alg = prf_alg_from_tpm_alg_id(this->hash_alg);
+       prf = lib->crypto->create_prf(lib->crypto, prf_alg);
+       if (!prf)
+       {
+               DBG1(DBG_PTS, "could not create PRF");
+               return FALSE;
+       }
+       if (!prf->set_key(prf, this->session_key))
+       {
+               DBG1(DBG_PTS, "could not set PRF key");
+               prf->destroy(prf);
+               return FALSE;
+       }
+
+       nonce_tpm = chunk_create(this->nonceTPM.buffer, this->nonceTPM.size);
+       nonce_caller = chunk_create(this->nonceCaller.buffer, this->nonceCaller.size);
+       session_attributes = chunk_create(&rsp.auths[0].sessionAttributes, 1);
+
+       success = prf->get_bytes(prf, rp_hash, NULL)       &&
+                         prf->get_bytes(prf, nonce_tpm, NULL)  &&
+                         prf->get_bytes(prf, nonce_caller, NULL)     &&
+                         prf->get_bytes(prf, session_attributes, rpHmac.buffer);
+       rpHmac.size = prf->get_block_size(prf);
+       prf->destroy(prf);
+
+       if (!success)
+       {
+               DBG1(DBG_PTS, "computation of rpHmac failed");
+               return FALSE;
+       }
+       rp_hmac = chunk_create(rpHmac.buffer, rpHmac.size);
+       DBG2(DBG_PTS, LABEL "rpHMAC: %B", &rp_hmac);
+
+       /* verify rpHmac */
+       if (!memeq(rsp.auths[0].hmac.buffer, rpHmac.buffer, rpHmac.size))
+       {
+               DBG1(DBG_PTS, LABEL "invalid HMAC received for session 0x%08x",
+                                         this->session_handle);
+               return FALSE;
+       }
+
+       /* decrypt parameter */
+       rval = Tss2_Sys_GetEncryptParam(this->sys_context, &param_size,
+                                                                                                          &param_buffer);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_GetEncryptParam failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       key_len = this->crypter->get_key_size(this->crypter);
+       iv_len  = this->crypter->get_iv_size(this->crypter);
+
+       /* derive decryption key using KDFa */
+       if (!kdf_a(this->hash_alg, this->session_key, kdf_label, nonce_tpm,
+                          nonce_caller,  key_len + iv_len , &key_mat))
+       {
+               return FALSE;
+       }
+       aes_key = chunk_create(key_mat.ptr, key_len);
+       aes_iv  = chunk_create(key_mat.ptr + key_len, iv_len);
+
+       if (!this->crypter->set_key(this->crypter, aes_key))
+       {
+               chunk_clear(&key_mat);
+               return FALSE;
+       }
+
+       /* copy ciphertext */
+       data = chunk_alloc(param_size);
+       memcpy(data.ptr, param_buffer, param_size);
+
+       /* decrypt ciphertext */
+       success = this->crypter->decrypt(this->crypter, data, aes_iv, NULL);
+       chunk_clear(&key_mat);
+       if (!success)
+       {
+               chunk_free(&data);
+               return FALSE;
+       }
+       DBG4(DBG_PTS, LABEL "plaintext: %B", &data);
+
+       /* copy back plaintext */
+       rval = Tss2_Sys_SetEncryptParam(this->sys_context, data.len, data.ptr);
+       chunk_clear(&data);
+
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_SetEncryptParam failed: 0x%06x", rval);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+METHOD(tpm_tss_tss2_session_t, destroy, void,
+       private_tpm_tss_tss2_session_t *this)
+{
+       if (this->session_handle)
+       {
+               uint32_t rval;
+
+               /* flush session context */
+               rval = Tss2_Sys_FlushContext(this->sys_context, this->session_handle);
+               if (rval != TPM2_RC_SUCCESS)
+               {
+                       DBG2(DBG_PTS, LABEL "Tss2_Sys_FlushContext failed: 0x%06x", rval);
+               }
+               chunk_clear(&this->session_key);
+       }
+       DESTROY_IF(this->crypter);
+       free(this);
+}
+
+static chunk_t secret_label = chunk_from_chars('S','E','C','R','E','T', 0x00);
+
+static bool rsa_salt(TPM2B_PUBLIC *public, TPMI_ALG_HASH hash_alg,
+                                        chunk_t *secret, TPM2B_ENCRYPTED_SECRET *encryptedSalt)
+{
+       encryption_scheme_t encryption_scheme;
+       public_key_t *pubkey = NULL;
+       nonce_gen_t *nonce_gen;
+       chunk_t encrypted_salt = chunk_empty;
+       chunk_t rsa_modulus;
+       chunk_t rsa_exponent = chunk_from_chars(0x01, 0x00, 0x01);
+       uint32_t exponent;
+       size_t hash_len;
+       bool success;
+
+       TPM2B_PUBLIC_KEY_RSA *rsa;
+
+       switch (hash_alg)
+       {
+               case TPM2_ALG_SHA1:
+                       encryption_scheme = ENCRYPT_RSA_OAEP_SHA1;
+                       break;
+               case TPM2_ALG_SHA256:
+                       encryption_scheme = ENCRYPT_RSA_OAEP_SHA256;
+                       break;
+               case TPM2_ALG_SHA384:
+                       encryption_scheme = ENCRYPT_RSA_OAEP_SHA384;
+                       break;
+               case TPM2_ALG_SHA512:
+                       encryption_scheme = ENCRYPT_RSA_OAEP_SHA512;
+                       break;
+               default:
+                       DBG1(DBG_PTS, LABEL "unsupported key hash algorithm");
+                       return FALSE;
+       }
+
+       hash_len = hash_len_from_tpm_alg_id(hash_alg);
+
+       /* create a salt nonce to be used as a shared secret */
+       nonce_gen = lib->crypto->create_nonce_gen(lib->crypto);
+       if (!nonce_gen)
+       {
+               DBG1(DBG_PTS, "no nonce generator available");
+               return FALSE;
+       }
+       success = nonce_gen->allocate_nonce(nonce_gen, hash_len, secret);
+       nonce_gen->destroy(nonce_gen);
+       if (!success)
+       {
+               DBG1(DBG_PTS, "generation of salt nonce failed");
+               return FALSE;
+       }
+
+       /* get RSA public key */
+       rsa = &public->publicArea.unique.rsa;
+       rsa_modulus = chunk_create(rsa->buffer, rsa->size);
+       exponent = htonl(public->publicArea.parameters.rsaDetail.exponent);
+       if (exponent)
+       {
+               rsa_exponent = chunk_from_thing(exponent);
+       }
+       pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
+                                               BUILD_RSA_MODULUS, rsa_modulus, BUILD_RSA_PUB_EXP,
+                                               rsa_exponent, BUILD_END);
+       if (!pubkey)
+       {
+               DBG1(DBG_PTS, "retrieval of EK public key failed");
+               chunk_clear(secret);
+               return FALSE;
+       }
+
+       /* use RSA public key encryption to encrypt secret salt nonce */
+       success = pubkey->encrypt(pubkey, encryption_scheme, &secret_label,
+                                                         *secret, &encrypted_salt);
+       pubkey->destroy(pubkey);
+       if (!success)
+       {
+               DBG1(DBG_PTS, "encryption of salt failed");
+               chunk_clear(secret);
+               return FALSE;
+       }
+
+       /* copy encryptedSalt to output parameter */
+       encryptedSalt->size = encrypted_salt.len;
+       memcpy(encryptedSalt->secret, encrypted_salt.ptr, encrypted_salt.len);
+       free(encrypted_salt.ptr);
+
+       return TRUE;
+}
+
+
+/**
+ * Key Derivation Function used to derive an ecc-based secret
+ * - the label is expected to be NUL terminated
+ */
+static bool kdf_e(TPMI_ALG_HASH hash_alg, chunk_t z, chunk_t label,
+                                 chunk_t context_u, chunk_t context_v, uint32_t bytes,
+                                 chunk_t *key_mat)
+{
+       hash_algorithm_t hash_algorithm;
+       chunk_t count_chunk;
+       uint32_t iterations, counter, count;
+       uint8_t *pos;
+       size_t hlen;
+       hasher_t *hasher;
+
+       hash_algorithm = hash_alg_from_tpm_alg_id(hash_alg);
+       hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
+       if (!hasher)
+       {
+               DBG1(DBG_PTS, "could not create hasher");
+               return FALSE;
+       }
+
+       hlen = hasher->get_hash_size(hasher);
+       iterations = (bytes + hlen - 1) / hlen;
+       *key_mat = chunk_alloc(iterations * hlen);
+       pos = key_mat->ptr;
+
+       for (counter = 1; counter <= iterations; counter++)
+       {
+               count = htonl(counter);
+               count_chunk = chunk_create((uint8_t*)&count, sizeof(count));
+
+               if (!hasher->get_hash(hasher, count_chunk, NULL) ||
+                       !hasher->get_hash(hasher, z, NULL)           ||
+                       !hasher->get_hash(hasher, label, NULL)       ||
+                       !hasher->get_hash(hasher, context_u, NULL)   ||
+                       !hasher->get_hash(hasher, context_v, pos))
+               {
+                       DBG1(DBG_PTS, "KDFe computation failed");
+                       chunk_free(key_mat);
+                       hasher->destroy(hasher);
+                       return FALSE;
+               }
+               pos += hlen;
+       }
+       hasher->destroy(hasher);
+
+       return TRUE;
+}
+
+static bool ecc_salt(TPM2B_PUBLIC *public, TPMI_ALG_HASH hash_alg,
+                                        chunk_t *secret, TPM2B_ENCRYPTED_SECRET *encryptedSalt)
+{
+       diffie_hellman_group_t ec_group;
+       diffie_hellman_t *dh;
+       chunk_t ecdh_pubkey = chunk_empty, ecdh_pubkey_x, ecdh_pubkey_y;
+       chunk_t ecc_pubkey  = chunk_empty, ecc_pubkey_x, ecc_pubkey_y;
+       chunk_t z = chunk_empty;
+       uint16_t len;
+       uint8_t *pos;
+       size_t hash_len;
+       bool success = FALSE;
+
+       switch (public->publicArea.parameters.eccDetail.curveID)
+       {
+               case TPM2_ECC_NIST_P256:
+                       ec_group = ECP_256_BIT;
+                       break;
+               case TPM2_ECC_NIST_P384:
+                       ec_group = ECP_384_BIT;
+                       break;
+               case TPM2_ECC_NIST_P521:
+                       ec_group = ECP_521_BIT;
+                       break;
+               default:
+                       DBG1(DBG_PTS, "type of ECC EK key not supported");
+                       return FALSE;
+       }
+
+       /* Generate ECDH key pair */
+       dh = lib->crypto->create_dh(lib->crypto, ec_group);
+       if (!dh)
+       {
+               DBG1(DBG_PTS, "DH group could not be created");
+               return FALSE;
+       }
+       if (!dh->get_my_public_value(dh, &ecdh_pubkey))
+       {
+               DBG1(DBG_PTS, "DH public key could not be generated");
+               dh->destroy(dh);
+               return FALSE;
+       }
+       ecdh_pubkey_x = chunk_create(ecdh_pubkey.ptr, ecdh_pubkey.len / 2);
+       ecdh_pubkey_y = chunk_create(ecdh_pubkey.ptr + ecdh_pubkey_x.len,
+                                                                ecdh_pubkey_x.len);
+
+       /* get ECC public key */
+       ecc_pubkey_x = chunk_create(public->publicArea.unique.ecc.x.buffer,
+                                                               public->publicArea.unique.ecc.x.size);
+       ecc_pubkey_y = chunk_create(public->publicArea.unique.ecc.y.buffer,
+                                                               public->publicArea.unique.ecc.y.size);
+       ecc_pubkey = chunk_cat("cc", ecc_pubkey_x, ecc_pubkey_y);
+
+       /* compute point multiplication of ecc_pubkey with ecdh_privkey */
+       if (!dh->set_other_public_value(dh, ecc_pubkey))
+       {
+               DBG1(DBG_PTS, "ECC public could not be set");
+               goto error;
+       }
+       if (!dh->get_shared_secret(dh, &z))
+       {
+               DBG1(DBG_PTS, "could not create shared secret");
+               goto error;
+       }
+
+       hash_len = hash_len_from_tpm_alg_id(hash_alg);
+
+       /* derive secret using KDFe */
+       if (!kdf_e(hash_alg, z, secret_label, ecdh_pubkey_x, ecc_pubkey_x,
+                          hash_len, secret))
+       {
+               goto error;
+       }
+
+       /* copy ECDH pubkey to encrypted salt parameter */
+       len = htons(ecdh_pubkey_x.len);
+       encryptedSalt->size = 2 * sizeof(len) + ecdh_pubkey.len;
+       pos = encryptedSalt->secret;
+       memcpy(pos, (uint8_t*)&len, sizeof(len));
+       pos += sizeof(len);
+       memcpy(pos, ecdh_pubkey_x.ptr, ecdh_pubkey_x.len);
+       pos += ecdh_pubkey_x.len;
+       memcpy(pos, (uint8_t*)&len, sizeof(len));
+       pos += sizeof(len);
+       memcpy(pos, ecdh_pubkey_y.ptr, ecdh_pubkey_y.len);
+
+       success = TRUE;
+
+error:
+       dh->destroy(dh);
+       chunk_free(&ecdh_pubkey);
+       chunk_free(&ecc_pubkey);
+       chunk_clear(&z);
+
+       return success;
+}
+
+/**
+ * See header
+ */
+tpm_tss_tss2_session_t* tpm_tss_tss2_session_create(uint32_t ek_handle,
+                                                       TPM2B_PUBLIC *public, TSS2_SYS_CONTEXT  *sys_context)
+{
+       private_tpm_tss_tss2_session_t *this;
+       chunk_t secret = chunk_empty;
+       chunk_t kdf_label = chunk_from_chars('A','T','H', 0x00);
+       chunk_t nonce_caller, nonce_tpm;
+       size_t hash_len;
+       uint32_t rval;
+
+       TPM2B_ENCRYPTED_SECRET encryptedSalt;
+       TPM2_SE sessionType = TPM2_SE_HMAC;
+       TPMT_SYM_DEF symmetric = { .algorithm = TPM2_ALG_AES,
+                                      .mode.aes  = TPM2_ALG_CFB, .keyBits.aes = 128 };
+
+       INIT(this,
+               .public = {
+                       .set_cmd_auths = _set_cmd_auths,
+                       .get_rsp_auths = _get_rsp_auths,
+                       .destroy = _destroy,
+               },
+               .sys_context = sys_context,
+               .hash_alg = public->publicArea.nameAlg,
+       );
+
+       hash_len = hash_len_from_tpm_alg_id(this->hash_alg);
+
+       this->crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CFB,
+                                                                                               symmetric.keyBits.aes / 8);
+       if (!this->crypter)
+       {
+               DBG1(DBG_PTS, "could not create %N crypter", encryption_algorithm_names,
+                                                                                                        ENCR_AES_CFB);
+               goto error;
+       }
+
+       if (!generate_nonce(hash_len, &this->nonceCaller))
+       {
+               goto error;
+       }
+
+       /* determine endorsement key type */
+       switch (public->publicArea.type)
+       {
+               case TPM2_ALG_RSA:
+                       DBG1(DBG_PTS, LABEL "RSA EK handle: 0x%08x", ek_handle);
+                       if (!rsa_salt(public, this->hash_alg, &secret, &encryptedSalt))
+                       {
+                               goto error;
+                       }
+                       break;
+               case TPM2_ALG_ECC:
+                       DBG1(DBG_PTS, LABEL "ECC EK handle: 0x%08x", ek_handle);
+                       if (!ecc_salt(public, this->hash_alg, &secret, &encryptedSalt))
+                       {
+                               goto error;
+                       }
+                       break;
+               default:
+                       DBG1(DBG_PTS, LABEL "unsupported ek key type");
+                       goto error;
+       }
+
+       rval = Tss2_Sys_StartAuthSession(this->sys_context, ek_handle, TPM2_RH_NULL,
+                               NULL, &this->nonceCaller, &encryptedSalt, sessionType, &symmetric,
+                               this->hash_alg, &this->session_handle, &this->nonceTPM, NULL);
+       if (rval != TSS2_RC_SUCCESS)
+       {
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_StartAuthSession failed: 0x%06x", rval);
+               goto error;
+    }
+       DBG2(DBG_PTS, LABEL "session handle: 0x%08x", this->session_handle);
+
+       nonce_tpm = chunk_create(this->nonceTPM.buffer, this->nonceTPM.size);
+       nonce_caller = chunk_create(this->nonceCaller.buffer, this->nonceCaller.size);
+
+       /* derive sessionKey using KDFa */
+       if (!kdf_a(this->hash_alg, secret, kdf_label, nonce_tpm, nonce_caller,
+                          hash_len, &this->session_key))
+       {
+               goto error;
+       }
+       chunk_clear(&secret);
+       DBG4(DBG_PTS, LABEL "session key: %B", &this->session_key);
+
+       return &this->public;
+
+       error:
+               chunk_clear(&secret);
+               destroy(this);
+               return NULL;
+}
+
+#endif /* TSS_TSS2_V2 */
diff --git a/src/libtpmtss/tpm_tss_tss2_session.h b/src/libtpmtss/tpm_tss_tss2_session.h
new file mode 100644 (file)
index 0000000..479ebf6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 Andreas Steffen, strongSec GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tpm_tss_tss2_session tpm_tss_tss2_session
+ * @{ @ingroup libtpmtss
+ */
+
+#ifndef TPM_TSS_TSS2_SESSION_H_
+#define TPM_TSS_TSS2_SESSION_H_
+
+#ifdef TSS_TSS2_V2
+
+#include <library.h>
+
+#include <tss2/tss2_sys.h>
+
+typedef struct tpm_tss_tss2_session_t tpm_tss_tss2_session_t;
+
+/**
+ * public interface of TPM 2.0 TSS session object
+ */
+struct tpm_tss_tss2_session_t {
+
+       /**
+        * Set TPM 2.0 TSS Command Authentications
+        *
+        * @return              TRUE if successful
+        */
+       bool (*set_cmd_auths)(tpm_tss_tss2_session_t *this);
+
+       /**
+        * Get TPM 2.0 TSS Response Authentications
+        *
+        * @return              TRUE if successful
+        */
+         bool (*get_rsp_auths)(tpm_tss_tss2_session_t *this);
+
+       /**
+        * Destroy the TPM 2.0 TSS session object
+        */
+       void (*destroy)(tpm_tss_tss2_session_t *this);
+
+};
+
+/**
+ * Create a tpm_tss_tss2_session instance.
+ *
+ * @param ek_handle     endorsement key handle
+ * @param public        public information on endorsement key
+ * @param sys_context   TSS2 system context
+ */
+tpm_tss_tss2_session_t* tpm_tss_tss2_session_create(uint32_t ek_handle,
+                                                       TPM2B_PUBLIC *public, TSS2_SYS_CONTEXT *sys_context);
+
+#endif /* TSS_TSS2_V2 */
+
+#endif /** TPM_TSS_TSS2_SESSION_H_ @}*/
index 7357fdeaf8bcf6381d8543b07496fa2089776595..915bd31b29e954e7819e7d61301058b91db1db31 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (C) 2018-2020 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
+ * Copyright (C) 2021 Andreas Steffen, strongSec GmbH
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
 
 #ifdef TSS_TSS2_V2
 
+#include "tpm_tss_tss2_session.h"
+
 #include <asn1/asn1.h>
 #include <asn1/oid.h>
 #include <bio/bio_reader.h>
 #include <bio/bio_writer.h>
 #include <threading/mutex.h>
 
-#include <tss2/tss2_sys.h>
-
 #include <dlfcn.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
-#define LABEL  "TPM 2.0 -"
+#define LABEL  "TPM 2.0 - "
 
 #define PLATFORM_PCR   24
 #define MAX_PCR_BANKS   4
@@ -94,6 +96,11 @@ struct private_tpm_tss_tss2_t {
         */
        bool old_event_digest_format;
 
+       /**
+        * TSS2 session used for protected communication with TPM 2.0
+        */
+       tpm_tss_tss2_session_t *session;
+
        /**
         * Mutex controlling access to the TPM 2.0 context
         */
@@ -144,7 +151,7 @@ static TPM2_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg)
 /**
  * Convert TPM2_ALG_ID to hash algorithm
  */
-static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg)
+hash_algorithm_t hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg)
 {
        switch (alg)
        {
@@ -167,6 +174,31 @@ static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg)
        }
 }
 
+/**
+ * Return hash length of TPM2_ALG_ID algorithm
+ */
+size_t hash_len_from_tpm_alg_id(TPM2_ALG_ID alg)
+{
+       switch (alg)
+       {
+               case TPM2_ALG_SHA1:
+                       return TPM2_SHA1_DIGEST_SIZE;
+               case TPM2_ALG_SHA256:
+               case TPM2_ALG_SHA3_256:
+                       return TPM2_SHA256_DIGEST_SIZE;
+               case TPM2_ALG_SHA384:
+               case TPM2_ALG_SHA3_384:
+                       return TPM2_SHA384_DIGEST_SIZE;
+               case TPM2_ALG_SHA512:
+               case TPM2_ALG_SHA3_512:
+                       return TPM2_SHA512_DIGEST_SIZE;
+               case TPM2_ALG_SM3_256:
+                       return TPM2_SM3_256_DIGEST_SIZE;
+               default:
+                       return 0;
+       }
+}
+
 /**
  * Check if an algorithm given by its TPM2_ALG_ID is supported by the TPM
  */
@@ -234,8 +266,8 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_TPM_PROPERTIES: 0x%06x",
-                                          LABEL, rval);
+               DBG1(DBG_PTS, LABEL "GetCapability failed for TPM2_CAP_TPM_PROPERTIES: 0x%06x",
+                                         rval);
                return FALSE;
        }
        memset(manufacturer,  '\0', sizeof(manufacturer));
@@ -280,7 +312,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
                this->fips_186_4 = lib->settings->get_bool(lib->settings,
                                        "%s.plugins.tpm.fips_186_4", FALSE, lib->ns);
        }
-       DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u %s", LABEL,
+       DBG2(DBG_PTS, LABEL "manufacturer: %s (%s) rev: %05.2f %u %s",
                 manufacturer, vendor_string, (float)revision/100, year,
                 fips_140_2 ? "FIPS 140-2" : (this->fips_186_4 ? "FIPS 186-4" : ""));
 
@@ -313,8 +345,8 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_ALGS: 0x%06x",
-                                          LABEL, rval);
+               DBG1(DBG_PTS, LABEL "GetCapability failed for TPM2_CAP_ALGS: 0x%06x",
+                                         rval);
                return FALSE;
        }
 
@@ -335,7 +367,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
                pos += written;
                len -= written;
        }
-       DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
+       DBG2(DBG_PTS, LABEL "algorithms:%s", buf);
 
        /* get supported ECC curves */
        this->mutex->lock(this->mutex);
@@ -344,8 +376,8 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_ECC_CURVES: 0x%06x",
-                                          LABEL, rval);
+               DBG1(DBG_PTS, LABEL "GetCapability failed for TPM2_CAP_ECC_CURVES: 0x%06x",
+                                         rval);
                return FALSE;
        }
 
@@ -365,7 +397,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
                pos += written;
                len -= written;
        }
-       DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
+       DBG2(DBG_PTS, LABEL "ECC curves:%s", buf);
 
        /* get assigned PCR banks */
        this->mutex->lock(this->mutex);
@@ -374,8 +406,8 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_PCRS: 0x%06x",
-                                          LABEL, rval);
+               DBG1(DBG_PTS, LABEL "GetCapability failed for TPM2_CAP_PCRS: 0x%06x",
+                                         rval);
                return FALSE;
        }
 
@@ -399,7 +431,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this)
                pos += written;
                len -= written;
        }
-       DBG2(DBG_PTS, "%s PCR banks:%s", LABEL, buf);
+       DBG2(DBG_PTS, LABEL "PCR banks:%s", buf);
 
        return TRUE;
 }
@@ -421,7 +453,7 @@ static bool initialize_tcti_context(private_tpm_tss_tss2_t *this)
        rval = tcti_init(NULL, &tcti_context_size, tcti_opts);
        if (rval != TSS2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s tcti init setup failed: 0x%06x",  LABEL, rval);
+               DBG1(DBG_PTS, LABEL "tcti init setup failed: 0x%06x", rval);
                return FALSE;
        }
 
@@ -433,7 +465,7 @@ static bool initialize_tcti_context(private_tpm_tss_tss2_t *this)
        rval = tcti_init(this->tcti_context, &tcti_context_size, tcti_opts);
        if (rval != TSS2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s tcti init allocation failed: 0x%06x", LABEL,rval);
+               DBG1(DBG_PTS, LABEL "tcti init allocation failed: 0x%06x", rval);
                return FALSE;
        }
        return TRUE;
@@ -465,8 +497,7 @@ static bool initialize_sys_context(private_tpm_tss_tss2_t *this)
                                                           this->tcti_context, &abi_version);
        if (rval != TSS2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
-                                          LABEL, rval);
+               DBG1(DBG_PTS, LABEL "could not get sys_context: 0x%06x", rval);
                return FALSE;
        }
 
@@ -523,8 +554,8 @@ bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
-                                          LABEL, handle, rval);
+               DBG1(DBG_PTS, LABEL "could not read public key from handle 0x%08x: 0x%06x",
+                                         handle, rval);
                return FALSE;
        }
        return TRUE;
@@ -577,8 +608,8 @@ METHOD(tpm_tss_t, get_public, chunk_t,
                                        NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
                                        CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
                        {
-                               DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of public key "
-                                                         "failed", LABEL);
+                               DBG1(DBG_PTS, LABEL "subjectPublicKeyInfo encoding of public key "
+                                                                       "failed");
                                return chunk_empty;
                        }
                        break;
@@ -618,7 +649,7 @@ METHOD(tpm_tss_t, get_public, chunk_t,
                        break;
                }
                default:
-                       DBG1(DBG_PTS, "%s unsupported key type", LABEL);
+                       DBG1(DBG_PTS, LABEL "unsupported key type");
                        return chunk_empty;
        }
        DBG1(DBG_PTS, "signature algorithm is %N with %N hash",
@@ -706,7 +737,7 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*,
                        break;
                }
                default:
-                       DBG1(DBG_PTS, "%s unsupported key type", LABEL);
+                       DBG1(DBG_PTS, LABEL "unsupported key type");
                        return enumerator_create_empty();
        }
        return enumerator_create_single(signature_params_clone(&supported_scheme),
@@ -743,8 +774,8 @@ static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs,
        /* check if there is an assigned PCR bank for this hash algorithm */
        if (!has_pcr_bank(this, alg))
        {
-               DBG1(DBG_PTS, "%s %N hash algorithm not supported by any PCR bank",
-                        LABEL, hash_algorithm_short_names, alg);
+               DBG1(DBG_PTS, LABEL "%N hash algorithm not supported by any PCR bank",
+                                         hash_algorithm_short_names, alg);
                return FALSE;
        }
 
@@ -781,8 +812,8 @@ METHOD(tpm_tss_t, read_pcr, bool,
 
        if (pcr_num >= PLATFORM_PCR)
        {
-               DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
-                                          LABEL, PLATFORM_PCR);
+               DBG1(DBG_PTS, LABEL "maximum number of supported PCR is %d",
+                                         PLATFORM_PCR);
                return FALSE;
        }
 
@@ -801,8 +832,7 @@ METHOD(tpm_tss_t, read_pcr, bool,
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
-                                          LABEL, rval);
+               DBG1(DBG_PTS, LABEL "PCR bank could not be read: 0x%60x", rval);
                return FALSE;
        }
        pcr_value_ptr = (uint8_t *)pcr_values.digests[0].buffer;
@@ -827,8 +857,8 @@ METHOD(tpm_tss_t, extend_pcr, bool,
        /* check if there is an assigned PCR bank for this hash algorithm */
        if (!has_pcr_bank(this, alg))
        {
-               DBG1(DBG_PTS, "%s %N hash algorithm not supported by any PCR bank",
-                        LABEL, hash_algorithm_short_names, alg);
+               DBG1(DBG_PTS, LABEL "%N hash algorithm not supported by any PCR bank",
+                                         hash_algorithm_short_names, alg);
                return FALSE;
        }
 
@@ -883,8 +913,8 @@ METHOD(tpm_tss_t, extend_pcr, bool,
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS, "%s PCR %02u could not be extended: 0x%06x",
-                        LABEL, pcr_num, rval);
+               DBG1(DBG_PTS, LABEL "PCR %02u could not be extended: 0x%06x",
+                                         pcr_num, rval);
                return FALSE;
        }
 
@@ -935,7 +965,7 @@ METHOD(tpm_tss_t, quote, bool,
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval);
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_Quote failed: 0x%06x", rval);
                return FALSE;
        }
        quoted_chunk = chunk_create(quoted.attestationData, quoted.size);
@@ -948,7 +978,7 @@ METHOD(tpm_tss_t, quote, bool,
                !reader->read_data  (reader, 10, &pcr_select) ||
                !reader->read_data16(reader, &pcr_digest))
        {
-               DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL);
+               DBG1(DBG_PTS, LABEL "parsing of quoted struct failed");
                reader->destroy(reader);
                return FALSE;
        }
@@ -987,8 +1017,8 @@ METHOD(tpm_tss_t, quote, bool,
                        hash_alg = sig.signature.ecdsa.hash;
                        break;
                default:
-                       DBG1(DBG_PTS, "%s unsupported %N signature algorithm",
-                                                  LABEL, tpm_alg_id_names, sig.sigAlg);
+                       DBG1(DBG_PTS, LABEL "unsupported %N signature algorithm",
+                                                 tpm_alg_id_names, sig.sigAlg);
                        return FALSE;
        }
 
@@ -1053,8 +1083,8 @@ METHOD(tpm_tss_t, sign, bool,
        alg_id = hash_alg_to_tpm_alg_id(hash_alg);
        if (!is_supported_alg(this, alg_id))
        {
-               DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
-                        LABEL, hash_algorithm_short_names, hash_alg);
+               DBG1(DBG_PTS, LABEL "%N hash algorithm not supported by TPM",
+                                         hash_algorithm_short_names, hash_alg);
                return FALSE;
        }
 
@@ -1085,8 +1115,8 @@ METHOD(tpm_tss_t, sign, bool,
        }
        else
        {
-               DBG1(DBG_PTS, "%s signature scheme %N not supported by TPM key",
-                        LABEL, signature_scheme_names, scheme);
+               DBG1(DBG_PTS, LABEL "signature scheme %N not supported by TPM key",
+                                         signature_scheme_names, scheme);
                return FALSE;
        }
 
@@ -1101,7 +1131,7 @@ METHOD(tpm_tss_t, sign, bool,
                this->mutex->unlock(this->mutex);
                if (rval != TPM2_RC_SUCCESS)
                {
-                       DBG1(DBG_PTS,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL, rval);
+                       DBG1(DBG_PTS,LABEL "Tss2_Sys_Hash failed: 0x%06x", rval);
                        return FALSE;
                }
        }
@@ -1116,8 +1146,8 @@ METHOD(tpm_tss_t, sign, bool,
                                                                                  alg_id, &sequence_handle, 0);
                if (rval != TPM2_RC_SUCCESS)
                {
-                       DBG1(DBG_PTS,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x",
-                                LABEL, rval);
+                       DBG1(DBG_PTS, LABEL "Tss2_Sys_HashSequenceStart failed: 0x%06x",
+                                                 rval);
                        this->mutex->unlock(this->mutex);
                        return FALSE;
                }
@@ -1133,8 +1163,8 @@ METHOD(tpm_tss_t, sign, bool,
                                                                                   &auth_cmd, &buffer, 0);
                        if (rval != TPM2_RC_SUCCESS)
                        {
-                               DBG1(DBG_PTS,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x",
-                                        LABEL, rval);
+                               DBG1(DBG_PTS, LABEL "Tss2_Sys_SequenceUpdate failed: 0x%06x",
+                                                         rval);
                                this->mutex->unlock(this->mutex);
                                return FALSE;
                        }
@@ -1147,8 +1177,8 @@ METHOD(tpm_tss_t, sign, bool,
                this->mutex->unlock(this->mutex);
                if (rval != TPM2_RC_SUCCESS)
                {
-                       DBG1(DBG_PTS,"%s Tss2_Sys_SequenceComplete failed: 0x%06x",
-                                LABEL, rval);
+                       DBG1(DBG_PTS, LABEL "Tss2_Sys_SequenceComplete failed: 0x%06x",
+                                                 rval);
                        return FALSE;
                }
        }
@@ -1159,7 +1189,7 @@ METHOD(tpm_tss_t, sign, bool,
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL, rval);
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_Sign failed: 0x%06x", rval);
                return FALSE;
        }
 
@@ -1206,34 +1236,107 @@ METHOD(tpm_tss_t, sign, bool,
                                                                        sig.signature.ecdsa.signatureS.size)));
                        break;
                default:
-                       DBG1(DBG_PTS, "%s unsupported %N signature scheme",
-                                                  LABEL, signature_scheme_names, scheme);
+                       DBG1(DBG_PTS, LABEL "unsupported %N signature scheme",
+                                                 signature_scheme_names, scheme);
                        return FALSE;
        }
 
        return TRUE;
 }
 
+/**
+ * Check if an authenticated session with the TPM 2.0 can be started
+ * The handle of the RSA Endorsement Key (EK) is required
+ */
+static void try_session_start(private_tpm_tss_tss2_t *this)
+{
+       uint32_t ek_handle = 0;
+       chunk_t handle_chunk;
+       char *handle_str;
+
+       TPM2B_PUBLIC public = { 0, };
+
+       /* get Endorsement Key (EK) handle from settings */
+       handle_str = lib->settings->get_str(lib->settings,
+                                                               "%s.plugins.tpm.ek_handle", NULL, lib->ns);
+       if (handle_str)
+       {
+               handle_chunk = chunk_from_hex(chunk_from_str(handle_str),
+                                                                        (char *)&ek_handle);
+               ek_handle = (handle_chunk.len == 4) ? htonl(ek_handle) : 0;
+
+               /* establish protected auth session if ek_handle is set */
+               if (ek_handle && read_public(this, ek_handle, &public))
+               {
+                       this->mutex->lock(this->mutex);
+                       this->session = tpm_tss_tss2_session_create(ek_handle, &public,
+                                                                                                               this->sys_context);
+                       this->mutex->unlock(this->mutex);
+               }
+       }
+}
+
 METHOD(tpm_tss_t, get_random, bool,
        private_tpm_tss_tss2_t *this, size_t bytes, uint8_t *buffer)
 {
-       size_t len, random_len= sizeof(TPM2B_DIGEST)-2;
+       size_t len, random_len = sizeof(TPM2B_DIGEST)-2;
        TPM2B_DIGEST random = { random_len, };
        uint8_t *pos = buffer;
        uint32_t rval;
 
+       if (!this->session)
+       {
+               try_session_start(this);
+       }
+
        while (bytes > 0)
        {
-               len = min(bytes, random_len);
+               bool success = FALSE;
 
+               len = min(bytes, random_len);
                this->mutex->lock(this->mutex);
-               rval = Tss2_Sys_GetRandom(this->sys_context, NULL, len, &random, NULL);
-               this->mutex->unlock(this->mutex);
+
+               rval = Tss2_Sys_GetRandom_Prepare(this->sys_context, len);
                if (rval != TSS2_RC_SUCCESS)
                {
-                       DBG1(DBG_PTS,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL, rval);
-                       return FALSE;
+                       DBG1(DBG_PTS, "%s Tss2_Sys_GetRandom_Prepare failed: 0x%06x",
+                                LABEL, rval);
+                       goto error;
            }
+
+               if (this->session && !this->session->set_cmd_auths(this->session))
+               {
+                       goto error;
+               }
+
+               rval = Tss2_Sys_Execute(this->sys_context);
+               if (rval != TSS2_RC_SUCCESS)
+               {
+                       DBG1(DBG_PTS, LABEL "Tss2_Sys_Execute failed: 0x%06x", rval);
+                       goto error;
+               }
+
+               if (this->session && !this->session->get_rsp_auths(this->session))
+               {
+                       goto error;
+               }
+
+               rval = Tss2_Sys_GetRandom_Complete(this->sys_context, &random);
+               if (rval != TSS2_RC_SUCCESS)
+               {
+                       DBG1(DBG_PTS, LABEL "Tss2_Sys_GetRandom_Complete failed: 0x%06x",
+                                                 rval);
+                       goto error;
+               }
+               success = TRUE;
+
+error:
+               this->mutex->unlock(this->mutex);
+               if (!success)
+               {
+                       return FALSE;
+               }
+
                memcpy(pos, random.buffer, random.size);
                pos   += random.size;
                bytes -= random.size;
@@ -1265,8 +1368,8 @@ METHOD(tpm_tss_t, get_data, bool,
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS,"%s Tss2_Sys_GetCapability failed for "
-                                        "TPM2_CAP_TPM_PROPERTIES: 0x%06x", LABEL, rval);
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_GetCapability failed for "
+                                                       "TPM2_CAP_TPM_PROPERTIES: 0x%06x", rval);
                return FALSE;
        }
        max_data_size = min(cap_data.data.tpmProperties.tpmProperty[0].value,
@@ -1279,7 +1382,7 @@ METHOD(tpm_tss_t, get_data, bool,
        this->mutex->unlock(this->mutex);
        if (rval != TPM2_RC_SUCCESS)
        {
-               DBG1(DBG_PTS,"%s Tss2_Sys_NV_ReadPublic failed: 0x%06x", LABEL, rval);
+               DBG1(DBG_PTS, LABEL "Tss2_Sys_NV_ReadPublic failed: 0x%06x", rval);
                return FALSE;
        }
        nv_size = nv_public.nvPublic.dataSize;
@@ -1304,7 +1407,7 @@ METHOD(tpm_tss_t, get_data, bool,
                this->mutex->unlock(this->mutex);
                if (rval != TPM2_RC_SUCCESS)
                {
-                       DBG1(DBG_PTS,"%s Tss2_Sys_NV_Read failed: 0x%06x", LABEL, rval);
+                       DBG1(DBG_PTS, LABEL "Tss2_Sys_NV_Read failed: 0x%06x", rval);
                        chunk_free(data);
                        return FALSE;
                }
@@ -1352,26 +1455,9 @@ METHOD(tpm_tss_t, get_event_digest, bool,
                        {
                                return FALSE;
                        }
-                       hash_alg = hash_alg_from_tpm_alg_id(alg_id);
+                       hash_alg =   hash_alg_from_tpm_alg_id(alg_id);
+                       digest_len = hash_len_from_tpm_alg_id(alg_id);
 
-                       switch (hash_alg)
-                       {
-                               case HASH_SHA1:
-                                       digest_len = HASH_SIZE_SHA1;
-                                       break;
-                               case HASH_SHA256:
-                                       digest_len = HASH_SIZE_SHA256;
-                                       break;
-                               case HASH_SHA384:
-                                       digest_len = HASH_SIZE_SHA384;
-                                       break;
-                               case HASH_SHA512:
-                                       digest_len = HASH_SIZE_SHA512;
-                                       break;
-                               default:
-                                       DBG2(DBG_PTS, "alg_id: 0x%04x", alg_id);
-                                       return FALSE;
-                       }
                        if (hash_alg == alg)
                        {
                                *digest = chunk_alloc(digest_len);
@@ -1397,6 +1483,7 @@ METHOD(tpm_tss_t, get_event_digest, bool,
 METHOD(tpm_tss_t, destroy, void,
        private_tpm_tss_tss2_t *this)
 {
+       DESTROY_IF(this->session);
        finalize_context(this);
        this->mutex->destroy(this->mutex);
        free(this->version_info.ptr);
@@ -1443,6 +1530,7 @@ tpm_tss_t *tpm_tss_tss2_create()
                destroy(this);
                return NULL;
        }
+
        return &this->public;
 }
 
@@ -1467,8 +1555,8 @@ bool tpm_tss_tss2_init(void)
        {
                i = 1;
        }
-       DBG2(DBG_PTS, "%s \"%s\" in-kernel resource manager is %spresent",
-                                  LABEL, tcti_options[0], i ? "not " : "");
+       DBG2(DBG_PTS, LABEL "\"%s\" in-kernel resource manager is %spresent",
+                                 tcti_options[0], i ? "not " : "");
 
        /* select a dynamic TCTI library (device, tabrmd or mssim) */
        tcti_name = lib->settings->get_str(lib->settings,
@@ -1485,8 +1573,7 @@ bool tpm_tss_tss2_init(void)
        }
        if (!match)
        {
-               DBG1(DBG_PTS, "%s \"%s\" is not a valid TCTI library name",
-                        LABEL, tcti_lib);
+               DBG1(DBG_PTS, LABEL "\"%s\" is not a valid TCTI library name", tcti_lib);
                return FALSE;
        }
 
@@ -1497,20 +1584,20 @@ bool tpm_tss_tss2_init(void)
        tcti_handle = dlopen(tcti_lib, RTLD_LAZY);
        if (!tcti_handle)
        {
-               DBG1(DBG_PTS, "%s could not load \"%s\"", LABEL, tcti_lib);
+               DBG1(DBG_PTS, LABEL "could not load \"%s\"", tcti_lib);
                return FALSE;
        }
 
        infofn = (TSS2_TCTI_INFO_FUNC)dlsym(tcti_handle, TSS2_TCTI_INFO_SYMBOL);
     if (!infofn)
        {
-        DBG1(DBG_PTS, "%s symbol \"%s\" not found in \"%s\"", LABEL,
-                                          TSS2_TCTI_INFO_SYMBOL, tcti_lib);
+        DBG1(DBG_PTS, LABEL "symbol \"%s\" not found in \"%s\"",
+                                         TSS2_TCTI_INFO_SYMBOL, tcti_lib);
                tpm_tss_tss2_deinit();
 
                return FALSE;
     }
-       DBG2(DBG_PTS, "%s \"%s\" successfully loaded", LABEL, tcti_lib);
+       DBG2(DBG_PTS, LABEL "\"%s\" successfully loaded", tcti_lib);
        info = infofn();
        tcti_init = info->init;