Delphi Indy 验证服务器证书 SSL

9
我已经在互联网上搜索过,但没有找到关于如何使用TIdHTTP连接HTTPS时验证证书的解决方案或方法。
我已经连接了一个IdSSLIOHandlerSocketOpenSSL组件作为IOHandler,并设置了SSLModes等参数,但当我浏览https://s3.amazonaws.com时,它无法验证证书。
OpenSSL(Indy)给出以下错误信息:
“Error connecting with SSL. SSL3_GET_SERVER_CERTIFICATE: Certificate verify failed”
OpenSSL库已成功加载(通过WhichFailedToLoad进行检查)。OnStatusInfo事件写入以下内容:
SSL status: "before/connect initialization"
SSL status: "before/connect initialization"
SSL status: "SSLv2/v3 write client hello A"
SSL status: "SSLv3 read server hello A"
SSL status: "SSLv3 read server certificate B"
SSL status: "SSLv3 read server certificate B"
SSL status: "SSLv3 read server certificate B"
而在OnVerifyPeer中,AOk = False。
我该如何使其正确验证证书?发生了什么?
谢谢阅读, Adrian
3个回答

12

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

从 IdSSLOpenSSL.pas 文件中可以看到:

请注意,你必须始终实现 OnVerifyPeer,否则连接到的对等方证书将不会被检查以确保其有效性。

如果你只想考虑与库认为有效相同的证书,则可以按照以下方式实现它:

function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509;
  AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
  Result := AOk;
end;
Indy首先检查证书的有效性并在AOk参数中传递给您。最后一个字是在您的代码中,因为您可能希望放过一些次要的验证错误,例如日期过期,或者甚至在任何错误(重要或不重要)的情况下询问用户是否接受证书。
为了理解为什么会这样,您可能还想阅读IdSSLOpenSSL.pas文件顶部的所有注释:
{关于OnVerifyPeer的重要信息: 2005年2月的版本1.39故意破坏了OnVerifyPeer接口, 这只影响实现了该回调作为SSL协商的一部分的程序。 请注意,您真的应该始终实现OnVerifyPeer, 否则将不会检查您正在连接到的对等方的证书以确保其有效性。}
在此之前,如果SSL库检测到证书存在问题或深度不足(即验证回调中的“Ok”参数为0 / FALSE), 那么无论您的OnVerifyPeer返回True还是False,SSL连接都将被故意失败。
这就创建了一个问题,即使证书链中的某个证书只有非常小的问题(OnVerifyPeer针对证书链中的每个证书调用一次),并且用户可能愿意接受它, SSL协商也会失败。然而,更改代码以允许用户返回OnVerifyPeer时SSL连接,将意味着依赖于自动拒绝无效证书的现有代码将接受无效证书, 这将是一种不可接受的安全变更。
因此,OnVerifyPeer被更改为故意破坏现有代码,添加了一个AOk参数。为保留先前的功能,您的OnVerifyPeer事件应该执行“Result:= AOk;”。 如果您希望考虑接受SSL库认为无效的证书,则在您的OnVerifyPeer中,请确保满足自己的要求,证明证书确实有效,然后将结果设置为True。 实际上,除了检查AOk之外,您还应始终实施代码,以确保只接受从您的角度来看有效的证书。}
RLebeau 1/12/2011: 再次破坏OnVerifyPeer事件,这次添加了一个额外的AError参数(补丁由“jvlad”、dmda@yandex.ru提供)。 这有助于用户代码区分自签名和无效证书。

1

我知道这是一篇古老的帖子,但这是我能找到的解决问题的方法。因此,我想为其他遇到相同问题的人增加Marcus答案的一些补充:

当OpenSSL在PC上找不到根证书时,AError将返回#19(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN),并且对于根证书,AOK将为false。当您手动从文件中加载根证书时,AOK应始终返回true(并且您已经实现了某种证书固定):

FSSLIOHandlerSocketOpenSSL.SSLOptions.RootCertFile := 'MyRoot.cer';


0
如果您遇到像 SSL3_GET_SERVER_CERTIFICATE:certificate verify failed 这样的错误,请继续阅读:
在Indy 10中,如果您将VerifyDepth设置为0,则似乎实际上意味着all

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接