sslv3警报握手失败Delphi

时间:2018-12-07 13:49:50

标签: delphi ssl openssl delphi-10-seattle

  • Delphi 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;

1 个答案:

答案 0 :(得分:1)

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

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

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

鉴于它以前曾经起作用,但现在却失败了,我建议其中一个是问题的原因:

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