能否通过tpm2-openssl provider用OSSL_STORE_open_ex加载带密码的TPM2密钥?
使用tpm2-openssl通过OSSL_STORE_open_ex加载带密码的TPM2密钥
可以实现,但需要注意TPM2密钥的授权机制在tpm2-openssl中的特殊处理——持久化TPM2密钥的用户授权(user auth)需要在**操作阶段(如签名、解密)**传递,而非仅在加载阶段。你遇到的错误码0x0000098e(授权HMAC校验失败),核心原因就是操作时未正确传递密钥密码。
解决方案
1. 确认密钥创建的正确性
你现有的密钥创建命令是合规的,确保持久化步骤完成后,TPM中已存储带密码的目标密钥:
# 创建主密钥并持久化 tpm2_createprimary -g sha256 -G ecc256 -f pem -o storagekey_PK.pem -c storagekey.ctx tpm2_evictcontrol -c storagekey.ctx 0x81000001 # 创建带密码的密钥并持久化 tpm2_create -C 0x81000001 -g sha256 -G ecc256 -u client_PK.obj -r client_SK.obj -p "1234" -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign|decrypt" tpm2_load -C 0x81000001 -u client_PK.obj -r client_SK.obj -c client_key.ctx tpm2_evictcontrol -C o -c client_key.ctx 0x81000002
2. 正确的代码实现
以下是可直接使用的示例代码,核心是在签名上下文初始化后,通过OSSL_PARAM将密码传递到操作阶段:
#include <openssl/core_names.h> #include <openssl/evp.h> #include <openssl/store.h> int sign_with_tpm_key(const char *key_uri, const char *password, const unsigned char *msg, size_t msg_len, unsigned char **sig, size_t *sig_len) { OSSL_STORE_CTX *store_ctx = NULL; EVP_PKEY *pkey = NULL; EVP_MD_CTX *md_ctx = NULL; OSSL_PARAM params[3] = {0}; int ret = 0; // 加载TPM2持久化密钥(加载阶段无需密码) store_ctx = OSSL_STORE_open_ex(key_uri, NULL, NULL, NULL, NULL, NULL); if (!store_ctx) goto cleanup; if (!OSSL_STORE_load(store_ctx, (void**)&pkey) || !pkey) goto cleanup; // 初始化签名上下文 md_ctx = EVP_MD_CTX_new(); if (!md_ctx) goto cleanup; if (EVP_DigestSignInit(md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) goto cleanup; // 向操作上下文传递TPM2密钥授权密码 params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_PASSWORD, (char*)password, 0); params[1] = OSSL_PARAM_construct_end(); if (EVP_PKEY_CTX_set_params(EVP_MD_CTX_get_pkey_ctx(md_ctx), params) != 1) goto cleanup; // 执行签名 if (EVP_DigestSign(md_ctx, NULL, sig_len, msg, msg_len) != 1) goto cleanup; *sig = OPENSSL_malloc(*sig_len); if (!*sig) goto cleanup; if (EVP_DigestSign(md_ctx, *sig, sig_len, msg, msg_len) != 1) goto cleanup; ret = 1; cleanup: OSSL_STORE_close(store_ctx); EVP_PKEY_free(pkey); EVP_MD_CTX_free(md_ctx); return ret; }
3. 关键注意事项
- URI格式:使用
tpm2:handle=0x81000002作为密钥URI,无需添加?pass或?password参数。 - 密码传递时机:加载阶段(
OSSL_STORE_open_ex)不需要密码,因为持久化密钥已在TPM中;操作阶段(签名/解密)必须传递密码完成TPM授权。 - ui_method替代方案:tpm2-openssl 1.3.0中自定义
ui_method对操作阶段的授权支持不完善,优先使用OSSL_PARAM传递密码。
你的4种尝试的问题分析
- VERSION 1:未在操作阶段传递密码,TPM执行签名时要求授权但未收到,导致失败。
- VERSION 2:URI添加
?pass不符合tpm2-openssl的规范,密钥加载流程无法识别该参数,导致加载失败。 - VERSION 3:自定义
ui_method未被tpm2-openssl在操作阶段调用,无法传递授权密码,仍触发授权失败。 - VERSION 4:仅在加载阶段传递密码,操作阶段未传递,TPM仍要求授权,导致失败。
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

