tpm2-software / tpm2-tss-engine

OpenSSL Engine for TPM2 devices
https://tpm2-software.github.io
BSD 3-Clause "New" or "Revised" License
148 stars 97 forks source link

Specifying parent with -P flag in tpm2tss-genkey yields overflow #221

Closed kuhlmannmarkus closed 2 years ago

kuhlmannmarkus commented 3 years ago

Hi all,

Im using tpm2tss-genkey to derive a PEM representation from some key material I generated via https://github.com/google/go-attestation. Therefore I export the public and private portions according to https://github.com/google/go-tpm/issues/233 and then do tpm2tss-genkey -u pubktpmmarshal -r pktpmmarshal -P 0x81000001 go-key.pem. The key generally seems fine, but I found that the parent part probably has an overflow. cat go-key.pem | openssl asn1parse yields:

0:d=0 hl=4 l= 498 cons: SEQUENCE 4:d=1 hl=2 l= 6 prim: OBJECT :2.23.133.10.1.3 12:d=1 hl=2 l= 3 cons: cont [ 0 ] 14:d=2 hl=2 l= 1 prim: BOOLEAN :1 17:d=1 hl=2 l= 4 prim: INTEGER :-7EFFFFFF 23:d=1 hl=4 l= 280 prim: OCTET STRING [HEX DUMP]:01160001000B0004007200000010001008000000000001009203AB176AD723B0B51BBE717115558F5AFC48A8171F81E4925CF3212E9915C506F6711ECF4957BDE2DBD2EE26856776083FBC8A26BCA37C73392E4CBC5E5F7C9FCEC13AED9EF7F39B7CC18A95EA1BFE7EE95BA7FB1CEF9CE42B07974DE0DC23A89FCF603A1523691FF877DD8F3623C6A2FE1C506CCDA2530C99965C36BD0C5CD43C750BE3F7F6772387F4779A150E427C843CDA73C6575EABA53E6FF1E3A908EC7D6B3BF78F45B67C7C814F11F863E2E40D04DC0E02E9D49A6C265C236B7DB77064037F5D9D5007DF56AB1D45A1EF709274F27A6AADA0CAA1DD0D865115775EBAFD5BEA12AD48125F364210691671F89C070FB6A405249533567BE35654FAA7 307:d=1 hl=3 l= 192 prim: OCTET STRING [HEX >DUMP]:00BE0020993A1BD55AF1AA2C50FAE080217EE72DEBE672330ED6C3336D98B629ED6AD67300106370621C91E5A0484808E03CE9B0D20D3BB6A312CE8CE694A346616A787F85F6456A7C55A2011406D5004E043358946F855B8F2C73F46529A880CE0F067C8E88880944B8691272DA93E7F842C3F83982A6B0432FF90B9F32459F57E005E71EFC4BA6F4F3D15ECDE07BF09756874990DB3453A8858351650A75D2C439D3C536FA1DA5910D5C19D454C196C06A13EEC63FB0908A22ED2ADD3D17FB

I intend to link this key to a token in https://github.com/tpm2-software/tpm2-pkcs11 with tpm2_ptool, but since the parent is faulty, I get (tpm2_ptool link --path /usr/share/tpmpkcs11store --label=mytoken2 --userpin=myuserpin --key-label="link-key" go-key.pem):

The primary object (id: 5) is persistent and the TSS Engine key does not have a persistent parent, got: 0x-7effffff

Any help is appreciated. Thanks in advance!

AndreasFuchsTPM commented 3 years ago

Said integer is the TPM2_HANDLE of the parent key. It is actually a UINT32 starting with 0x81?????? i.e. the most significant bit is set. In the PEM format this is encoded as a signed integer and thus interpreted as a negative number by ASN.1 parse. But that is not a problem afaik.

I guess this is a bug in tpm2_ptool that should be fixed there.

kuhlmannmarkus commented 3 years ago

Hi @AndreasFuchsSIT Thanks for the quick reply! Exactly: I tried to set 0x81000001, since this is predetermined by go-attestation. I will try to move this issue to tpm2_ptool.

niooss-ledger commented 3 years ago

Hi, I tried to reproduce the issue, and on my system (x86_64 Arch Linux), openssl asn1parse yields:

    0:d=0  hl=4 l= 531 cons: SEQUENCE          
    4:d=1  hl=2 l=   6 prim: OBJECT            :2.23.133.10.1.3
   12:d=1  hl=2 l=   3 cons: cont [ 0 ]        
   14:d=2  hl=2 l=   1 prim: BOOLEAN           :1
   17:d=1  hl=2 l=   5 prim: INTEGER           :81000001
...

Looking at the hexadecimal dump of go-key.pem (with cat go-key.pem | grep -v '[-]' |base64 -d |xxd), I see near at offset 17: 02 05 00 81 00 00 01. This is the encoding for a 5-byte integer 0x0081000001, which is why asn1parse sees 0x81000001 and not -7EFFFFFF. As said in a previous comment, -7EFFFFFF is the value encoded by 81 00 00 01 (or more precisely, by the ASN.1 object 02 04 81 00 00 01 in DER notation). This can be verified with:

$ echo "02 04 81 00 00 01" |xxd -p -r |openssl asn1parse -inform DER
   0:d=0  hl=2 l=   4 prim: INTEGER           :-7EFFFFFF

Now, why would tpm2tss-genkey create files with -7EFFFFFF on some machines and 81000001 on others? The code responsible to write this value is in function tpm2tss_tpm2data_write: https://github.com/tpm2-software/tpm2-tss-engine/blob/89327fa8b51962348c46ddc659fb8c3636336a60/src/tpm2-tss-engine-common.c#L175

As documented on https://www.openssl.org/docs/man1.1.0/man3/ASN1_INTEGER_set.html, ASN1_INTEGER_set takes a long value as parameter. On some systems (like 32-bit CPU), long are 32-bit integers, so in fact ASN1_INTEGER_set(tpk->parent, tpm2Data->parent); is setting a 32-bit signed integer. But parent is of type TPM2_HANDLE, which is unsigned 32-bit integer.

TL;DR: tpm2tss_tpm2data_write behaves differently between systems where long are 32-bit integers and those ones where long are 64-bit integers. Is this a bug which should be fixed in tpm2-tss-engine, or should all consumers of serialized keys cast parent to unsigned 32-bit integers, or both?

williamcroberts commented 3 years ago

So IIUC the root cause is that if the PEM file is generated on a 32 bit system, the ASN1 integer is getting represented as a signed value (since the top bit is high) in Python over the C code since it casts it to an unsigned 32 bit value (TPM2_HANDLE), is that correct thus far?

Secondly the fix linked in here (#222) is correcting the encoding of the ASN1 integer so it's always positive . Ie will be a length of 5 with the leading 00 followed by the handle?