Alberto Paganini 3 Posted December 4, 2020 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
Remy Lebeau 1392 Posted December 4, 2020 (edited) 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 December 4, 2020 by Remy Lebeau 1 Share this post Link to post
Alberto Paganini 3 Posted December 4, 2020 @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
Alberto Paganini 3 Posted December 5, 2020 (edited) 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 December 5, 2020 by Alberto Paganini Additional details Share this post Link to post
Alberto Paganini 3 Posted December 5, 2020 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
Remy Lebeau 1392 Posted December 6, 2020 (edited) 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 December 6, 2020 by Remy Lebeau Share this post Link to post
JeanCremers 1 Posted February 22, 2021 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
Remy Lebeau 1392 Posted February 23, 2021 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. 1 Share this post Link to post