delphi 当TLS协商失败时,应该触发哪个TIdSMTP/SSLIOToken事件?

qlvxas9a  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(151)

我想让SMTP TLS“隐式/显式”配置透明,为此我想到了使用事件触发器。
我的想法是捕捉TLS协商成功或失败,然后用另一个选项再试一次。
我在TIdSMTPTIdSSLIOHandlerSocketOpenSSL上看到了一些事件,但似乎都没有正确触发。
Indy的文档也无法下载here(DNS中断错误)。
我使用以下带有“Sleep(1);“的事件只是为了在其中放置一个断点。
TIdSMTP
OnTLSNotAvailable
OnTLSHandShakeFailed
OnTLSNegCmdFailed
OnFailedEHLO
TIdSSLIOHandlerSocketOpenSSL
OnStatus
OnStatusInfo
OnStatusInfoEx
我测试过的:
例如,我使用Outlooksmtp.office365.com,端口为587(在Indy中为STARTTLS-utUseExplicitTLS),但我故意将TIdSMTP.UseTLS更改为utUseImlicitTLS以模拟TLS协商失败。
在第一个TIdSMTP.Connect()测试中,我得到了一个EIdSocketError异常('*Socket Error # 10060 Connection timed out'),而不是TLS协商失败的消息/异常。在这个测试中,唯一触发的事件是TIdSSLIOHandlerSocketOpenSSL.OnStatusTIdSMTP.OnStatus
在第二次TIdSMTP.Connect()测试中,我没有收到EIdSocketError的超时消息,除了第一次尝试的事件外,它还触发了TIdSSLIOHandlerSocketOpenSSL.OnStatusInfoTIdSSLIOHandlerSocketOpenSSL.OnStatusInfoEx事件,处理TLS连接错误。
一些代码片段:

procedure Connect;
var
  LSMTP: TIdSMTP;
  LSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
  LSMTP:= TIdSMTP.Create(nil);
  LSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  
  {functions to be declared}
  LSMTP.OnTLSNotAvailable   := MyTLSNotAvailable;
  LSMTP.OnTLSHandShakeFailed:= MyTLSHandShakeFailed;
  LSMTP.OnTLSNegCmdFailed   := MyTLSNegCmdFailed;
  LSMTP.OnFailedEHLO        := MyFailedEHLO;

  LSSL.OnStatus      := MyOnStatus;
  LSSL.OnStatusInfo  := MySSLInfo;
  LSSL.OnStatusInfoEx:= MySSlInfoEx;
  LSSL.ConnectTimeout:= 1000000;
  LSSL.ReadTimeout   := 1000000;

  LSMTP.IOHandler       := FSSL;
  LSMTP.AuthType        := satDefault;
  LSMTP.UseTLS          := utUseExplicitTLS;
  LSSL.SSLOptions.Method:= sslvSSLv23;
  LSSL.SSLOptions.Mode  := sslmBoth;

  LSMTP.Host:= 'smtp.office365.com';
  LSMTP.Port:= '587';
  LSMTP.Username:= [email protected];
  LSMTP.Password:= password;
  LSMTP.From:= LSMTP.Username;

  try
    LSMTP.Connect;
  except
      raise Exception.Create(Format('Error during connect attempt: %s',[Exception(ExceptObject).Message]));
  end;

end;

字符串
我有几个问题

  • 为什么在这些情况下不触发TIdSMTP.OnTLSNotAvailableTIdSMTP.OnTLSHandShakeFailedTIdSMTP.OnTLSNegCmdFailed事件?
  • 为什么TIdSSLIOHandlerSocketOpenSSL.OnStatusInfoTIdSSLIOHandlerSocketOpenSSL.OnStatusInfoEx事件只在第二次连接尝试中触发?

我错过了什么吗?

xe55xuns

xe55xuns1#

您不应该使用事件来完成您正在尝试的操作,因为Indy不是事件驱动的。事件仅用于提供信息,而不是用于流控制。如果TLS握手失败,将相应地引发异常。捕获异常,关闭TCP连接,然后根据需要重试。
至于你试图模拟TLS失败:

  • 如果您在非tls或显式tls SMTP端口上使用utUseImplicitTLS,则客户端将在建立TCP连接后立即发送TLS握手,然后当它将服务器的未加密SMTP问候误解为TLS握手响应时,TLS握手失败。
  • 如果在隐式tls端口上使用utUseExplicitTLS,则客户端将在建立TCP连接后超时(或死锁,如果不使用超时),因为它将等待服务器从未发送的未加密SMTP问候,因为服务器正在等待客户端从未发送的TLS握手。

关于现有的各种活动:

  • OnTLSNotAvailable在以下情况下触发:
  • UseTLSutUseRequireTLS 1,并且
  • UseEhloTrue,并且
  • 当客户端发送EHLO命令以了解服务器的功能时,SMTP服务器不会通告对STARTTLS的支持。

如果事件处理程序将VContinue参数设置为False,则会引发EIdTLSClientTLSNotAvailable异常,否则SMTP会话将继续不加密。默认值为True
一曰:在客户端,utUseRequireTLS类似于utUseExplicitTLS,但服务器拒绝使用TLS是不可接受的。而utUseExplicitTLS的TLS是可选的。

  • OnTLSHandShakeFailed在以下情况下被触发:
  • UseTLSutUseImplicitTLSutUseExplicitTLS(不是utUseRequireTLS),并且
  • SSLIOHandler在TLS握手期间引发异常。

如果事件处理程序将VContinue参数设置为False,则会引发EIdTLSClientTLSHandShakeFailed异常,否则SMTP会话将继续不加密。默认值为False
注意事项:在这种情况下,如果绕过异常,那么SMTP会话在技术上将处于 undefined behavior 领域,因为套接字数据的状态将是未知的(异常是在数据包中间引发的吗?在数据包之间?还有更多的数据包仍在飞行中?等等)。与其他事件不同,套接字数据处于良好定义的状态。

  • OnTLSNegCmdFailed在以下情况下被触发:
  • UseTLSutUseExplicitTLS(不是utUseRequireTLS),并且
  • 在TLS握手开始之前,服务器向STARTTLS命令发送失败响应。

如果事件处理程序将VContinue参数设置为False,则会引发EIdTLSClientTLSNegCmdFailed异常,否则SMTP会话将继续不加密。默认值为False

  • OnFailedEHLO在以下情况下被触发:
  • UseEhloTrue,并且
  • 服务器向EHLO命令发送失败响应。

如果事件处理程序将VContinue参数设置为False,则TCP连接将关闭并引发EIdSMTPReplyError异常,否则SMTP会话将继续,而不知道服务器的功能。默认值为True

  • OnStatus用于一些通用组件级操作,如解析主机名的IP地址、连接到TCP端口、编码电子邮件等。
  • OnStatusInfo/ExSSLIOHandler触发,以在TLS会话期间从OpenSSL库提供状态更新。有关提供哪种状态值的信息,请参阅OpenSSL的文档:

https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_info_callback.html

相关问题