【问题标题】:Verifying SSL client authenticity fails due to SSL3_GET_CLIENT_CERTIFICATE:no certificate returned由于 SSL3_GET_CLIENT_CERTIFICATE,验证 SSL 客户端真实性失败:没有返回证书
【发布时间】:2015-03-08 09:41:26
【问题描述】:

我正在为 C++ 使用 OpenSSL API。通信是在嵌入式 linux 设备(SSL 服务器)和 Windows 软件(SSL 客户端)之间进行的。

我想确保预期的服务器和客户端只能相互交谈。我已经为 服务器 生成了一个根密钥,以及以下内容:

  • 根 CA(客户端用于授权服务器)
  • 服务器证书
  • 服务器私钥

仅在握手期间授权服务器证书时,我的 SSL 连接工作正常。

但是,我还想验证客户端的真实性,所以我为 客户端 生成了另一个根密钥,以及以下内容:

  • 根 CA(服务器用来授权客户端)
  • 客户端证书
  • 客户端私钥

使用下面的代码,由于以下错误,我的服务器无法接受客户端连接:

724428760:错误:140890B2:SSL 例程:SSL3_GET_CLIENT_CERTIFICATE:未返回证书:s3_srvr.c:3291:

这是我与 SSL 证书相关的服务器代码:

bool SSLServer::loadCertificates(const char * sCertFile,
                                 const char * sKeyFile,
                                 const char * sCAFile)
{
    // set server certificate
    if (SSL_CTX_use_certificate_file(_pCTX, sCertFile, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // set the private key
    if (SSL_CTX_use_PrivateKey_file(_pCTX, sKeyFile, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // verify private key
    if (!SSL_CTX_check_private_key(_pCTX))
    {
        qWarning() << "Private key does not match the public certificate.";
        return false;
    }

    SSL_CTX_set_verify(_pCTX, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);

    // load the trusted client CA certificate into context
    if (SSL_CTX_load_verify_locations(_pCTX, sCAFile, NULL) != 1)
    {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // allow this CA to be sent to the client during handshake
    STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(sCAFile);
    if (NULL == list)
    {
        qWarning() << "Failed to load SSL client CA file.";
        return false;
    }
    SSL_CTX_set_client_CA_list(_pCTX, list);
    SSL_CTX_set_verify_depth(_pCTX, 1);

    return true;
}

这是我的客户端代码:

bool SSLClient::LoadCertificates(const char * sCAFile,
                                 const char * sClientCertFile,
                                 const char * sClientKeyFile)
{
    ASSERT(NULL != sCAFile && NULL != sClientCertFile && NULL != sClientKeyFile);

    // load RSA CA certificate into context to let client verify server's authenticity
    // (will be used with server certificate and private key)
    if (!SSL_CTX_load_verify_locations(_pCTX, sCAFile, NULL))
    {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // load client certificate into context to let server verify client's authenticity
    // (will be used with server's RSA CA certificate)
    if (SSL_CTX_use_certificate_file(_pCTX, sClientCertFile, SSL_FILETYPE_PEM) != 1)
    {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // load client certificate private key into context
    if (SSL_CTX_use_PrivateKey_file(_pCTX, sClientKeyFile, SSL_FILETYPE_PEM) != 1)
    {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // verify that client cert and private key match
    if (!SSL_CTX_check_private_key(_pCTX))
    {
        OutputDebugString("Private key does not match the certificate public key\n");
        return false;
    }

    // require server certificate verification
    SSL_CTX_set_verify(_pCTX, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
    SSL_CTX_set_verify_depth(_pCTX, 1);

    return true;
}

同样,如果我删除与验证客户端证书相关的代码,它完全可以正常工作。我错过了什么,还是做错了什么?

【问题讨论】:

  • 乍一看,除了 SSL_VERIFY_FAIL_IF_NO_PEER_CERT 对客户端没有影响之外,代码看起来不错。您确定您真的在其余代码中调用 SSLClient::LoadCertificates 吗?
  • @SteffenUllrich 是的,我肯定会调用 LoadCertificates。我尝试过使用和不使用 SSL_VERIFY_FAIL_IF_NO_PEER_CERT ......似乎没有任何效果。我是否需要做任何事情来允许操作系统(Windows 和/或 Linux)使用证书,即使我在我的代码中特别说明了要使用哪些证书?
  • 客户端应该只发回配置的任何证书。检查此证书是否有效由服务器完成。但从错误消息看来,服务器没有获得证书,而不是验证失败。您能否通过数据包捕获(wireshark 等)确认这一点?
  • 在服务器代码中sCAFile指向客户端证书的CA?
  • @VladimirKunschikov 是的,这是正确的,在服务器代码中 sCAFile 指向客户端证书的 CA。

标签: c++ ssl openssl


【解决方案1】:

您的代码的工作副本以及证书:http://files.webfile.ru/567c28b8973091cbdad036f3e43e989b

如果生成证书只需点击“输入”回答问题,就可以重现您的问题。您将获得“自签名”证书,而无意制作它。与OpenSSL - error 18 at 0 depth lookup:self signed certificate 完全相同的问题 当窥探 ssl 问题时,您不应该使用wireshark,而是使用ssldump。

【讨论】:

  • 我将您的回调添加到我的代码中,并尝试使用您的证书,一切正常。之后,我很好奇,所以我再次尝试使用我的证书和你的回调,并且令人惊讶的是一切正常。仍在试图弄清楚为什么会这样......
  • 我开始认为我做了一些愚蠢的事情,比如没有正确地将证书复制到客户端/服务器。即使在删除回调之后,一切正常......我唯一能认为不同的是我通过 scp 将证书重新复制到服务器和客户端......我觉得有点愚蠢,但非常感谢你的帮助,你的代码/证书肯定帮助我找到了这个错误。
  • 你们有没有机会把那个代码链接放回去。我遇到了同样的错误。非常感谢
  • @EvrenBingøl 很抱歉没有回答。如果问题仍然存在,我可以添加该代码
  • @Vladimir Kunschikov。谢谢一堆。我发现我的也是这样。我的问题是由于最新的 chrome 证书验证,其中 chrome 希望在证书中有 DNS“SAN”字段并且必须将 CN 字段与域匹配是不够的。无论如何,谢谢。
【解决方案2】:

724428760:错误:140890B2:SSL 例程:SSL3_GET_CLIENT_CERTIFICATE:未返回证书:s3_srvr.c:3291:

错误信息具有误导性。虽然它说客户端没有返回任何证书,但如果客户端发送服务器无法验证的证书,它也会发生。请确保客户端发送的证书实际上可以针对服务器sCAFile进行验证。

【讨论】:

  • 绝对是一个误导性的错误消息...由于不正确地部署我的证书,我似乎遇到了某种无效的证书问题。感谢您的帮助。
猜你喜欢
  • 2011-11-21
  • 2016-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-08
  • 2017-05-18
相关资源
最近更新 更多