aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2021-04-04 13:44:58 -0700
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2021-04-11 11:04:35 -0700
commit505479dedf49bc6b02701df9b2b9d4ef6a945972 (patch)
tree0b894f71ac4b9ad24c22dfee597db246821badd2
parent989984514ccd9f27a25dc838666b8ef6c4b7ecb2 (diff)
downloadopenssl_tpm2_engine-505479dedf49bc6b02701df9b2b9d4ef6a945972.tar.gz
create_tpm2_key: Add PCR policy option to key creation
The only current way to add policy to a key is to use policymaker to create it. This is actually a bit beyond most people, so this is a patch to simplify that: since most people only want very simple policies like PCR locking. This patch allows PCR policy to be specified as --pcr-lock [hash:]<pcr list>. This option may be repeated multiple times to add new banks. The option will collect the *current* values of the selected PCRs and lock the key to them (this means it can't be used for importable keys which are usually created away from the platform containing the TPM). Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--create_tpm2_key.1.in14
-rw-r--r--create_tpm2_key.c56
-rw-r--r--ibm-tss.h26
-rw-r--r--intel-tss.h22
-rw-r--r--tpm2-common.c253
-rw-r--r--tpm2-common.h6
6 files changed, 367 insertions, 10 deletions
diff --git a/create_tpm2_key.1.in b/create_tpm2_key.1.in
index b49c931..d7ff3ec 100644
--- a/create_tpm2_key.1.in
+++ b/create_tpm2_key.1.in
@@ -31,6 +31,20 @@ Example (PolicyAuthValue):
$ echo 0000016b >> policy.txt
+[PCR Values]
+
+The PCR values are specified as
+
+ <bank>:<list>
+
+Where <bank> is any supported PCR hash bank and list specifies the
+PCRs to lock the key to as both comma separated individual values as
+well as comma separated ranges. So
+
+ sha256:1,3 means PCRs 1 and 3 in the sha256 bank
+
+ sha512:1,3-5 means PCRs 1,3,4 and 5 in the sha512 bank
+
[examples]
Create a self-signed cert using the TPM engine:
diff --git a/create_tpm2_key.c b/create_tpm2_key.c
index 69cc516..530512d 100644
--- a/create_tpm2_key.c
+++ b/create_tpm2_key.c
@@ -36,6 +36,7 @@ static struct option long_options[] = {
{"key-size", 1, 0, 's'},
{"name-scheme", 1, 0, 'n'},
{"parent-handle", 1, 0, 'p'},
+ {"pcr-lock", 1, 0, 'x'},
{"wrap", 1, 0, 'w'},
{"version", 0, 0, 'v'},
{"password", 1, 0, 'k'},
@@ -94,6 +95,9 @@ usage(char *argv0)
" may not be used for general signing or\n"
" decryption but may be the parent of other\n"
" keys (i.e. it is a storage key)\n"
+ "\t-x, --pcr-lock <pcrs> Lock the created key to the specified PCRs\n"
+ " By current value. See PCR VALUES for\n"
+ " details about formatting\n"
"\n"
"Report bugs to " PACKAGE_BUGREPORT "\n",
argv0);
@@ -817,6 +821,10 @@ int main(int argc, char **argv)
ENCRYPTED_SECRET_2B secret, *enc_secret = NULL;
int restricted = 0;
char *parent_str = NULL;
+ TPML_PCR_SELECTION pcr_lock;
+ int has_policy = 0;
+
+ pcr_lock.count = 0;
OpenSSL_add_all_digests();
/* may be needed to decrypt the key */
@@ -824,7 +832,7 @@ int main(int argc, char **argv)
while (1) {
option_index = 0;
- c = getopt_long(argc, argv, "n:s:ab:p:hw:vk:re:ldc:i:",
+ c = getopt_long(argc, argv, "n:s:ab:p:hw:vk:re:ldc:i:x:",
long_options, &option_index);
if (c == -1)
break;
@@ -899,6 +907,9 @@ int main(int argc, char **argv)
case 'i':
import = optarg;
break;
+ case 'x':
+ tpm2_get_pcr_lock(&pcr_lock, optarg);
+ break;
case OPT_DEPRECATED:
version = 0;
break;
@@ -944,11 +955,24 @@ int main(int argc, char **argv)
exit(1);
}
+ if (pcr_lock.count !=0 && policyFilename) {
+ fprintf(stderr, "cannot specify both policy file and pcr lock\n");
+ exit(1);
+ }
+
+ if (pcr_lock.count != 0 && import) {
+ fprintf(stderr, "cannot specify pcr lock and import because pcrs may not be correct\n");
+ exit(1);
+ }
+
+ if (pcr_lock.count != 0 || policyFilename)
+ has_policy = 1;
+
digest.hashAlg = name_alg;
sizeInBytes = TSS_GetDigestSize(digest.hashAlg);
memset((uint8_t *)&digest.digest, 0, sizeInBytes);
- if (policyFilename) {
+ if (has_policy) {
sk = sk_TSSOPTPOLICY_new_null();
if (!sk) {
rc = NOT_TPM_ERROR;
@@ -956,10 +980,11 @@ int main(int argc, char **argv)
goto out_err;
}
- rc = tpm2_parse_policy_file(policyFilename, sk, auth, &digest);
- if (rc) {
+ if (policyFilename) {
+ rc = tpm2_parse_policy_file(policyFilename, sk, auth, &digest);
reason = "parse_policy_file";
- goto out_free_policy;
+ if (rc)
+ goto out_free_policy;
}
}
@@ -975,6 +1000,8 @@ int main(int argc, char **argv)
goto out_free_auth;
}
}
+ if (has_policy && !policyFilename)
+ tpm2_add_auth_policy(sk, &digest);
}
if (import) {
@@ -982,6 +1009,8 @@ int main(int argc, char **argv)
EVP_PKEY *pkey = openssl_read_key(wrap);
TPMT_SENSITIVE s;
+ rc = NOT_TPM_ERROR;
+
if (parent_str) {
parent = tpm2_get_parent_ext(parent_str);
if (parent == 0) {
@@ -996,8 +1025,6 @@ int main(int argc, char **argv)
pub = &objectPublic;
priv = &outPrivate;
- rc = NOT_TPM_ERROR;
-
if (!p_pkey || !pkey) {
reason = "read openssl key";
goto out_err;
@@ -1014,7 +1041,7 @@ int main(int argc, char **argv)
reason = "openssl_to_tpm_public";
goto out_err;
}
- if (policyFilename) {
+ if (has_policy) {
VAL(pub->publicArea.objectAttributes) &=
~TPMA_OBJECT_USERWITHAUTH;
rc = TSS_TPM2B_Create(
@@ -1059,6 +1086,15 @@ int main(int argc, char **argv)
goto out_free_auth;
}
+ if (pcr_lock.count != 0) {
+ rc = tpm2_pcr_lock_policy(tssContext, &pcr_lock,
+ sk, &digest);
+ if (rc) {
+ reason = "create pcr policy";
+ goto out_free_auth;
+ }
+ }
+
if (parent_str) {
parent = tpm2_get_parent(tssContext, parent_str);
if (parent == 0) {
@@ -1111,7 +1147,7 @@ int main(int argc, char **argv)
goto out_flush;
}
- if (policyFilename) {
+ if (has_policy) {
VAL(objectPublic.publicArea.objectAttributes) &=
~TPMA_OBJECT_USERWITHAUTH;
rc = TSS_TPM2B_Create(
@@ -1171,7 +1207,7 @@ int main(int argc, char **argv)
tpm2_public_template_ecc(&objectPublic.publicArea, ecc);
}
- if (policyFilename) {
+ if (has_policy) {
VAL(objectPublic.publicArea.objectAttributes) &=
~TPMA_OBJECT_USERWITHAUTH;
rc = TSS_TPM2B_Create(
diff --git a/ibm-tss.h b/ibm-tss.h
index d40eb46..d7502ab 100644
--- a/ibm-tss.h
+++ b/ibm-tss.h
@@ -487,6 +487,32 @@ tpm2_PolicyCounterTimer(TSS_CONTEXT *tssContext, TPM_HANDLE policySession,
return rc;
}
+static inline TPM_RC
+tpm2_PCR_Read(TSS_CONTEXT *tssContext, TPML_PCR_SELECTION *pcrSelectionIn,
+ TPML_PCR_SELECTION *pcrSelectionOut, TPML_DIGEST *pcrValues)
+{
+ PCR_Read_In in;
+ PCR_Read_Out out;
+ TPM_RC rc;
+
+ in.pcrSelectionIn = *pcrSelectionIn;
+
+ rc = TSS_Execute(tssContext,
+ (RESPONSE_PARAMETERS *)&out,
+ (COMMAND_PARAMETERS *)&in,
+ NULL,
+ TPM_CC_PCR_Read,
+ TPM_RH_NULL, NULL, 0);
+
+ if (rc)
+ return rc;
+
+ *pcrSelectionOut = out.pcrSelectionOut;
+ *pcrValues = out.pcrValues;
+
+ return rc;
+}
+
static inline TPM_HANDLE
tpm2_handle_int(TSS_CONTEXT *tssContext, TPM_HANDLE h)
{
diff --git a/intel-tss.h b/intel-tss.h
index 0fda8c1..3edd9ea 100644
--- a/intel-tss.h
+++ b/intel-tss.h
@@ -179,6 +179,9 @@ TSS_CONVERT_MARSHAL(TPM2B_ECC_POINT, )
TSS_CONVERT_MARSHAL(TPM2B_DIGEST, )
TSS_CONVERT_MARSHAL(TPM2B_PUBLIC, )
TSS_CONVERT_MARSHAL(TPM2B_PRIVATE, )
+TSS_CONVERT_MARSHAL(TPML_PCR_SELECTION, )
+TSS_CONVERT_MARSHAL(UINT32, *)
+#define TSS_TPM_CC_Marshal TSS_UINT32_Marshal
TSS_CONVERT_UNMARSHAL(TPML_PCR_SELECTION, )
TSS_CONVERT_UNMARSHAL(TPM2B_PRIVATE, )
@@ -935,6 +938,25 @@ tpm2_PolicyCounterTimer(TSS_CONTEXT *tssContext, TPM_HANDLE policySession,
operandB, offset, operation);
}
+static inline TPM_RC
+tpm2_PCR_Read(TSS_CONTEXT *tssContext, TPML_PCR_SELECTION *pcrSelectionIn,
+ TPML_PCR_SELECTION *pcrSelectionOut, TPML_DIGEST *pcrValues)
+{
+ TPML_PCR_SELECTION *out;
+ TPML_DIGEST *val;
+ TPM_RC rc;
+
+ rc = Esys_PCR_Read(tssContext, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
+ pcrSelectionIn, NULL, &out, &val);
+ if (rc)
+ return rc;
+
+ *pcrSelectionOut = *out;
+ *pcrValues = *val;
+
+ return rc;
+}
+
static inline TPM_HANDLE
tpm2_handle_ext(TSS_CONTEXT *tssContext, TPM_HANDLE esysh)
{
diff --git a/tpm2-common.c b/tpm2-common.c
index 537bda6..9db6be4 100644
--- a/tpm2-common.c
+++ b/tpm2-common.c
@@ -29,6 +29,25 @@
#include "tpm2-asn.h"
#include "tpm2-common.h"
+static struct {
+ const char *hash;
+ TPM_ALG_ID alg;
+} tpm2_hashes[] = {
+ { "sha1", TPM_ALG_SHA1 },
+ { "sha256", TPM_ALG_SHA256 },
+ { "sha384", TPM_ALG_SHA384 },
+#ifdef TPM_ALG_SHA512
+ { "sha512", TPM_ALG_SHA512 },
+#endif
+#ifdef TPM_ALG_SM3_256
+ { "sm3", TPM_ALG_SM3_256 },
+#endif
+ { NULL, 0 }
+};
+
+#define MAX_TPM_PCRS 24
+const int MAX_TPM_PCRS_ARRAY = (MAX_TPM_PCRS + 7)/8;
+
struct myTPM2B {
UINT16 s;
BYTE *const b;
@@ -1891,6 +1910,240 @@ void tpm2_free_policy(STACK_OF(TSSOPTPOLICY) *sk)
sk_TSSOPTPOLICY_free(sk);
}
+static const char *get_hash_by_alg(TPM_ALG_ID alg)
+{
+ int i;
+
+ for (i = 0; tpm2_hashes[i].hash; i++)
+ if (tpm2_hashes[i].alg == alg)
+ break;
+
+ return tpm2_hashes[i].hash;
+}
+
+static int add_pcrs_hash(TPML_PCR_SELECTION *pcrs, char *bank)
+{
+ int i;
+ TPM_ALG_ID alg;
+
+ for (i = 0; tpm2_hashes[i].hash; i++)
+ if (strcmp(tpm2_hashes[i].hash, bank) == 0)
+ break;
+
+ if (!tpm2_hashes[i].hash) {
+ fprintf(stderr, "unknown bank in pcrs list %s\n", bank);
+ exit(1);
+ }
+ alg = tpm2_hashes[i].alg;
+
+ for (i = 0; i < pcrs->count; i++)
+ if (pcrs->pcrSelections[i].hash == alg) {
+ fprintf(stderr, "hash bank %s was already specified\n", bank);
+ exit(1);
+ }
+
+ pcrs->pcrSelections[i].hash = alg;
+ pcrs->pcrSelections[i].sizeofSelect = MAX_TPM_PCRS_ARRAY;
+ pcrs->count++;
+
+ return i;
+}
+
+static void update_pcrs(TPML_PCR_SELECTION *pcrs, int bank, char *str)
+{
+ char *sep = strchr(str, '-');
+ char *endptr;
+ long from, to;
+ int i;
+
+ if (sep)
+ *sep = '\0';
+ from = to = strtol(str, &endptr, 10);
+ if (*endptr != '\0' || from < 0 || from >= MAX_TPM_PCRS)
+ goto err;
+
+ if (sep) {
+ str = sep + 1;
+ to = strtol(str, &endptr, 10);
+
+ if (*endptr != '\0' || to < 0 || to >= MAX_TPM_PCRS)
+ goto err;
+ }
+ if (to < from) {
+ fprintf(stderr, "Incorrect PCR range specified %ld-%ld\n",
+ from, to);
+ exit(1);
+ }
+
+ for (i = from; i <= to; i++)
+ pcrs->pcrSelections[bank].pcrSelect[i/8] |= (1 << (i%8));
+
+ return;
+ err:
+ fprintf(stderr, "incorrect PCR specification %s\n", str);
+ exit(1);
+}
+
+void tpm2_get_pcr_lock(TPML_PCR_SELECTION *pcrs, char *arg)
+{
+ char *sep = strchr(arg, ':');
+ char *bankstr = arg;
+ int bank;
+
+ if (sep) {
+ *sep = '\0';
+ arg = sep + 1;
+ } else {
+ bankstr = "sha256";
+ }
+ bank = add_pcrs_hash(pcrs, bankstr);
+ for (sep = strchr(arg, ','); sep; arg = sep + 1, sep = strchr(arg, ',')) {
+ *sep = '\0';
+ update_pcrs(pcrs, bank, arg);
+ }
+ update_pcrs(pcrs, bank, arg);
+}
+
+static int hash_print(const char *hash, int start, BYTE val, int k,
+ TPML_DIGEST *dl, EVP_MD_CTX *ctx)
+{
+ int i, j;
+
+ for (i = 0; i < 8; i++) {
+ TPM2B_DIGEST *d;
+ BYTE *db;
+
+ if ((val & (1 << i)) == 0)
+ continue;
+
+ d = &dl->digests[k++];
+ db = VAL_2B_P(d, buffer);
+ EVP_DigestUpdate(ctx, VAL_2B_P(d, buffer), VAL_2B_P(d, size));
+ printf("%s: %02d: ", hash, start + i);
+ for (j = 0; j < VAL_2B_P(d, size); j++) {
+ printf("%02x", db[j]);
+ }
+ printf("\n");
+ }
+ return k;
+}
+
+static void pcr_digests_process(TPML_PCR_SELECTION *in, TPML_PCR_SELECTION *out,
+ TPML_DIGEST *d, EVP_MD_CTX *ctx)
+{
+ int i, j, k = 0;
+
+ for (i = 0; i < in->count; i++) {
+ const char *hash = get_hash_by_alg(out->pcrSelections[i].hash);
+
+ for (j = 0; j < MAX_TPM_PCRS_ARRAY; j++) {
+ in->pcrSelections[i].pcrSelect[j] &=
+ ~out->pcrSelections[i].pcrSelect[j];
+
+ k = hash_print(hash, j * 8,
+ out->pcrSelections[i].pcrSelect[j],
+ k, d, ctx);
+ }
+ }
+}
+
+TPM_RC tpm2_pcr_lock_policy(TSS_CONTEXT *tssContext,
+ TPML_PCR_SELECTION *pcrs,
+ STACK_OF(TSSOPTPOLICY) *sk,
+ TPMT_HA *digest)
+{
+ TSSOPTPOLICY *policy = TSSOPTPOLICY_new();
+ TPM_RC rc;
+ BYTE buf[1024];
+ UINT16 written = 0;
+ INT32 size = sizeof(buf);
+ const TPM_CC cc = TPM_CC_PolicyPCR;
+ DIGEST_2B pcrDigest;
+ BYTE *buffer = buf;
+ TPML_PCR_SELECTION pcrread, pcrreturn;
+ TPML_DIGEST pcr_digests;
+ EVP_MD_CTX *ctx = EVP_MD_CTX_create();
+
+ switch (digest->hashAlg) {
+ case TPM_ALG_SHA1:
+ EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
+ break;
+ case TPM_ALG_SHA256:
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
+ break;
+ case TPM_ALG_SHA384:
+ EVP_DigestInit_ex(ctx, EVP_sha384(), NULL);
+ break;
+#ifdef TPM_ALG_SHA512
+ case TPM_ALG_SHA512:
+ EVP_DigestInit_ex(ctx, EVP_sha512(), NULL);
+ break;
+#endif
+#ifdef TPM_ALG_SM3_256
+ case TPM_ALG_SM3_256:
+ EVP_DigestInit_ex(ctx, EVP_sm3(), NULL);
+ break;
+#endif
+ default:
+ fprintf(stderr, "Unknown TPM hash algorithm 0x%x\n",
+ digest->hashAlg);
+ exit(1);
+ }
+
+ pcrread = *pcrs;
+
+ for (;;) {
+ rc = tpm2_PCR_Read(tssContext, &pcrread, &pcrreturn, &pcr_digests);
+ if (pcr_digests.count == 0 || rc != TPM_RC_SUCCESS)
+ break;
+
+ pcr_digests_process(&pcrread, &pcrreturn, &pcr_digests, ctx);
+ }
+
+ EVP_DigestFinal_ex(ctx, pcrDigest.buffer, NULL);
+ pcrDigest.size = TSS_GetDigestSize(digest->hashAlg);
+ EVP_MD_CTX_destroy(ctx);
+
+ if (rc)
+ return rc;
+
+ ASN1_INTEGER_set(policy->CommandCode, cc);
+ TSS_TPM_CC_Marshal(&cc, &written, &buffer, &size);
+ TSS_TPML_PCR_SELECTION_Marshal(pcrs, &written, &buffer, &size);
+ memcpy(buffer, pcrDigest.buffer, pcrDigest.size);
+ written += pcrDigest.size;
+ ASN1_STRING_set(policy->CommandPolicy, buf + 4, written - 4);
+ sk_TSSOPTPOLICY_push(sk, policy);
+
+ TSS_Hash_Generate(digest,
+ TSS_GetDigestSize(digest->hashAlg),
+ (uint8_t *)&digest->digest,
+ written, buf, 0, NULL);
+
+ return TPM_RC_SUCCESS;
+}
+
+void tpm2_add_auth_policy(STACK_OF(TSSOPTPOLICY) *sk, TPMT_HA *digest)
+{
+ TSSOPTPOLICY *policy = TSSOPTPOLICY_new();
+ BYTE buf[4];
+ BYTE *buffer = buf;
+ UINT16 written = 0;
+ INT32 size = sizeof(buf);
+ const TPM_CC cc = TPM_CC_PolicyAuthValue;
+
+ TSS_TPM_CC_Marshal(&cc, &written, &buffer, &size);
+
+ ASN1_INTEGER_set(policy->CommandCode, cc);
+ ASN1_STRING_set(policy->CommandPolicy, "", 0);
+ sk_TSSOPTPOLICY_push(sk, policy);
+
+ TSS_Hash_Generate(digest,
+ TSS_GetDigestSize(digest->hashAlg),
+ (uint8_t *)&digest->digest,
+ written, buf, 0, NULL);
+}
+
IMPLEMENT_ASN1_FUNCTIONS(TSSOPTPOLICY)
IMPLEMENT_ASN1_FUNCTIONS(TSSLOADABLE)
IMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY)
diff --git a/tpm2-common.h b/tpm2-common.h
index 2d6c561..bd90488 100644
--- a/tpm2-common.h
+++ b/tpm2-common.h
@@ -88,4 +88,10 @@ TPM_RC tpm2_parse_policy_file(const char *policy_file,
STACK_OF(TSSOPTPOLICY) *sk,
char *auth, TPMT_HA *digest);
void tpm2_free_policy(STACK_OF(TSSOPTPOLICY) *sk);
+void tpm2_get_pcr_lock(TPML_PCR_SELECTION *pcrs, char *arg);
+TPM_RC tpm2_pcr_lock_policy(TSS_CONTEXT *tssContext,
+ TPML_PCR_SELECTION *pcrs,
+ STACK_OF(TSSOPTPOLICY) *sk,
+ TPMT_HA *digest);
+void tpm2_add_auth_policy(STACK_OF(TSSOPTPOLICY) *sk, TPMT_HA *digest);
#endif