0

I'm getting the error

REST request failed! Error connecting with SSL. error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

using the TREST components, here is the example code -- full unit code below
seems to be specific to the url link e.g. other https: calls work fine

function Getcall_UsingRest : String;
var
  fRstclnt1: TRESTClient;
  fRstrqst1: TRESTRequest;
  fRstrspns1: TRESTResponse;
begin
  result := '';
  try
    fRstclnt1:= TRESTClient.Create('https://au-api.basiq.io');
    fRstrqst1:= TRESTRequest.Create(nil);
    fRstrspns1:= TRESTResponse.Create(nil);
    try
      fRstrqst1.Client := fRstclnt1;
      fRstrqst1.Response := fRstrspns1;

      fRstrqst1.Execute;
      result := fRstrspns1.Content;
    finally
      fRstclnt1.Free;
      fRstrqst1.Free;
      fRstrspns1.Free;
    end;
  except
    on E:Exception do begin
      result := e.Message;
    end;
  end;
end;

I have been trying the following to try and fix but i haven't been able to get it to work

using TIdHTTP component i get the same error

function Getcall_UsingHTTP_WithSameIssue : String;
var
  fIdHTTP1: TIdHTTP;
  fIdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
  fresp: TMemoryStream;
  fMySL : TStringList;
begin
  result := '';
  try
    fIdHTTP1:= TIdHTTP.Create(nil);
    try
      fIdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(fIdHTTP1);
      fIdHTTP1.IOHandler := fIdSSLIOHandlerSocketOpenSSL1;

      fresp := TMemoryStream.Create;
      fMySL := TStringList.Create;
      try
        fIdHTTP1.Get('https://au-api.basiq.io', fresp);
        fresp.Position := 0;
        fMySL.LoadFromStream( fresp );
        result := fMySL.Text;
      finally
        fMySL.Free;
        fresp.Free;
      end;
    finally
      fIdHTTP1.Free;
    end;
  except
    on E:Exception do begin
      result := e.Message;
    end;
  end;
end;

there is a fix for this which is to put

procedure OnStatusInfoEx(ASender: TObject; const AsslSocket: PSSL;
  const AWhere, Aret: TIdC_INT; const AType, AMsg: String);
begin
  SSL_set_tlsext_host_name(AsslSocket, Request.Host);
end;

onto the fIdSSLIOHandlerSocketOpenSSL1.OnStatusInfoEx := OnStatusInfoEx;

the TIdSSLIOHandlerSocketOpenSSL component is buried deep in the TRESTClient and i haven't been able to find a way to see if i can apply the fix above to work on the TRESTClient

can someone help with how to get the TREST to be able to communicate


here is the full source code for the examples above

unit RestExample;

interface
uses
  System.Generics.Collections
, REST.Types
, REST.Client
, sysutils
, IdHTTP
, IdSSLOpenSSL
, IdSSLOpenSSLHeaders, IdCTypes
, system.Classes
;

function Getcall_UsingRest : String;
function Getcall_UsingHTTP_WithSameIssue : String;
function Getcall_UsingHTTP_WithFix : String;

type
  TCustomIdHTTP = class(TIdHTTP)
  public
    constructor Create(AOwner: TComponent);
  private
    procedure OnStatusInfoEx(ASender: TObject; const AsslSocket: PSSL; const AWhere, Aret: TIdC_INT; const AType, AMsg: String);
  end;

implementation


function Getcall_UsingRest : String;
var
  fRstclnt1: TRESTClient;
  fRstrqst1: TRESTRequest;
  fRstrspns1: TRESTResponse;
begin
  result := '';
  try
    fRstclnt1:= TRESTClient.Create('https://au-api.basiq.io');
    fRstrqst1:= TRESTRequest.Create(nil);
    fRstrspns1:= TRESTResponse.Create(nil);
    try
      fRstrqst1.Client := fRstclnt1;
      fRstrqst1.Response := fRstrspns1;

      fRstrqst1.Execute;
      result := fRstrspns1.Content;
    finally
      fRstclnt1.Free;
      fRstrqst1.Free;
      fRstrspns1.Free;
    end;
  except
    on E:Exception do begin
      result := e.Message;
    end;
  end;
end;

function Getcall_UsingHTTP_WithSameIssue : String;
var
  fIdHTTP1: TIdHTTP;
  fIdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
  fresp: TMemoryStream;
  fMySL : TStringList;
begin
  result := '';
  try
    fIdHTTP1:= TIdHTTP.Create(nil);
    try
      fIdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(fIdHTTP1);
      fIdHTTP1.IOHandler := fIdSSLIOHandlerSocketOpenSSL1;

      fresp := TMemoryStream.Create;
      fMySL := TStringList.Create;
      try
        fIdHTTP1.Get('https://au-api.basiq.io', fresp);
        fresp.Position := 0;
        fMySL.LoadFromStream( fresp );
        result := fMySL.Text;
      finally
        fMySL.Free;
        fresp.Free;
      end;
    finally
      fIdHTTP1.Free;
    end;
  except
    on E:Exception do begin
      result := e.Message;
    end;
  end;
end;

function Getcall_UsingHTTP_WithFix : String;
var
  fTCustomIdHTTP: TCustomIdHTTP;
  fresp: TMemoryStream;
  fMySL : TStringList;
begin
  result := '';
  try
    fTCustomIdHTTP:= TCustomIdHTTP.Create(nil);
    try
      fresp := TMemoryStream.Create;
      fMySL := TStringList.Create;
      try
        fTCustomIdHTTP.Get('https://au-api.basiq.io', fresp);
        fresp.Position := 0;
        fMySL.LoadFromStream( fresp );
        result := fMySL.Text;
      finally
        fMySL.Free;
        fresp.Free;
      end;
    finally
      fTCustomIdHTTP.Free;
    end;
  except
    on E:Exception do begin
      result := e.Message;
    end;
  end;

end;

{ TCustomIdHTTP }

constructor TCustomIdHTTP.Create(AOwner: TComponent);
begin
  IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  with IOHandler as TIdSSLIOHandlerSocketOpenSSL do begin
    OnStatusInfoEx := Self.OnStatusInfoEx;
  end;
  inherited Create(AOwner);
end;

procedure TCustomIdHTTP.OnStatusInfoEx(ASender: TObject; const AsslSocket: PSSL;
  const AWhere, Aret: TIdC_INT; const AType, AMsg: String);
begin
  SSL_set_tlsext_host_name(AsslSocket, Request.Host);
end;

end.
Dangas56
  • 849
  • 1
  • 8
  • 32
  • [Indy calls `SSL_set_tlsext_host_name()` internally](https://www.indyproject.org/2016/01/10/client-side-sni-support-added-to-tidssliohandlersocketopenssl/) when establishing an outbound TLS connection, and has for several years now, so if you still have to resort to calling `SSL_set_tlsext_host_name()` manually when using `TIdHTTP` then you are using an outdated version of Indy and need to update. – Remy Lebeau May 30 '19 at 07:11
  • we are using XE5 - i managed to get indy updated but the REST Components use delphi IPPeerAPI.pas code - getting access violations when calling the TRESTClient.Create('URL') – Dangas56 Jun 03 '19 at 08:20

0 Answers0