OpenSSL忽略自签名证书错误

问题描述:

我正在写一个OpenSSL库的小程序,该程序假设与SSLv3服务器建立连接。此服务器分配一个自签名证书,导致握手失败,并显示以下消息:“sslv3警报握手失败,证书链中的自签名证书”。OpenSSL忽略自签名证书错误

有没有办法强制连接进行?我已经打过电话SSL_CTX_set_verify像这样:

SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); 

但它似乎并没有改变任何东西。

有什么建议吗?

+0

'SSL_VERIFY_NONE'完全禁用证书验证。你可能不想这样做,因为这会让你容易受到MITM攻击。正确的做法是将自签名证书添加到可信证书列表中。 (请参阅SSL_CTX_load_verify_locations()。) – 2017-02-03 10:52:43

+0

顺便说一句,错误消息并不意味着服务器的证书是自签名的。这意味着您不信任根CA的证书: ** X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ** _证书链中存在自签名证书。可以使用不受信任的证书构建证书链,但无法在本地找到根CA. 根CA证书始终是自签名的。 – 2017-02-03 11:15:02

默认情况下OpenSSL的走证书链,并尝试来验证每一个步骤,SSL_set_verify()不改变这种状况,看塔人页。引用它:执行

实际验证程序或者使用 内置验证过程或使用另一应用程序提供 验证函数SSL_CTX_set_cert_verify_callback(3)设置。

因此,解决方案是创建一个简单的回调,并设置一个,这样就覆盖所有证书链行走:

static int always_true_callback(X509_STORE_CTX *ctx, void *arg) 
{ 
    return 1; 
} 

SSL_CTX_set_cert_verify_callback(CTX, always_true_callback); 
+2

只需引用文本下面几段:'如果未指定verify_callback,则将使用默认回调。它的返回值与preverify_ok相同,因此,如果设置了SSL_VERIFY_PEER,则任何验证失败都将导致终止TLS/SSL握手并发出警报消息。“ 您的答案不正确,将验证模式设置为SSL_VERIFY_NONE应该足够了。 – Spidey 2015-01-15 15:24:10

+1

@Spidey你看过这个问题吗?它被认为SSL_VERIFY_NONE *不够*。你自己尝试过吗?仅供参考,您所引用的手册适用于'SSL_CTX_set_verify()'。但即使* set_verify *回调总是成功,验证失败的方式还有很多,这就是为什么您必须使用'SSL_CTX_set_cert_verify_callback()'设置更通用的回调。 – jimis 2015-01-19 10:05:31

+0

总是返回'1'完全禁用证书验证。这与设置'SSL_VERIFY_NONE'相同。 (即@Spidey是对的。)你可能不想这样做,因为这会让你容易受到MITM攻击。正确的做法是将自签名证书添加到可信证书列表中。 (请参阅SSL_CTX_load_verify_locations()。) – 2017-02-03 10:54:51

您是否尝试过设置SSL_set_verify?

SSL_set_verify(s, SSL_VERIFY_NONE, NULL); 
+0

试过,没有变化 – Ramsey 2010-02-13 09:24:17

+0

更多的代码在这一点上会很好。 – Xorlev 2010-02-13 09:37:49

+0

感谢您的回复。我尝试了所有的建议,但仍然没有运气。我在这里粘贴了程序的关键部分: http://pastebin.com/m78497bf3 – Ramsey 2010-02-13 17:32:14

您是否尝试过给你的应用程序服务器的CA证书,以便您的应用程序可以验证证书链?

+0

正确,但在此情况下,签名证书,OP必须让他的应用信任的不是CA证书,而是服务器的证书。 – 2017-02-03 11:02:11

+0

我的不好,OP是错的。服务器证书不是自签名的。问题中包含的错误消息显示错误是'X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN',这意味着所提到的自签名证书不是服务器证书,而是根CA证书。 – 2017-02-03 11:11:06

您可以尝试将自己的回调传递给SSL_set_verify(),然后进行自己的验证。这并不理想,因为我认为你需要完成所有的验证,然后让自签名错误被忽略,但是你应该能够计算出标准验证代码从OpenSSL源代码所做的事情,然后简单地将它拉出来到你自己的验证回调,并允许特定的错误代码......

+0

如果您打算接受自签名证书,那么其余的验证步骤无论如何都毫无意义。 – caf 2010-03-02 08:43:10

+0

caf - 可能,是... – 2010-03-02 16:09:02

检查这些OpenSSL的例子:http://www.rtfm.com/openssl-examples/

wclient.c连接到任何HTTPS网页,例如:

wclient -h www.yahoo.com -p 443 

如果你使用默认安装运行它,你会得到一个证书错误(你可以使用-i标志绕过证书检查)。

验证证书,你需要下载CA证书(威瑞信,Thawte的,Equifax公司等),因此谷歌这个文件cacert.pem,下载并重新命名为root.pem和你将能够连接到Web服务器并验证其证书。

+0

另外,如果要打印证书,请在check_cert(ssl,host)之后插入以下行(在wclient.c中):X509_print_fp(stdout,SSL_get_peer_certificate(ssl)); – 2010-02-18 20:08:24

+0

正确,尽管在这种情况下服务器使用自签名证书,但OP必须使其应用信任的内容不是CA证书,而是服务器的证书。 – 2017-02-03 11:02:05

+0

我的不好,OP是错的。服务器证书不是自签名的。问题中包含的错误消息显示错误是'X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN',这意味着所提到的自签名证书不是服务器证书,而是根CA证书。 – 2017-02-03 11:10:52

我的示例客户端代码(link)可以正常使用自签名服务器证书。我所以SSL_connect后,下面的代码,并有超过自签名的证书,接受的完全控制在我的客户

SSL_CTX* ctx = SSL_CTX_new(SSLv3_method()); 

// TCP connection and SSL handshake ... 

/* Check the certificate */ 

rc = SSL_get_verify_result(ssl); 
if(rc != X509_V_OK) { 
    if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || rc == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) { 
    fprintf(stderr, "self signed certificate\n"); 
    } 
    else { 
    fprintf(stderr, "Certificate verification error: %ld\n", SSL_get_verify_result(ssl)); 
    SSL_CTX_free(ctx); 
    return 0; 
    } 
} 
+0

这会让你容易受到MITM攻击!如果你这样做,任何自签证书都会被接受。如果证书是可信的,则不会引发您忽略的错误。正确的做法是将自签名证书添加到可信证书列表中。 (请参阅SSL_CTX_load_verify_locations()。) – 2017-02-03 10:59:30