tpm2-pytss icon indicating copy to clipboard operation
tpm2-pytss copied to clipboard

Attributes of TPM NV counters (and bits) cannot be represented as string

Open niooss-ledger opened this issue 3 years ago • 1 comments

Hello,

While testing https://github.com/tpm2-software/tpm2-pytss/pull/317 on a real TPM, I encountered an exception because I use a NV index with a counter. This issue can be reproduced without a TPM by the following Python script:

from tpm2_pytss import *
nvPublic=TPMS_NV_PUBLIC(
    nvIndex=0x1000000,
    nameAlg=TPM2_ALG.SHA256,
    attributes=TPMA_NV.OWNERWRITE
    | TPMA_NV.OWNERREAD
    | TPMA_NV.AUTHREAD
    | TPMA_NV.AUTHWRITE
    | (TPM2_NT.COUNTER << TPMA_NV.TPM2_NT_SHIFT),
    authPolicy=b"",
    dataSize=8,
)
print(str(nvPublic.attributes))

With tpm2-pytss 1.0.0-rc1, this outputs:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../tpm2_pytss/constants.py", line 283, in __str__
    raise ValueError(f"unnmatched values left: 0x{cv:x}")
ValueError: unnmatched values left: 0x10

This exception occurs because TPM2_NT.COUNTER << TPMA_NV.TPM2_NT_SHIFT is not defined in TPMA_NV. To fix it, maybe TPMA_NV could override __str__() to report the value of the four TPM2_NT bits.

For information with tpm2-tools, tpm2_nvreadpublic displays this value as ownerwrite|authwrite|nt=0x1|writeall|ownerread|authread|written. It would be nice if there was a way to report nt=1, nt=counter or counter in the result of str(nvPublic.attributes).

By the way, I also found two other issues related to this:

  • TPMA_NV.to_string(0x60006) does not work (it raises ValueError: Could not match 393222 to class TPMA_NV). Users have to use str(TPMA_NV(0x60006)) to get a friendly representation. This feels strange.
  • The value 4 is defined twice in TPMA_NV: TPMA_NV.TPM2_NT_SHIFT = 4 and TPMA_NV.AUTHWRITE = 4. It would be strange to have TPM2_NT_SHIFT reported in the friendly representation of a NV attribute and the code seems to be fragile to ensure that AUTHWRITE is always preferred to TPM2_NT_SHIFT when using for example str(TPMA_NV(4)): it relies of the order given by vars(TPMA_NV).items().

niooss-ledger avatar Jan 13 '22 11:01 niooss-ledger

TPMA_NV.to_string(0x60006) does not work (it raises ValueError: Could not match 393222 to class TPMA_NV). Users have to use str(TPMA_NV(0x60006)) to get a friendly representation. This feels strange

So to_string is for mapping something like a constant in a class, which is why it's a class method versus an instance method. So in TPMA_NV class something like TPMA_NV.to_string(0x20000) will return the full constant name of TPMA_NV.OWNERREAD. Where the instance method for __str__ will return the lowercase, normalized, friendly values.

str(TPMA_NV.OWNERREAD|TPMA_NV.OWNERWRITE)
'ownerwrite|ownerread'

So to make the classmethod to_string try and figure out if they want the class constant or the friendly name, would be tricky, ie would TPMA_NV.to_string(0x20000) return TPMA_NV.OWENERREAD or ownerread

williamcroberts avatar Jan 14 '22 14:01 williamcroberts