Delphi - SSL TCP communication with Indy component

2019-01-24 23:44发布

问题:

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.

回答1:

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.



回答2:

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:

  1. TIdHTTP
  2. TIdSSLIOHandlerSocketOpenSSL
  3. 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.