2012-11-27 246 views
5

我已经浏览了因特网,但未找到有关如何通过使用TIdHTTP通过HTTPS进行连接时验证证书的解决方案或方法。Delphi Indy验证服务器证书SSL

我连接了一个IdSSLIOHandlerSocketOpenSSL组件作为IOHandler,设置SSLModes等,但是当我浏览到https://s3.amazonaws.com时,它无法验证证书。

OpenSSL的(印)给出

“使用SSL连接SSL3_GET_SERVER_CERTIFICATE错误:证书验证失败”

OpenSSL库已成功加载(检查与WhichFailedToLoad)。该OnStatusInfo事​​件写入以下内容:

SSL状态: “前/连接初始化”

SSL状态: “前/连接初始化”

SSL状态 “的SSLv2/v3的写客户端问候A”

SSL状态: “读SSLv3的服务器问候A”

SSL状态: “SSLv3的读取服务器证书B”

SSL小号tatus: “SSLv3的读取服务器证书B”

SSL状态: “SSLv3的读取服务器证书B”

而且OnVerifyPeer,AOK =假。

我怎样才能得到它的正确验证。这是怎么回事?

感谢您的阅读, 阿德里安

回答

7

你要实现你的TIdSSLIOHandlerSocketOpenSSL组件的OnVerifyPeer事件的事件处理程序。

从IdSSLOpenSSL.pas:

请注意,你真的应该始终 实施OnVerifyPeer,对等的,否则证书你 连接不检查,以确保它是有效的。

如果你只是要考虑有效的图书馆认为也适用同样的证书,你就必须实现它是这样的:

function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509; 
    AOk: Boolean; ADepth, AError: Integer): Boolean; 
begin 
    Result := AOk; 
end; 

至于证书和合格的有效性印首先检查你是否确定或不在AOk参数中。最后一句话是在你的代码中,因为你可能想要让某些小验证错误像过时一样,或甚至询问用户证书是否被接受,以防出现任何错误(小或不)。

要理解为什么它以这种方式工作,您可能还需要阅读IdSSLOpenSSL顶部的所有注释。PAS文件:

{

重要信息有关OnVerifyPeer: 版本2005年2月的1.39故意打破了OnVerifyPeer接口, 它(明显?)只会影响实现该回调 程序作为SSL的一部分谈判。请注意,你确实应该始终使用 实现OnVerifyPeer,否则不会检查连接到的对等证书以确保其有效。

在此之前,如果SSL库检测与证书 问题或深度不足(即VerifyCallback “确定”参数为0/FALSE),那么无论你OnVerifyPeer是否返回真 或错误的是,SSL连接将故意失败。

这在创建一个问题,即使在仅仅存在一个很小的 问题与该链中的证书之一,其中用户可以 已经(OnVerifyPeer一种用于在证书链中的每个证书称为 一次)很高兴接受,SSL协商将失败。但是, 更改代码以允许SSL连接,当用户为OnVerifyPeer返回True 意味着依赖于 自动拒绝无效证书的现有代码将接受 无效证书,这将是不可接受的安全性 更改。

因此,OnVerifyPeer已更改为通过添加AOk参数故意破坏现有代码 。为了保留以前的功能,您的OnVerifyPeer事件应该执行“Result:= AOk;”。如果您希望考虑 接受SSL库认为无效的证书,然后在您的OnVerifyPeer中使用 ,请确保您确信证书 确实有效,然后将Result设置为True。实际上,除了检查AOk的 之外,还应该执行代码,以确保只有 接受有效的证书(至少从您的角度来看)。

夏兰Costelloe,ccostelloe [_a_t_] flogas.ie

}

{

RLebeau 1/12/2011:断裂OnVerifyPeer事件,这一次增加一个额外的 AERROR参数(补丁提供“jvlad”,[email protected])。这 帮助用户代码区分自签名和无效 证书。

}

1

如果你喜欢SSL3_GET_SERVER_CERTIFICATE:certificate verify failed错误,那么请继续阅读:

似乎在印第安纳波利斯10,如果你设置的0一个VerifyDepth,该0实际上意味着all。不幸的是,印似乎只了解根CA,所以为了验证仅根部,请尝试以下OnVerify方法:

function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509; 
    AOk: Boolean; ADepth, AError: Integer): Boolean; 
begin 
    if ADepth = 0 then 
    begin 
    Result := AOk; 
    end 
    else 
    begin 
    Result := True; 
    end; 
end; 
+1

这是错误的。 Indy默认不知道根证书。这使你容易受到MitM攻击。您至少需要设置'VerifyMode','VerifyDepth'和'RootCertFile'来完成安全连接。之后,您可以将'AOk'返回任意深度,因为OpenSSL为您做了正确的事情。 – TobiX

1

我知道这是一个古老的职位,但它是所有我能找到解决这个问题。所以我想给Marcus的答案加上同样的问题: 当OpenSSL在PC上找不到根证书时,AError将返回#19(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN),并且根证书的AOK将为false。当您手动从文件加载根证书,AOK应该总是返回真值(和你有某种取得证书钉扎过):

FSSLIOHandlerSocketOpenSSL.SSLOptions.RootCertFile:=“MyRoot.cer”;