zos icon indicating copy to clipboard operation
zos copied to clipboard

ZOS TPM Support specifications

Open muhamadazmy opened this issue 3 years ago • 12 comments

Related issues #1319

muhamadazmy avatar Jan 31 '22 18:01 muhamadazmy

Theses commands rely on the fact that tpm2-abrmd daemon runs.

/etc/init.d/tpm2-abrmd start

Using OpenSSL

Check TPM support in openssl:

# openssl engine -c tpm2tss
(tpm2tss) TPM2-TSS engine for OpenSSL
 [RSA, RAND]

Clear the current state to start from scratch:

tpm2_clear

Generate a new RSA key (ecdsa is supported as well but not as widely available than RSA in the field):

tpm2tss-genkey -a rsa rsakey

Extract the public key from the generated key:

openssl rsa -engine tpm2tss -inform engine -in rsakey -pubout -outform pem -out mykey.pub
cat mykey.pub

Generate some data and sign them with the key:

echo HelloWorld > data
openssl pkeyutl -pubin -inkey mykey.pub -in data -encrypt -out data.sign

Decrypt the data signed by public key:

openssl pkeyutl -engine tpm2tss -keyform engine -inkey rsakey -decrypt -in data.sign -out data.decrypt
md5sum data.decrypt data

Using tpm2 natively

Create a parent key and a custom key (simple rsa key)

# tpm2_createprimary -C o -c parent.ctx -G rsa2048:null:aes128cfb
# openssl genrsa > maxux.key

Install the key inside tpm memory and make it persistant:

tpm2_evictcontrol -c parent.ctx

Get a public and private key usable by tpm2, linked to parent and coming from custom key:

tpm2_import -i maxux.key -r private_key.tss -u public_key.tss -Grsa -C parent.ctx

Get a context file usable by tpm2 from maxux.key (key.ctx will be usable)

tpm2_load -C parent.ctx -u public_key.tss -r private_key.tss -c key.ctx

You can now sign using that key:

tpm2_sign -c key.ctx -g sha256 -o message.sign message.dat

And verify signature:

tpm2_verifysignature -c key.ctx -g sha256 -s message.sign -m message.dat

Extra search

Based on PCR (registers), you can disallow access to a key if registers are not in a well-known state. Theses registers are accumulators, each settings in specific part (boot process, bios settings, etc:) increment the accumulator, you cannot set the register to something specific. Theses register ensure that any change to any settings won't produce the same register, so if a register is in a specific state, you know all settings behind get the expected values.

image

List current registers state:

tpm2_pcrread

Tool tpm2_policypcr can be used to play with this but I don't get the commands anymore, will take a look later :)

maxux avatar Jan 31 '22 19:01 maxux

Note that titan nodes (and freefarm zos nodes) don't have tpm devices built in. So far I am experimenting with some tpm2 libraries (including native golang libs) What i am trying to achieve is:

  • Store node identity seed used for block chain operation in a tpm this will be much safer than using a seed file on the hard disk of the node.
  • This can be used to drive an encryption key (with the user public key) for user data encryption
  • be able to sign hash other data.

TPM documentations is very obscure (tools, specs, and libraries) which is why it's taking to long to get the first prototype.

muhamadazmy avatar Feb 09 '22 11:02 muhamadazmy

Just to clarify, we should use tpm mainly to "store" the node key securely not to use it to sign/verify. This operation should then be done without depending on external context files or other files from storage (unless those files can be generated again with the same tpm device).

muhamadazmy avatar Jul 26 '22 08:07 muhamadazmy

So far i have reached here:

Those are done first time to only

tpm2_createprimary -c primary.ctx -Q

tpm2_pcrread -Q -o pcr.bin sha256:0,1,2,3

tpm2_createpolicy -Q --policy-pcr -l sha256:0,1,2,3 -f pcr.bin -L pcr.policy
 
echo 'secret' | tpm2_create -C primary.ctx -L pcr.policy -i-\
-u seal.pub -r seal.priv -c seal.ctx -Q

After that, the object need to be loaded to be unsealed

Note: after a reboot the primary.ctx need to be re-created with tpm2_createprimary

tpm2_load -c seal.ctx -C primary.ctx -u seal.pub -r seal.priv
tpm2_unseal -c seal.ctx -p pcr:sha256:0,1,2,3 > unsealed.txt

The problem is we still need to persist the seal.* files on disk. They are not usable on other machines but we might lose them. I am still looking into a way to store them on the tpm itself.

muhamadazmy avatar Aug 01 '22 08:08 muhamadazmy

Here is a script which uses same PCR and seal data into TPM without the need of local file. Please try it locally and tell me if it works for you. You maybe need to uncomment the tpm2_clear to start from scratch. Can you try a reboot and ensure you can only unseal it if PCR is the same ? Maybe try adding more PCR which changes. I don't have a machine I can reboot right now to test that.

I use sha1 and not sha256 for PCR because some machine (like mine) don't support sha256.

We can use this method to store disk-encryption key as well and fix our storage key issue :)

#!/bin/bash
set -ex

echo "Private Key Data" > secret.bin

# tpm2_clear
tpm2_createpolicy --policy-pcr -l sha1:0,1,2 -L policy.digest
tpm2_createprimary -C e -g sha1 -G rsa -c primary.context

tpm2_create -g sha256 -u obj.pub -r obj.priv -C primary.context -L policy.digest -a "noda|adminwithpolicy|fixedparent|fixedtpm" -i secret.bin

tpm2_load -C primary.context -u obj.pub -r obj.priv -c load.context
tpm2_evictcontrol -C o -c load.context 0x81000000

rm -f load.context obj.priv obj.pub policy.digest primary.context

tpm2_getcap handles-persistent
tpm2_readpublic -c 0x81000000

tpm2_unseal -c 0x81000000 -p pcr:sha1:0,1,2 # -o secret.bin

# remove
# tpm2_evictcontrol -C o -c 0x81000000

maxux avatar Aug 09 '22 12:08 maxux

I use the swtpm to emulate a tpm device for a VM. so rebooting is no problem

I tested your code and it works fine after a reboot and also after a complete power off and it works just fine, so thanks. I will see what I can do to change the values of the PCR without wiping the tpm data files (from the emulator)

muhamadazmy avatar Aug 10 '22 08:08 muhamadazmy

I think including more PCR or some PCR which changes across reboot could do it

maxux avatar Aug 10 '22 08:08 maxux

I think including more PCR or some PCR which changes across reboot could do it

Not sure about this because the policy (as u specify it) include only PCR 0, 1, and 2 so if I added more this won't change the values of 0, 1 or 2. So only changes to those PCRs would So a quick test would be doing something like

tpm2_unseal -c 0x81000000 -p pcr:sha1:0,1,3  # replace one of the PRCs with 3 instead of 2

which "as expected" fails. I will see if i can change something to actually affect the PRCs values.

muhamadazmy avatar Aug 10 '22 08:08 muhamadazmy

I mean, start from scratch and include PCR 1 > 7 in the tpm2_createpolicy I think some value above 3 will changes across reboot :) Use same values on unseal, of course

maxux avatar Aug 10 '22 08:08 maxux

Yeah, i understand. That's what i was trying to do. Anyway, i used pcrextend command to change values of PRCs at other positions (8) and included this in the sealing policy. after rebooting i couldn't unseal until i rexetended the same banks with the same values again.

So this is great. I can work on the implementation now. Thanks @maxux :)

muhamadazmy avatar Aug 10 '22 09:08 muhamadazmy

Awesome :heart: To implement, this can maybe helps to not runs commands: https://github.com/canonical/go-tpm2

maxux avatar Aug 10 '22 09:08 maxux

Yeah, i landed on this a while back. As if the commands are already not complex enough!

The good side of how to use this is that now we won't have to include the tpm2 binary, hence this will work on machines booted with older images that doesn't include the tpm command. On the other side, i now have to figure out how to basically re-write the command using the tpm2 API.

I will give it another look see if I can do it.

muhamadazmy avatar Aug 10 '22 14:08 muhamadazmy