tpm2-tools/Add-ability-to-run-tpm2_makecredential-without-a-TPM.patch
Javier Martinez Canillas af88e806f0
Add tpm2_pcrreset and tpm2_checkquote tools
This change adds the backported tpm2_pcrreset and tpm2_checkquote tools
and also the support to allow tpm2_makecredential tool to run off-TPM.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
2019-05-10 15:24:01 +02:00

1306 lines
44 KiB
Diff

From d74b094191f2e09b29cfad4f03322e0cd64497ab Mon Sep 17 00:00:00 2001
From: jetwhiz <charles.munson@ll.mit.edu>
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 <Charles.Munson@ll.mit.edu>
---
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 <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <openssl/aes.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+#include <openssl/obj_mac.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+
+#include <tss2/tss2_mu.h>
+#include <tss2/tss2_sys.h>
+
+#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 <tss2/tss2_sys.h>
+
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+#include <openssl/rsa.h>
+
+
+/**
+ * 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 <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <openssl/aes.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+#include <openssl/obj_mac.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+
+#include <tss2/tss2_sys.h>
+
+#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 <tss2/tss2_sys.h>
+
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+#include <openssl/rsa.h>
+
+#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 <filePath> -o <filePath>
tpm2_activatecredential -c ak.context -C ek.context -P abc123 -e abc123 -f <filePath> -o <filePath>
-tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -X -f <filePath> -o <filePath>
+tpm2_activatecredential -H 0x81010002 -k 0x81010001 -P 123abc -e 1a1b1c -f <filePath> -o <filePath>
```
# 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 <fileName> -s <fileName>
tpm2_certify -C obj.context -c key.context -P 0x0011 -K 0x00FF -g 0x00B -a <fileName> -s <fileName>
-tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -X -g 0x00B -a <fileName> -s <fileName>
+tpm2_certify -H 0x81010002 -k 0x81010001 -P 0011 -K 00FF -g 0x00B -a <fileName> -s <fileName>
```
# 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 <filePath> -o <filePath>
tpm2_encryptdecrypt -c key.context -P abc123 -D NO -I <filePath> -o <filePath>
-tpm2_encryptdecrypt -k 0x81010001 -P 123abca -X -D NO -I <filePath> -o <filePath>
+tpm2_encryptdecrypt -k 0x81010001 -P 123abca -D NO -I <filePath> -o <filePath>
```
# 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 <tss2/tss2_sys.h>
#include <tss2/tss2_mu.h>
+#include <openssl/rand.h>
#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