diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2018-08-10 20:14:56 -0700 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2018-08-12 07:58:57 -0700 |
commit | ed4ed23bc8990575345ad007bd944c8b79b6aaae (patch) | |
tree | f123d854a03a5d6102b2feea1e01f4312f0fd31a | |
parent | b82de3cc6126d719a25487815c74b7ec5e7baf94 (diff) | |
download | openssl_tpm2_engine-ed4ed23bc8990575345ad007bd944c8b79b6aaae.tar.gz |
policy: add the ability to have time limited keys
Implement TPM2_PolicyCounterTimer which allows comparison of the
current counter and timer values. There is a problem with the policy
file in that traditionally the policy file is simply hashed to make
the final policy, but CounterTimer is different: the necessary
information has to be hashed and then that hash is hashed into the
policy meaning that we have to special case the
TPM_CC_PolicyCounterTimer in the computation of the hash.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | create_tpm2_key.c | 31 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rwxr-xr-x | tests/check_counter_timer.sh | 51 | ||||
-rw-r--r-- | tpm2-common.c | 51 |
4 files changed, 126 insertions, 8 deletions
diff --git a/create_tpm2_key.c b/create_tpm2_key.c index 9845520..f624acb 100644 --- a/create_tpm2_key.c +++ b/create_tpm2_key.c @@ -160,6 +160,10 @@ parse_policy_file(const char *policy_file, STACK_OF(TSSOPTPOLICY) *sk, } while ((data_ptr = strsep(&data, "\n"))) { + TPMT_HA hash_digest; + unsigned char *hash = (unsigned char *)hash_digest.digest.tssmax; + INT32 hash_len; + buf_ptr = buf; buf_len = strlen(data_ptr) / 2; if (buf_len > sizeof(buf)) { @@ -178,18 +182,31 @@ parse_policy_file(const char *policy_file, STACK_OF(TSSOPTPOLICY) *sk, goto out_munmap; } - rc = TSS_Hash_Generate(digest, - TSS_GetDigestSize(digest->hashAlg), - (uint8_t *)&digest->digest, - buf_len, buf_ptr, 0, NULL); + rc = TPM_CC_Unmarshal(&code, &buf_ptr, &buf_len); if (rc) { - fprintf(stderr, "TSS_Hash_Generate() failed\n"); + fprintf(stderr, "TPM_CC_Unmarshal() failed\n"); goto out_munmap; } - rc = TPM_CC_Unmarshal(&code, &buf_ptr, &buf_len); + if (code == TPM_CC_PolicyCounterTimer) { + /* for a countertimer, the policy is a hash of the hash */ + hash_digest.hashAlg = digest->hashAlg; + hash_len = TSS_GetDigestSize(digest->hashAlg); + TSS_Hash_Generate(&hash_digest, buf_len, buf_ptr, 0, NULL); + hash = hash_digest.digest.tssmax; + } else { + hash = buf_ptr; + hash_len = buf_len; + } + + rc = TSS_Hash_Generate(digest, + TSS_GetDigestSize(digest->hashAlg), + (uint8_t *)&digest->digest, + /* the command code */ + 4, buf_ptr - 4, + hash_len, hash, 0, NULL); if (rc) { - fprintf(stderr, "TPM_CC_Unmarshal() failed\n"); + fprintf(stderr, "TSS_Hash_Generate() failed\n"); goto out_munmap; } diff --git a/tests/Makefile.am b/tests/Makefile.am index d9713d1..499ba20 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,6 +15,7 @@ TESTS = fail_connect.sh \ da_check.sh \ test_nv_key.sh \ check_enhanced_auth.sh \ + check_counter_timer.sh \ stop_sw_tpm.sh AM_TESTS_ENVIRONMENT = TPM_INTERFACE_TYPE=socsim; \ diff --git a/tests/check_counter_timer.sh b/tests/check_counter_timer.sh new file mode 100755 index 0000000..987eaf0 --- /dev/null +++ b/tests/check_counter_timer.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +bindir=${srcdir}/.. + +## +# create a policy based on the tpm current clock the failing policy +# compares to current time and the passing one current time plus 10 +# minutes (provided it doesn't take 10 minutes to get to the test) +## +# get current TPM clock value +clock=$(tssreadclock|awk '/TPMS_CLOCK_INFO clock/{print $3}') +# add 10 minutes in ms +clock=$[$clock + 600000] +# TPM_CC_PolicyAuthValue +echo "0000016b" > policy.txt +# the TPM_CC_PolicyCounterTimer +echo -n "0000016d" >> policy.txt +# time value as a 8 byte number +printf "%016x" $clock >> policy.txt +# the offset of the clock and the <= unsigned operator +echo "00080009" >> policy.txt + +## +# test is +# 1. create TPM internal private key with PolicyCounterTimer +# 2. get the corresponding public key from the engine +# 3. encode a message using the TPM key +# 4. verify the message through the public key +## +${bindir}/create_tpm2_key key.tpm -a -k paSSW0RD -c policy.txt && \ +openssl rsa -engine tpm2 -inform engine -passin pass:paSSW0RD -in key.tpm -pubout -out key.pub && \ +echo "policy counter timer" | openssl rsautl -sign -passin pass:paSSW0RD -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg && \ +openssl rsautl -verify -in tmp.msg -inkey key.pub -pubin || exit 1 + +## +# advance the TPM clock by ten minutes and a second which should make +# the policy fail and try the same test again +## +echo "Advance clock to expire key" +clock=$[$clock+1000] +tssclockset -hi o -clock ${clock} || exit 1 + +## +# now the signing operation should fail +## +echo "Check key failure due to counter timer policy" +echo "policy fail counter timer" | openssl rsautl -sign -passin pass:paSSW0RD -engine tpm2 -engine tpm2 -keyform engine -inkey key.tpm -out tmp.msg 2> tmp.txt && exit 1 +# check we got the right failure message +grep "Policy Failure: Counter Timer at offset 8 is not <=" tmp.txt + + diff --git a/tpm2-common.c b/tpm2-common.c index 0b704f2..d0f0831 100644 --- a/tpm2-common.c +++ b/tpm2-common.c @@ -616,7 +616,9 @@ TPM_RC tpm2_init_session(TSS_CONTEXT *tssContext, TPM_HANDLE handle, TPM_RC rc = 0; COMMAND_PARAMETERS in; int i; + char reason[256]; + reason[0] = '\0'; ((PolicyPCR_In *)&in)->policySession = handle; for (i = 0; i < num_commands; i++) { @@ -631,6 +633,50 @@ TPM_RC tpm2_init_session(TSS_CONTEXT *tssContext, TPM_HANDLE handle, break; case TPM_CC_PolicyAuthValue: break; + case TPM_CC_PolicyCounterTimer: { + PolicyCounterTimer_In *pctin = &in.PolicyCounterTimer; + BYTE *p_buffer; + INT32 p_size; + int i, c; + const char *const operand[] = { + [TPM_EO_EQ] = "==", + [TPM_EO_NEQ] = "!=", + [TPM_EO_SIGNED_GT] = ">(s)", + [TPM_EO_UNSIGNED_GT] = ">", + [TPM_EO_SIGNED_LT] = "<(s)", + [TPM_EO_UNSIGNED_LT] = "<", + [TPM_EO_SIGNED_GE] = ">=(s)", + [TPM_EO_UNSIGNED_GE] = ">=", + [TPM_EO_SIGNED_LE] = "<=(s)", + [TPM_EO_UNSIGNED_LE] = "<=", + [TPM_EO_BITSET] = "bitset", + [TPM_EO_BITCLEAR] = "bitclear", + }; + + /* last UINT16 is the operand */ + p_buffer = policy + size - 2; + p_size = 2; + TPM_EO_Unmarshal(&pctin->operation, &p_buffer, + &p_size); + /* second to last UINT16 is the offset */ + p_buffer = policy + size - 4; + p_size = 2; + UINT16_Unmarshal(&pctin->offset, &p_buffer, &p_size); + + /* and the rest is the OperandB */ + pctin->operandB.b.size = size - 4; + memcpy(pctin->operandB.b.buffer, policy, size - 4); + + c = sprintf(reason, + "Counter Timer at offset %d is not %s ", + pctin->offset, operand[pctin->operation]); + for (i = 0; i < size - 4; i++) + c += sprintf(&reason[c], "%02x", policy[i]); + + reason[c] = '\0'; + + break; + } default: fprintf(stderr, "Unsupported policy command %d\n", commands[i].code); @@ -650,7 +696,10 @@ TPM_RC tpm2_init_session(TSS_CONTEXT *tssContext, TPM_HANDLE handle, commands[i].code, TPM_RH_NULL, NULL, 0); if (rc) { - tpm2_error(rc, "policy command"); + if (rc == TPM_RC_POLICY && reason[0]) + fprintf(stderr, "Policy Failure: %s\n", reason); + else + tpm2_error(rc, "policy command"); goto out_flush; } } |