123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /* SPDX-License-Identifier: BSD-3-Clause */
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <openssl/rand.h>
- #include "files.h"
- #include "log.h"
- #include "tpm2.h"
- #include "tpm2_tool.h"
- #include "tpm2_alg_util.h"
- #include "tpm2_identity_util.h"
- #include "tpm2_options.h"
- #include "tpm2_openssl.h"
- typedef struct tpm_makecred_ctx tpm_makecred_ctx;
- struct tpm_makecred_ctx {
- TPM2B_NAME object_name;
- char *out_file_path;
- char *input_secret_data;
- char *public_key_path; /* path to the public portion of an object */
- TPM2B_PUBLIC public;
- TPM2B_DIGEST credential;
- struct {
- UINT8 e :1;
- UINT8 s :1;
- UINT8 n :1;
- UINT8 o :1;
- } flags;
- char *key_type; //type of key attempting to load, defaults to auto attempt
- };
- static tpm_makecred_ctx ctx = {
- .object_name = TPM2B_EMPTY_INIT,
- .public = TPM2B_EMPTY_INIT,
- .credential = TPM2B_EMPTY_INIT,
- };
- static bool write_cred_and_secret(const char *path, TPM2B_ID_OBJECT *cred,
- TPM2B_ENCRYPTED_SECRET *secret) {
- bool result = false;
- FILE *fp = fopen(path, "wb+");
- if (!fp) {
- LOG_ERR("Could not open file \"%s\" error: \"%s\"", path,
- strerror(errno));
- return false;
- }
- result = files_write_header(fp, 1);
- if (!result) {
- LOG_ERR("Could not write version header");
- goto out;
- }
- result = files_write_16(fp, cred->size);
- if (!result) {
- LOG_ERR("Could not write credential size");
- goto out;
- }
- result = files_write_bytes(fp, cred->credential, cred->size);
- if (!result) {
- LOG_ERR("Could not write credential data");
- goto out;
- }
- result = files_write_16(fp, secret->size);
- if (!result) {
- LOG_ERR("Could not write secret size");
- goto out;
- }
- result = files_write_bytes(fp, secret->secret, secret->size);
- if (!result) {
- LOG_ERR("Could not write secret data");
- goto out;
- }
- result = true;
- out:
- fclose(fp);
- return result;
- }
- static tool_rc make_external_credential_and_save(void) {
- /*
- * 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);
- 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_share_secret_with_public_key(&seed,
- &ctx.public, label, 9, &encrypted_seed);
- if (!res) {
- LOG_ERR("Failed Seed Encryption\n");
- return tool_rc_general_error;
- }
- /*
- * 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 cred_size = ctx.credential.size;
- if (!tpm2_util_is_big_endian()) {
- cred_size = tpm2_util_endian_swap_16(cred_size);
- }
- memcpy(marshalled_inner_integrity.buffer, &cred_size, sizeof(cred_size));
- 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) ? tool_rc_success : tool_rc_general_error;
- }
- static tool_rc make_credential_and_save(ESYS_CONTEXT *ectx) {
- TPM2B_ID_OBJECT *cred_blob;
- TPM2B_ENCRYPTED_SECRET *secret;
- ESYS_TR tr_handle = ESYS_TR_NONE;
- tool_rc rc = tpm2_loadexternal(ectx,
- NULL, &ctx.public, TPM2_RH_NULL, &tr_handle);
- if (rc != tool_rc_success) {
- return rc;
- }
- rc = tpm2_makecredential(ectx, tr_handle,
- &ctx.credential, &ctx.object_name, &cred_blob,
- &secret);
- if (rc != tool_rc_success) {
- return rc;
- }
- rc = tpm2_flush_context(ectx, tr_handle);
- if (rc != tool_rc_success) {
- free(cred_blob);
- free(secret);
- return rc;
- }
- bool ret = write_cred_and_secret(ctx.out_file_path, cred_blob, secret);
- free(cred_blob);
- free(secret);
- return ret ? tool_rc_success : tool_rc_general_error;
- }
- static bool on_option(char key, char *value) {
- switch (key) {
- case 'u':
- if (ctx.flags.e) {
- LOG_ERR("Specify public key with **-u** or **-e**, not both");
- return false;
- }
- ctx.public_key_path = value;
- ctx.flags.e = 1;
- break;
- case 'e':
- if (ctx.flags.e) {
- LOG_ERR("Specify encryption key with **-u** or **-e**, not both");
- return false;
- }
- ctx.public_key_path = value;
- ctx.flags.e = 1;
- break;
- case 's':
- ctx.input_secret_data = strcmp("-", value) ? value : NULL;
- ctx.flags.s = 1;
- break;
- case 'n':
- ctx.object_name.size = BUFFER_SIZE(TPM2B_NAME, name);
- int q;
- if ((q = tpm2_util_hex_to_byte_structure(value, &ctx.object_name.size,
- ctx.object_name.name)) != 0) {
- LOG_ERR("FAILED: %d", q);
- return false;
- }
- ctx.flags.n = 1;
- break;
- case 'o':
- ctx.out_file_path = value;
- ctx.flags.o = 1;
- break;
- case 'G':
- ctx.key_type = value;
- break;
- }
- return true;
- }
- static bool tpm2_tool_onstart(tpm2_options **opts) {
- const struct option topts[] = {
- {"encryption-key", required_argument, NULL, 'e'},
- {"public", required_argument, NULL, 'u'},
- {"secret", required_argument, NULL, 's'},
- {"name", required_argument, NULL, 'n'},
- {"credential-blob", required_argument, NULL, 'o'},
- { "key-algorithm", required_argument, NULL, 'G'},
- };
- *opts = tpm2_options_new("G:u:e:s:n:o:", ARRAY_LEN(topts), topts, on_option,
- NULL, TPM2_OPTIONS_OPTIONAL_SAPI);
- return *opts != NULL;
- }
- static void set_default_TCG_EK_template(TPMI_ALG_PUBLIC alg) {
- switch (alg) {
- case TPM2_ALG_RSA:
- ctx.public.publicArea.parameters.rsaDetail.symmetric.algorithm =
- TPM2_ALG_AES;
- ctx.public.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
- ctx.public.publicArea.parameters.rsaDetail.symmetric.mode.aes =
- TPM2_ALG_CFB;
- ctx.public.publicArea.parameters.rsaDetail.scheme.scheme = TPM2_ALG_NULL;
- ctx.public.publicArea.parameters.rsaDetail.keyBits = 2048;
- ctx.public.publicArea.parameters.rsaDetail.exponent = 0;
- ctx.public.publicArea.unique.rsa.size = 256;
- break;
- case TPM2_ALG_ECC:
- ctx.public.publicArea.parameters.eccDetail.symmetric.algorithm =
- TPM2_ALG_AES;
- ctx.public.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
- ctx.public.publicArea.parameters.eccDetail.symmetric.mode.sym =
- TPM2_ALG_CFB;
- ctx.public.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG_NULL;
- ctx.public.publicArea.parameters.eccDetail.curveID = TPM2_ECC_NIST_P256;
- ctx.public.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG_NULL;
- ctx.public.publicArea.unique.ecc.x.size = 32;
- ctx.public.publicArea.unique.ecc.y.size = 32;
- break;
- }
- ctx.public.publicArea.objectAttributes =
- TPMA_OBJECT_RESTRICTED | TPMA_OBJECT_ADMINWITHPOLICY
- | TPMA_OBJECT_DECRYPT | TPMA_OBJECT_FIXEDTPM
- | TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_SENSITIVEDATAORIGIN;
- static const TPM2B_DIGEST auth_policy = {
- .size = 32,
- .buffer = {
- 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xB3, 0xF8, 0x1A, 0x90, 0xCC,
- 0x8D, 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, 0xD7, 0x6E, 0x06, 0x52,
- 0x0B, 0x64, 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, 0x69, 0xAA
- }
- };
- TPM2B_DIGEST *authp = &ctx.public.publicArea.authPolicy;
- *authp = auth_policy;
- ctx.public.publicArea.nameAlg = TPM2_ALG_SHA256;
- }
- static tool_rc process_input(void) {
- TPMI_ALG_PUBLIC alg = TPM2_ALG_NULL;
- if (ctx.key_type) {
- LOG_WARN("Because **-G** is specified, assuming input encryption public key is in PEM format.");
- alg = tpm2_alg_util_from_optarg(ctx.key_type,
- tpm2_alg_util_flags_asymmetric);
- if (alg == TPM2_ALG_ERROR ||
- (alg != TPM2_ALG_RSA && alg != TPM2_ALG_ECC)) {
- LOG_ERR("Unsupported key type, got: \"%s\"", ctx.key_type);
- return tool_rc_general_error;
- }
- }
- if (ctx.public_key_path) {
- bool result = tpm2_openssl_load_public(ctx.public_key_path, alg,
- &ctx.public);
- if (!result) {
- return tool_rc_general_error;
- }
- }
- /*
- * Since it is a PEM we will fixate the key properties from TCG EK
- * template since we had to choose "a template".
- */
- if (ctx.key_type) {
- set_default_TCG_EK_template(alg);
- }
- if (!ctx.flags.s) {
- LOG_ERR("Specify the secret either as a file or a '-' for stdin");
- return tool_rc_option_error;
- }
- if (!ctx.flags.e || !ctx.flags.n || !ctx.flags.o) {
- LOG_ERR("Expected mandatory options e, n, o.");
- return tool_rc_option_error;
- }
- /*
- * Maximum size of the allowed secret-data size to fit in TPM2B_DIGEST
- */
- ctx.credential.size = TPM2_SHA512_DIGEST_SIZE;
- bool result = files_load_bytes_from_buffer_or_file_or_stdin(NULL,
- ctx.input_secret_data, &ctx.credential.size, ctx.credential.buffer);
- if (!result) {
- return tool_rc_general_error;
- }
- return tool_rc_success;
- }
- static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
- UNUSED(flags);
- tool_rc rc = process_input();
- if (rc != tool_rc_success) {
- return rc;
- }
- // Run it outside of a TPM
- return ectx ?
- make_credential_and_save(ectx) :
- make_external_credential_and_save();
- }
- // Register this tool with tpm2_tool.c
- TPM2_TOOL_REGISTER("makecredential", tpm2_tool_onstart, tpm2_tool_onrun, NULL, NULL)
|