OpenSSL 3 FIPS模式下EVP_VerifyInit为何对常见摘要类型失败?
启用OpenSSL 3 FIPS模式时EVP_VerifyInit失败问题排查
启用OpenSSL 3的FIPS模式后,调用EVP_VerifyInit会抛出错误error:0308010C:digital envelope routines::unsupported,禁用FIPS模式则程序可正常运行。
复现代码
#include "stdio.h" #include "openssl/evp.h" #include "openssl/err.h" const char *openssl_error() { return ERR_error_string(ERR_get_error(), nullptr); } int main() { if (!EVP_default_properties_enable_fips(nullptr, 1)) { printf("Failed to enable FIPS: %s\n", openssl_error()); return -1; } auto ctx = EVP_MD_CTX_new(); if (!ctx) { printf("Failed to make CTX: %s\n", openssl_error()); return -1; } if (!EVP_VerifyInit(ctx, EVP_sha256())) { printf("Failed to start verification: %s\n", openssl_error()); return -1; } printf("Everything looks OK.\n"); return 0; }
报错信息
Failed to start verification: error:0308010C:digital envelope routines::unsupported
已尝试操作
- 使用
EVP_sha1()、EVP_sha384()作为摘要算法,同样报错; - 调用
EVP_VerifyInit_ex()并传入nullptr作为engine,问题未解决。
排查与解决建议
由于OpenSSL 3为内部编译版本,核心问题大概率是FIPS模块未正确编译或加载,可从以下方向排查:
1. 检查OpenSSL编译配置
- 确认编译时添加了
enable-fips配置项,且已正确指定FIPS模块源码路径(OpenSSL 3要求单独编译FIPS模块后再编译主库); - 执行
openssl version -a,检查输出中是否包含FIPS相关标识,确认FIPS模块已被纳入编译。
2. 验证FIPS模块加载状态
- 在代码中添加状态检查:调用
FIPS_mode(),返回1表示FIPS模式已生效,0则说明EVP_default_properties_enable_fips调用未真正启用FIPS; - 可通过环境变量强制指定FIPS配置:设置
OPENSSL_CONF指向包含FIPS模块路径的配置文件,示例配置如下:config_diagnostics = 1 openssl_conf = openssl_init [openssl_init] providers = provider_sect [provider_sect] fips = fips_sect base = base_sect [fips_sect] activate = 1 module = /path/to/fipsmodule.so # 替换为实际FIPS模块路径 [base_sect] activate = 1
3. 确认算法的FIPS合规性
- 执行
openssl list -providers -verbose,查看FIPS模块支持的算法列表,确认SHA系列摘要算法是否在其中; - 若算法未被纳入FIPS模块,需重新编译OpenSSL并确保FIPS模块包含所需算法。
4. 适配OpenSSL 3的API调用方式
OpenSSL 3推荐通过属性查询获取FIPS合规的算法实现,替代旧版直接调用EVP_sha256()的方式,修改后代码示例:
// 获取FIPS合规的SHA256算法实现 EVP_MD *md = EVP_MD_fetch(nullptr, "SHA256", "fips=yes"); if (!md) { printf("Failed to fetch FIPS-compliant SHA256: %s\n", openssl_error()); return -1; } if (!EVP_VerifyInit(ctx, md)) { printf("Failed to start verification: %s\n", openssl_error()); EVP_MD_free(md); EVP_MD_CTX_free(ctx); return -1; } // 使用完毕后释放资源 EVP_MD_free(md);
内容的提问来源于stack exchange,提问作者Calmarius
相关产品推荐
相关产品推荐

