【问题标题】:OPENSSL connection to a public server gives X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY与公共服务器的 OPENSSL 连接提供 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
【发布时间】:2014-08-10 12:26:30
【问题描述】:

我正在编写一个非常基本的 SSL 客户端来连接到 HTTPS Web 服务器。我可以很好地连接和处理请求/响应。然而 OpenSSL 报告了UNABLE_TO_GET_ISSUER_CERT_LOCALLY,但到目前为止我选择忽略错误:-)。现在我想解决这部分问题。

我正在通过 HTTPS 连接到公共 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 (error code 20)

那么,我在这里遗漏了一些概念吗?这不会给我X509_V_OK 结果,因为它具有受信任的证书吗?只有两个来自 google.com,我使用了它们。

【问题讨论】:

    标签: ssl openssl certificate


    【解决方案1】:

    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_locationsNOTES 部分:

    如果 CAfile 不为 NULL,它指向 PEM 中的 CA 证书文件 格式。该文件可以包含多个由

    标识的 CA 证书

    -----开始证书-----

    ...(base64 编码的 CA 证书)...

    -----结束证书-----

    序列。允许证书文本之前、之间和之后 可以使用例如有关证书的说明。


    这里只是自行车脱落...

    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,执行匹配。

    【讨论】:

    • 我很感激(我没有收到有答案的电子邮件......也许我应该发布一个关于这个的问题:-)。至于检查对等证书,是否仅在我要验证客户端时才适用?如果我允许匿名客户端,但只是想避免嗅探,那不是必需的吗?
    • (是的,这是作为客户端的测试,只是询问,因为我最终需要同时支持这两种类型)
    • 另外一个问题,这适用于“google”,但是当我使用我们公司的网站时,我仍然在SSL_get_verify_result() 调用中收到错误代码 20。这是我们使用“通配符”证书的结果吗? *.domain.com。我目前使用的OpenSSL版本是1.0.1g
    【解决方案2】:

    感谢这篇文章,我终于可以让SSL/TLS Client 在 Windows 上工作。我built openssl using MSYS2。我必须对openssl-bio-fetch.tar.gz 代码进行一些更改,以便它可以在 Windows/MSYS2 中构建/运行,主要是调整 Makefile 包含并设置 -DNDEBUG 以避免 Posix 信号。

    但是在运行我得到的代码时:

        $ ./openssl-bio-fetch.exe
        Warning: thread locking is not implemented
        verify_callback (depth=1)(preverify=0)
            Issuer (cn): DigiCert High Assurance EV Root CA
            Subject (cn): DigiCert SHA2 Extended Validation Server CA
            Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
        certificate verify failed
    

    我必须下载 2 个 .pem 文件:

    DigiCert High Assurance EV Root CA

    DigiCert SHA2 Extended Validation Server CA

    并将证书粘贴到代码已在使用的同一 .pem 文件中:random-org-chain.pem

    谢谢!

    【讨论】:

      猜你喜欢
      • 2017-10-07
      • 2017-01-11
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 2012-03-06
      • 2017-01-27
      • 1970-01-01
      • 2017-05-21
      相关资源
      最近更新 更多