Jump to content
Alberto Paganini

tlsv1 alert protocol version

Recommended Posts

Hello,

 

I have a problem with a Win32 application using Indy. All of a sudden it throws me the following error message:
"Error connecting with SSL. error 1409442E:SSL routine:ssl3_read_bytes:tlsv1 alert protocol version"

 

In the beginning, I supposed it had something to do with an obsolete version I manage in my source. 
The following is the only place in my source where I set the SSL version and it supports the version 1.2

 

function TConnectionClass.GetToken: Boolean;
var
  LJSONObject: TJSONObject;
  LJSONValue: TJSONValue;
  {$IFDEF VER230}
  LJSONPair: TJSONPair;
  {$ENDIF}
  LJSONToken: TJSONValue;
  IdHTTP: TIdHTTP;
  IdSSL: TIdSSLIOHandlerSocketOpenSSL;
  IdLogFile: TIdLogFile;
  sList: TStringList;
begin
  Result := False;
  FToken := '';

  IdHTTP := TIdHTTP.Create(nil);
  try
    IdHTTP.HTTPOptions := IdHTTP.HTTPOptions + [hoForceEncodeParams];
    IdHTTP.HandleRedirects := True;

    IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    IdSSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    IdHTTP.IOHandler := IdSSL;

    IdLogFile := TIdLogFile.Create(IdHTTP);
    IdLogFile.Filename := 'c:\' + ChangeFileExt(ExtractFileName(ParamStr(0)), '.log');
    IdLogFile.Active := True;
    IdHTTP.Intercept := IdLogFile;

    IdHTTP.Request.Accept := 'application/json';
    IdHTTP.Request.CustomHeaders.Values['X-Application'] := cBetfair_AppKey;
    IdHTTP.Request.ContentType := 'application/x-www-form-urlencoded';

    sList := TStringList.Create;
    try
      sList.Add('username=' + FUserID);
      sList.Add('password=' + FPassword);

      LJSONValue := TJSONObject.ParseJSONValue(IdHTTP.Post(URL_LOGIN, sList));
      try
        if LJSONValue is TJSONObject then
        begin
          LJSONObject := TJSONObject(LJSONValue);
          {$IFDEF VER230}
          LJSONPair := LJSONObject.Get('token');
          if LJSONPair <> nil then
            LJSONToken := LJSONPair.JsonValue
          else
            LJSONToken := nil;
          {$ELSE}
          LJSONToken := LJSONObject.Values['token'];
          {$ENDIF}
          if LJSONToken <> nil then
            FToken := LJSONToken.Value;
        end;
      finally
        LJSONValue.Free;
      end;
    finally
      sList.Free;
    end;
  finally
    IdHTTP.Free;
  end;

  Result := (FToken <> '');
end;


I also tried to amend the options into

IdSSL.SSLOptions.SSLVersions := [sslvTLSv1_2]; 

but the error is still the same

 

Then I updated the SSL .dll files in my system32 folder by downloading the latest version of libeay32.dll and ssleay32.dll from here https://indy.fulgan.com/SSL/ and replace the old files with the new ones. 
I have double-checked and now the .dll have Version file 1.0.2.21 and Version 1.0.2u

 

Despite these attempts, the application still throws me the same exception.

Is there anything else I should change?

 

Many thanks

Alberto

Share this post


Link to post
2 hours ago, Alberto Paganini said:

I have a problem with a Win32 application using Indy. All of a sudden it throws me the following error message:

"Error connecting with SSL. error 1409442E:SSL routine:ssl3_read_bytes:tlsv1 alert protocol version"

Which version of Delphi are you using?  Which version of Indy?

Quote

The following is the only place in my source where I set the SSL version and it supports the version 1.2

The code looks fine, so the issue has to be with the OpenSSL DLLs themselves,

Quote

I also tried to amend the options into


IdSSL.SSLOptions.SSLVersions := [sslvTLSv1_2]; 

but the error is still the same

Do you know what version of TLS the server requires?  Does it even support TLS v1.0..v1.2 nowadays?  Maybe it requires TLS v1.3 instead?  If so, you won't be able to use TIdSSLIOHandlerSocketOpenSSL for TLS v1.3, you will have to use this new SSLIOHandler instead (work in progress), which uses OpenSSL 1.1.x instead of 1.0.2.

Quote

Then I updated the SSL .dll files in my system32 folder

They don't belong there.  Put them in your application's folder instead.

Quote

by downloading the latest version of libeay32.dll and ssleay32.dll from here https://indy.fulgan.com/SSL/

Just FYI: https://www.indyproject.org/2020/06/16/openssl-binaries-moved-to-github/

Quote

and replace the old files with the new ones. 

Do you know what the old version was?

Quote

I have double-checked and now the .dll have Version file 1.0.2.21 and Version 1.0.2u

Are you SURE about that?  At runtime, what does Indy's OpenSSLVersion() function in the IdSSLOpenSSL unit report after OpenSSL has been loaded?  How about the IsOpenSSL_TLSv(1_0|1_1|1_2)_Available() functions in the IdSSLOpenSSLHeaders unit?

Quote

Despite these attempts, the application still throws me the same exception.

Have you tried looking at the TLS handshake in a packet sniffer, such as Wireshark?  What TLS version is your app claiming to use?

Edited by Remy Lebeau
  • Thanks 1

Share this post


Link to post

@Remy Lebeau

Quote

Do you know what version of TLS the server requires?  Does it even support TLS v1.0..v1.2 nowadays?  

Yes, this is the issue. I have just found out from the provider that "From 1st December only TLS 1.2 and above will be supported".

I renamed libeay32.dll and ssleay32.dll in the system32 folder, downloaded the two .DLLs from Github, placed them in the application folder but the error is still the same.

 

Quote

 

I have double-checked and now the .dll have Version file 1.0.2.21 and Version 1.0.2u

Are you SURE about that?  At runtime, what does Indy's OpenSSLVersion() function in the IdSSLOpenSSL unit report after OpenSSL has been loaded? 

 

The version I have reported is the one found in the properties of the .DLL files. 

However, the OpenSSLVersion function reports OpenSSL 1.0.0d 8 Feb 2011, and that explains why the .exe is not working any longer.

 

Does it mean my application uses other SSL .DLLs on my hard disk? (yes, I have a few installed by other third-party software. Each of them resides in the relevant application folder)

How can I tell my application that the correct .DLL resides in the same folder of the application itself? I don't want to delete the other .DLLs in order not to stop the other applications to work.

 

Many thanks.

Alberto

Share this post


Link to post

It seems I am making progress with this.

 

I have amended the class in a way the application loads the .DLLs residing in the application folder. This is achieved with IdSSLOpenSSLHeaders.IdOpenSSLSetLibPath(). (Thanks to Remi for this post https://stackoverflow.com/questions/13269169/how-to-use-a-dll-outside-of-the-system-path)

IdSSLOpenSSL.OpenSSLVersion; confirms now "OpenSSL 1.0.2q  20 Nov 2018" is loaded and this collides with the .DLLs version in the application folder.

 

As far as I can see from the https://www.openssl.org/news/openssl-1.0.2-notes.html the OpenSSL 1.0.2 supports TLS 1.2 for a long time (Jan 2015). Despite that my application still throws "tlsv1 alert protocol version"

Is there anything else I should be aware of ?

 

The amended source code is here above if anybody may be interested.

 

Many thanks

Alberto

function TConnectionClass.GetToken: Boolean;
var
  LJSONObject: TJSONObject;
  LJSONValue: TJSONValue;
  {$IFDEF VER230}
  LJSONPair: TJSONPair;
  {$ENDIF}
  LJSONToken: TJSONValue;
  IdHTTP: TIdHTTP;
  IdSSL: TIdSSLIOHandlerSocketOpenSSL;
  IdLogFile: TIdLogFile;
  sList: TStringList;
  Path:string;
  OpenSSLVersion:string;
begin

begin
  Result := False;
  FToken := '';

  Path:=ExtractFilePath(ParamStr(0));
  IdSSLOpenSSLHeaders.IdOpenSSLSetLibPath(Path);
  OpenSSLVersion:= IdSSLOpenSSL.OpenSSLVersion;
  IdHTTP := TIdHTTP.Create(nil);
  try
    IdHTTP.HTTPOptions := IdHTTP.HTTPOptions + [hoForceEncodeParams];
    IdHTTP.HandleRedirects := True;

    IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    IdSSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    IdHTTP.IOHandler := IdSSL;

    IdLogFile := TIdLogFile.Create(IdHTTP);
    IdLogFile.Filename := 'c:\' + ChangeFileExt(ExtractFileName(ParamStr(0)), '.log');
    IdLogFile.Active := True;
    IdHTTP.Intercept := IdLogFile;

    IdHTTP.Request.Accept := 'application/json';
    IdHTTP.Request.CustomHeaders.Values['X-Application'] := cBetfair_AppKey;
    IdHTTP.Request.ContentType := 'application/x-www-form-urlencoded';

    sList := TStringList.Create;
    try
      sList.Add('username=' + FUserID);
      sList.Add('password=' + FPassword);

      LJSONValue := TJSONObject.ParseJSONValue(IdHTTP.Post(URL_LOGIN, sList));
      try
        if LJSONValue is TJSONObject then
        begin
          LJSONObject := TJSONObject(LJSONValue);
          {$IFDEF VER230}
          LJSONPair := LJSONObject.Get('token');
          if LJSONPair <> nil then
            LJSONToken := LJSONPair.JsonValue
          else
            LJSONToken := nil;
          {$ELSE}
          LJSONToken := LJSONObject.Values['token'];
          {$ENDIF}
          if LJSONToken <> nil then
            FToken := LJSONToken.Value;
        end;
      finally
        LJSONValue.Free;
      end;
    finally
      sList.Free;
    end;
  finally
    IdHTTP.Free;
  end;

  Result := (FToken <> '');
end;

 

Edited by Alberto Paganini
Additional details

Share this post


Link to post

Ok, I have found out the final issues.

 

It turned out that Windows 7 does not enable TLS 1.2 by default. You have to do it manually by following this process https://support.site24x7.com/portal/en/kb/articles/how-to-check-if-tls-1-2-is-enabled

At this stage, the function above started working.

 

Next, I had to add one extra line in a third party code every time TIdSSLIOHandlerSocketOpenSSL is created.

The extra line is

sslIOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2]; 

 

After that, the application started working as before.

 

@Remy LebeauThank you for your help

 

Alberto

 

Share this post


Link to post
On 12/4/2020 at 1:09 PM, Alberto Paganini said:

Yes, this is the issue. I have just found out from the provider that "From 1st December only TLS 1.2 and above will be supported".

That is fine, Indy supports TLS 1.2.  Just make sure you are using an up-to-date version of Indy so that TLS 1.2 is being supported properly - ie, by enabling the SNI extension, which most TLS 1.2 servers require, etc.

Quote

The version I have reported is the one found in the properties of the .DLL files. 

However, the OpenSSLVersion function reports OpenSSL 1.0.0d 8 Feb 2011, and that explains why the .exe is not working any longer.

 

Does it mean my application uses other SSL .DLLs on my hard disk?

Yes, it does.  You can use a tool like SysInternals' Process Monitor or Process Explorer to see exactly which DLL files your app is actually using.  Or, using Indy's GetSSLLibHandle() and GetCryptLibHandle() functions in the IdSSLOpenSSLHeaders unit, you can pass those handles to the Win32 GetModuleFileName() function.

Quote

(yes, I have a few installed by other third-party software. Each of them resides in the relevant application folder)

Then they should not be colliding with each other, unless those paths are in the OS's global search path.

Quote

How can I tell my application that the correct .DLL resides in the same folder of the application itself?

That is the first place the OS should be looking for them.  But, if needed, you can use Indy's IdOpenSSLSetLibPath() function in the IdSSLOpenSSLHeaders unit to force it.

On 12/5/2020 at 4:40 AM, Alberto Paganini said:

IdSSLOpenSSL.OpenSSLVersion; confirms now "OpenSSL 1.0.2q  20 Nov 2018" is loaded and this collides with the .DLLs version in the application folder.

You said earlier that you downloaded DLLs for 1.0.2u, you should be using those instead.

Quote

The amended source code is here above if anybody may be interested.

The IdOpenSSLSetLibPath() function should be called only 1 time, preferably at program startup.

On 12/5/2020 at 10:01 AM, Alberto Paganini said:

It turned out that Windows 7 does not enable TLS 1.2 by default. You have to do it manually by following this process https://support.site24x7.com/portal/en/kb/articles/how-to-check-if-tls-1-2-is-enabled

That has no effect whatsoever on OpenSSL.  That only affects Microsoft's own implementation of TLS, such as in the WinInet and WinHTTP APIs.  Which OpenSSL does not use (and neither does Indy).

Quote

Next, I had to add one extra line in a third party code every time TIdSSLIOHandlerSocketOpenSSL is created.

The extra line is


sslIOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2]; 

Your previous code was just fine.  The above line enables ONLY TLS 1.2.  Not all servers have migrated to TLS 1.2 solely.  Most still support at least TLS 1.1, and maybe TLS 1.0.  So you should leave all three enabled.  Unless you know for a fact that the target server supports only TLS 1.2.

Edited by Remy Lebeau

Share this post


Link to post

Remy i'm on c++builder 6 with Indy 10 (changelog says 30 juil. 2009) and indeed https does not work, throwing a tlsv1 exception.

Can i use my indy version with the new protocol / dll's?

Otherwise can i update indy on bcb6 to get https going again?

 

Thanks.

Share this post


Link to post
22 hours ago, JeanCremers said:

Remy i'm on c++builder 6 with Indy 10 (changelog says 30 juil. 2009) and indeed https does not work, throwing a tlsv1 exception.

Can i use my indy version with the new protocol / dll's?

Otherwise can i update indy on bcb6 to get https going again?

You need to upgrade to the latest Indy, yes.  Indy 10 still supports Delphi/C++Builder 6.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×