From d74b094191f2e09b29cfad4f03322e0cd64497ab Mon Sep 17 00:00:00 2001 From: jetwhiz Date: Tue, 5 Feb 2019 17:24:44 -0500 Subject: [PATCH] Add ability to run tpm2_makecredential without a TPM Used some functions from tpm2_import for off-TPM functionality - Move needed, overlap code into tpm2_identity_util Add new global -X/--openssl-backend option for any tools that can operate w/o TPM Signed-off-by: jetwhiz --- Makefile.am | 6 +- lib/tpm2_identity_util.c | 480 ++++++++++++++++++++++++ lib/tpm2_identity_util.h | 141 +++++++ lib/tpm2_openssl.c | 162 ++++++++ lib/tpm2_openssl.h | 108 ++++++ lib/tpm2_options.c | 36 +- lib/tpm2_options.h | 1 + man/common/tcti.md | 4 + man/tpm2_activatecredential.1.md | 2 +- man/tpm2_certify.1.md | 2 +- man/tpm2_create.1.md | 2 +- man/tpm2_encryptdecrypt.1.md | 2 +- man/tpm2_getpubak.1.md | 2 +- man/tpm2_makecredential.1.md | 3 +- test/system/test_tpm2_makecredential.sh | 2 + tools/tpm2_makecredential.c | 103 ++++- 16 files changed, 1033 insertions(+), 23 deletions(-) create mode 100644 lib/tpm2_identity_util.c create mode 100644 lib/tpm2_identity_util.h create mode 100644 lib/tpm2_openssl.c create mode 100644 lib/tpm2_openssl.h diff --git a/Makefile.am b/Makefile.am index ffe22f383e3..2195537ce01 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,7 +119,11 @@ lib_libcommon_a_SOURCES = \ lib/tpm2_errata.c \ lib/tpm2_errata.h \ lib/tpm2_header.h \ + lib/tpm2_identity_util.c \ + lib/tpm2_identity_util.h \ lib/tpm2_nv_util.h \ + lib/tpm2_openssl.c \ + lib/tpm2_openssl.h \ lib/tpm2_password_util.c \ lib/tpm2_password_util.h \ lib/tpm2_policy.c \ @@ -347,4 +351,4 @@ man/man1/%.1 : man/%.1.md $(MARKDOWN_COMMON_DEPS) -e '/\[object attribute specifiers\]/d' \ < $< | pandoc -s -t man > $@ -CLEANFILES = $(man1_MANS) +CLEANFILES = $(man1_MANS) \ No newline at end of file diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c new file mode 100644 index 00000000000..70bf03647eb --- /dev/null +++ b/lib/tpm2_identity_util.c @@ -0,0 +1,480 @@ +//**********************************************************************; +// Copyright (c) 2017, Intel Corporation +// Copyright (c) 2019 Massachusetts Institute of Technology +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +//********************************************************************** + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "files.h" +#include "log.h" +#include "tpm2_alg_util.h" +#include "tpm_kdfa.h" +#include "tpm2_openssl.h" +#include "tpm2_identity_util.h" +#include "tpm2_util.h" + + +// Identity-related functionality that the TPM normally does, but using OpenSSL + +#if defined(LIBRESSL_VERSION_NUMBER) +static int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen, + const unsigned char *from, int flen, const unsigned char *param, int plen, + const EVP_MD *md, const EVP_MD *mgf1md) { + + int ret = 0; + int i, emlen = tlen - 1; + unsigned char *db, *seed; + unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE]; + int mdlen; + + if (md == NULL) + md = EVP_sha1(); + if (mgf1md == NULL) + mgf1md = md; + + mdlen = EVP_MD_size(md); + + if (flen > emlen - 2 * mdlen - 1) { + RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, + RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + if (emlen < 2 * mdlen + 1) { + RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, + RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + to[0] = 0; + seed = to + 1; + db = to + mdlen + 1; + + if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL)) + return 0; + memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1); + db[emlen - flen - mdlen - 1] = 0x01; + memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen); + if (RAND_bytes(seed, mdlen) <= 0) + return 0; + + dbmask = OPENSSL_malloc(emlen - mdlen); + if (dbmask == NULL) { + RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0) + goto err; + for (i = 0; i < emlen - mdlen; i++) + db[i] ^= dbmask[i]; + + if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0) + goto err; + for (i = 0; i < mdlen; i++) + seed[i] ^= seedmask[i]; + + ret = 1; + + err: + OPENSSL_free(dbmask); + + return ret; +} +#endif + +static TPM2_KEY_BITS get_pub_asym_key_bits(TPM2B_PUBLIC *public) { + + TPMU_PUBLIC_PARMS *p = &public->publicArea.parameters; + switch(public->publicArea.type) { + case TPM2_ALG_ECC: + /* fall-thru */ + case TPM2_ALG_RSA: + return p->asymDetail.symmetric.keyBits.sym; + /* no default */ + } + + return 0; +} + +static bool encrypt_seed_with_tpm2_rsa_public_key(TPM2B_DIGEST *protection_seed, + TPM2B_PUBLIC *parent_pub, unsigned char *label, int labelLen, + TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed) { + bool rval = false; + RSA *rsa = NULL; + + // Public modulus (RSA-only!) + TPMI_RSA_KEY_BITS mod_size_bits = parent_pub->publicArea.parameters.rsaDetail.keyBits; + UINT16 mod_size = mod_size_bits / 8; + TPM2B *pub_key_val = (TPM2B *)&parent_pub->publicArea.unique.rsa; + unsigned char *pub_modulus = malloc(mod_size); + if (pub_modulus == NULL) { + LOG_ERR("Failed to allocate memory to store public key's modulus."); + return false; + } + memcpy(pub_modulus, pub_key_val->buffer, mod_size); + + TPMI_ALG_HASH parent_name_alg = parent_pub->publicArea.nameAlg; + + /* + * This is the biggest buffer value, so it should always be sufficient. + */ + unsigned char encoded[TPM2_MAX_DIGEST_BUFFER]; + int return_code = RSA_padding_add_PKCS1_OAEP_mgf1(encoded, + mod_size, protection_seed->buffer, protection_seed->size, label, labelLen, + tpm2_openssl_halg_from_tpmhalg(parent_name_alg), NULL); + if (return_code != 1) { + LOG_ERR("Failed RSA_padding_add_PKCS1_OAEP_mgf1\n"); + goto error; + } + BIGNUM* bne = BN_new(); + if (!bne) { + LOG_ERR("BN_new for bne failed\n"); + goto error; + } + return_code = BN_set_word(bne, RSA_F4); + if (return_code != 1) { + LOG_ERR("BN_set_word failed\n"); + BN_free(bne); + goto error; + } + rsa = RSA_new(); + if (!rsa) { + LOG_ERR("RSA_new failed\n"); + BN_free(bne); + goto error; + } + return_code = RSA_generate_key_ex(rsa, mod_size_bits, bne, NULL); + BN_free(bne); + if (return_code != 1) { + LOG_ERR("RSA_generate_key_ex failed\n"); + goto error; + } + BIGNUM *n = BN_bin2bn(pub_modulus, mod_size, NULL); + if (n == NULL) { + LOG_ERR("BN_bin2bn failed\n"); + goto error; + } + if (!RSA_set0_key(rsa, n, NULL, NULL)) { + LOG_ERR("RSA_set0_key failed\n"); + BN_free(n); + goto error; + } + // Encrypting + encrypted_protection_seed->size = mod_size; + return_code = RSA_public_encrypt(mod_size, encoded, + encrypted_protection_seed->secret, rsa, RSA_NO_PADDING); + if (return_code < 0) { + LOG_ERR("Failed RSA_public_encrypt\n"); + goto error; + } + + rval = true; + +error: + free(pub_modulus); + RSA_free(rsa); + return rval; +} + +bool tpm2_identity_util_calc_outer_integrity_hmac_key_and_dupsensitive_enc_key( + TPM2B_PUBLIC *parent_pub, + TPM2B_NAME *pubname, + TPM2B_DIGEST *protection_seed, + TPM2B_MAX_BUFFER *protection_hmac_key, + TPM2B_MAX_BUFFER *protection_enc_key) { + + TPM2B null_2b = { .size = 0 }; + + TPMI_ALG_HASH parent_alg = parent_pub->publicArea.nameAlg; + UINT16 parent_hash_size = tpm2_alg_util_get_hash_size(parent_alg); + + TSS2_RC rval = tpm_kdfa(parent_alg, (TPM2B *)protection_seed, "INTEGRITY", + &null_2b, &null_2b, parent_hash_size * 8, protection_hmac_key); + if (rval != TPM2_RC_SUCCESS) { + return false; + } + + TPM2_KEY_BITS pub_key_bits = get_pub_asym_key_bits(parent_pub); + + rval = tpm_kdfa(parent_alg, (TPM2B *)protection_seed, "STORAGE", + (TPM2B *)pubname, &null_2b, pub_key_bits, + protection_enc_key); + if (rval != TPM2_RC_SUCCESS) { + return false; + } + + return true; +} + + +bool tpm2_identity_util_encrypt_seed_with_public_key(TPM2B_DIGEST *protection_seed, + TPM2B_PUBLIC *parent_pub, unsigned char *label, int labelLen, + TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed) { + bool result = false; + TPMI_ALG_PUBLIC alg = parent_pub->publicArea.type; + + switch (alg) { + case TPM2_ALG_RSA: + result = encrypt_seed_with_tpm2_rsa_public_key(protection_seed, + parent_pub, label, labelLen, encrypted_protection_seed); + break; + case TPM2_ALG_ECC: + LOG_ERR("Algorithm '%s' not supported yet", tpm2_alg_util_algtostr(alg)); + result = false; + break; + default: + LOG_ERR("Cannot handle algorithm, got: %s", tpm2_alg_util_algtostr(alg)); + return false; + } + + return result; +} + +static const EVP_CIPHER *tpm_alg_to_ossl(TPMT_SYM_DEF_OBJECT *sym) { + + switch(sym->algorithm) { + case TPM2_ALG_AES: { + switch (sym->keyBits.aes) { + case 128: + return EVP_aes_128_cfb(); + case 256: + return EVP_aes_256_cfb(); + /* no default */ + } + } + /* no default */ + } + + LOG_ERR("Unsupported parent key symmetric parameters"); + + return NULL; +} + +static bool aes_encrypt_buffers(TPMT_SYM_DEF_OBJECT *sym, uint8_t *encryption_key, + uint8_t *buf1, size_t buf1_len, + uint8_t *buf2, size_t buf2_len, + TPM2B_MAX_BUFFER *cipher_text) { + + bool result = false; + + unsigned offset = 0; + size_t total_len = buf1_len + buf2_len; + + if (total_len > sizeof(cipher_text->buffer)) { + LOG_ERR("Plaintext too big, got %zu, expected less then %zu", + total_len, sizeof(cipher_text->buffer)); + return false; + } + + const EVP_CIPHER *cipher = tpm_alg_to_ossl(sym); + if (!cipher) { + return false; + } + + const unsigned char iv[512] = { 0 }; + + if (((unsigned long)EVP_CIPHER_iv_length(cipher)) > sizeof(iv)) { + LOG_ERR("IV size is bigger then IV buffer size"); + return false; + } + + EVP_CIPHER_CTX *ctx = tpm2_openssl_cipher_new(); + + int rc = EVP_EncryptInit_ex(ctx, cipher, NULL, encryption_key, iv); + if (!rc) { + return false; + } + + EVP_CIPHER_CTX_set_padding(ctx, 0); + + uint8_t *bufs[2] = { + buf1, + buf2 + }; + + size_t lens[ARRAY_LEN(bufs)] = { + buf1_len, + buf2_len + }; + + unsigned i; + for (i=0; i < ARRAY_LEN(bufs); i++) { + + uint8_t *b = bufs[i]; + size_t l = lens[i]; + + if (!b) { + continue; + } + + int output_len = total_len - offset; + + rc = EVP_EncryptUpdate(ctx, &cipher_text->buffer[offset], &output_len, b, l); + if (!rc) { + LOG_ERR("Encrypt failed"); + goto out; + } + + offset += l; + } + + int tmp_len = 0; + rc = EVP_EncryptFinal_ex(ctx, NULL, &tmp_len); + if (!rc) { + LOG_ERR("Encrypt failed"); + goto out; + } + + cipher_text->size = total_len; + + result = true; + +out: + tpm2_openssl_cipher_free(ctx); + + return result; +} + +static void hmac_outer_integrity( + TPMI_ALG_HASH parent_name_alg, + uint8_t *buffer1, uint16_t buffer1_size, + uint8_t *buffer2, uint16_t buffer2_size, uint8_t *hmac_key, + TPM2B_DIGEST *outer_integrity_hmac) { + + uint8_t to_hmac_buffer[TPM2_MAX_DIGEST_BUFFER]; + memcpy(to_hmac_buffer, buffer1, buffer1_size); + memcpy(to_hmac_buffer + buffer1_size, buffer2, buffer2_size); + uint32_t size = 0; + + UINT16 hash_size = tpm2_alg_util_get_hash_size(parent_name_alg); + + HMAC(tpm2_openssl_halg_from_tpmhalg(parent_name_alg), hmac_key, hash_size, to_hmac_buffer, + buffer1_size + buffer2_size, outer_integrity_hmac->buffer, &size); + outer_integrity_hmac->size = size; +} + +bool tpm2_identity_util_calculate_inner_integrity( + TPMI_ALG_HASH name_alg, + TPM2B_SENSITIVE *sensitive, + TPM2B_NAME *pubname, + TPM2B_DATA *enc_sensitive_key, + TPMT_SYM_DEF_OBJECT *sym_alg, + TPM2B_MAX_BUFFER *encrypted_inner_integrity) { + + //Marshal sensitive area + uint8_t buffer_marshalled_sensitiveArea[TPM2_MAX_DIGEST_BUFFER] = { 0 }; + size_t marshalled_sensitive_size = 0; + Tss2_MU_TPMT_SENSITIVE_Marshal(&sensitive->sensitiveArea, + buffer_marshalled_sensitiveArea + sizeof(uint16_t), TPM2_MAX_DIGEST_BUFFER, + &marshalled_sensitive_size); + size_t marshalled_sensitive_size_info = 0; + Tss2_MU_UINT16_Marshal(marshalled_sensitive_size, buffer_marshalled_sensitiveArea, + sizeof(uint16_t), &marshalled_sensitive_size_info); + + //concatenate NAME + memcpy( + buffer_marshalled_sensitiveArea + marshalled_sensitive_size + + marshalled_sensitive_size_info, + pubname->name, + pubname->size); + + //Digest marshalled-sensitive || name + uint8_t *marshalled_sensitive_and_name_digest = + buffer_marshalled_sensitiveArea + marshalled_sensitive_size + + marshalled_sensitive_size_info + + pubname->size; + size_t digest_size_info = 0; + UINT16 hash_size = tpm2_alg_util_get_hash_size(name_alg); + Tss2_MU_UINT16_Marshal(hash_size, marshalled_sensitive_and_name_digest, + sizeof(uint16_t), &digest_size_info); + + digester d = tpm2_openssl_halg_to_digester(name_alg); + d(buffer_marshalled_sensitiveArea, + marshalled_sensitive_size_info + marshalled_sensitive_size + + pubname->size, + marshalled_sensitive_and_name_digest + digest_size_info); + + //Inner integrity + encrypted_inner_integrity->size = marshalled_sensitive_size_info + + marshalled_sensitive_size + pubname->size; + + return aes_encrypt_buffers( + sym_alg, + enc_sensitive_key->buffer, + marshalled_sensitive_and_name_digest, + hash_size + digest_size_info, + buffer_marshalled_sensitiveArea, + marshalled_sensitive_size_info + marshalled_sensitive_size, + encrypted_inner_integrity); +} + +void tpm2_identity_util_calculate_outer_integrity( + TPMI_ALG_HASH parent_name_alg, + TPM2B_NAME *pubname, + TPM2B_MAX_BUFFER *marshalled_sensitive, + TPM2B_MAX_BUFFER *protection_hmac_key, + TPM2B_MAX_BUFFER *protection_enc_key, + TPMT_SYM_DEF_OBJECT *sym_alg, + TPM2B_MAX_BUFFER *encrypted_duplicate_sensitive, + TPM2B_DIGEST *outer_hmac) { + + //Calculate dupSensitive + encrypted_duplicate_sensitive->size = + marshalled_sensitive->size; + + aes_encrypt_buffers( + sym_alg, + protection_enc_key->buffer, + marshalled_sensitive->buffer, + marshalled_sensitive->size, + NULL, 0, + encrypted_duplicate_sensitive); + //Calculate outerHMAC + hmac_outer_integrity( + parent_name_alg, + encrypted_duplicate_sensitive->buffer, + encrypted_duplicate_sensitive->size, + pubname->name, + pubname->size, + protection_hmac_key->buffer, + outer_hmac); +} diff --git a/lib/tpm2_identity_util.h b/lib/tpm2_identity_util.h new file mode 100644 index 00000000000..49f231a3347 --- /dev/null +++ b/lib/tpm2_identity_util.h @@ -0,0 +1,141 @@ +//**********************************************************************; +// Copyright (c) 2017, Intel Corporation +// Copyright (c) 2019 Massachusetts Institute of Technology +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +//********************************************************************** + +#ifndef LIB_TPM2_IDENTITY_UTIL_H_ +#define LIB_TPM2_IDENTITY_UTIL_H_ + +#include + +#include +#include +#include + + +/** + * Generates HMAC integrity and symmetric encryption keys for TPM2 identies. + * + * @param parent_pub + * The public key used for seed generation and protection. + * @param pubname + * The Name object associated with the parent_pub credential. + * @param protection_seed + * The symmetric seed value used to generate protection keys. + * @param protection_hmac_key + * The HMAC integrity key to populate. + * @param protection_enc_key + * The symmetric encryption key to populate. + * @return + * True on success, false on failure. + */ +bool tpm2_identity_util_calc_outer_integrity_hmac_key_and_dupsensitive_enc_key( + TPM2B_PUBLIC *parent_pub, + TPM2B_NAME *pubname, + TPM2B_DIGEST *protection_seed, + TPM2B_MAX_BUFFER *protection_hmac_key, + TPM2B_MAX_BUFFER *protection_enc_key); + +/** + * Encrypts seed with parent public key for TPM2 credential protection process. + * + * @param protection_seed + * The identity structure protection seed that is to be encrypted. + * @param parent_pub + * The public key used for encryption. + * @param label + * Indicates label for the seed, such as "IDENTITY" or "DUPLICATE". + * @param labelLen + * Length of label. + * @param encrypted_protection_seed + * The encrypted protection seed to populate. + * @return + * True on success, false on failure. + */ +bool tpm2_identity_util_encrypt_seed_with_public_key( + TPM2B_DIGEST *protection_seed, + TPM2B_PUBLIC *parent_pub, + unsigned char *label, + int labelLen, + TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed); + +/** + * Marshalls Credential Value and encrypts it with the symmetric encryption key. + * + * @param name_alg + * Hash algorithm used to compute Name of the public key. + * @param sensitive + * The Credential Value to be marshalled and encrypted with symmetric key. + * @param pubname + * The Name object corresponding to the public key. + * @param enc_sensitive_key + * The symmetric encryption key. + * @param sym_alg + * The algorithm used for the symmetric encryption key. + * @param encrypted_inner_integrity + * The encrypted, marshalled Credential Value to populate. + * @return + * True on success, false on failure. + */ +bool tpm2_identity_util_calculate_inner_integrity( + TPMI_ALG_HASH name_alg, + TPM2B_SENSITIVE *sensitive, + TPM2B_NAME *pubname, + TPM2B_DATA *enc_sensitive_key, + TPMT_SYM_DEF_OBJECT *sym_alg, + TPM2B_MAX_BUFFER *encrypted_inner_integrity); + +/** + * Encrypts Credential Value with enc key and calculates HMAC with hmac key. + * + * @param parent_name_alg + * Hash algorithm used to compute Name of the public key. + * @param pubname + * The Name object corresponding to the public key. + * @param marshalled_sensitive + * Marshalled Credential Value to be encrypted with symmetric encryption key. + * @param protection_hmac_key + * The HMAC integrity key. + * @param protection_enc_key + * The symmetric encryption key. + * @param sym_alg + * The algorithm used for the symmetric encryption key. + * @param encrypted_duplicate_sensitive + * The encrypted Credential Value to populate. + * @param outer_hmac + * The outer HMAC structure to populate. + */ +void tpm2_identity_util_calculate_outer_integrity( + TPMI_ALG_HASH parent_name_alg, + TPM2B_NAME *pubname, + TPM2B_MAX_BUFFER *marshalled_sensitive, + TPM2B_MAX_BUFFER *protection_hmac_key, + TPM2B_MAX_BUFFER *protection_enc_key, + TPMT_SYM_DEF_OBJECT *sym_alg, + TPM2B_MAX_BUFFER *encrypted_duplicate_sensitive, + TPM2B_DIGEST *outer_hmac); + +#endif /* LIB_TPM2_IDENTITY_UTIL_H_ */ diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c new file mode 100644 index 00000000000..0bfc95bd1ef --- /dev/null +++ b/lib/tpm2_openssl.c @@ -0,0 +1,162 @@ +//**********************************************************************; +// Copyright (c) 2017, Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +//********************************************************************** + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "files.h" +#include "log.h" +#include "tpm2_alg_util.h" +#include "tpm2_openssl.h" +#include "tpm2_util.h" + + +const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm) { + + switch (algorithm) { + case TPM2_ALG_SHA1: + return EVP_sha1(); + case TPM2_ALG_SHA256: + return EVP_sha256(); + case TPM2_ALG_SHA384: + return EVP_sha384(); + case TPM2_ALG_SHA512: + return EVP_sha512(); + default: + return NULL; + } + /* no return, not possible */ +} + +#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { + + if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL)) { + return 0; + } + + if (n != NULL) { + BN_free(r->n); + r->n = n; + } + + if (e != NULL) { + BN_free(r->e); + r->e = e; + } + + if (d != NULL) { + BN_free(r->d); + r->d = d; + } + + return 1; +} +#endif + +static inline const char *get_openssl_err(void) { + return ERR_error_string(ERR_get_error(), NULL); +} + + +EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void) { + EVP_CIPHER_CTX *ctx; +#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) + ctx = malloc(sizeof(*ctx)); +#else + ctx = EVP_CIPHER_CTX_new(); +#endif + if (!ctx) + return NULL; + +#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) + EVP_CIPHER_CTX_init(ctx); +#endif + + return ctx; +} + +void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx) { +#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) + EVP_CIPHER_CTX_cleanup(ctx); + free(ctx); +#else + EVP_CIPHER_CTX_free(ctx); +#endif +} + +digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) { + + switch(halg) { + case TPM2_ALG_SHA1: + return SHA1; + case TPM2_ALG_SHA256: + return SHA256; + case TPM2_ALG_SHA384: + return SHA384; + case TPM2_ALG_SHA512: + return SHA512; + /* no default */ + } + + return NULL; +} + +/* + * Per man openssl(1), handle the following --passin formats: + * pass:password + * the actual password is password. Since the password is visible to utilities (like 'ps' under Unix) this form should only be used where security is not + * important. + * + * env:var obtain the password from the environment variable var. Since the environment of other processes is visible on certain platforms (e.g. ps under certain + * Unix OSes) this option should be used with caution. + * + * file:pathname + * the first line of pathname is the password. If the same pathname argument is supplied to -passin and -passout arguments then the first line will be used + * for the input password and the next line for the output password. pathname need not refer to a regular file: it could for example refer to a device or + * named pipe. + * + * fd:number read the password from the file descriptor number. This can be used to send the data via a pipe for example. + * + * stdin read the password from standard input. + * + */ + +typedef bool (*pfn_ossl_pw_handler)(const char *passin, char **pass); diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h new file mode 100644 index 00000000000..d749cb350ac --- /dev/null +++ b/lib/tpm2_openssl.h @@ -0,0 +1,108 @@ +//**********************************************************************; +// Copyright (c) 2017, Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +//********************************************************************** + +#ifndef LIB_TPM2_OPENSSL_H_ +#define LIB_TPM2_OPENSSL_H_ + +#include + +#include +#include +#include + +#if (OPENSSL_VERSION_NUMBER < 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) /* OpenSSL 1.1.0 */ +#define LIB_TPM2_OPENSSL_OPENSSL_PRE11 +#endif + + +#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11) +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); +#endif + + +/** + * Function prototype for a hashing routine. + * + * This is a wrapper around OSSL SHA256|384 and etc digesters. + * + * @param d + * The data to digest. + * @param n + * The length of the data to digest. + * @param md + * The output message digest. + * @return + * A pointer to the digest or NULL on error. + */ +typedef unsigned char *(*digester)(const unsigned char *d, size_t n, unsigned char *md); + +/** + * Get an openssl message digest from a tpm hashing algorithm. + * @param algorithm + * The tpm algorithm to get the corresponding openssl version of. + * @return + * A pointer to a message digester or NULL on failure. + */ +const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm); + +/** + * Obtains an OpenSSL EVP_CIPHER_CTX dealing with version + * API changes in OSSL. + * + * @return + * An Initialized OpenSSL EVP_CIPHER_CTX. + */ +EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void); + +/** + * Free's an EVP_CIPHER_CTX obtained via tpm2_openssl_cipher_new() + * dealing with OSSL API version changes. + * @param ctx + * The EVP_CIPHER_CTX to free. + */ +void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx); + +/** + * Returns a function pointer capable of performing the + * given digest from a TPMI_HASH_ALG. + * + * @param halg + * The hashing algorithm to use. + * @return + * NULL on failure or a valid digester on success. + */ +digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg); + +typedef enum tpm2_openssl_load_rc tpm2_openssl_load_rc; +enum tpm2_openssl_load_rc { + lprc_error = 0, /* an error has occurred */ + lprc_private = 1 << 0, /* successfully loaded a private portion of object */ + lprc_public = 1 << 1, /* successfully loaded a public portion of object */ +}; + + +#endif /* LIB_TPM2_OPENSSL_H_ */ diff --git a/lib/tpm2_options.c b/lib/tpm2_options.c index c2962ee95d4..8c3f36cacea 100644 --- a/lib/tpm2_options.c +++ b/lib/tpm2_options.c @@ -268,9 +268,8 @@ static char* parse_socket_tcti(void) { static tcti_conf tcti_get_config(const char *optstr) { - tcti_conf conf = { - .name = NULL - }; + /* set up the default configuration */ + tcti_conf conf = { 0 }; /* no tcti config supplied, get it from env */ if (!optstr) { @@ -294,6 +293,11 @@ static tcti_conf tcti_get_config(const char *optstr) { } } } else { + /* handle case of TCTI set as "-T none" */ + if (!strcmp(optstr, "none")) { + return conf; + } + parse_env_tcti(optstr, &conf); } @@ -400,7 +404,7 @@ tpm2_option_code tpm2_handle_options (int argc, char **argv, * grep -rn case\ \'[a-zA-Z]\' | awk '{print $3}' | sed s/\'//g | sed s/\://g | sort | uniq | less */ struct option long_options [] = { - { "tcti", required_argument, NULL, 'T' }, + { "tcti", optional_argument, NULL, 'T' }, { "help", no_argument, NULL, 'h' }, { "verbose", no_argument, NULL, 'V' }, { "quiet", no_argument, NULL, 'Q' }, @@ -492,17 +496,23 @@ tpm2_option_code tpm2_handle_options (int argc, char **argv, if (!tool_opts || !(tool_opts->flags & TPM2_OPTIONS_NO_SAPI)) { tcti_conf conf = tcti_get_config(tcti_conf_option); - *tcti = tpm2_tcti_ldr_load(conf.name, conf.opts); - if (!*tcti) { - LOG_ERR("Could not load tcti, got: \"%s\"", conf.name); - goto out; - } + /* name can be NULL for optional SAPI tools */ + if (conf.name) { + *tcti = tpm2_tcti_ldr_load(conf.name, conf.opts); + if (!*tcti) { + LOG_ERR("Could not load tcti, got: \"%s\"", conf.name); + goto out; + } - if (!flags->enable_errata) { - flags->enable_errata = !!getenv (TPM2TOOLS_ENV_ENABLE_ERRATA); + if (!flags->enable_errata) { + flags->enable_errata = !!getenv (TPM2TOOLS_ENV_ENABLE_ERRATA); + } + free(conf.name); + free(conf.opts); + } else if (!tool_opts || !(tool_opts->flags & TPM2_OPTIONS_OPTIONAL_SAPI)) { + LOG_ERR("Requested no tcti, but tool requires TCTI."); + goto out; } - free(conf.name); - free(conf.opts); } rc = tpm2_option_code_continue; diff --git a/lib/tpm2_options.h b/lib/tpm2_options.h index 860d9b0deee..e16c5205044 100644 --- a/lib/tpm2_options.h +++ b/lib/tpm2_options.h @@ -105,6 +105,7 @@ typedef bool (*tpm2_arg_handler)(int argc, char **argv); */ #define TPM2_OPTIONS_SHOW_USAGE 0x1 #define TPM2_OPTIONS_NO_SAPI 0x2 +#define TPM2_OPTIONS_OPTIONAL_SAPI 0x4 struct tpm2_options { struct { diff --git a/man/common/tcti.md b/man/common/tcti.md index fd5f1683dfe..0cb06e3c403 100644 --- a/man/common/tcti.md +++ b/man/common/tcti.md @@ -18,6 +18,10 @@ The variables respected depend on how the software was configured. * socket - Typically used with the old resource manager, or talking directly to a simulator. * device - Used when talking directly to a TPM device file. + * none - Do not initialize a connection with the TPM. Some tools allow for off-tpm + options and thus support not using a TCTI. Tools that do not support it + will error when attempted to be used without a TCTI connection. Does not + support *ANY* options and *MUST BE* presented as the exact text of "none". * _TPM2TOOLS\_DEVICE\_FILE_: When using the device TCTI, specify the TPM device file. The default is diff --git a/man/tpm2_activatecredential.1.md b/man/tpm2_activatecredential.1.md index 25478790baf..b15569ae5cf 100644 --- a/man/tpm2_activatecredential.1.md +++ b/man/tpm2_activatecredential.1.md @@ -56,7 +56,7 @@ These options control the object verification: ``` tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P abc123 -e abc123 -f -o tpm2_activatecredential -c ak.context -C ek.context -P abc123 -e abc123 -f -o -tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -X -f -o +tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -f -o ``` # RETURNS diff --git a/man/tpm2_certify.1.md b/man/tpm2_certify.1.md index fba4a8f7c65..f4a78c70c00 100644 --- a/man/tpm2_certify.1.md +++ b/man/tpm2_certify.1.md @@ -71,7 +71,7 @@ These options control the ceritifcation: ``` tpm2_certify -H 0x81010002 -k 0x81010001 -P 0x0011 -K 0x00FF -g 0x00B -a -s tpm2_certify -C obj.context -c key.context -P 0x0011 -K 0x00FF -g 0x00B -a -s -tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -X -g 0x00B -a -s +tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -g 0x00B -a -s ``` # RETURNS diff --git a/man/tpm2_create.1.md b/man/tpm2_create.1.md index f6aed4a7756..51d71db2c75 100644 --- a/man/tpm2_create.1.md +++ b/man/tpm2_create.1.md @@ -86,7 +86,7 @@ These options for creating the tpm entity: ``` tpm2_create -H 0x81010001 -P abc123 -K def456 -g sha256 -G keyedhash-I data.File tpm2_create -c parent.context -P abc123 -K def456 -g sha256 -G keyedhash -I data.File -tpm2_create -H 0x81010001 -P 123abc -K 456def -X -g sha256 -G keyedhash -I data.File +tpm2_create -H 0x81010001 -P 123abc -K 456def -g sha256 -G keyedhash -I data.File ``` # RETURNS diff --git a/man/tpm2_encryptdecrypt.1.md b/man/tpm2_encryptdecrypt.1.md index ea349bec1e8..350737182dd 100644 --- a/man/tpm2_encryptdecrypt.1.md +++ b/man/tpm2_encryptdecrypt.1.md @@ -48,7 +48,7 @@ specified symmetric key. ``` tpm2_encryptdecrypt -k 0x81010001 -P abc123 -D NO -I -o tpm2_encryptdecrypt -c key.context -P abc123 -D NO -I -o -tpm2_encryptdecrypt -k 0x81010001 -P 123abca -X -D NO -I -o +tpm2_encryptdecrypt -k 0x81010001 -P 123abca -D NO -I -o ``` # RETURNS diff --git a/man/tpm2_getpubak.1.md b/man/tpm2_getpubak.1.md index 22ade8f0b33..1a71b49c110 100644 --- a/man/tpm2_getpubak.1.md +++ b/man/tpm2_getpubak.1.md @@ -80,7 +80,7 @@ loaded-key: ``` tpm2_getpubak -e abc123 -P abc123 -o passwd -E 0x81010001 -k 0x81010002 -f ./ak.pub -n ./ak.name -tpm2_getpubak -e 1a1b1c -P 123abc -o 1a1b1c -X -E 0x81010001 -k 0x81010002 -f ./ak.pub -n ./ak.name +tpm2_getpubak -e 1a1b1c -P 123abc -o 1a1b1c -E 0x81010001 -k 0x81010002 -f ./ak.pub -n ./ak.name ``` # RETURNS diff --git a/man/tpm2_makecredential.1.md b/man/tpm2_makecredential.1.md index 736ead591b8..1008682fe7f 100644 --- a/man/tpm2_makecredential.1.md +++ b/man/tpm2_makecredential.1.md @@ -14,7 +14,8 @@ TPM. # DESCRIPTION **tpm2_makecredential**(1) - Use a TPM public key to protect a secret that is used -to encrypt the AK certififcate. +to encrypt the AK certificate. This can be used without a TPM by using +the **none** TCTI option. # OPTIONS diff --git a/test/system/test_tpm2_makecredential.sh b/test/system/test_tpm2_makecredential.sh index cc920ccae07..84f77b3647b 100755 --- a/test/system/test_tpm2_makecredential.sh +++ b/test/system/test_tpm2_makecredential.sh @@ -72,4 +72,6 @@ Loadkeyname=`cat $output_ak_pub_name | xxd -p -c $file_size` tpm2_makecredential -Q -e $output_ek_pub -s $file_input_data -n $Loadkeyname -o $output_mkcredential +tpm2_makecredential -T none -Q -e $output_ek_pub -s $file_input_data -n $Loadkeyname -o $output_mkcredential + exit 0 diff --git a/tools/tpm2_makecredential.c b/tools/tpm2_makecredential.c index c8f49fe0207..259d39f30f3 100644 --- a/tools/tpm2_makecredential.c +++ b/tools/tpm2_makecredential.c @@ -1,5 +1,6 @@ //**********************************************************************; // Copyright (c) 2015-2018, Intel Corporation +// Copyright (c) 2019 Massachusetts Institute of Technology // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -38,12 +39,15 @@ #include #include +#include #include "files.h" #include "tpm2_options.h" #include "log.h" #include "files.h" -#include "tpm2_options.h" +#include "tpm2_alg_util.h" +#include "tpm2_openssl.h" +#include "tpm2_identity_util.h" #include "tpm2_tool.h" #include "tpm2_util.h" @@ -117,6 +121,93 @@ out: return result; } +static bool make_external_credential_and_save() { + + /* + * Get name_alg from the public key + */ + TPMI_ALG_HASH name_alg = ctx.public.publicArea.nameAlg; + + + /* + * Generate and encrypt seed + */ + TPM2B_DIGEST seed = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer); + seed.size = tpm2_alg_util_get_hash_size(name_alg); + RAND_bytes(seed.buffer, seed.size); + + TPM2B_ENCRYPTED_SECRET encrypted_seed = TPM2B_EMPTY_INIT; + unsigned char label[10] = { 'I', 'D', 'E', 'N', 'T', 'I', 'T', 'Y', 0 }; + bool res = tpm2_identity_util_encrypt_seed_with_public_key(&seed, + &ctx.public, label, 9, + &encrypted_seed); + if (!res) { + LOG_ERR("Failed Seed Encryption\n"); + return false; + } + + /* + * Perform identity structure calculations (off of the TPM) + */ + TPM2B_MAX_BUFFER hmac_key; + TPM2B_MAX_BUFFER enc_key; + tpm2_identity_util_calc_outer_integrity_hmac_key_and_dupsensitive_enc_key( + &ctx.public, + &ctx.object_name, + &seed, + &hmac_key, + &enc_key); + + /* + * The ctx.credential needs to be marshalled into struct with + * both size and contents together (to be encrypted as a block) + */ + TPM2B_MAX_BUFFER marshalled_inner_integrity = TPM2B_EMPTY_INIT; + marshalled_inner_integrity.size = ctx.credential.size + sizeof(ctx.credential.size); + UINT16 credSize = ctx.credential.size; + if (!tpm2_util_is_big_endian()) { + credSize = tpm2_util_endian_swap_16(credSize); + } + memcpy(marshalled_inner_integrity.buffer, &credSize, sizeof(credSize)); + memcpy(&marshalled_inner_integrity.buffer[2], ctx.credential.buffer, ctx.credential.size); + + /* + * Perform inner encryption (encIdentity) and outer HMAC (outerHMAC) + */ + TPM2B_DIGEST outer_hmac = TPM2B_EMPTY_INIT; + TPM2B_MAX_BUFFER encrypted_sensitive = TPM2B_EMPTY_INIT; + tpm2_identity_util_calculate_outer_integrity( + name_alg, + &ctx.object_name, + &marshalled_inner_integrity, + &hmac_key, + &enc_key, + &ctx.public.publicArea.parameters.rsaDetail.symmetric, + &encrypted_sensitive, + &outer_hmac); + + /* + * Package up the info to save + * cred_bloc = outer_hmac || encrypted_sensitive + * secret = encrypted_seed (with pubEK) + */ + TPM2B_ID_OBJECT cred_blob = TPM2B_TYPE_INIT(TPM2B_ID_OBJECT, credential); + + UINT16 outer_hmac_size = outer_hmac.size; + if (!tpm2_util_is_big_endian()) { + outer_hmac_size = tpm2_util_endian_swap_16(outer_hmac_size); + } + int offset = 0; + memcpy(cred_blob.credential + offset, &outer_hmac_size, sizeof(outer_hmac.size));offset += sizeof(outer_hmac.size); + memcpy(cred_blob.credential + offset, outer_hmac.buffer, outer_hmac.size);offset += outer_hmac.size; + //NOTE: do NOT include the encrypted_sensitive size, since it is encrypted with the blob! + memcpy(cred_blob.credential + offset, encrypted_sensitive.buffer, encrypted_sensitive.size); + + cred_blob.size = outer_hmac.size + encrypted_sensitive.size + sizeof(outer_hmac.size); + + return write_cred_and_secret(ctx.out_file_path, &cred_blob, &encrypted_seed); +} + static bool make_credential_and_save(TSS2_SYS_CONTEXT *sapi_context) { TSS2L_SYS_AUTH_RESPONSE sessions_data_out; @@ -198,7 +289,8 @@ bool tpm2_tool_onstart(tpm2_options **opts) { }; *opts = tpm2_options_new("e:s:n:o:", ARRAY_LEN(topts), topts, - on_option, NULL, TPM2_OPTIONS_SHOW_USAGE); + on_option, NULL, + TPM2_OPTIONS_SHOW_USAGE | TPM2_OPTIONS_OPTIONAL_SAPI); return *opts != NULL; } @@ -212,5 +304,10 @@ int tpm2_tool_onrun(TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) { return false; } - return make_credential_and_save(sapi_context) != true; + printf("make credential has SAPI CTX: %p", sapi_context); + + bool result = sapi_context ? make_credential_and_save(sapi_context) : + make_external_credential_and_save(); + + return result != true; } -- 2.21.0