Handling Self-Signed Certificates (Delphi)

Remoting SDK's client channels for Delphi allow to enable TLS/SSL protection quite easily: simply by using the appropriate https://, superhttps://, tcps:// or supertcps:// URL Scheme, the clients will automatically choose Secure Socket Layer and communicate securely with the server.

For that, your server has to be set up with a "proper" certificate – that is, a certificate signed by (and usually bought from) a known certificate authority that is implicitly trusted by the OS. For production applications that is recommended practice, but sometimes – for example in Enterprise deployment or during debugging – it is helpful to be able to work with "invalid" or self-signed certificates, just to get things going before spending money on a real certificate.

Depending on the target OS and used channel type (see below), the channel will either refuse to connect or just accept the formally invalid certificate. Unfortunately, accepting unknown certificates blindly could enable Man-in-the-middle Attacks and essentially negate any security you aim to gain by using SSL. Even more, blindly accepting a formally valid certificate is still not MITM-attacks proof.

So a more advanced certificate validity check is required for real-worlds applications.

In Remoting SDK for Delphi there are 4 different kinds of channels, based on different libraries:

  • Indy library
  • WinInet API library
  • NetHTTP library (XE8+ only)
  • Synapse library

These channel kinds require different approaches to handle self-signed certificates and will be covered separately.

Indy-based channels:

drop TIdSSLIOHandlerSocketOpenSSL instance

include sslvrfPeer option:

IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyMode :=
       IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyMode + [sslvrfPeer];

implement OnVerifyPeer event like

function TMyForm.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509; AOk: Boolean;
  ADepth,  AError: Integer): Boolean;
begin
  result := ValidateCertificate(Certificate);
end;

link TIdSSLIOHandlerSocketOpenSSL instance with channel.IndyClient.IOHandler

TROWinInetHTTPChannel:

implement OnInvalidCertificate method:

procedure TMyForm.ROWinInetHTTPChannel1InvalidCertificate(Sender: TObject;
  const aIssuer, aSubject: AnsiString; var aAllow: Boolean);
begin
  aAllow := ValidateCertificate(aIssuer, aSubject);
end;

TRONetHttpClientChannel:

implement OnValidateServerCertificate (or channel.http.OnValidateServerCertificate) event:

procedure TServerForm.NetHTTPClientValidateServerCertificate(const Sender: TObject;
  const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean);
begin
  Accepted = ValidateCertificate(Certificate);
end;

Synapse-based channels:

Synapse-based channels aren't supported yet.