I'm using the TIdSSLIOHandlerSocketOpenSSL Indy component in Delphi XE2 to send data to an SSL server (Apple Push Notification Service) over TCP. I've got it working to a degree but not sure if I'm going about it the best way. I'm doing the following :
Set the SSL properties inc. path to certificates
Call the .Open method to open the connection
Check the AType parameter in the OnStatusInfoEx event until I get a 'Handshake Done'
Send the data using .WriteDirect
Close the connection with .Close
Is there a better way to know when the connection is ready to send data? Does anybody have sample code using the TIdSSLIOHandlerSocketOpenSSL component directly over TCP? The samples I've found are mainly for HTTP calls where the TIdSSLIOHandlerSocketOpenSSL component is just attached to secure the connection.
Since you are using the client component, you only need to setup the certificates on the client if the server is going to authenticate the client's certificate.
Otherwise, set the TIdSSLIOHandlerSocketOpenSSL's SSLOptions.Mode to sslmClient, and you should be able to connect.
It's a good idea to enable the VerifyMode and use the OnVerifyPeer event on the socket component to verify the fingerprint on the server certificate in order to avoid man in the middle attacks.
Depending on your version of Indy, you may need to set the SSLOptions Method to sslvTLSv1. Some web servers no longer support SSLv2, which Indy 9 defaults to.
Here's some sample code that demonstrates retrieving a web page over SSL using the TCP component:
procedure TForm1.Button1Click(Sender: TObject);
var
s: String;
begin
IdTCPClient1.Host := 'example.com';
IdTCPClient1.Port := 443;
IdTCPClient1.Connect;
IdTCPClient1.WriteLn('GET / HTTP/1.1');
IdTCPClient1.WriteLn('Host: example.com');
IdTCPClient1.WriteLn('');
// Retrieve all the data until the server closes the connection
s := IdTCPClient1.AllData;
Memo1.Lines.Add(s);
end;
Don't forget to include the OpenSSL libraries libeay32.sll and ssleay32.dll in the same folder as your EXE on Windows. Use the standard (latest) binaries for Indy 10.
This is what works for me. I am using Delphi 2010, but it this probably works just as well on Delphi XE2 (not tested). I use the current tip revision of Indy, which is revision 4774, rather that the out-of-the-box version.
I have 3 components on a datamodule or webmodule:
TIdHTTP
TIdSSLIOHandlerSocketOpenSSL
TidCookieManager
Hook all the components up to each other at design-time, with the following change at run-time: If the protocol is plain http:, then disconnect the TIdSSLIOHandlerSocketOpenSSL component. If the protocol is https:, then set the Handler property of the IdHTTP to the IdSSLIOHandlerSocketOpenSSL.
In the SSL Options, set method to sslvSSLv23 and SSLVersions to [sslvSSLv2,sslvSSLv3,sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2]. I found that other permutations these properties just did not work. I can't explain it. I just know that this works with a wide range of webservers.
From there it is dead easy. To GET, simple call the Get() method on the TIdHTTP. For POST, call Post(). Parameters and Cookies are accessible by obviously named properties.
I had a lot of trouble get the out-of-the-box version to POST correctly, but with the tip revision, and setting the options as I mentioned, its been a breeze.
Related
I have a basic "Web Server Application" created by going to File > New > Web Server Application and choosing ISAPI Dynamic Link Library, which I am using to test Windows Authentication when running within IIS.
I have code that reads in the TWebRequest.Authorization property and decodes the string that is sent from IIS (which is usually Negotiate xxxxxxxxxxxx...) This all works when running the site without SSL. I can extract the username, password, domain and workstation name from the Type3 Message as per http://davenport.sourceforge.net/ntlm.html#type3MessageExample.
When SSL is enabled, it seems the string is somehow further encrypted and I get a mess of data from my code which as stated works when SSL is not enabled.
Could anyone tell me what I could be missing? I have not posted any code (but can) as I suspect this is not specific to my code but something to do with SSL that I am not aware of. And searching for answers to this has been somewhat uneventful as I am unaware of the correct terminology to use to get the to correct answers.
I am not so much looking for a "here is the answer" but a pointer in the correct direction would be most appriciated.
When not using SSL, the Negotiate value is: 'Negotiate TlRMTVNT....
When using SSL, the Negotiate value is: 'Negotiate oXcwdaADCgEBo......
Note on the Non-SSL version the string begins TlRMTVNT, this is what I would expect as that is the NTMLSSP signature Base64Encoded.
When you create a "Web Service Application" project, Delphi creates a TIdHTTPWebBrokerBridge object by default as Server :
type
TForm1 = class(TForm)
...
private
FServer: TIdHTTPWebBrokerBridge;
procedure StartServer;
...
end;
During the wizard of creating Web Service Application project, you have an option to use HTTPS :
By Activating this check-box, you will be prompted for information of a Certificate file :
You can search a bit about SSL Certificate files, but you can use OpenSSL to create a self-signed SSL Certificate, here are some useful explanations: https://www.cloudflare.com/learning/ssl/what-is-an-ssl-certificate/
And regarding using OpenSSL : How to generate a self-signed SSL certificate using OpenSSL?
Here are the OpenSSL binary file and Indy SSL required DLL files:
https://github.com/IndySockets/OpenSSL-Binaries
....
After creating your project by activating HTTPS option you will have some other things included by default, the main difference is that now the TIdHTTPWebBrokerBridge component is using a TIdServerIOHandlerSSLOpenSSL component as IO-Handler:
procedure TForm1.FormCreate(Sender: TObject);
var
LIOHandleSSL: TIdServerIOHandlerSSLOpenSSL;
begin
FServer := TIdHTTPWebBrokerBridge.Create(Self);
LIOHandleSSL := TIdServerIOHandlerSSLOpenSSL.Create(FServer);
LIOHandleSSL.SSLOptions.CertFile := '';
LIOHandleSSL.SSLOptions.RootCertFile := '';
LIOHandleSSL.SSLOptions.KeyFile := '';
LIOHandleSSL.OnGetPassword := OnGetSSLPassword;
FServer.IOHandler := LIOHandleSSL;
end;
You just need to make SSL Certificate files and put their addresses on OnCreate event as shown above, that IOHandler will handle SSL decryption
I'm not have expertise with Delphi and TLS using Indy.
Maybe it's not a problem, just config, I need examples.
I tried some questions on Stackoverflow too, all unsuccessfully.
Page: https://testesmoleculares.com.br/
Errors:
---------------------------
Debugger Exception Notification
---------------------------
Project IntegradorApoiado.exe raised exception
class EIdOSSLUnderlyingCryptoError with message 'Error connecting with SSL.
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure'.
---------------------------
Break Continue Help
---------------------------
Actual config:
LHandler.SSLOptions.Method := sslvSSLv2;
LHandler.SSLOptions.Mode := sslmClient;
LHandler.SSLOptions.SSLVersions := [sslvSSLv2];
Tried:
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method := sslvTLSv1_2;
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.SSLVersions := [sslvTLSv1_2];
Someone can help?
Maybe providing an example of POST? I'm using Delphi XE4
Thanks!
Github issue:
https://github.com/IndySockets/Indy/issues/317
Tried:
https://stackoverflow.com/a/49061252
ssl v3 poodle and move to tls with indy
Using Indy 10 IdHTTP with TLS 1.2
https://indy.fulgan.com/SSL/?C=M;O=A
Others
Without seeing the actual handshake data, it is difficult to say for sure why it is failing.
However, I will mention that sslvSSLv2 is for SSL v2.0, which nobody uses anymore, as it is no longer secure. Same with sslvSSLv3 (SSL v3.0). So, never use sslvSSLv2 and sslvSSLv3 (unless you HAVE to, for legacy purposes).
sslvTLSv1_2 is for TLS v1.2. A lot of servers are now migrating to this. But many servers haven't fully migrated yet. So, you should enable TLS v1.0 and v1.1 as well for wider acceptance, eg (do not use SSLOptions.Method at all, just use SSLOptions.SSLVersions):
LHandler.SSLOptions.Mode := sslmClient;
LHandler.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
By specifying multiple TLS versions, that will allow OpenSSL to negotiate an available version that both peers support.
Also, make sure you are using an up-to-date version of Indy (if you are not already) so that you have all of its fixes for TLS support, such as use of SNI (which many servers now require TLS clients to use).
I can connect to https://testesmoleculares.com.br/ in a web browser using TLS 1.2, so it should be possible to connect to it using TLS 1.2 in Indy as well.
UPDATE: based on additional comments you have posted for this same issue in Indy's issue tracker (#317: TLS - Problems with https://testesmoleculares.com.br/ on Cloudflare), you are using an outdated version of Indy (10.6.0.4975), which does not fully handle TLS 1.2. You need to upgrade to the latest version (10.6.2) in order to use TLS 1.2 properly.
I import WinHTTP and try execute a request in a https url, like this:
function TForm1.GetPage(AURL: String): String;
var
WinHttpRequest: IWinHTTPRequest;
begin
CoInitialize(nil);
try
WinHttpRequest := CoWinHttpRequest.Create;
WinHttpRequest.Open('GET', AURL, False);
WinHttpRequest.Send(EmptyParam);
Result := WinHttpRequest.ResponseText;
finally
WinHTTPRequest := nil;
CoUninitialize;
end;
end;
It works in same pages (ex: https://www.google.com), but not in others (ex: https://sourceforge.net), with error "The connection with the server was terminated abnormally".
Are there any additional settings I'm forgetting?
I'm using Delphi 2010.
Most servers have migrated away from accepting SSL incoming traffic in favor of TLS protocol. Windows 7 and 8 do not have TLS protocol defined and hence VBA sendss traffic with SSL which is then blocked/dropped by such servers.
You will need to apply a 2-step patch/update to fix this for windows 7,
Step 1. Get Microsoft Update:
Download relevant (32-bits or 64-bits of user's Windows version)
Microsoft Security Protocol Update and install if not already install.
Step 2. Download Microsoft Easy Fix:
Download Microsoft “Easy Fix” from
Microsoft Support Article, and execute to set TLS 1.1+ as default.
Source : Update to enable TLS 1.1 and TLS 1.2 as default secure protocols in WinHTTP in Windows
Can anyone diagnose my failure to connect to smtp.office365.com using Delphi 2010 and Indy 10.5.5?
I have read the code examples provided by Indy expert Remy Lebeau in this question: Using INDY 10 SMTP with Office365.
I have taken each of the two alternate code samples (one using AuthType satDefault and the other satSASL) from that question and cut-and-pasted them into a console application. In each case get the following error when run:
EIdOSSLUnderlyingCryptoError: Error connecting with SSL.
Error connecting with SSL.
error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number
When I change UseTLS to utUseExplicitTLS (as suggested in some other answers that state a plain text connection is required before attempting TLS) I get the following error:
EIdOSSLConnectError: Error connecting with SSL.
Error connecting with SSL.
EOF was observed that violates the protocol
I notice some references in other answers to setting SSLOptions.SSLVersions instead of SSLOptions.Method (which is said to be deprecated) but that property does not appear to exist on TIdSSLIOHandlerSocketOpenSSL in my version of Indy.
I believe I have the version of Indy which shipped with the D2010 updates but that it's somewhat out-of-date. I would be willing to update a newer version if one exists but can't seem to find anyway to do so without installing SVN, learning it, checking out from Development, and recompiling.
Finally, I've tried running all four variants of my console application with no DLLs present in the executable directory and with the DLLs from OpenSSL v1.0.2h present without any apparent effect.
EDIT: One other piece of information. The SMTP credentials supplied by the client (this project sends emails through a single dedicated outbound email address) is of the form project#myclientsdomain.com, rather than #office365.
Apparently, since Remy wrote the answer in the linked question, Office365 has stopped supporting SSLv3 (presumably to avoid a known exploit) and now requires TLS. The code from his answer in the original question works if you change these two lines:
idSMTP1.UseTLS := utUseImplicitTLS;
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvSSLv3;
to:
idSMTP1.UseTLS := utUseExplicitTLS;
TIdSSLIOHandlerSocketOpenSSL(idSMTP1.IOHandler).SSLOptions.Method := sslvTLSv1;
i have analyzed a site to see how data sent .. but i got some problem ..
the site use connect method to connect to site like this connet to "http://example.com:443" and there is no S in the http ..
there is no such method in Indy or clever compenents .. only post ,Get , put ..
this is a pic to understand me ..
so how i can use that connect method in indy or clever compenents .. !!
CONNECT is used to let a client connect to a target server through an HTTP proxy. This is most commonly used (but not limited) to proxying SSL connections, like those used for HTTPS.
Indy's TIdHTTP component uses CONNECT internally when you have configured a proxy Host:Port in the TIdHTTP.ProxyParams property and then:
request an HTTPS url.
request an HTTP url and have the hoNonSSLProxyUseConnectVerb flag enabled in the TIdHTTP.HTTPOptions property.
Indy also has a TIdConnectThroughHttpProxy component that can be used with Indy's other non-HTTP TCP clients to proxy connections through an HTTP proxy using CONNECT.
If I remember correctly, the following Synapse-based code would trigger a CONNECT to port 443 using the OpenSSL libraries...
procedure Test;
var HTTP:THTTPSend;
begin
HTTP:=THTTPSend.Create;
try
HTTP.Sock.CreateWithSSL(TSSLOpenSSL);
HTTP.Sock.SSLDoConnect; // CONNECT happens here
HTTP.HTTPMethod('GET','https://www.google.com/');
(...)
finally
HTTP.Free;
end;
end;