为什么我在 Delphi 2010 中将 SSl 添加到 Indy 邮政编码查找示例时得到 "wrong version error"?

Why do I get "wrong version error" when I add SSl to the Indy Zip Code Lookup example in Delphi 2010?

我想我会尝试一些简单的东西来尝试理解 Web client/server 应用程序,因为我对此一无所知,但我需要学习。我从网络(客户端和服务器)下载了 "Zip Code look up" 示例。编译它们,一切都像宣传的那样工作。

然后我在每个表单上放置了一个 SSL IO 处理程序,并将它们指定为处理程序,并在两个表单中都选择了 "sslvTLSv1"。现在它不起作用。每次我尝试在客户端应用程序中查找邮政编码时,我都会 "error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number." 我卸载了原始的 Indy 库并安装了最新版本 (10.6.2.5264)。可以肯定的是,我得到了最新的 SSL 库并将它们放在两个程序文件夹中。

我在 Indy 中查看了许多关于 SSL 的问题和答案,它似乎应该有效。我错过了什么?

这是服务器 DFM 中的相关部分:

object IdTCPServer1: TIdTCPServer
  Active = True
  Bindings = <
    item
      IP = '127.0.0.1'
      Port = 6000
    end>
  DefaultPort = 6000
  IOHandler = Handler
  OnConnect = IdTCPServer1Connect
  OnExecute = IdTCPServer1Execute
  Left = 32
  Top = 24
end
object Handler: TIdServerIOHandlerSSLOpenSSL
  SSLOptions.Mode = sslmServer
  SSLOptions.VerifyMode = []
  SSLOptions.VerifyDepth = 0
  Left = 100
  Top = 32
end

这是客户端 DFM 的相关部分。

object Client: TIdTCPClient
  IOHandler = Handler
  ConnectTimeout = 0
  Host = '127.0.0.1'
  IPVersion = Id_IPv4
  Port = 6000
  ReadTimeout = -1
  Left = 209
  Top = 16
end
object Handler: TIdSSLIOHandlerSocketOpenSSL
  Destination = '127.0.0.1:6000'
  Host = '127.0.0.1'
  MaxLineAction = maException
  Port = 6000
  DefaultPort = 0
  SSLOptions.Mode = sslmClient
  SSLOptions.VerifyMode = []
  SSLOptions.VerifyDepth = 0
  Left = 296
  Top = 32
end

在尝试了 Remy 的建议后

我添加了将 PassThrough 设置为 false 的代码,但现在出现了不同的错误。 "error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure."

对于那些想要查看源代码的人,它位于 http://www.atozedsoftware.com/indy/demos/10/index.EN.aspx 的 Web 上(我使用的是服务器的 OnExecute 版本)。现在唯一的区别是每个单元中设置 PassThrough 模式的线路。

在服务器代码中:

procedure TformMain.IdTCPServer1Connect(AContext: TIdContext);
begin
  TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;
  AContext.Connection.IOHandler.WriteLn('200 Zip Code Server Ready.');
  AContext.Data := TUserData.Create;
end;

客户端代码中:

procedure TformMain.butnLookupClick(Sender: TObject);
var
  i: integer;
begin
  butnLookup.Enabled := False; try
    lboxResults.Clear;
    Handler.PassThrough := False;

您没有显示任何代码,只显示了您的 DFM。这还不够。但我怀疑 可能 发生的是你在客户端将 IOHandler.PassThrough 属性 设置为 false,但在服务器端没有做同样的事情.

当客户端连接到 TIdTCPServer 时,SSL/TLS 默认情况下不会被服务器激活,因此服务器可以分析客户端,甚至可能与它进行不安全的通信,然后再决定是否 [=30] =] 是必需的。这是为了方便服务器侦听多个端口,而并非所有端口都使用 SSL/TLS(想想 HTTP 与 HTTPS),并处理基于 STARTTLS 的协议。

因此,如果您还没有这样做,请确保将连接两端的 IOHandler.PassThrough 设置为 false,例如:

Handler.PassThrough := False;
IdTCPClient1.Connect;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
  TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;
end;

如果你确实在两端都这样做了,但仍然得到同样的错误,那么请确保 IOHandler.SSLOptions.SSLMethod/IOHandler.SSLOptions.TLSVersions 属性 在两端确实配置正确他们正在使用兼容的设置。你说你在两端都使用 TLSv1,所以你不应该收到错误,除非服务器真的没有使用 TLSv1。

所以,最后我要做的不仅仅是在窗体上放置几个控件。

首先,我必须添加代码以将每个 SSL 控件的 PassThrough 属性 设置为 false(也许它们应该是已发布的属性?)。

然后我必须安装一个有效的证书并在服务器端设置 CertFile、KeyFile 和 RootCertFile 属性。

现在可以使用了!

感谢 Remy 的帮助,顺便说一句,这是使用 OpenSSL v1.0.2 和 Indy 10.5.5。在 Win32 (Vista) 中 Delphi 2010.