嵌入式Linux设备OpenSSL连接自签名证书服务器验证失败求助
我来帮你搞定这个OpenSSL错误码18的问题——先明确一下,这个错误对应的是X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,说白了就是OpenSSL在验证证书链的时候,发现最顶层的证书是自签名的,而你的代码默认没把它加入信任列表。
为啥浏览器和openssl s_client能成功?因为浏览器是你手动添加了信任,命令行大概率是用-CAfile参数指定了这个自签名证书,而你的代码里没做这一步,所以验证失败了。
下面给你几个排查和解决的方向:
给代码的SSL上下文加载自签名证书
这是最常见的原因:你的代码默认使用系统根证书池,而自签名证书不在这个池里。你需要手动把服务器的自签名证书加载到OpenSSL的信任存储中。
示例代码(假设你已经创建好SSL_CTX* ctx):// 加载PEM格式的自签名证书文件 if (!SSL_CTX_load_verify_locations(ctx, "/path/to/your/server.crt", NULL)) { ERR_print_errors_fp(stderr); // 处理加载失败的逻辑 return -1; }如果你的证书是内嵌在代码中的(比如字节数组),可以用内存BIO加载:
// cert_data是证书字节数组,cert_len是数组长度 BIO *bio = BIO_new_mem_buf(cert_data, cert_len); X509 *cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); if (cert) { // 将证书添加到SSL上下文的信任存储 X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert); X509_free(cert); } else { ERR_print_errors_fp(stderr); // 错误处理 } BIO_free(bio);检查证书路径与权限
嵌入式设备上很容易犯这个错:代码里指定的证书路径不对,或者运行程序的用户没有读取证书文件的权限。而你用命令行测试时,可能用了绝对路径或者root权限,所以能成功。
排查步骤:- 确保代码里用的是证书文件的绝对路径(嵌入式环境相对路径容易出问题)
- 用
ls -l /path/to/server.crt检查文件权限,确保运行程序的用户有读权限
确认证书格式匹配
OpenSSL加载证书时需要格式对应:如果你的证书是DER格式(没有-----BEGIN CERTIFICATE-----头),直接用SSL_CTX_load_verify_locations会失败。
你可以用这个命令确认证书格式:openssl x509 -in server.crt -text -noout如果是DER格式,先转成PEM格式再用:
openssl x509 -in server.der -inform der -out server.crt -outform pem检查SSL验证模式
虽然可能性不大,但可以确认一下你的代码没有错误地修改验证模式。默认情况下OpenSSL是开启SSL_VERIFY_PEER的(要求验证服务器证书),如果被改成SSL_VERIFY_NONE就不会有错误,但你这里返回了错误码18,说明验证是开启的,这一步主要是排除误配置。
按照上面的步骤调整后,应该就能让代码成功验证自签名证书并建立SSL连接了。
内容的提问来源于stack exchange,提问作者MHD

