我正在编写一个非常基本的 SSL 客户端来连接到 HTTPS 网络服务器。我可以很好地连接和处理请求/响应。然而 OpenSSL 正在报告 UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,但到目前为止我选择忽略错误 :-)。现在我想解决这部分问题。
我通过连接到 HTTPS 上的公共(public) SSL 服务器(例如 Google 或 Yahoo)进行测试,并检查 SSL_get_verify_result(...)
的返回值。
据我了解,我需要该特定站点的 CA pem 文件,以便 OpenSSL 可以验证到可信证书颁发机构的链。在这种情况下,这将是为 Google 或 Yahoo 签署证书的机构。
为了获得我期望的 PEM 文件,我打开了我的 FireFox,导航到这些站点,执行了查看证书并将每个文件导出到列表中。因此,例如,我有一个名为“GeoTrustGlobalCA.pem”的文件,它看起来都不错。事实上,当我直接访问 GeoTrust 站点并下载他们的根证书时,正如我所料,它与我从 FireFox 导出的根证书相同。
因此,例如 Google 在 FireFox 的树中显示了两个证书,我加载每个:
result = SSL_CTX_load_verify_locations(ctx,"GoogleInternetAuthorityG2.pem",NULL);
if (result == 0) {
puts("Opps... Can't load the certificate");
}
result = SSL_CTX_load_verify_locations(ctx,"GeoTrustGlobalCA.pem",NULL);
if (result == 0) {
puts("Opps... Can't load the certificate");
}
之后,连接和交流的常规内容:
BIO_set_conn_hostname(bio, "www.google.com:https");
并且在加载或连接时不会出错。
但是,验证不起作用。
result = SSL_get_verify_result(ssl);
printf("The Verify Result is %d \n",result);
我得到返回值 UNABLE_TO_GET_ISSUER_CERT_LOCALLY(错误代码 20)
。
那么,我是不是漏掉了一些概念?这不会给我 X509_V_OK
结果,因为它有受信任的证书吗?只有两个来自 google.com 的上链,我使用了它们。
最佳答案
对 SSL_CTX_load_verify_locations
的第二次调用替换了第一次调用的证书。
你应该将你的根合并到一个文件中:
$ cat my-trusted-roots.pem
-----BEGIN CERTIFICATE-----
... (CA certificate in base64 encoding) ...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (CA certificate in base64 encoding) ...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (CA certificate in base64 encoding) ...
-----END CERTIFICATE-----
然后使用 SSL_CTX_load_verify_locations
加载该单个文件。请参阅 OpenSSL docs on SSL_CTX_load_verify_locations
.特别是NOTES部分:
If CAfile is not NULL, it points to a file of CA certificates in PEM format. The file can contain several CA certificates identified by
-----BEGIN CERTIFICATE-----
... (CA certificate in base64 encoding) ...
-----END CERTIFICATE-----
sequences. Before, between, and after the certificates text is allowed which can be used e.g. for descriptions of the certificates.
这里只是自行车脱落...
result = SSL_get_verify_result(ssl);
printf("The Verify Result is %d \n",result);
这是您需要执行的三个测试之一。
您需要执行的第二个测试如下。匿名 Diffie-Hellman (ADH) 不使用证书,因此您需要进行检查。
X509* cert = SSL_get_peer_certificate(ssl);
if(cert) X509_free(cert);
if(cert == NULL)
/* Error - Anonymous Diffie-Hellman */
SSL_get_peer_certificate
会增加证书的引用计数,因此您需要对 X509_free
进行匹配调用。
您需要执行的第三项测试是主机名匹配。 OpenSSL 1.1.0 将执行主机名匹配(和其他名称匹配,如 PKCS9 电子邮件地址);但较小的版本,如 0.9.8 和 1.0.1,不要执行匹配。
关于ssl - 与公共(public)服务器的 OPENSSL 连接给出 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24315526/