tpm2-software / tpm2-pkcs11

A PKCS#11 interface for TPM2 hardware
https://tpm2-software.github.io
Other
278 stars 104 forks source link

PCR policy authmodel #833

Open SergiiDmytruk opened 1 year ago

SergiiDmytruk commented 1 year ago

Hi.

As was mentioned in #301 about a month ago, we want to have the ability to bind use of a private key to an expected value of a PCR.

Currently the changes include a new attribute and related modifications to tpm2_ptool. Sending the PR just in case you can see an issue with the changes right away.

I've added --policy parameter to addkey, import and link subcommands. There is also a new subcommand called objpol, which is similar to objmod but deals only with the policy. objpol can be dropped if you don't see much value in it, but then it would be nice to add --raw to objmod for printing value as is rather than as a YAML.


Update. Fixed a bug in tpm2_ptool and added code for executing a policy during signing if it's present on a private key. The only callback set is "get PCR" which is enough for handling of PCR policies and their templates.

I've noticed that there seems to be an effort to maintain compatibility with tpm2-tss v2.0, so handling of policies is optional and is disabled if tpm2-policy isn't present or --without-policy is passed to configure.

There are also a couple of trivial changes in separate commits.

codecov[bot] commented 1 year ago

Codecov Report

Merging #833 (bccb707) into master (1b3aab9) will decrease coverage by 0.01%. The diff coverage is 70.00%.

@@            Coverage Diff             @@
##           master     #833      +/-   ##
==========================================
- Coverage   72.43%   72.43%   -0.01%     
==========================================
  Files          34       34              
  Lines        9773     9783      +10     
==========================================
+ Hits         7079     7086       +7     
- Misses       2694     2697       +3     
Impacted Files Coverage Δ
src/lib/attrs.c 72.00% <ø> (ø)
src/lib/tpm.c 71.41% <ø> (ø)
src/lib/sign.c 76.55% <70.00%> (-0.21%) :arrow_down:

:mega: We’re building smart automated test selection to slash your CI/CD build times. Learn more

glance- commented 10 months ago

I'd like to see some examples on how to use this, to for example lock a key to only be usable when a set of pcr's has a certain value.

SergiiDmytruk commented 10 months ago

@glance-, we ended up not needing the changes (at least not yet), so haven't touched this stuff for awhile, but some example based on notes is provided below.

Create a policy (tpm-policy.json)

Policies are described in JSON format (specification), the case of a PCR policy is quite simple:

{
  "description": "PCR7 policy",
  "policy": [{
    "type": "pcr",
    "pcrs": [{
        "pcr": 7,
        "hashAlg": "sha256",
        "digest": "0000000000000000000000000000000000000000000000000000000000000000"
    }]
  }]
}

The description field is merely informational and is optional in the specification, but implementation in tpm2-tss requires it to be present.

Current value of a PCR can be obtained via:

tpm2_pcrread sha256:7

Use it

# initialize pkcs#11
tpm2_ptool init
# create token
tpm2_ptool addtoken --pid 1 --sopin mysopin --userpin myuserpin --label tpm20
# create a key protected by the policy
tpm2_ptool addkey --label=tpm20 --key-label=mykey --userpin=myuserpin \
                  --algorithm=rsa2048 --policy="$(cat tpm-policy.json)"
glance- commented 10 months ago

I think I'm missing something here. I've built a tpm2-pkcs11 with this pull-request merged ontop of master, tpm2-tss 4.0.1 and tpm2-pytss 2.2.0-rc0 which all where the latest when I started playing around with this.

When I create a key with a policy just as you've described, only changed policy from pcr 7 to pcr 8 for my tests to be simpler.

To create a simple self signed certificate with that key I've used openssl with -provider tpm as shown in https://github.com/tpm2-software/tpm2-pkcs11/issues/766#issuecomment-1119360906 to create such a certificate:

yaml_rsa0=$(tpm2_ptool export --label=tpm20 --key-label=mykey --userpin=myuserpin)
auth_rsa0=$(echo "$yaml_rsa0" | grep "object-auth" | cut -d' ' -f2-)
openssl req -new -x509 -provider tpm2 -provider base -key "mykey".pem -passin "pass:$auth_rsa0" -subj "/CN=$HOSTNAME" -out "$HOSTNAME.pem" -days 3650 -nodes -sha256 -addext 'basicConstraints=critical,CA:FALSE' -addext 'keyUsage=digitalSignature'

All goes fine while:

# tpm2_pcrread sha256:8
  sha256:
    8 : 0x0000000000000000000000000000000000000000000000000000000000000000

I can even use it via libtpm2_pkcs11.so with ex sbsign:

sbsign --engine pkcs11 --key 'pkcs11:token=tpm20;pin-value=myuserpin' --cert "$HOSTNAME.pem" --output test-signed.efi /boot/vmlinuz-6.1.0-17-amd64

If I now "break" things by tpm2_pcrextend 8:sha256=f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2

I can't run above sbsign command via the pkcs11 module, but above openssl -provider tpm2 runs just fine.

How can the tpm still allow the openssl tpm provider to access to the key?

SergiiDmytruk commented 10 months ago

Not sure, but it might be related to the fact that policy is processed only for signing here.

glance- commented 10 months ago

But the whole idea is that the tpm should refuse to do anything with the key unless it knows the policy is satisfied. That means that even if I dig up the handles to the key some other way it should know that there's a policy on this key, and refuse to do anything unless it's satisfied.

I just tried the following dirty hack:

diff --git i/src/lib/sign.c w/src/lib/sign.c
index bd91a88..47a07f7 100644
--- i/src/lib/sign.c
+++ w/src/lib/sign.c
@@ -255,7 +255,8 @@ static CK_RV common_init(operation op, session_ctx *ctx, CK_MECHANISM_PTR mechan
     if (op == operation_sign) {
         rv = policy_is_satisfied(tok->tctx, tobj, tok->pobject.handle);
         if (rv != CKR_OK) {
-            return rv;
+            LOGE("policy_is_satisfied failed, continuing anyway");
+            rv = CKR_OK;
         }
     }

And now I get the libtpm2_pkcs11.so to ignore any policies and just sign things anyway, so something is definitely not the way it should be.

SergiiDmytruk commented 10 months ago

You might want to look into something like this key creation and its usage with a policy. This one is enforced by TPM.

glance- commented 10 months ago

I was just expecting the key to be setup in a way requiring the policy to be fulfilled for usage, when it was created with tpm2_ptool addkey ... --policy

I'd guess any other user also would expect that to.

But this concludes, that this part of this feature isn't implemented in this PR, which I'd guess would be a blocker for actually merging this.

SergiiDmytruk commented 10 months ago

But this concludes, that this part of this feature isn't implemented in this PR, which I'd guess would be a blocker for actually merging this.

The implementation follows this comment. There is always a chance of misunderstanding, so maybe you're right and the implementation isn't correct.