使用tpm2-pytss进行TPM2签名时报哈希算法不支持错误
问题背景
已通过终端命令创建并持久化ECC密钥(句柄0x81000000),终端签名流程可正常运行,但使用Python的tpm2-pytss库复现时,签名步骤报错:tpm:parameter(2):hash algorithm not supported or not appropriate,且密钥的签名方案显示为null。
终端工作流程
tpm2_createprimary -C e -g sha256 -G ecc -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign" tpm2_evictcontrol -C o -c primary.ctx 0x81000000 # 持久化密钥 echo "data to sign" > data.in.raw # 创建原始数据 sha256sum data.in.raw | awk '{ print "000000 " $1 }' | xxd -r -c 32 > data.in.digest # 生成摘要 tpm2_sign -Q -c 0x81000000 -g sha256 -d -f plain -o data.out.signed data.in.digest
出错的Python代码
import tpm2_pytss # Initialize TPM tpm = tpm2_pytss.ESAPI(tcti=None) tpm.startup(tpm2_pytss.TPM2_SU.CLEAR) # Handle for the persistent key handle = tpm.tr_from_tpmpublic(0x81000000) # Inspect public key data public_data, _, _ = tpm.read_public(handle) public_area = public_data.publicArea ecc_params = public_area.parameters.eccDetail print(f"Key Type: {public_area.type}") print(f"Name Algorithm: {public_area.nameAlg}") print(f"Attributes: {public_area.objectAttributes}") print(f"ECC Curve: {ecc_params.curveID}") print(f"ECC Scheme: {ecc_params.scheme.scheme}") # Data to be signed data = b"data to sign" # Generate digest and validation ticket digest, validation = tpm.hash( data, hash_alg=tpm2_pytss.TPM2_ALG.SHA256, hierarchy=tpm2_pytss.ESYS_TR.NULL ) # Set up ECDSA signing scheme signing_scheme = tpm2_pytss.TPMT_SIG_SCHEME( scheme=tpm2_pytss.TPM2_ALG.ECDSA, details=tpm2_pytss.TPMU_SIG_SCHEME() # Empty scheme for ECDSA ) # Attempt to sign the digest using TPM try: signature = tpm.sign( handle, # Key handle in TPM digest, # Generated digest in_scheme=signing_scheme, # ECDSA signing scheme validation=validation # Validation ticket ) print(f"Generated Signature: {signature}") except tpm2_pytss.TSS2_Exception as e: print(f"Error while signing: {e}")
错误输出
Key Type: ecc Name Algorithm: sha256 Attributes: fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign ECC Curve: nist_p256 ECC Scheme: null WARNING:esys:src/tss2-esys/api/Esys_Sign.c:314:Esys_Sign_Finish() Received TPM Error ERROR:esys:src/tss2-esys/api/Esys_Sign.c:108:Esys_Sign() Esys Finish ErrorCode (0x000002c3) Error while signing: tpm:parameter(2):hash algorithm not supported or not appropriate
错误原因分析
- 密钥创建时未指定绑定哈希算法的签名方案,导致密钥的
scheme字段为null,TPM要求签名时必须明确指定哈希算法与签名方案的绑定关系。 - Python代码中创建的
TPMT_SIG_SCHEME仅指定了ECDSA方案,但未配置对应的哈希算法细节,TPM无法识别有效的签名参数组合。 - 终端的
tpm2_sign命令通过-g sha256参数自动补全了签名方案的哈希算法配置,而Python代码需要显式完成这一步。
解决方案
方案1:修正密钥创建命令(可选,固定签名方案)
如果希望密钥默认绑定SHA256的ECDSA方案,创建主密钥时显式指定签名方案:
tpm2_createprimary -C e -g sha256 -G ecc:ecdsa-sha256 -c primary.ctx -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign"
重新持久化密钥后,密钥的scheme会显示为ecdsa,后续签名时可省略部分配置。
方案2:修正Python代码的签名方案配置
即使密钥scheme为null,只要签名时显式指定包含哈希算法的完整签名方案即可。修改签名方案的创建代码:
# 正确配置ECDSA签名方案,绑定SHA256哈希算法 signing_scheme = tpm2_pytss.TPMT_SIG_SCHEME( scheme=tpm2_pytss.TPM2_ALG.ECDSA, details=tpm2_pytss.TPMU_SIG_SCHEME( ecdsa=tpm2_pytss.TPMT_SIG_SCHEME_ECDSA( hashAlg=tpm2_pytss.TPM2_ALG.SHA256 ) ) )
方案3:验证摘要与验证票据的设置
当前代码中的tpm.hash调用是正确的:
- 若使用预计算的外部摘要(类似终端的
-d参数),可跳过tpm.hash直接传入32字节的SHA256摘要值,此时验证票据可设为None,但需在sign调用中指定hierarchy参数。 - 当前生成的验证票据有效,无需修改。
完整修正后的Python代码
import tpm2_pytss # Initialize TPM tpm = tpm2_pytss.ESAPI(tcti=None) tpm.startup(tpm2_pytss.TPM2_SU.CLEAR) # Handle for the persistent key handle = tpm.tr_from_tpmpublic(0x81000000) # Inspect public key data public_data, _, _ = tpm.read_public(handle) public_area = public_data.publicArea ecc_params = public_area.parameters.eccDetail print(f"Key Type: {public_area.type}") print(f"Name Algorithm: {public_area.nameAlg}") print(f"Attributes: {public_area.objectAttributes}") print(f"ECC Curve: {ecc_params.curveID}") print(f"ECC Scheme: {ecc_params.scheme.scheme}") # Data to be signed data = b"data to sign" # Generate digest and validation ticket digest, validation = tpm.hash( data, hash_alg=tpm2_pytss.TPM2_ALG.SHA256, hierarchy=tpm2_pytss.ESYS_TR.NULL ) # 正确配置ECDSA签名方案,绑定SHA256哈希算法 signing_scheme = tpm2_pytss.TPMT_SIG_SCHEME( scheme=tpm2_pytss.TPM2_ALG.ECDSA, details=tpm2_pytss.TPMU_SIG_SCHEME( ecdsa=tpm2_pytss.TPMT_SIG_SCHEME_ECDSA( hashAlg=tpm2_pytss.TPM2_ALG.SHA256 ) ) ) # Attempt to sign the digest using TPM try: signature = tpm.sign( handle, # Key handle in TPM digest, # Generated digest in_scheme=signing_scheme, # 完整的ECDSA签名方案 validation=validation # Validation ticket ) print(f"Generated Signature: {signature}") except tpm2_pytss.TSS2_Exception as e: print(f"Error while signing: {e}")
针对问题的解答
如何在tpm2-pytss中为TPM2_ALG.ECDSA密钥正确指定签名方案?
需要创建包含哈希算法细节的TPMT_SIG_SCHEME对象:通过TPMU_SIG_SCHEME的ecdsa字段,指定TPMT_SIG_SCHEME_ECDSA并设置对应的哈希算法(如SHA256),不能使用空的TPMU_SIG_SCHEME。摘要或验证票据的设置是否存在问题?
当前的tpm.hash调用是正确的,生成的摘要和验证票据有效。若使用预计算的外部摘要,需确保摘要长度与哈希算法匹配(SHA256为32字节),此时验证票据可设为None,但需在sign调用中补充hierarchy参数。创建密钥时是否需要显式设置方案以支持ECDSA?
不是必须,但显式设置(如-G ecc:ecdsa-sha256)会让密钥默认绑定该签名方案,后续签名时可省略部分配置。如果密钥scheme为null,只要签名时显式指定完整的签名方案即可正常工作。
内容的提问来源于stack exchange,提问作者Nathol_Laki

