tpm2-software / tpm2-pkcs11

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

Attestation of generated keys #280

Open mdempsky opened 5 years ago

mdempsky commented 5 years ago

I'd like to remotely verify that a tpm2-pkcs11-generated key was actually generated on a real TPM.

E.g., Yubico's yubico-piv-tool personalization tool supports an "attest" command to generate a signature for the public key, and a way to read the device's attestation certificate out: https://developers.yubico.com/yubico-piv-tool/Attestation.html

It looks like I can use tpm2_nvread 0x1c00002 and tpm2_nvread 0x1c0000a to read my TPM's RSA and ECC endorsement certificates, respectively. However, I can't immediately figure out how to generate signatures corresponding to these certificates for keys generated with tpm2-pkcs11's tpm2_ptool.py.

williamcroberts commented 4 years ago

I'd like to remotely verify that a tpm2-pkcs11-generated key was actually generated on a real TPM.

E.g., Yubico's yubico-piv-tool personalization tool supports an "attest" command to generate a signature for the public key, and a way to read the device's attestation certificate out: https://developers.yubico.com/yubico-piv-tool/Attestation.html

It looks like I can use tpm2_nvread 0x1c00002 and tpm2_nvread 0x1c0000a to read my TPM's RSA and ECC endorsement certificates, respectively. However, I can't immediately figure out how to

That's for the endorsement hierarchy primary keys created with the proper template. Currently, we're working out of the owner hierarchy (but can/eventually) be configurable.

generate signatures corresponding to these certificates for keys generated with tpm2-pkcs11's tpm2_ptool.py.

Keys are generated in the owner hierarchy. For this to work we need to be able to pull in the endorsement hierarchy. Which I am not sure what the flow of, this key is a child of my EK, attest to that.... We'd have to figure out the flow and look at enabling this post 1.0

williamcroberts commented 4 years ago

@mdempsky I am not really sure what your looking for here? Is their anything for me to do with this? FYI the tpm2_createek tool actually reads them out of NVRAM if you're looking for a complete example?

steschuser commented 4 years ago

I'm trying to solve the same problem.

An example in the documentation would be nice ...

kuba00739 commented 3 years ago

Hello, I would like to know if there is any solution. Is it possible right now or in other case- do you know any workaround?

Thank you in advance!

tracefinder commented 3 years ago

Hi there! These posts are a good introduction in remote attestation (in case anyone needs):

Remote attestation is also implemented in go-attestation package.

I'm currently trying to implement attestation for tpm2-pkcs11 + golang pkcs11 wrapper + go-attestation. One of the obstacles is the absence of creation_data, creation_hash and creation_ticket (but it's still possible to use just tpm2-certify).

However, I don't see any interface in PKCS#11 which allows this (any?) kind of attestation. Perhaps, if it was possible to use an existing TPM private key for tpm2-pkcs11, it would be possible to certify it.

williamcroberts commented 3 years ago

If you create the tpm key with tpm2 tools or tss2-openssle-engine and use tpm2_ptool link, you can use normal tpm2 tools commands on it as shown here: https://github.com/tpm2-software/tpm2-pkcs11/blob/master/docs/INTEROPERABILITY.md

If you already have the key in tpm2-pkcs11 and you want to get it out, you need to know the parent, which is by default persistent and the key blobs for tpm2_load.

For item 1, it depends on the type of token, but you can create a matching parent with tpm2_createprimary and then extract the key blobs like so:

tpm2_ptool objmod --id=33 --key=2399141890 --path=~/tmp | cut -d' ' -f 2- | xxd -p -r > key.pub
tpm2_ptool objmod --id=33 --key=2399141891 --path=~/tmp | cut -d' ' -f 2- | xxd -p -r > key.priv

tpm2_load -C0x81000000 -Pfoopass -u key.pub -r key.priv -c key.ctx
name: 000b10c606dab0618144c22f2940a74f3f6b6638cab7d5fbc1bb9f8a6e5bc0368092

In this case I knew that this key was associated with a token that has a persistent primary key at 0x81000000. You can use the various tpm2_ptool commands to search through and find the key you want to extract and what its parent looks like.

To get through the rest, its helfpful to know how the data is organized. A pkcs11-store can have P>=0 primary objects of various designs, persistent, tpm2-tool style and tpm2-tss-engine style. Each of those primary objects can have T>=0 tokens, and each token can have N>=0 objects. So you kind of have to sleuth your way through this using the tpm2_ptool commands.

Know that each object stores its key blobs in attributes of 2399141890 and 2399141891 as shown above.

Know that each primary object has either its ESYS_TR which can be used instead of a raw handle, its more secure as it prevents MITM attacks be verifying name, or it's "template-name". This is in a JSON config that gets spit out. These template meanings are spelled out in that interoperability document. Below you'll find some examples to help guide you.

List all the known parent keys:

tpm2_ptool listprimaries --path=~/tmp

Take the pid and list the tokens:

tpm2_ptool listtokens --pid=1 --path=~/tmp

List the objects of a token:

tpm2_ptool listobjects --label=label --path=~/tmp

Take the id from the last command and extract it like shown.

Now if you have a result from this command tpm2_ptool listprimaries --path=~/tmp:

- config:
    esys-tr: 810000020022000b62841f85cddacf070f9d880b6cd26f0dd5926841474f16cc3802fe8259012eb900000001011a0001000b00030072000000060080004300100800000000000100c9ce417c8a646ffe2957b61d51e5d7c5aa8bc90b680eb14bd921c70072c6d78072b5fdf852c81e88a7aeac5907e3518e6120d5ae519706fbe3f645555d5fce88600fc2806beb581d660b21d07e16ca499936a2705b7fecbbdbfdf40a625891a8810839a52e16105bb4acaf4fc0a82db786f2e450fe82f76f2b18da18381873323982f12de0ec5c86c993f4b923bb8830b12f8975a8c28a0c54a07e8678bbb04a2a52ffdb8831a0407eb205479b779f445e1ecf3a829674cceceba11ffc0be46fc7345c81d67205c876a76c17172cd026665bc152e8f8acf7247d72659fab506b879f69e0b3ed87bb1b77bb0d033177caea9d03f16310d53c905a1924703947d9
    transient: false
  id: 3
- config:
    template-name: tpm2-tools-default
    transient: true
  id: 4

The config's with ESYS_TR's can be used in tpm2_load as well, and probably should be:

# ESYS_TR's are name checked to make sure you get the object you expect and are not MITM'd.
echo -n '810000000022000b62841f85cddacf070f9d880b6cd26f0dd5926841474f16cc3802fe8259012eb900000001011a0001000b00030072000000060080004300100800000000000100c9ce417c8a646ffe2957b61d51e5d7c5aa8bc90b680eb14bd921c70072c6d78072b5fdf852c81e88a7aeac5907e3518e6120d5ae519706fbe3f645555d5fce88600fc2806beb581d660b21d07e16ca499936a2705b7fecbbdbfdf40a625891a8810839a52e16105bb4acaf4fc0a82db786f2e450fe82f76f2b18da18381873323982f12de0ec5c86c993f4b923bb8830b12f8975a8c28a0c54a07e8678bbb04a2a52ffdb8831a0407eb205479b779f445e1ecf3a829674cceceba11ffc0be46fc7345c81d67205c876a76c17172cd026665bc152e8f8acf7247d72659fab506b879f69e0b3ed87bb1b77bb0d033177caea9d03f16310d53c905a1924703947d9' | xxd -p -r > primary.handle

tpm2_load -Cprimary.handle -Pfoopass -u key.pub -r key.priv -c key.ctx
name: 000b10c606dab0618144c22f2940a74f3f6b6638cab7d5fbc1bb9f8a6e5bc0368092

If "template-name" is a tpm2-tools-default template, you can just:

tpm2_createprimary -C primary.ctx

and then load any key like above, if you need a different template, just craft your createprimary call correctly as shown in interoperability.

From here you have something you can easily get at using tpm2 tools. However, if you need the auth value, that becomes more complicated as the auth value is wrapped by an AES 256 GCM key sealed to the TPM. This is all possible using existing command line tooling, but it would probably be easier to have a helper in tpm2_ptool for this.

If you need this feature, let me know.

tracefinder commented 3 years ago

@williamcroberts Thank you for extensive description of possible solutions. I'll try to use interoperability feature first. Personally, I don't want to execute external scripts from my program. That's why, I suppose, I'll need to implement new_key_save and create_from_key_blobs on my own.

williamcroberts commented 3 years ago

It just dawned on me that the verify commandlet for tpm2_ptool outputs the objects auth value

williamcroberts commented 3 years ago

@williamcroberts Thank you for extensive description of possible solutions. I'll try to use interoperability feature first. Personally, I don't want to execute external scripts from my program. That's why, I suppose, I'll need to implement new_key_save and create_from_key_blobs on my own.

Some of that logic exists in the C code, you could link statically to the library to access internal routines. libtpm2_test_pkcs11.la

Firstyear commented 10 months ago

If you create the tpm key with tpm2 tools or tss2-openssle-engine and use tpm2_ptool link, you can use normal tpm2 tools commands on it as shown here: https://github.com/tpm2-software/tpm2-pkcs11/blob/master/docs/INTEROPERABILITY.md

Even if this is true, it's an obscure and reasonably complex dance. Having this library able to output a defined attestation "blob" that is rooted in the ek would help users of this library. Not all of us are tpm experts, so having these "recipes" will make these features more accessible to others.

Firstyear commented 10 months ago

Worth also pointing out here, that many TPM's now support directly attesting keys with the EK, which AFAIK is required for webauthn. What is good for this library is it allows a "oneshot" attest mode where the EK can directly attest a pkcs11 key without any other dance around AIK required.