uROSocket.pas - failed to initialize SSL socket

Hello,

I think I found a bug in the uROSocket.pas unit, here:

procedure TROSocketOpenSSL.LoadCertificate;
begin
  InternalLoadCertificate(fCertFile, fCertFile);
end;

In this form, an error EROOpenSSLApi occurs in the nested call to the TROSocketOpenSSL.InternalLoadCertificate method, here:

procedure TROSocketOpenSSL.InternalLoadCertificate(aCert, aKey: string);
var
  l_cert: TBytes;
begin
{$IFDEF LOG}Log(Format(' ->TROSocketOpenSSL.InternalLoadCertificate(%s, %s)', [aCert, aKey])); try{$ENDIF}
  if aCert <> '' then begin
    l_cert := StringToUTF8Bytes(aCert + #0);
    if (SSL_CTX_use_certificate_chain_file(fCTX, @l_cert[0]) <> 1) then begin
      //"Error loading certificate from file"
      SSLCheck;
      Exit;
    end;
    l_cert := StringToUTF8Bytes(aKey + #0);
!!!!!!!! ---> this fails
    if (SSL_CTX_use_PrivateKey_file(fCTX, @l_cert[0], SSL_FILETYPE_PEM) <> 1) then begin
      //"Error loading private key from file"
      SSLCheck;
      Exit;
    end;
    if SSL_CTX_check_private_key(fCTX) <> 1 then begin
      SSLCheck;
      Exit;
    end;
  end;
{$IFDEF LOG}finally Log(' <-TROSocketOpenSSL.InternalLoadCertificate'); end;{$ENDIF}
end;

…because the value of aKey is the same as the value of aCert. I think it’s just a typo, but the consequences are quite fatal - in case of using an externally referenced certificate in the file, the server transport cannot be activated properly.

The TROSocketOpenSSL.LoadCertificate method should probably look like this:

procedure TROSocketOpenSSL.LoadCertificate;
begin
  InternalLoadCertificate(fCertFile, {fCertFile} fCAKeyFile);
end;

I tried it, it works fine.

Regards from Prague,

Jiri

Hi,

CAKeyFile - certificate authority key file. it cannot be used here.


PEM certificate should contain server certificate and private key like:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----

optionally, it can include server CA and root CA like:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

check more at SSL/TLS (Delphi)

Hello, Evgeny

According to your answer, meaning of CAFile, CAKeyFile and CertFile values in TROOpenSSL class is a bit different from meaning of RootCertFile, CertFile, KeyFile values in TIdSSLOptions class.

TROOpenSSL.CertFile value expects certificate to be present together with private key, but in the TIdSSLOptions class certificate must be stored in the CertFile value and the private key in the KeyFile value, i.e. separately. Is this correct?

Thanks, regards from Prague

Jiri

Hi,

TROOpenSSL uses this meanings:

    /// <summary>default CA certificate file </summary>
    property CAFile: string read fCAFile write SetCAFile;
    /// <summary>CA private file, is needed for generating self-signed certificate</summary>
    property CAKeyFile: string read fCAKeyFile write SetCAKeyFile;
    /// <summary>
    /// certificate file that compains cert.pem + key.pem [+ CAcert.pem ] [+ rootcert.pem]
    /// </summary>
    property CertFile: string read fCertFile write SetCertFile;

Yes, I can read and understand comments in the code. I wanted to point out differences that might be important to other developers who have been using Indy and want to switch to TROHTTPServer… like me, for example.