tpm2-pytss
tpm2-pytss copied to clipboard
Attributes of TPM NV counters (and bits) cannot be represented as string
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 raisesValueError: Could not match 393222 to class TPMA_NV
). Users have to usestr(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
andTPMA_NV.AUTHWRITE = 4
. It would be strange to haveTPM2_NT_SHIFT
reported in the friendly representation of a NV attribute and the code seems to be fragile to ensure thatAUTHWRITE
is always preferred toTPM2_NT_SHIFT
when using for examplestr(TPMA_NV(4))
: it relies of the order given byvars(TPMA_NV).items()
.
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