-
-
Notifications
You must be signed in to change notification settings - Fork 826
/
Copy pathSslCertificateValidation.cs
81 lines (66 loc) · 3.16 KB
/
SslCertificateValidation.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System;
using System.Net.Security;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using MimeKit;
using MailKit;
using MailKit.Security;
using MailKit.Net.Smtp;
namespace MailKit.Examples
{
public static class SslCertificateValidationExample
{
public static void SendMessage (MimeMessage message)
{
using (var client = new SmtpClient ()) {
// Set our custom SSL certificate validation callback.
client.ServerCertificateValidationCallback = MySslCertificateValidationCallback;
// Connect to smtp.gmail.com on the SSL-wrapped port.
client.Connect ("smtp.gmail.com", 465, SecureSocketOptions.SslOnConnect);
// Authenticate with our username and password.
client.Authenticate ("username@gmail.com", "password");
// Send our message.
client.Send (message);
// Disconnect cleanly from the server.
client.Disconnect (true);
}
}
static bool MySslCertificateValidationCallback (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// If there are no errors, then everything went smoothly.
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
// Note: MailKit will always pass the host name string as the `sender` argument.
var host = (string) sender;
if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0) {
// This means that the remote certificate is unavailable. Notify the user and return false.
Console.WriteLine ("The SSL certificate was not available for {0}", host);
return false;
}
if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0) {
// This means that the server's SSL certificate did not match the host name that we are trying to connect to.
var certificate2 = certificate as X509Certificate2;
var cn = certificate2 != null ? certificate2.GetNameInfo (X509NameType.SimpleName, false) : certificate.Subject;
Console.WriteLine ("The Common Name for the SSL certificate did not match {0}. Instead, it was {1}.", host, cn);
return false;
}
// The only other errors left are chain errors.
Console.WriteLine ("The SSL certificate for the server could not be validated for the following reasons:");
// The first element's certificate will be the server's SSL certificate (and will match the `certificate` argument)
// while the last element in the chain will typically either be the Root Certificate Authority's certificate -or- it
// will be a non-authoritative self-signed certificate that the server admin created.
foreach (var element in chain.ChainElements) {
// Each element in the chain will have its own status list. If the status list is empty, it means that the
// certificate itself did not contain any errors.
if (element.ChainElementStatus.Length == 0)
continue;
Console.WriteLine ("\u2022 {0}", element.Certificate.Subject);
foreach (var error in element.ChainElementStatus) {
// `error.StatusInformation` contains a human-readable error string while `error.Status` is the corresponding enum value.
Console.WriteLine ("\t\u2022 {0}", error.StatusInformation);
}
}
return false;
}
}
}