在使用 FFmpeg 通过 HTTPS 协议拉取或推送流媒体时,若启用 OpenSSL 的证书吊销列表(CRL)检查,常出现“CRL has expired”或“unable to get certificate CRL”等错误,导致连接中断。该问题多因系统未正确配置 CRL 分发点、CRL 文件过期、网络无法访问 CRL 下载地址,或 OpenSSL 未启用 CRL 检查支持所致。即使证书本身有效,OpenSSL 在开启严格模式下仍会因无法获取或验证 CRL 而拒绝连接,影响 FFmpeg 的正常运行。如何在确保安全性的前提下正确配置 CRL 验证机制,成为实际部署中的关键难题。
1条回答 默认 最新
泰坦V 2025-10-03 22:35关注一、问题背景与现象分析
在使用 FFmpeg 通过 HTTPS 协议拉取或推送流媒体时,若启用了 OpenSSL 的证书吊销列表(CRL)检查机制,常出现以下典型错误:
SSL routines:tls_process_server_certificate:CRL has expiredunable to get certificate CRLcertificate verification failed: unable to get issuer certificate
这些错误表明 OpenSSL 在执行 X.509 证书链验证过程中尝试获取并校验 CRL 文件失败。尽管目标服务器的证书本身可能仍处于有效期内,但由于 CRL 检查未通过,连接被强制中断。
根本原因通常包括:
- CRL 分发点(CRL Distribution Points)配置缺失或不可访问;
- 本地缓存的 CRL 文件已过期;
- 网络策略阻止对 CRL 下载地址(如
http://crl.example.com/...)的访问; - OpenSSL 编译时未启用 CRL 支持或运行时未正确加载 CRL 数据;
- 中间 CA 或根 CA 的 CRL 过期导致整个信任链失效。
二、技术原理深度解析
为理解该问题的本质,需从 PKI(公钥基础设施)体系入手。X.509 证书验证不仅依赖于证书有效期和签名链,还涉及吊销状态检查。CRL 是一种由 CA 定期发布的已吊销证书序列号列表,客户端应下载并比对目标证书是否被列入。
OpenSSL 默认行为如下:
配置项 默认值 说明 X509_V_FLAG_CRL_CHECK 未启用 启用后要求验证 CRL X509_V_FLAG_CRL_CHECK_ALL — 对整条证书链进行 CRL 检查 crl_download_timeout 5 秒 超时将导致检查失败 FFmpeg 基于 libavformat 和底层 SSL 库(如 OpenSSL)实现 HTTPS 流传输。当调用
https_open时,会触发 SSL 握手过程中的证书验证流程。若应用程序或系统设置了严格的证书策略(例如通过环境变量或配置文件强制开启 CRL 检查),则任何 CRL 获取失败都会直接终止连接。三、常见排查路径与诊断方法
以下是逐步排查此类问题的标准流程:
- 使用
openssl x509 -in cert.pem -text -noout查看证书中的 CRL 分发点字段; - 通过浏览器或
curl -O <crl_url>手动测试 CRL 地址可达性; - 检查系统时间是否准确(CRL 验证高度依赖时间戳);
- 确认 OpenSSL 是否支持 CRL 功能:
openssl version并查看编译选项; - 使用
strace -e trace=network ffmpeg ...跟踪网络请求行为; - 启用 OpenSSL 调试日志:
SSL_CTX_set_info_callback()输出详细握手信息; - 检查防火墙或代理是否拦截了非 HTTPS 请求(CRL 多使用 HTTP);
- 验证本地 CA bundle 是否包含最新 CRL 文件;
- 尝试临时禁用 CRL 检查以隔离问题:
ffmpeg -sslvfy 0 ...; - 部署 OCSP 替代方案进行对比测试。
四、解决方案架构设计
为在保障安全性的前提下解决 CRL 验证失败问题,建议采用分层应对策略:
graph TD A[FFmpeg HTTPS Stream] --> B{SSL/TLS Handshake} B --> C[证书链验证] C --> D{是否启用CRL检查?} D -- 否 --> E[仅验证签名与有效期] D -- 是 --> F[获取CRL分发点URL] F --> G{网络可访问?} G -- 否 --> H[降级至OCSP或本地缓存] G -- 是 --> I[下载CRL文件] I --> J{CRL是否有效?} J -- 否 --> K[使用预置可信CRL副本] J -- 是 --> L[执行吊销状态比对] L --> M[完成连接]五、具体实施建议
实际部署中可采取以下措施:
- 定期更新本地 CRL 缓存:编写脚本定时从各主流 CA 下载 CRL 并导入系统信任库;
- 配置透明代理缓存 CRL:在企业网关部署 HTTP 代理,缓存常见 CRL 文件以减少外网依赖;
- 启用 OCSP Stapling:要求服务器在 TLS 握手中附带 OCSP 响应,避免客户端主动查询;
- 自定义 verify_callback:在嵌入式 FFmpeg 应用中重写证书验证逻辑,加入容错机制;
- 使用 mbed TLS 或 BoringSSL 替代 OpenSSL:部分库对 CRL 处理更灵活;
- 设置合理的超时与重试策略:避免因短暂网络波动导致验证失败;
- 构建内部 PKI 管控平台:统一管理证书生命周期与 CRL 分发;
- 监控 CRL 到期时间:对接 Zabbix 或 Prometheus 实现告警;
- 灰度启用严格模式:先在非关键服务上线验证;
- 文档化应急响应流程:明确何时允许临时绕过 CRL 检查。
六、代码示例:手动加载 CRL 到 SSL 上下文
以下为 C 语言片段,展示如何在基于 OpenSSL 的应用中显式加载 CRL:
#include <openssl/ssl.h> #include <openssl/x509_vfy.h> void setup_crl_check(SSL_CTX *ctx, const char *crl_file) { X509_STORE *store = SSL_CTX_get_cert_store(ctx); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); if (X509_load_crl_file(lookup, crl_file, X509_FILETYPE_PEM)) { X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } else { fprintf(stderr, "Failed to load CRL file: %s\n", crl_file); } }本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报