-1
  • Delphi 10 seattle
  • OpenSSL 1.0.0.10 but same result with more recent libraries.

the following code has been working for about two years, but lately we are getting an error:

14094410:SSL3_read_bytes:sslv3 alert handshake failure

Have used wireshark to confirm TLSv1.2 is being used. can provide capture file if needed.

 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;
Y. Biscompte
  • 21
  • 1
  • 6
  • *"OpenSSL 1.0.0.10"* - there is no such OpenSSL version. Please check again. Also *"sslv3 alert handshake failure"* can be lots of different things, like mismatch of TLS protocol version, no shared ciphers, client certificate expected but not given or wrong given ... Maybe you'll find more information when looking at error logs at the server side. Another way would be to do a packet capture and analyze with wireshark to see at which stage the problem occurs (i.e. when trying to agree on cipher, as reaction to client certificate ...). – Steffen Ullrich Dec 07 '18 at 14:16
  • 1
    1.0.0.10 equals 1.0.0j – Y. Biscompte Dec 07 '18 at 14:23
  • 1
    If this is really 1.0.0j then TLS 1.2 can not work since TLS 1.2 is only supported since OpenSSL 1.0.1. But you state *"Have used wireshark to confirm TLSv1.2 is being used"*. Thus, either the OpenSSL version is not the advertised one or the statement about the use of TLSv1.2 is not true. – Steffen Ullrich Dec 07 '18 at 14:29
  • packet capture : [link](https://imgur.com/dRxotac) – Y. Biscompte Dec 07 '18 at 14:43
  • This is a very strange capture - or better only an image which shows part of the capture. What is strange is that you highlight a message which includes the *"...sslv3 alert handshake failure..."* in plain. Given that a TLS alert is just a number and not a text and the translation to a text message is done by OpenSSL internally what you show is not the TLS connection affected by the problem but just some plain TCP connection which is used to forward the error message as text. If you want me to have a closer look at it please provide the actual pcap file and not an image. – Steffen Ullrich Dec 07 '18 at 14:55
  • actual capture: [link](https://drive.google.com/open?id=1pClgwqMKUdilXkubDMMuerKaOPaUeAcw) – Y. Biscompte Dec 07 '18 at 15:10

1 Answers1

1

From the pcap it can be seen that an initial successful TLS handshake is done and also application data are transferred from the client to the server and then a new handshake is initiated by the server followed with an alert send by the server. The successful initial handshake means that neither TLS protocol version, nor cipher, nor server certificate are the problem.

While it is impossible to look at the details of the application data, the second handshake and the alert since they are encrypted the sequence of records suggests that:

  1. After the successful initial TLS handshake a HTTP request (i.e. application data) is done for a resource which requires authentication with a client certificate.
  2. The server therefore triggers a renegotiation. In the second TLS handshake the server will request this certificate.
  3. The server does not like the certificate send by the client or the client does not send a certificate. The server therefore aborts the connection with an alert message.

Given that it worked before but fails now I suggest that one of these is the cause of the problem:

  • The existing certificate might be expired or revoked.
  • Changes to the server result in the server no longer accepting the certificate, for example because the CA is no longer trusted.
  • The certificate was replaced on the client side. But the new certificate is not what the server expects to get or is wrongly setup (like missing a chain certificate).
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • thanks for the clear explanation. Nothing has changed on the client side so option 3 can be ruled out. Certificate is valid until 2016 thus not expired. Could be revoked tho. We do not manage the server side so will need to contact them to sort this out. Will report back. Thanks again. – Y. Biscompte Dec 07 '18 at 15:56
  • * valid until 2026, not 2016. – Y. Biscompte Dec 07 '18 at 16:02