In file included from tpm_sign_example.c:1: /usr/include/tss2/tss2_esys.h:954:25: note: expected ‘TPMT_TK_HASHCHECK **’ {aka ‘struct <anonymous> **’} but argument is of type ‘TPM2B_DIGEST *’ {aka ‘struct <anonymous> *’} 954 | TPMT_TK_HASHCHECK **validation); | ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~ tpm_sign_example.c: In function ‘verify_signature’: tpm_sign_example.c:89:5: error: unknown type name ‘RSA’ 89 | RSA *rsa = RSA_new(); | ^~~ tpm_sign_example.c:89:16: warning: implicit declaration of function ‘RSA_new’ [-Wimplicit-function-declaration] 89 | RSA *rsa = RSA_new(); | ^~~~~~~ tpm_sign_example.c:89:16: warning: initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion] tpm_sign_example.c:90:8: error: request for member ‘n’ in something not a structure or union 90 | rsa->n = BN_bin2bn(pubKey->publicArea.unique.rsa.buffer, pubKey->publicArea.unique.rsa.size, NULL); | ^~ tpm_sign_example.c:90:14: warning: implicit declaration of function ‘BN_bin2bn’ [-Wimplicit-function-declaration] 90 | rsa->n = BN_bin2bn(pubKey->publicArea.unique.rsa.buffer, pubKey->publicArea.unique.rsa.size, NULL); | ^~~~~~~~~ tpm_sign_example.c:91:8: error: request for member ‘e’ in something not a structure or union 91 | rsa->e = BN_new(); | ^~ tpm_sign_example.c:91:14: warning: implicit declaration of function ‘BN_new’ [-Wimplicit-function-declaration] 91 | rsa->e = BN_new(); | ^~~~~~ tpm_sign_example.c:92:5: warning: implicit declaration of function ‘BN_set_word’ [-Wimplicit-function-declaration] 92 | BN_set_word(rsa->e, pubKey->publicArea.parameters.rsaDetail.exponent); | ^~~~~~~~~~~ tpm_sign_example.c:92:20: error: request for member ‘e’ in something not a structure or union 92 | BN_set_word(rsa->e, pubKey->publicArea.parameters.rsaDetail.exponent); | ^~ tpm_sign_example.c:95:15: warning: implicit declaration of function ‘RSA_verify’ [-Wimplicit-function-declaration] 95 | int ret = RSA_verify( | ^~~~~~~~~~ tpm_sign_example.c:96:9: error: ‘NID_sha256’ undeclared (first use in this function) 96 | NID_sha256, | ^~~~~~~~~~ tpm_sign_example.c:96:9: note: each undeclared identifier is reported only once for each function it appears in tpm_sign_example.c:106:5: warning: implicit declaration of function ‘RSA_free’ [-Wimplicit-function-declaration] 106 | RSA_free(rsa); | ^~~~~~~~ tpm_sign_example.c: In function ‘main’: tpm_sign_example.c:124:77: warning: implicit declaration of function ‘strlen’ [-Wimplicit-function-declaration] 124 | TPMT_SIGNATURE *signature = tpm_sign(ctx, keyHandle, (uint8_t*)message, strlen(message)); | ^~~~~~ tpm_sign_example.c:124:77: warning: incompatible implicit declaration of built-in function ‘strlen’ tpm_sign_example.c:4:1: note: include ‘<string.h>’ or provide a declaration of ‘strlen’ 3 | #include <stdlib.h> +++ |+#include <string.h>
首先,用户遇到的错误主要集中在两个地方:类型不匹配和缺少头文件或函数声明。还有结构体成员的访问问题以及未声明的标识符。
第一个错误是在tpm_sign_example.c的第89行,报错是“unknown type name ‘RSA’”。这说明编译器不认识RSA类型。通常,RSA结构体是在OpenSSL的rsa.h头文件中定义的,所以可能用户没有包含这个头文件。用户代码中可能只包含了tss2_esys.h和其他一些标准头文件,但缺少了OpenSSL相关的头文件。因此,解决方法应该是检查是否包含了#include <openssl/rsa.h>和#include <openssl/bn.h>,因为这些头文件定义了RSA和BIGNUM相关的函数和结构体。
接下来,第89行的另一个错误是隐式声明函数RSA_new,这同样是因为没有包含正确的头文件。隐式声明函数会导致编译器假设返回类型为int,而实际返回的是指针,所以会有类型转换的警告。这也支持了缺少openssl头文件的结论。
然后,在访问rsa->n和rsa->e时,错误提示说结构体或联合中没有这些成员。这可能是因为OpenSSL版本的问题。在较新的OpenSSL版本中,RSA结构体的成员不再是直接访问的,而是需要通过函数来获取。例如,使用RSA_set0_key()来设置n、e、d等参数,而不是直接赋值给rsa->n。用户代码中直接操作rsa->n和rsa->e可能已经过时,需要改用对应的函数。例如:
RSA *rsa = RSA_new(); BIGNUM *n = BN_bin2bn(...); BIGNUM *e = BN_new(); BN_set_word(e, exponent); RSA_set0_key(rsa, n, e, NULL);
这样修改后,就不会直接访问结构体成员,避免了错误。
接下来,NID_sha256未声明的错误,这是因为缺少了对应的头文件,openssl/obj_mac.h或者openssl/evp.h可能没有被包含。通常,使用NID_sha256需要包含openssl/objects.h或者evp.h。添加相应的#include指令可以解决这个问题。
然后是strlen的隐式声明警告,提示用户没有包含string.h头文件。在代码中,用户可能在main函数里使用了strlen但没有包含string.h。解决方法是在文件头部添加#include <string.h>。
另外,关于类型不匹配的错误:在调用Esys_Sign函数时,validation参数的类型应该是TPMT_TK_HASHCHECK*,但用户传入了TPM2B_DIGEST类型。这说明函数调用时的参数类型不正确,需要检查函数原型,并确保传入正确的指针类型。可能用户误用了变量,需要更正参数类型。
总结一下,解决步骤应该是:
- 包含必要的OpenSSL头文件,如openssl/rsa.h, openssl/bn.h, openssl/evp.h等。
- 修改RSA结构体的成员访问,使用RSA_set0_key等函数代替直接赋值。
- 包含string.h以解决strlen的问题。
- 修正Esys_Sign函数调用时的参数类型,确保与函数原型一致。
- 确保所有使用的函数(如RSA_new, BN_bin2bn等)都有正确的声明,即对应的头文件已被包含。
在实现过程中,还需要注意OpenSSL版本的兼容性问题,尤其是在处理RSA结构体成员时,不同版本的方法可能不同。用户可能需要查阅当前使用的OpenSSL版本的文档,以确定正确的API使用方法。此外,链接时可能需要添加-lssl -lcrypto等选项,确保正确链接到OpenSSL库。
最后,建议用户检查编译命令,确认所有必要的库和头文件路径都已正确设置,避免因路径问题导致头文件无法找到或链接失败。在分析您的代码编译错误时,发现主要问题集中在 OpenSSL头文件缺失、RSA结构体使用方式过时 以及 函数参数类型不匹配 上。以下是分步解决方案:
一、错误原因及修复步骤
1. unknown type name 'RSA'
和隐式函数声明警告
- 原因:未包含 OpenSSL 相关头文件。
- 修复:在文件头部添加以下头文件:
#include <openssl/rsa.h> // 提供RSA结构体和函数 #include <openssl/bn.h> // 提供BIGNUM操作函数 #include <openssl/evp.h> // 提供NID_sha256常量 #include <string.h> // 提供strlen函数
2. request for member 'n'/'e' in something not a structure
- 原因:OpenSSL 1.1.0 及以上版本中,RSA结构体成员(如
n
、e
)不再允许直接访问,需通过 API 操作。 - 修复:改用
RSA_set0_key()
函数设置 RSA 参数:RSA *rsa = RSA_new(); BIGNUM *n = BN_bin2bn( pubKey->publicArea.unique.rsa.buffer, pubKey->publicArea.unique.rsa.size, NULL ); BIGNUM *e = BN_new(); BN_set_word(e, pubKey->publicArea.parameters.rsaDetail.exponent); // 将n和e绑定到RSA对象 RSA_set0_key(rsa, n, e, NULL); // 第三个参数为私钥d,此处为NULL
3. NID_sha256 undeclared
- 原因:未包含定义该常量的头文件。
- 修复:确保已包含
<openssl/evp.h>
。
4. implicit declaration of 'strlen'
- 原因:未包含
<string.h>
。 - 修复:在文件头部添加
#include <string.h>
。
5. 函数参数类型不匹配(TPMT_TK_HASHCHECK**
vs TPM2B_DIGEST*
)
- 原因:调用
Esys_Sign
时传入的validation
参数类型错误。 - 修复:根据函数原型调整参数类型:
// 原错误代码可能类似: TPM2B_DIGEST *validation; Esys_Sign(..., &validation); // 应改为: TPMT_TK_HASHCHECK *validation = NULL; Esys_Sign(..., &validation);
二、修改后的代码示例(关键部分)
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <string.h>
int verify_signature(TPM2B_PUBLIC *pubKey, TPMT_SIGNATURE *signature, const uint8_t *message, size_t message_len) {
RSA *rsa = RSA_new();
BIGNUM *n = BN_bin2bn(
pubKey->publicArea.unique.rsa.buffer,
pubKey->publicArea.unique.rsa.size,
NULL
);
BIGNUM *e = BN_new();
BN_set_word(e, pubKey->publicArea.parameters.rsaDetail.exponent);
RSA_set0_key(rsa, n, e, NULL);
int ret = RSA_verify(
NID_sha256,
message, message_len,
signature->signature.rsassa.sig.buffer,
signature->signature.rsassa.sig.size,
rsa
);
RSA_free(rsa);
return ret == 1;
}
三、编译命令注意事项
确保链接 OpenSSL 库:
gcc tpm_sign_example.c -o tpm_sign_example -ltss2-esys -lssl -lcrypto
四、总结
- 头文件缺失:补全 OpenSSL 和标准库头文件。
- API 过时:使用
RSA_set0_key()
替代直接访问结构体成员。 - 参数类型:严格匹配函数原型中的类型(如
TPMT_TK_HASHCHECK**
)。 - 编译链接:添加
-lssl -lcrypto
确保链接正确。
若问题仍未解决,请检查 OpenSSL 版本(需 ≥1.1.0)和 TPM2 库的安装完整性。
相关推荐


















