OpenSSL not working for iOS Simulator in Delphi DX
Using info at:
http://blog.marcocantu.com/blog/using_ssl_delphi_ios.html
http://docwiki.embarcadero.com/RADStudio/Seattle/en/OpenSSL
https://plus.google.com/100777187605111792758/posts/SPnHdXvTTNu
I can get it to work on devices, but not on the iOS simulator. Same URL works when I use a TWebbrowser.navigate, but not with INDY of course.. See below, and possibly offer suggestions on how to make HTTPS calls on the iOS simulator ! This worked before in earlier versions of Rad Studio ( XE4, XE5 ) but hasnt since XE7 if my memory has served me right.
I have these files in my usr/lib folder:
libcrypto.0.9.8.dylib
libssl.0.9.8.dylib
Here is my uses
uses
IdSSLOpenSSL,
{$IF Defined(IOS) and Defined(CPUARM)}
IdSSLOpenSSLHeaders_Static,
{$ELSE}
IdSSLOpenSSLHeaders,
{$ENDIF}
...
Here is my onCreate for the main form
procedure TmLoginForm.FormCreate(Sender: TObject);
var
t:string;
begin
IdOpenSSLSetLibPath('/usr/lib/');
...
Here is part of a function that I use, where on the last line an exception is thrown
function ParseGroups(OnlyUserCreated:boolean):integer;
var
IdHTTP :TIdHTTP;
HTML :String;
JSON_Groups :TJSONObject;
Group :uGroup;
begin
result:=0;
HTML:='';
IdHTTP:=TIdHTTP.Create(nil);
IdHTTP.HandleRedirects:=false;
try
HTML:=IdHTTP.Get(URL_Host+ACCESSTOKEN);
Error is: 'Could Not Load SSL Library'
ShowMessage(IdSSLOpenSSLHeaders.WhichFailedToLoad); shows a blank message
Update:
adding
IdSSLOpenSSLHeaders.Load;
after setting the path now causes the whichFailedToLoad say: 'Failed to Load /usr/lib/libcrypto.'
Use System.Net.HttpClient.THTTPClient instead of the Indy components.
var
http : THTTPClient;
html : string;
http := THTTPClient.Create;
try
html := http.Get( url ).ContentAsString();
...
finally
http.Free;
end;
It is a wrapper of the http function from the operating system. If the OS supports https, then this class will do also.
You can also follow this nifty blogpost http://delphiworlds.com/2016/03/building-openssl-dylibs-for-ios-simulator/
It worked just fine for me. I needed it, because my Soap client needs to connect via https, and I did not want to rewrite the soap libs.
Related
I use Delphi 10.1 Berlin and Indy 10.6.2, 32bit on a Windows Server 2012.
I implemented a server based on TIdHTTPServer. Works like a charm for many years.
Now my customer wants the traffic secured. SSL is an area I have little knowledge of.
There are several helpful pointers on the web that have helped me make CA certificate and key files with OpenSSL. And from several examples I've put together the code below, using TIdServerIOHandlerSSLOpenSSL.
The cert/key files are in the exe directory and so are the OpenSSL dlls ssleay32 and libeay32.
The server responds to http://localhost:8080 but there is no response when addressing it via https://localhost. It behaves as if the TIdServerIOHandlerSSLOpenSSL is not there at all. (The IOHandler does read the cert/key files and it complains when I remove the OpenSSL DLLs). It is as if I've forgotten to throw a switch somewhere.
The analysis of Windows Network Diagnostics (in IEdge) is 'The device or resource (localhost) is not set up to accept connections on port "https".'
I tried to log a message via the OnConnect event, but that stage is never reached with HTTPS.
I have run out of ideas, and can not find relevant suggestions on the web.
Here is my code (the components are all declared in code):
procedure TServerForm.FormCreate(Sender: TObject);
var
ServerSSLIOHandler: TIdServerIOHandlerSSLOpenSSL;
rootdir : string;
begin
inherited;
rootdir:=ExtractFilePath(Application.ExeName);
ServerSSLIOHandler:=TIdServerIOHandlerSSLOpenSSL.Create(self);
ServerSSLIOhandler.SSLOptions.RootCertFile:=rootdir+'ca.cert.pem';
ServerSSLIOhandler.SSLOptions.CertFile:=rootdir+'localhost.cert.pem';
ServerSSLIOhandler.SSLOptions.KeyFile:=rootdir+'localhost.key.pem';
ServerSSLIOhandler.SSLOptions.Method:=sslvSSLv23;
ServerSSLIOhandler.SSLOptions.Mode:=sslmServer;
ServerSSLIOhandler.OnGetPassword:=NIL;
ServerSSLIOhandler.OnVerifyPeer:=OnVerifyPeer;
HTTPServer:=TIdHTTPServer.Create(self);
HTTPServer.IOhandler:=ServerSSLIOHandler;
HTTPserver.Bindings.Add.Port:=443;
HTTPserver.Bindings.Add.Port:=8080;
HTTPServer.Active:=True;
HTTPServer.AutoStartSession:=True;
HTTPServer.SessionTimeOut:=1200000;
HTTPserver.OnQuerySSLPort:=OnQuerySSLPort;
HTTPServer.OnCommandGet:=HTTPServerCommandGet;
...
end;
procedure TServerForm.OnQuerySSLPort(APort: Word; var VUseSSL: Boolean);
// This will not be called when the request is a HTTPS request
// It facilitates the use of the server for testing via HTTP://localhost:8080 (i.e. without SSL)
begin
VUseSSL := (APort<>8080);
end;
function TServerForm.OnVerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
result:=AOk;
end;
Thank you. Remy's remark about OnConnect and his suggestion to use netstat did the trick. I.e. it lead me to discover that the problem was elsewhere. In the past I had to move away from port 80 because it became in use by a Windows service. From then on I specified a port number (8080) in an ini file and acted as follows.
Code:
prt:=parameters.ReadInteger('settings','port',80);
if prt<>HTTPserver.DefaultPort
then begin HTTPserver.Active:=false;
HTTPserver.Bindings.Clear;
HTTPserver.DefaultPort:=prt;
HTTPserver.Active:=true;
end;
Since this piece of code was still there, obviously only the specified port (8080) was active. netstat revealed that immediately.
Will you believe that I am very happy with your quick response!
I'm a new in mORMot.
I made a mormot server and FMX client.
It works on Win mode.
Next I changed destination to Android and get an error.
[DCC Fatal Error] SynCrtSock.pas(253): F2613 Unit 'Contnrs' not found (unit SynCrtSock;).
{$R *.fmx}
{$R *.LgXhdpiTb.fmx ANDROID}
function Client(const SQL: RawUTF8): RawUTF8;
var
Http: THttpClientSocket;
URI: AnsiString;
begin
if ParamCount<>0 then
URI := AnsiString(ParamStr(1))
else
URI := '192.168.1.20';
Http := OpenHttp(URI,'888');
if Http <> nil then
try
Http.Post('root',SQL,TEXT_CONTENT_TYPE);
result := Http.Content;
finally
Http.Free;
end
else
result := '';
end;
procedure TForm3.TMSFMXButton1Click(Sender: TObject);
begin
ds1.DataSet := JSONToClientDataSet(self,Client('select * from Lists'));
end;
It works good for Win but doesn't work for Android.
How to make demo for iOS and Android?
As stated by the documentation, current version of the main framework units target only Win32 / Win64 systems under Delphi, and (in a preliminary state) Windows or Linux under FPC. So you can run a Server on those platforms.
But you can write a Client on all Delphi supported platforms, by using some dedicated cross-platform client units, and generate some code to consume the server ORM and SOA content.
To write an OSX or Mobile client, using FMX for the UI, do not use regular SynCommons.pas mORMot.pas units, but the dedicated units as available in the CrossPlatform sub-folder.
The documentation is pretty detailed about it.
See also this sample and the associated generated client unit.
I am trying to accept file uploads in a Delphi 7 Webbroker CGI.
I'm using Shiv Kumar's TMsMultipartParser, but I have a problem with Chrome. I can't access the parsed data (surprisingly, Explorer works fine).
This is my code:
with TMsMultipartFormParser.Create do
begin
Parse(Request);
lsExternalID:=ContentFields.Values['external_id'];
if (lsExternalID='') then
raise Exception.Create('No external ID');
for i := 0 to Files.Count -1 do
begin
lsFileName:=files[i].FileName;
//Rename file using external ID (not included for simplicity)
Files[i].SaveToFile(lsFilename);
end;
Response.Content := 'OK';
free;
end;
As suggested here, I tried to use http://www.mrsoft.org/Delphi/MultipartParser.pas but I can't compile it. It uses a unit called UniversalUtils that I can't find anywhere.
I know this is a very obsolete technology. Almost all references to it have already disappeared from the web (believe me, I have searched). Buy any help would be deeply appreciated.
Thanks.
I finally solved my problem, thanks to #mrabat.
This project started in Delphi 5. It was later upgraded to Delphi 7 (it can't be upgraded further, because many parts can't support Unicode strings, we use ANSI).
We were using Shiv's TMsMultipartParser because Delphi 5 didn't have any parser included.
Delphi 7 has TMultipartContentParser in unit ReqMulti.pas, and it works perfectly.
For anyone that need an example, I'll post my working code:
with TMultipartContentParser.Create(Request) do
begin
lsExternalID:=ContentFields.Values['external_id'];
if (lsExternalID='') then
raise Exception.Create('No external ID');
for i := 0 to Request.Files.Count -1 do
begin
lsFileName:=Request.Files[i].FileName;
//Rename file using external ID (not included for simplicity)
TMemoryStream(Request.Files[i].Stream).SaveToFile(lsFilename);
end;
Response.Content := 'OK';
Free;
end;
I wrote something similar once here:
https://github.com/stijnsanders/xxm/blob/master/Delphi/common/xxmParams.pas#L159
but that may be tightly coupled with SplitHeaderValue that parses the header lines, and TStreamNozzle that throttles incoming data. (and TXxmReqPar... objects, and IXxmContext...)
(Of course you're warmly welcomed to accept file uploads with xxm...)
I'm trying to connect to google documents (following Marco Cantu's excellent REST example) but I am getting the following SSL errors:
1) If I use the SSL dlls from openssl-0.9.8i-i386-win32.zip I get the error:
"Could not load SSL library"
2) If I use the SSL dlls from indy_OpenSSL096m.zip I get the error:
"Error connecting with SSL"
3) If I use the SSL dlls from openssl-0.9.8h-i386-win32-Indy-IntraWebEdition.zip I get the error:
"Could not load SSl Library"
Now I've researched this and there are a lot of recommendations with dead links to dlls about, including links on stack overflow. I suspect I need to find the SSL dlls that are compatible with the version of INDY I am using.
My question is, does anyone know exactly which SSL dlls are compatible with Delphi 2006 & INDY 10.1.5?
I had the same problem even after I upgrading to INDY 10.2.3 and I tryed every different version of the “libeay32.dll” and “ssleay32.dll” files I could find ... Like Matt I always got one of the two errors: "Could not load SSL library" or the "Error connecting with SSL" with something like "error:00000006:lib(0):func(0):EVP lib" ...
I was very happy when I change the TidSSLioHandlerSocketOpenSSL.SSLOptions.Method to sslvSSLv23 and everything started working.
A bit more research and I quickly understood anytime I got the error "Could not load SSL library" I was using the wrong version of the DLL files and anytime I got the "Error connecting with SSL" with something like "error:00000006:lib(0):func(0):EVP lib" I was using the wrong SSLOptions.Method value.
Other Info: I'm using Delphi 2006, INDY 10.2.3 and I'm runnin on WinXP Pro
This caused me so much pain, I hope this post will save someone some time.
You could resort to some trial and error using downloads from the Fulgan site.
You might want to think about updating your copy of Indy and using the most recent OpenSSL DLLs.
FWIW, since I have spent a lot of time getting this https thing to work, here are the results of my successful efforts.
1- Delphi 7
2- indy9.0.19_d7.exe
3- IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLSv1; or,
IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLSv23; or,
IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLSv3;
I tried indy10.0.76_d7.exe and indy10.1.5_d7.exe under Delphi 7 and I cannot get them to install properly, let alone get HTTPS to work. I get the infamous message "Unit IdSysWin32 was compiled with a different version of IdException.EIdException." I searched for a solution to that problem on the web and couldn't find one - loads of others had the same message.
A useful site for testing https is https://msp.f-secure.com/web-test/common/test.html
Here is my source:
procedure TForm1.ButtonHTTPSClick(Sender: TObject);
var
IdHTTP1: TIdHTTP;
ParamStringList: TStringList;
s1: String;
MemoryStream1: TMemoryStream;
IdSSLIOHandlerSocket1: TIdSSLIOHandlerSocket;
begin // ssl works fine must have Indy version indy9.0.19_d7.exe and must use option sslvSSLv23
Screen.Cursor := crHourGlass;
IdHTTP1 := TIdHTTP.Create(nil);
IdSSLIOHandlerSocket1 := TIdSSLIOHandlerSocket.Create(nil);
IdHTTP1.IOHandler := IdSSLIOHandlerSocket1;
// IdSSLIOHandlerSocket1.SSLOptions.Method := sslvTLSv1; // sslvSSLv1 works fine
IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv3; // sslvSSLv3 works fine
// IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv23; // sslvSSLv23 works fine
// IdSSLIOHandlerSocket1.SSLOptions.Method := sslvSSLv2; sslvSSLv2 does not work
IdSSLIOHandlerSocket1.SSLOptions.Mode := sslmUnassigned;
IdSSLIOHandlerSocket1.SSLOptions.VerifyMode := [];
IdSSLIOHandlerSocket1.SSLOptions.VerifyDepth := 0;
ParamStringList := TStringList.Create;
MemoryStream1 := TMemoryStream.Create;
s1 := IdHTTP1.Post('https://msp.f-secure.com/web-test/common/test.html', ParamStringList);
MemoryStream1.Write(s1[1], Length(s1));
MemoryStream1.Position := 0;
MemoryStream1.SaveToFile('c:\temp\MemoryStream1.txt');
Memo1.Lines.Clear;
Memo1.Lines.LoadFromFile('c:\temp\MemoryStream1.txt');
MemoryStream1.Free;
ParamStringList.Free;
IdSSLIOHandlerSocket1.Free;
IdHTTP1.Free;
Screen.Cursor := crDefault;
end;
As far as I am aware the more recent versions of Indy work with standard OpenSSL binaries.
Download from here. We produced a Delphi FTP client app a while ago using Indy with SSL connections and I'm sure we just shipped the current OpenSSL dlls.
Edit: Just checked the app directory and the DLLs we used are OpenSSL 0.9.8.2 (3-Aug-06). (It's an old app)
Edit 2: And I've just copied the more recent 0.9.8k dlls over and they work fine too.
Find the Indy version you are using.Copy the Indy dlls i.e libeay32.dll,libssl32.dll and
ssleay32.dll into the Windows/System 32 Folder.It will resolve the error "Could not Load SSL Library"
I need to consume a Web Service via SSL. In order to accomplish that I have built a web client in Delphi 6 that uses Indy to read the client certificates and write the soap request via https. The compilated version of the code is a DLL that runs in IIS 5.0. After tested the code in my local machine it works fine (I'm behind a proxy). But after the code is deployed to prod servers (not proxy) the SSL connection fails saying "Error connecting with SSL".
Here is my code:
var
Response: TStringStream;
IdHttp: TIdHTTP;
IdCnxSLL: TIdConnectionInterceptOpenSSL;
XmlSoapDoc: IXMLDocument;
begin
Response := TStringStream.Create('');
IdHttp := TIdHTTP.Create(nil);
IdCnxSLL := TIdConnectionInterceptOpenSSL.Create(nil);
XmlSoapDoc := TXMLDocument.Create(nil);
with IdCnxSLL do
begin
IdCnxSLL.SSLOptions.Method := sslvSSLv23;
IdCnxSLL.SSLOptions.RootCertFile := IniHttpConnectionData.Values['RootCertFile'];
IdCnxSLL.SSLOptions.CertFile := IniHttpConnectionData.Values['CertFile'];
IdCnxSLL.SSLOptions.KeyFile := IniHttpConnectionData.Values['KeyFile'];
IdCnxSLL.OnGetPassword := IdConInterceptOpenSSLGetPassword;
end;
with IdHttp do
begin
if bUseProxy then
begin
Request.ProxyServer := IniHttpConnectionData.Values['ProxyServer'];
Request.ProxyPort := StrToIntDef(IniHttpConnectionData.Values['ProxyPort'], 0);
end
else
begin
Host := IniHttpConnectionData.Values['HTTPHost'];
Port := StrToIntDef(IniHttpConnectionData.Values['HTTPPort'], 443);
end;
Request.ContentType := 'text/xml';
Intercept := IdCnxSLL;
InterceptEnabled := True;
end;
try
IdHttp.Post(ServiceURL, SoapEnv, Response);
except
on E:EIdOSSLConnectError do
LogError('SSL Connect Error: ' + E.Message);
on E:Exception do
LogError('Error' + E.ClassName + ' - ' + E.Message);
end;
I also try this code compiling into an exe program and it works. Is there something else I need to configure/add?
Thanks.
The fact that you are using TIdConnectionInterceptOpenSSL tells me that you are using a VERY old version of Indy. I am guessing Indy 8, which shipped with D6. Indy 8 and earlier are no longer officially supported by the Indy development team (which I am a member of). You really should upgrade to Indy 9, if not to Indy 10. In Indy 9, TIdConnectionInterceptOpenSSL was replaced with a new TIdSSLIOHandlerSocket component. Also, Indy 9 and earlier required custom-made OpenSSL DLLs, which may be contributing to your error as well, if you are using the wrong DLLs for your version of Indy. Indy 10, on the other hand, uses the standard DLLs from OpenSSL's website now.
Finnally It worked. Although I strongly encourage you to use a newer version of Indy as Remy suggests. I will post the steps that did the trick for me since there should be other people with the same problem.
The original code I posted is functional, it works when we need to post information via secured http (https) but the remote server requires prior authentification using a client certificate.
In order to make it work, it is necessary to verify the following:
TIdHttp and TIdConnectionInterceptOpenSSL configuration
Certificates
For the first 2 steps follow the steps mentioned here link text or (in case link is expired) Google "IndySSL - using certificate authentication". It worked for me.
Indy SSL DLLs. (For D6/Indy 8 download indy_openssl096g.zip from Indy SSL or Intelicom) This DLLs where the only ones that worked for this version of Indy.
Hope this will help.