【问题标题】:sslv3 alert handshake failure Delphisslv3 警报握手失败 Delphi
【发布时间】:2018-12-07 13:49:49
【问题描述】:
  • 德尔福 10 西雅图
  • OpenSSL 1.0.0.10 但与更新的库相同。

以下代码已经运行了大约两年,但最近我们遇到了错误:

14094410:SSL3_read_bytes:sslv3 警报握手失败

已使用wireshark 确认正在使用TLSv1.2。如果需要,可以提供捕获文件。

 function GetAddress(ID_ID : Integer; Rijksregister : String) : Boolean;
var

  gp : GetPerson;
  Cor : CorrelationType;
  P : RrSimplePersonService_v02PortType;
  Resp : GetPersonResponse;
  FHTTPRio: THTTPRio;
  FReqResp : TWisaHTTPReqResp;
  FSSLIOHandler: TIdSSLIOHandlerSocketOpenSSL;
  Adr : PersonLegalAddressType;
  CERTPath : String;
  i, j : integer;
begin
  CERTPath := IncludeTrailingPathDelimiter(ExtractFilePath(Paramstr(0)));
  Result := false;
  // declarations
  Cor := CorrelationType.Create;
  Cor.requestorId := '01234567890';
  Cor.requestorName := 'WisaMockupService';
  Cor.applicationId := 'WISA';
  Cor.correlationId := getGUID;
  gp := getPerson.Create;
  gp.identifier := Rijksregister;
  gp.correlation := Cor;
  // actual call
  CoInitialize(nil);
  fHTTPRio:=THTTPRio.Create(Self);
  fHTTPRio.URL:=fURL;
  fHTTPRio.Converter.Options := fHTTPRio.Converter.Options + [soSendMultiRefObj, soTryAllSchema, soRootRefNodesToBody, soCacheMimeResponse, soUTF8EncodeXML, soSOAP12];
  fHTTPRio.OnBeforeExecute := IH7BeforeExecute;
  fHTTPRio.OnAfterExecute := IH7AfterExecute;
  FReqResp := TWisaHTTPReqResp.Create(self);
  FReqResp.URL := fURL;
  FReqResp.InvokeOptions := FReqResp.InvokeOptions + [soNoSOAPActionHeader];
  FReqResp.ConnectTimeout := 60000;
  FReqResp.ReceiveTimeout := 60000;
  FReqResp.SendTimeout := 60000;
  FReqResp.WebNodeOptions:= FReqResp.WebNodeOptions+[wnoSOAP12];
  fHTTPRio.HTTPwebNode := FReqResp;
  fHTTPRio.HTTPwebNode.UserName := fUser;
  fHTTPRio.HTTPwebNode.Password := fPaswoord;
  fHTTPRio.HTTPwebNode.OnBeforePost := BeforePost;
  FSSLIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(self);
  FSSLIOHandler.SSLOptions.Method := sslvTLSv1_2;
  FSSLIOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2,sslvTLSv1_1,sslvTLSv1];
  FSSLIOHandler.SSLOptions.CipherList := 'ALL';
  FSSLIOHandler.SSLOptions.RootCertFile := CERTPath + 'CACert.crt';
  FSSLIOHandler.SSLOptions.KeyFile := CERTPath + 'privateKey.key';
  FSSLIOHandler.SSLOptions.CertFile := CERTPath + 'certificate.crt';
  FSSLIOHandler.SSLOptions.Mode := sslmUnassigned;
  FSSLIOHandler.SSLOptions.VerifyMode := [];
  FSSLIOHandler.SSLOptions.VerifyDepth := 3;
  FSSLIOHandler.OnGetPassword := getPassword;
  FSSLIOHandler.UseNagle := true;
  FSSLIOHandler.ReadTimeout := 60000;
  FSSLIOHandler.ConnectTimeout := 60000;
  FSSLIOHandler.OnStatusInfoEx := SSLStatusInfoEx;
  FSSLIOHandler.OnVerifyPeer := VerifyPeer;
  FReqResp.IOHandler := FSSLIOHandler;
  // actual call
  P := (fHTTPRio as RrSimplePersonService_v02PortType);
  Try
    Resp := P.GetPerson(gp);
  Except
    on e : exception do
      begin
      Showerror(ID_ID, e.message + ' ' + format(rsRijksregister2,
        [Rijksregister]), '', '');
      exit;
      end;
  End;

  if not Assigned(Resp) then
    exit;
  # do something with Response

  # end
  Result := true;
end;


procedure IH7BeforeExecute(const MethodName: string;
  SOAPRequest: TStream);
var
  S : TStringStream;
  MyStringList: TStringList;
  CreateTime, ExpiryTime : TDateTime;
begin
  MyStringList := TStringList.Create;
  try
    Inherited;
    CreateTime := Now;
    ExpiryTime := IncSecond(CreateTime,600);
    SOAPRequest.Position := 0;
    MyStringList.LoadFromStream(SOAPRequest);
    MyStringList.Text := StringReplace(MyStringList.Text, '<soap-env:body>', Format(SoapHeader,[getTSToken, TimeToString(CreateTime), TimeToString(ExpiryTime), getToken, fGebruiker, fPaswoord]) + '<SOAP-ENV:Body>', [RfIgnoreCase]);
    MyStringList.Text := StringReplace(MyStringList.Text, '</GetPerson>', '</ws:GetPerson>', [RfIgnoreCase]);
    MyStringList.Text := StringReplace(MyStringList.Text, 'SOAP-ENV:', 'SOAP:', [RfReplaceAll, RfIgnoreCase]);
    MyStringList.Text := StringReplace(MyStringList.Text, 'SOAP-ENV=', 'SOAP=', [RfReplaceAll, RfIgnoreCase]);
    MyStringList.Text := StringReplace(MyStringList.Text, '<SOAP:Envelope xmlns:SOAP="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">', '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://person.ws.egov.apogado.com/SimplePersonSchema/v1_2/ws">', [RfReplaceAll, RfIgnoreCase]);
    MyStringList.Text := StringReplace(MyStringList.Text, 'SOAP:Body', 'soap:Body', [RfReplaceAll]);
    MyStringList.Text := StringReplace(MyStringList.Text, '<GetPerson xmlns="http://person.ws.egov.apogado.com/SimplePersonSchema/v1_2/ws">', '<ws:GetPerson>', [RfReplaceAll]);
    MyStringList.Text := StringReplace(MyStringList.Text, '<transaction xmlns="" xsi:nil="true"/>', '', [RfReplaceAll]);
    MyStringList.Text := StringReplace(MyStringList.Text, '</SOAP:Envelope>', '</soap:Envelope>', [RfReplaceAll]);
    MyStringList.Text := StringReplace(MyStringList.Text, '<identifier xmlns="urn:oslo:names:specification:schema:xsd:CommonBasicComponents-1"><Identifier xmlns="http://www.w3.org/ns/corevocabulary/BasicComponents">', '<identifier>', [RfReplaceAll]);
    MyStringList.Text := StringReplace(MyStringList.Text, '</Identifier>', '', [RfReplaceAll]);
    MyStringList.Text := StringReplace(MyStringList.Text, 'SOAP:Header', 'soap:Header', [RfReplaceAll]);
    MyStringList.Text := StringReplace(MyStringList.Text, 'SOAP:mustUnderstand="true"', 'soap:mustUnderstand="true"', [RfReplaceAll]);
    SOAPRequest.Position := 0;
    SOAPRequest.Size:=0;
    MyStringList.SaveToStream(SOAPRequest);
  finally
    MyStringList.Free;
  end;
  S:=TStringStream.Create('');
  try
    S.CopyFrom(SOAPRequest,0);
    SOAPRequest.Position:=0;
    // eventueel loggen van request
    //Log('HTTPRIO Verstuurd bericht:'+sLineBreak+S.DataString);
  finally
    S.Free;
  end;
end;

procedure IH7AfterExecute(const MethodName: string;
  SOAPResponse: TStream);
Var
  S : TStringStream;
begin
  S:=TStringStream.Create('');
  try
    S.CopyFrom(SOAPResponse,0);
    SOAPResponse.Position:=0;
  finally
    S.Free;
  end;
end;

Procedure GetPassword(var Password: string);
begin
  Password := ansistring('********');
end;

procedure SSLStatusInfoEx(ASender: TObject; const AsslSocket: PSSL;
const AWhere, Aret: Integer; const AType, AMsg: string);
begin
  SSL_set_tlsext_host_name(AsslSocket, fURL);
end;

procedure BeforePost(const HTTPReqResp: THTTPReqResp; Data: Pointer);
begin
 // nothing atm
end;

【问题讨论】:

  • "OpenSSL 1.0.0.10" - 没有这样的 OpenSSL 版本。请再检查一次。此外,"sslv3 alert handshake failure" 可能有很多不同的情况,例如 TLS 协议版本不匹配、没有共享密码、预期客户端证书但未给出或给出错误……也许你会发现更多在服务器端查看错误日志时的信息。另一种方法是使用wireshark进行数据包捕获和分析,以查看问题发生在哪个阶段(即当尝试就密码达成一致时,作为对客户端证书的反应......)。
  • 1.0.0.10 等于 1.0.0j
  • 如果这真的是 1.0.0j 则 TLS 1.2 无法工作,因为 TLS 1.2 仅在 OpenSSL 1.0.1 之后才被支持。但是您声明“已使用wireshark 确认正在使用TLSv1.2”。因此,要么 OpenSSL 版本不是宣传的版本,要么关于使用 TLSv1.2 的声明不正确。
  • 抓包:link
  • 这是一个非常奇怪的捕获 - 或者更好的是仅显示部分捕获的图像。奇怪的是,您突出显示了一条包含 "...sslv3 alert handshake failure..." 的消息。鉴于 TLS 警报只是一个数字而不是文本,并且文本消息的转换是由 OpenSSL 在内部完成的,您所显示的不是受问题影响的 TLS 连接,而只是一些用于转发错误的普通 TCP 连接消息作为文本。如果您希望我仔细查看它,请提供实际的 pcap 文件而不是图像。

标签: delphi ssl openssl delphi-10-seattle


【解决方案1】:

从 pcap 可以看出,初始成功的 TLS 握手已经完成,应用程序数据也从客户端传输到服务器,然后服务器启动新的握手,然后服务器发送警报。成功的初始握手意味着 TLS 协议版本、密码和服务器证书都不是问题。

虽然无法查看应用程序数据的详细信息,但由于第二次握手和警报已加密,因此记录序列表明:

  1. 在初始 TLS 握手成功后,对需要使用客户端证书进行身份验证的资源完成 HTTP 请求(即应用程序数据)。
  2. 服务器因此触发重新协商。在第二次 TLS 握手中,服务器将请求此证书。
  3. 服务器不喜欢客户端发送的证书或客户端没有发送证书。因此,服务器会通过警告消息中止连接。

鉴于它以前有效但现在失败了,我建议其中之一是问题的原因:

  • 现有证书可能已过期或被吊销。
  • 对服务器的更改会导致服务器不再接受证书,例如因为 CA 不再受信任。
  • 证书在客户端被替换。但是新证书不是服务器期望获得的或设置错误(如缺少链证书)。

【讨论】:

  • 感谢您的明确解释。客户端没有任何变化,因此可以排除选项 3。证书有效期至 2016 年,因此不会过期。可以撤销。我们不管理服务器端,因此需要联系他们来解决这个问题。会回来汇报的。再次感谢。
  • * 有效期至 2026 年,而非 2016 年。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
  • 2016-07-03
  • 2015-12-06
  • 1970-01-01
  • 2021-02-20
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多