These are chat archives for IndySockets/Indy

9th
May 2017
Justin
@klsyzzz
May 09 2017 02:04
hi @rlebeau just wondering is it possible to enable certificate validation with ssl? We are using TidSMTP with UseTLS as ExplicitTLS and IOHandler as SocketOpenSSL, but looks like it is not validating the certificate
Remy Lebeau
@rlebeau
May 09 2017 02:05
@klsyzzz Are you enabling the sslvrfPeer flag in the SSLIOHandler's VerifyMode, and using its OnVerifyPeer event? OpenSSL does validate certificates, but first you have to tell it to do so, and then you have a chance to look at the result of the validation and provide your own additional feedback based on your own needs/policies.
Justin
@klsyzzz
May 09 2017 02:06
currently all options under VerifyMode is false
Remy Lebeau
@rlebeau
May 09 2017 02:07
@klsyzzz Well, then turn them on, or at least sslvrfPeer
Justin
@klsyzzz
May 09 2017 02:08
ok so I just need to turn VerifyPeer property, do I need to add anything to the OnVerifyPeer event?
Remy Lebeau
@rlebeau
May 09 2017 02:10
@klsyzzz only if you don't trust OpenSSL's default validations, and/or you want to verify anything yourself.
Justin
@klsyzzz
May 09 2017 02:10
@rlebeau thank you very much
Justin
@klsyzzz
May 09 2017 02:18
sorry @rlebeau I'm new to this, do I need to set the property for CertFile or RootCertFile under SSLOptions? I got a SSL negotiation failed error after turn on sslverfPeer
Justin
@klsyzzz
May 09 2017 02:30
@rlebeau the underlying error is this when debugging : error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
mezen
@mezen
May 09 2017 06:46

@klsyzzz OpenSSL certificate validation with Indy is a little bit tricky (or maybe its the OpenSSL part that makes it tricky^^), sslvrfPeer says "if the server sends a certificate, it wil be verified. If the verification fails, the handshake will be terminated immediately. The only time that a server would not send a certificate is when an anonymous cipher is in use" (which should never be used^^). sslvrfFailIfNoPeerCert and sslvrfClientOnce are only used for server. If no VerifyMode is set, OpenSSL (in client mode) will verify the server certificate, but failure will not terminate the handshake.
I even believe you have always to implement a OnVerifyPeer, otherwise Indy uses a default implementation which is Result := True which overrides the verification result of OpenSSL.
If OpenSSL should verify the certificate, it needs to know which certificate are trustable. For this OpenSSL uses all public certs which are stored in the directory which you specified in SSLOptions.VerifyDir. If you want to use the windows certificate store, you could use this snippet, but you have to have a look into the msdn for CertOpenSystemStore, CertEnumCertificatesInStore and maybe is CertEnumSystemStore interessting for you.

    LCert := CertEnumCertificatesInStore(LStore, nil);
    while Assigned(LCert) do
    begin
      LX509 := d2i_X509(nil, @lCert.pbCertEncoded, LCert.cbCertEncoded);
      if Assigned(LX509) then
      begin
        X509_STORE_add_cert(ctx.cert_store, LX509);
        X509_free(LX509);
      end;
      LCert := CertEnumCertificatesInStore(LStore, LCert);
    end;
    // Calls of CertFreeCertificateContext are not needed, because
    // CertEnumCertificatesInStore frees the pPrevCertContext Argument

Another Point for certificate verification is the VerifyDepth: OpenSSL uses as default 9, but Indy overrides this with its own default, which is default(Integer) = 0. If the SMTP Server sends a certificate issued by a intermediate CA, OpenSSL terminate the connection with cert chain too long. VerifyDepth specifies the max length of a certificate chain.

mezen
@mezen
May 09 2017 07:36
@rlebeau FYI: the shipped version of Indy with Delphi Berlin does not contain a IdSASL_NTLM.pas, that file is missing.
Jos de Bruijn
@josdebr_twitter
May 09 2017 09:49
@rlebeau I am using D2005. And i've tried to add {R-} before my call to IMAPClient.retrieveMsg() but with no result. Unfortunately I cannot directly connect to this server, so I cannot debug the Indy library to see what value the different parameters are.
Jos de Bruijn
@josdebr_twitter
May 09 2017 14:12

@rlebeau I've changed the function to use a UID for the temp file name:

    if(CreateGuid(Uid) = S_OK) then
      Result := Copy(stringreplace(GuidToString(Uid),'-','', [rfReplaceAll]), 2, 10) + LFQE;
//    Result := LFName + IntToHex(LNamePart, 8) + LFQE;
    if not FileExists(Result) then begin
      Break;
    end;

The first test of this change is hopefull, my application is again able to parse the messages with attachments.
Can you think of any problems I might run into using this change (Apart from compatibilty issues when I try to upgrade the Indy components)

Remy Lebeau
@rlebeau
May 09 2017 16:36
@mezen the missing file is an Embarcadero issue, take it up with them. The file is in Indy's SVN repository, which they pull their releases from.
@josdebr_twitter you can't add the {$R-} directive to your code and expect it to apply to Indy. You would have to add it directly to Indy's source code and then recompile Indy. But either way, another solution that does not involve altering any Indy source code is to derive a class from TIdAttachmentFile and override its virtual PrepareTempStream() method to return a TFileStream object using whatever temp filename you want, and then you can use the TIdMessage.OnCreateAttachment event to create an instance of your attachment class
Remy Lebeau
@rlebeau
May 09 2017 17:16
@josdebr_twitter I just checked in an update that limits the range of ticks that GetUniqueFileName() uses. Hopefully the range check errors won't happen anymore
Justin
@klsyzzz
May 09 2017 22:16
thank you @mezen, so I guess the error (14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed) I'm getting is because OpenSSL doesn't know which certificate are trustable.