Search code examples
c#ssl-certificatemailkit

Mailkit IMapClient not hitting ServerCertificateValidationCallback & SslHandshakeException


I'm attempting to connect to an IMAP server using the following code on a Windows Server 2019 machine:

using (var client = new ImapClient(new ProtocolLogger("protocol.log")))
 {
        var address = EnvReader.GetStringValue("EMAIL_ADDRESS");
        var password = EnvReader.GetStringValue("EMAIL_PASSWORD");
        var creds = new NetworkCredential(address, password);

        client.CheckCertificateRevocation = false;
        client.ServerCertificateValidationCallback = (s, c, h, e) =>
        {
          Console.WriteLine("ALL UP IN THIS CALLBACK" + e.ToString());
          return true;
        };
        client.Connect("outlook.office365.com", 993, SecureSocketOptions.SslOnConnect);
        client.Authenticate(address, password);
 }

On my Mac, this code runs perfectly fine, I can connect and subsequently authenticate just fine.

On the Windows machine I receive the following exception:

MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.
This usually means that the SSL certificate presented by the server is not trusted by the system for one or more of
the following reasons:
1. The server is using a self-signed certificate which cannot be verified.
2. The local system is missing a Root or Intermediate certificate needed to verify the server's certificate.
3. A Certificate Authority CRL server for one or more of the certificates in the chain is temporarily unavailable.
4. The certificate presented by the server is expired or invalid.
5. The set of SSL/TLS protocols supported by the client and server do not match.
6. You are trying to connect to a port which does not support SSL/TLS.

See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#SslHandshakeException for possible solutions

Based on the info in the linked FAQ, I added the ServerCertificateValidationCallback, however the callback is never hit (The previously mentioned exception is still thrown, the relevant console logging never occurs, and a breakpoint inside the callback is never hit while debugging).

From my reading, the ServerCertificateValidationCallback should handle cases #1-4 that the exception message mentions. The fact that I can connect on the specified port on my Mac would seem to rule out case #6 (I also tried port 143 + SecureSocketOptions.StartTls). That leaves case #5, however, I can't find any information suggesting that Windows Server 2019 can't handle SSL/TSL protocols.

Any ideas for a) dealing with this exception and/or b) figuring out why the ServerCertificateValidationCallback is not firing would be greatly appreciated.

Edit: My project is referencing .NET 5.0


Solution

  • Let's go through each of the possibilities:

    1. The server is using a self-signed certificate which cannot be verified.

    outlook.office365.com would not be using a self-signed certificate, so that wouldn't be an issue in this case.

    1. The local system is missing a Root or Intermediate certificate needed to verify the server's certificate.

    This one is very possible, but the ServerCertificateValidationCallback override should be overriding this failure. However, it's not getting hit... so it's not actually bypassing this potential error.

    1. A Certificate Authority CRL server for one or more of the certificates in the chain is temporarily unavailable.

    This would be negated by client.CheckCertificateRevocation = false;

    1. The certificate presented by the server is expired or invalid.

    This is not the case because the certificate does not expire until 1/21/2022.

    1. The set of SSL/TLS protocols supported by the client and server do not match.

    The server supports at least TLSv1.2 which is a default TLS protocol version supported by MailKit in all target framework versions (.NET 4.5 -> 5.0 + netstandard2.x's).

    1. You are trying to connect to a port which does not support SSL/TLS.

    Port 993 is the correct port and SslOnConnect is the correct option, so this is not the issue.

    Assuming there isn't a bug in MailKit's SslStream.AuthenticateAsClientAsync() call that passes in the validation callback method (.NET 5.0 is different than other versions), what is the InnerException? Maybe that will provide some insight.