SSL error 1409442E downloading file over HTTPS with TIdHTTP [duplicate] - delphi

This question already has an answer here:
How can we connect with a website? Getting SSL error 1409442E
(1 answer)
Closed 2 years ago.
I'm using Delphi 10.3.3. The code below used to work but now I'm getting an error when trying to download a file over HTTPS:
Error connecting with SSL error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version'
var
ms : tmemorystream;
ssl : TIdSSLIOHandlerSocketOpenSSL;
source,dest : string;
begin
source := 'https://www.myaddress.com/myfile.zip';
dest := 'c:\myfile.zip';
ms := TMemoryStream.Create;
try
if pos('https',source) > 0 then
begin
ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
idh.IOHandler := ssl;
end;
idhttp1.get(source,ms);
ms.savetofile(dest);
result := 'ok';
finally
ms.Free;
end;
end;

TIdSSLIOHandlerSocketOpenSSL uses only TLS v1.0 by default and the server is rejecting that. You must explicitly allow newer TLS versions:
ssl := TIdSSLIOHandlerSocketOpenSSL.Create();
ssl.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
idh.IOHandler := ssl;

Recent versions of Indy have https support built-in (so no need to create SSL IOHandler, Indy will take care of that automatically).
Also when dealing with files, it is better to use TFilestream instead of TMemoryStream because you you will get into trouble when trying to download files that don't fit into memory.
Here is a MRE for you:
program SO60578855;
{$APPTYPE CONSOLE}
{$R *.res}
uses
idHttp,
Classes,
System.SysUtils;
var
Http : TidHttp;
Fs : TFileStream;
begin
try
Fs := TFileStream.Create('c:\temp\100mb.bin', fmcreate);
Http := TidHttp.Create(nil);
try
Http.Get('https://speed.hetzner.de/100MB.bin', Fs);
finally
Http.Free;
Fs.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.

Related

Cannot connect to https site with Delphi Indy control

I try to use Delphi XE3 + Indy Control(TIdhttp) to connect to a https site, but the Get method raise an exception "Error connecting with SSL. Error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv 1 alert protocol version"
Below is my code:
var
IOHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
IdHTTP1.IOHandler := IOHandler;
IdHTTP1.Get(PostURL, Stream);
finally
IOHandler.Free;
end;
end;

Delphi EIdOSSLUnderlyingCryptoError Exception - SSL3_GET_RECORD Wrong Version Number

I tried using TRESTClient to connect to an HTTPS web service using TLS 1.2. But NO LUCK with sending multipart/form-data.
So now I am trying with Indy. I got this "Wrong Version Number" error.
I think there is nothing wrong with the code since it worked with HTTP.
Probably my Delphi is missing something. What should I install and how?
procedure TForm10.Button2Click(Sender: TObject);
var
HTTP: TIdHTTP;
RequestBody: TStream;
ResponseBody: string;
myssl: TIdSSLIOHandlerSocketOpenSSL;
Input: TIdMultipartFormDataStream;
begin
ResponseBody := '';
try
try
HTTP := TIdHTTP.Create;
try
Input := TIdMultipartFormDataStream.Create;
try
Input.Clear;
Input.AddFormField('Email', 'xx#xx.com.tr');
Input.AddFormField('Password', 'xx');
myssl := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
HTTP.IOHandler := myssl;
myssl.SSLOptions.Mode := sslmUnassigned;
myssl.SSLOptions.Method := sslvTLSv1_2;
myssl.SSLOptions.SSLVersions := [sslvTLSv1_2];
HTTP.HTTPOptions := [hoForceEncodeParams];
HTTP.Request.CustomHeaders.FoldLines := False;
ResponseBody := HTTP.Post('https://xxx.com.tr/api/Mobile/MobileLoginControl', Input);
finally
Input.Free;
end;
finally
HTTP.Free;
end;
finally
end;
except
ResponseBody := '"-20"';
end;
end;
The code is fine, though you are enabling only TLS 1.2 on the SSLIOHandler. Maybe the website in question doesn't support TLS 1.2? Try enabling TLS 1.0 and 1.1 as well:
myssl.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
And don't set the SSLOptions.Method at all. Setting the SSLVersions updates the Method and vice versa. So set one or the other, not both.

Error connecting with SSL using IdHttp Indy

I have a problem in IdHttp using Indy (Delphi).
I try to using IdHttp to post XML in web service SOAP, but dont work. Return "Error connecting with SSL." in IdSSLOpenSSL.Connect#1437 from indy.
My code is simple:
procedure TForm1.Button1Click(Sender: TObject);
var
vRequest : TStringStream;
s : String;
begin
vRequest := TStringStream.Create((Memo1.Lines.Text));
try
IdHTTP1.Host := edHost.Text;
IdHTTP1.Request.ContentLength := length(Memo1.Lines.Text);
IdHTTP1.Request.ContentType := edContentType.Text;
IdHTTP1.Request.CustomHeaders.Text := 'SOAPAction: "removed for safe"'#13#10;
IdHTTP1.request.CacheControl := 'no-cache';
IdHTTP1.Request.AcceptEncoding := edAccept.Text;
IdHTTP1.HTTPOptions := [hoKeepOrigProtocol];
IdHTTP1.ProtocolVersion := pv1_1;
Memo2.Clear;
try
s := IdHTTP1.post(Edit1.Text, vRequest);
Memo2.Lines.Text := s;
except
on e: EIdHTTPProtocolException do begin
Label1.Caption := e.Message;
MEMO2.LINES.TEXT := e.Message;
end;
on e:Exception do begin
Label1.Caption := e.Message;
MEMO2.LINES.TEXT := e.Message;
end;
end;
requestHeaders.Lines.Text := IdHTTP1.Request.RawHeaders.Text;
responseHeaders.Lines.Text := IdHTTP1.Response.RawHeaders.Text;
finally
vRequest.Free;
end;
end;
In exe folder contain libeay32.dll and ssleay32.dll. Any sugestion?
I Used delphi 5, but in delphi 7 is the same problem.
By default, the SSLVersions property of TIdSSLIOHandlerSockOpenSSL is set to enable only TLS 1.0 1. But many websites are starting to phase out TLS 1.0 and only accept TLS 1.1+. So try enabling TLS 1.1 and TLS 1.2 in the SSLVersions property and see if it helps.
1: there is an open ticket in Indy's issue tracker to also enable TLS 1.1 and TLS 1.2 by default.
On a side note, there are some further tweaks you should make to your code:
do not assign any values to TIdHTTP's Host or ContentLength properties. They are populated automatically by TIdHTTP.
if you set the AcceptEncoding property manually, make sure NOT to include deflate or gzip unless you have a Compressor assigned to TIdHTTP, otherwise it will fail to decode a compressed response. You really should not assign anything to AcceptEncoding unless you are prepared to handle custom encodings. The Compressor handles deflate/gzip and TIdHTTP will update AcceptEncoding accordingly if a Compressor is assigned and ready for use.
use the CustomHeaders.Values property to set individual headers, not the CustomHeaders.Text property.
you do not need to catch EIdHTTPProtocolException explicitly, since that exception handler is not doing anything extra that the more generic Exception handler is not doing.
the RawHeaders property is a TStringList descendant, so it is more efficient to use Lines.Assign(RawHeaders) instead of Lines.Text := RawHeaders.Text.
Try this:
procedure TForm1.Button1Click(Sender: TObject);
var
vRequest : TStringStream;
s : String;
begin
IdHTTP1.Request.ContentType := edContentType.Text;
IdHTTP1.Request.CustomHeaders.Values['SOAPAction'] := 'removed for safe';
IdHTTP1.Request.CacheControl := 'no-cache';
IdHTTP1.HTTPOptions := [hoKeepOrigProtocol];
IdHTTP1.ProtocolVersion := pv1_1;
Memo2.Clear;
try
vRequest := TStringStream.Create(Memo1.Lines.Text);
try
s := IdHTTP1.Post(Edit1.Text, vRequest);
finally
vRequest.Free;
end;
Memo2.Lines.Text := s;
except
on e: Exception do begin
Label1.Caption := e.Message;
Memo2.Lines.Text := e.Message;
end;
end;
RequestHeaders.Lines.Assign(IdHTTP1.Request.RawHeaders);
ResponseHeaders.Lines.Assign(IdHTTP1.Response.RawHeaders);
end;

Can't open Https TSL page with Delphi - Indy Error : SSL23_GET_SERVER_HELLO

I want to read an HTML page via HTTPS using Indy's TIdHTTP in Delphi XE5.
ssleay32.dll and libeay32.dll are in the main program folder.
I am getting an error: SSL23_GET_SERVER_HELLO. What can I do to fix this?
function get_page_text:string;
var
Response: String;
HTTPClient: TidHTTP;
const
url = 'https://www.lustundreiz.com/login';
begin
HTTPClient := TidHTTP.Create;
HTTPClient.AllowCookies := True;
HTTPClient.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
Response := HTTPClient.get(url);
HTTPClient.Free;
result := response;
end;
The default SSL/TLS version used by TIdSSLIOHandlerSocketOpenSSL when you don't specify a version is TLSv1, not SSLv23. So it is very unusual for you to be getting an SSL23 error.
Many modern web servers now require TLS 1.1 or higher, TLS extensions like SNI, etc. So consider enabling sslvTLSv1_1 and sslvTLSv1_2 in the TIdSSLIOHandlerSocketOpenSSL.SSLOptions.SSLVersions property, in addition to the default sslvTLSv1. And make sure you are using an up-to-date version of Indy and the OpenSSL DLLs to support those versions.
You should also wrap your code in a try..finally so you can Free the TIdHTTP object even if Get() raises an exception.
Try this:
function get_page_text:string;
var
HTTPClient: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
const
url = 'https://www.lustundreiz.com/login';
begin
HTTPClient := TIdHTTP.Create;
try
HTTPClient.AllowCookies := True;
// set other HTTP properties as needed...
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTPClient);
SSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
// set other SSL properties as needed...
HTTPClient.IOHandler := SSL;
Result := HTTPClient.Get(url);
finally
HTTPClient.Free;
end;
end;
Ok, after I updated from Delphi XE5 to Delphi XE10 the Code works well without any Errors.
Thanks to Remy for the Support.

Execute in delphi a curl code for connection to stripe payment

I try to connect me to my stripe payment test account with delphi.
The connect API is here:
Stripe connect API
Curl example:
curl https://api.stripe.com/v1/charges \
-u sk_test_CpkBxhx9gcmNYYQTZIXU43Bv:
I tried using Indy TIdHTTP component with TIdSSLIOHandlerSocketOpenSSL
and calling post with Tstringlist or TIdMultipartFormDataStream as parameter
but I receive always response: 401 - Unauthorized
Here my code:
var
Data: TIdMultipartFormDataStream;
https: TIdHTTP;
ssl: TIdSSLIOHandlerSocketOpenSSL;
begin
https := TIdHTTP.Create(self);
ssl := TIdSSLIOHandlerSocketOpenSSL.Create(Self);
https.IOHandler := ssl;
https.Request.BasicAuthentication := True;
Data := TIdMultipartFormDataStream.Create;
//Data.AddFormField('api_key', 'sk_test_CpkBxhx9gcmNYYQTZIXU43Bv');
Data.AddFormField('apikey', 'sk_test_CpkBxhx9gcmNYYQTZIXU43Bv');
https.Post('https://api.stripe.com/v1/charges', Data);
Memo1.lines.Add( https.ResponseText );
Data.Free;
end;
Any help or suggestion would bee very appreciated.
Thanks,
Peter
You must not use a form field to transfer the API key. Instead, set the Request.Username property. The password is empty, so Request.Passwort is unused. From the API docs on your linked page:
Authentication to the API occurs via HTTP Basic Auth. Provide your API
key as the basic auth username. You do not need to provide a password.
This example works with Indy 10.6.2 and OpenSSL libraries in the program folder:
program Project31229779;
{$APPTYPE CONSOLE}
uses
IdHTTP, SysUtils;
var
HTTP: TIdHTTP;
begin
HTTP := TIdHTTP.Create;
try
HTTP.Request.BasicAuthentication := True;
HTTP.Request.Username := 'sk_test_CpkBxhx9gcmNYYQTZIXU43Bv';
try
WriteLn(HTTP.Get('https://api.stripe.com/v1/charges'));
except
on E: EIdHTTPProtocolException do
begin
WriteLn(E.Message);
WriteLn(E.ErrorMessage);
end;
on E: Exception do
begin
WriteLn(E.Message);
end;
end;
finally
HTTP.Free;
end;
ReadLn;
end.
Note: you may also put the user name / password in the URL:
HTTP.Request.BasicAuthentication := True;
try
WriteLn(HTTP.Get('https://sk_test_CpkBxhx9gcmNYYQTZIXU43Bv:#api.stripe.com/v1/charges'));

Resources