centospostfix-mtamailkitdovecot

MailKit gets an SslHandshakeException with LetsEncrypt SSL certificates


I have a server (Centos 7) setup to be used as mail server. Using postfix/dovecot/opendkim/opendmarc.. It works as it should, users are able to connect their emails using gmail for example. Able to send and receive mail.

Also when I use MailKit and test my .NET Core application from my home pc MailKit connects fine and the emails are send.

However, when I deploy the application to my server MailKit fails to connect.

If I look in the logs I see the following

postfix/submission/smtpd[4486]: match_hostname: unknown ~? 127.0.0.1/32
postfix/submission/smtpd[4486]: match_hostaddr: MY_SERVER_IP ~? 127.0.0.1/32
postfix/submission/smtpd[4486]: match_hostname: unknown ~? MY_SERVER_IP/32
postfix/submission/smtpd[4486]: match_hostaddr: MY_SERVER_IP  ~? MY_SERVER_IP/32
postfix/submission/smtpd[4486]: lost connection after STARTTLS from unknown[MY_SERVER_IP]

But if I look a bit higher in the logs I see

Anonymous TLS connection established from unknown[MY_SERVER_IP]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)

My MailKit (which works fine from outside of the server):

using (SmtpClient emailClient = new SmtpClient())
{
    await emailClient.ConnectAsync(emailConfiguration.SmtpServer, emailConfiguration.SmtpPort, SecureSocketOptions.StartTls);
    emailClient.AuthenticationMechanisms.Remove("XOAUTH2");  

    await emailClient.AuthenticateAsync(emailConfiguration.SmtpUsername, emailConfiguration.SmtpPassword);
    await emailClient.SendAsync(message);

    await emailClient.DisconnectAsync(true);
}

edit: The exception from MailKit (certificate is proper and not self-signed):

MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.
May 19 16:07:37 domain.com NETCoreApp[4452]: The server's SSL certificate could not be validated for the following reasons:
May 19 16:07:37 domain.com NETCoreApp[4452]: • The server certificate has the following errors:
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get certificate CRL
May 19 16:07:37 domain.com NETCoreApp[4452]: • The root certificate has the following errors:
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get certificate CRL
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get local issuer certificate
May 19 16:07:37 domain.com NETCoreApp[4452]: ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

Solution

  • The unable to get certificate CRL error sounds like SslStream was unable to get the CRL, perhaps because the CRL server is unreachable for some reason.

    You could try adding emailClient.CheckCertificateRevocation = false; before the ConnectAsync to check if that's the issue.

    The other error, unable to get local issuer certificate, might be because the server that MailKit is running on doesn't have the Root CA certificate in its X509Store but your home PC does.

    Update:

    The problem is that LetsEncrypt SSL certificates do not include a CRL location which means that certificate revocation checks will fail.

    To bypass this, you need to set client.CheckCertificateRevocation = false; before connecting.