SSLでサーバーに接続する、もっとも単純な方法のサンプルコードを示します。
サーバーからSSL証明書を受信したときに実行するプロシージャを、ValidationCallbackフィールドに指定します。本来このプロシージャには、証明書の妥当性をチェックし、問題がない場合はTrue、問題がある場合はFalseを戻り値として返す処理を実装します。
ただし、以下のサンプルコードではプロシージャ内で証明書の妥当性を判断していません。この場合、サーバーから受信した証明書が信頼されないものであっても、その証明書を承認してSSL通信が確立されます。
この方法は、接続先が信頼できるサーバーであることがあらかじめ分かっている場合や、テスト用サーバーに証明書作成ツール(Makecert.exe)で作成した自己証明書を置いた場合など、SSL証明書の検証を省略しても問題のない条件下のみで利用できます。
Imports Dart.Mail
Imports Dart.Mail.Pop
Imports System.Net.Security
Imports System.Security.Authentication
Imports System.Security.Cryptography.X509Certificates
Private Sub SecurePopLogin()
' SSL接続の種類を指定します。
Pop1.Session.Security.Encrypt = Encrypt.Implicit
' プロトコルを指定します。
Pop1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls
' サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
Pop1.Session.Security.ValidationCallback = AddressOf remoteCertificateValidation
' POPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
Pop1.Session.RemoteEndPoint = New Dart.Mail.IPEndPoint("pop.myMailServer.com", Pop.GetDefaultPort(Pop1.Session))
Pop1.Session.Username = "myUsername"
Pop1.Session.Password = "myPassword"
' POPサーバーに接続します。
Pop1.Connect()
' POPサーバーにログインし、メールの情報を取得します。
Pop1.Authenticate(True, True)
End Sub
Private Function remoteCertificateValidation(ByVal sender As Object, ByVal remoteCertificate As X509Certificate, _
ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors)
' SSL証明書の検証を行わず、すべての証明書に対してTrue(問題なし)を返します。
Return True
End Function
using Dart.Mail;
using Dart.Mail.Pop;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
private void SecurePopLogin()
{
// SSL接続の種類を指定します。
pop1.Session.Security.Encrypt = Encrypt.Implicit;
// プロトコルを指定します。
pop1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls;
// サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
pop1.Session.Security.ValidationCallback = remoteCertificateValidation;
// POPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
pop1.Session.RemoteEndPoint = new Dart.Mail.IPEndPoint("pop.myMailServer.com", Pop.GetDefaultPort(pop1.Session));
pop1.Session.Username = "myUsername";
pop1.Session.Password = "myPassword";
// POPサーバーに接続します。
pop1.Connect();
// POPサーバーにログインします。
pop1.Authenticate(true, true);
}
private bool remoteCertificateValidation(Object sender, X509Certificate remoteCertificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// SSL証明書の検証を行わず、すべての証明書に対してTrue(問題なし)を返します。
return true;
}
サーバーのSSL証明書を検証して、問題がない場合はTrue、問題がある場合はFalseを戻り値として返すプロシージャを作成し、そのプロシージャをValidationCallbackフィールドに指定します。このプロシージャはConnectメソッドの実行時に呼び出されますが、Falseが返された場合はメソッドの処理で例外が発生します。
ValidationCallbackフィールドに指定する、サーバーのSSL証明書を検証するプロシージャは、RemoteCertificateValidationCallbackデリゲート型(System.Net.Security名前空間のクラス)のプロシージャです。以下のサンプルコードでは、一例として、.NET Framework標準の機能のみを使用したremoteCertificateValidationプロシージャで、SSL証明書の検証を行っています。各処理の詳細については、MSDNライブラリなどを参照してください。
Imports Dart.Mail
Imports Dart.Mail.Pop
Imports System.Net.Security
Imports System.Security.Authentication
Imports System.Security.Cryptography.X509Certificates
Private Sub SecurePopLogin()
' SSL接続の種類を指定します。
Pop1.Session.Security.Encrypt = Encrypt.Implicit
' プロトコルを指定します。
Pop1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls
' サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
Pop1.Session.Security.ValidationCallback = AddressOf remoteCertificateValidation
' POPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
Pop1.Session.RemoteEndPoint = New Dart.Mail.IPEndPoint("pop.myMailServer.com", Pop.GetDefaultPort(Pop1.Session))
Pop1.Session.Username = "myUsername"
Pop1.Session.Password = "myPassword"
' POPサーバーに接続します。
Pop1.Connect()
' POPサーバーにログインし、メールの情報を取得します。
Pop1.Authenticate(True, True)
End Sub
' サーバーのSSL証明書を検証するプロシージャの一例です。
Private Function remoteCertificateValidation(ByVal sender As Object, ByVal remoteCertificate As X509Certificate, _
ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors) As Boolean
' サーバー証明書に問題がない場合、trueを返します。
If sslPolicyErrors = SslPolicyErrors.None Then
Return True
End If
Dim acceptCertificate As Boolean = True
Dim msg As String = "このサーバーの証明書には、以下の問題があります。" & Constants.vbCrLf
' サーバーが証明書を提示しなかった場合
If (sslPolicyErrors And _
SslPolicyErrors.RemoteCertificateNotAvailable) = SslPolicyErrors.RemoteCertificateNotAvailable Then
msg = msg & Constants.vbCrLf & " - サーバーから証明書が提示されませんでした。" & Constants.vbCrLf<
acceptCertificate = False
Else
' 証明書の名前が一致しない場合
If ((sslPolicyErrors And _
SslPolicyErrors.RemoteCertificateNameMismatch) = SslPolicyErrors.RemoteCertificateNameMismatch) Then
msg = msg & Constants.vbCrLf & _
" - 証明書の名前が一致しませんでした。" & Constants.vbCrLf
acceptCertificate = False
End If
' 証明書に関するその他の問題がある場合
If (sslPolicyErrors And _
SslPolicyErrors.RemoteCertificateChainErrors) = SslPolicyErrors.RemoteCertificateChainErrors Then
For Each item As X509ChainStatus In chain.ChainStatus
If item.Status <> X509ChainStatusFlags.RevocationStatusUnknown AndAlso _
item.Status <> X509ChainStatusFlags.OfflineRevocation Then
Exit For
End If
If (item.Status <> X509ChainStatusFlags.NoError) Then
msg = msg & Constants.vbCrLf & " -" & item.StatusInformation
acceptCertificate = False
End If
Next item
End If
End If
' 検証結果が不正だった場合、メッセージボックスを表示します。
If acceptCertificate = False Then
msg = msg & Constants.vbCrLf & "接続を続行しますか?"
If MessageBox.Show(msg, "セキュリティの警告: サーバーのSSL証明書エラー", _
MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) = System.Windows.Forms.DialogResult.Yes Then
acceptCertificate = True
End If
End If
Return acceptCertificate
End Function
using Dart.Mail;
using Dart.Mail.Pop;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
private void SecurePopLogin()
{
// SSL接続の種類を指定します。
pop1.Session.Security.Encrypt = Encrypt.Implicit;
// プロトコルを指定します。
pop1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls;
// サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
pop1.Session.Security.ValidationCallback = remoteCertificateValidation;
// POPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
pop1.Session.RemoteEndPoint = new Dart.Mail.IPEndPoint("pop.myMailServer.com", Pop.GetDefaultPort(pop1.Session));
pop1.Session.Username = "myUsername";
pop1.Session.Password = "myPassword";
// POPサーバーに接続します。
pop1.Connect();
// POPサーバーにログインします。
pop1.Authenticate(true, true);
}
private static bool remoteCertificateValidation(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// サーバー証明書に問題がない場合、trueを返します。
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
bool acceptCertificate = true;
string msg = "このサーバーの証明書には、以下の問題があります。\r\n";
// サーバーが証明書を提示しなかった場合
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable)
{
msg = msg + "\r\n - サーバーから証明書が提示されませんでした。\r\n";
acceptCertificate = false;
}
else
{
// 証明書がサーバー名と一致しない場合
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
{
msg = msg + "\r\n - 証明書の名前が一致しませんでした。\r\n";
acceptCertificate = false;
}
// 証明書に関するその他の問題がある場合
if ((sslPolicyErrors &
SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
{
foreach (X509ChainStatus item in chain.ChainStatus)
{
if (item.Status != X509ChainStatusFlags.RevocationStatusUnknown &&
item.Status != X509ChainStatusFlags.OfflineRevocation)
break;
if (item.Status != X509ChainStatusFlags.NoError)
{
msg = msg + "\r\n -" + item.StatusInformation;
acceptCertificate = false;
}
}
}
}
// 検証が失敗した場合、メッセージボックスを表示します。
if (acceptCertificate == false)
{
msg = msg + "\r\n接続を続行しますか?";
if (MessageBox.Show(msg, "セキュリティの警告: サーバーのSSL証明書エラー",
MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
acceptCertificate = true;
}
return acceptCertificate;
}
セキュアなPOPサーバーは、接続時にクライアントへ証明書を要求し、身元の証明を求める場合があります。このプロセスをクライアント認証といいます。
ユーザーが証明書を選択する方法
サーバーからクライアントへ証明書の要求があった場合に、ユーザーがローカルシステムにある任意の証明書を選択し、クライアント認証に使用する方法です。
ユーザーが選択した証明書を戻り値として返すメソッドを作成し、そのメソッドをSelectionCallbackフィールドに指定します。サーバーから証明書の要求があったときには、このメソッドが実行され、戻り値として返された証明書がサーバーへ提示されます。
付属サンプルのフォーム「CertificateListForm」では、クライアント認証に使用する証明書をユーザーが選択するUI処理を実現しています。具体的な実装例についてはサンプルをご覧ください。
SelectionCallbackフィールドに指定する、クライアント認証に使用する証明書を返すメソッドは、LocalCertificateSelectionCallbackデリゲート型(System.Net.Security名前空間のクラス)のメソッドです。付属サンプルのLocalCertificateSelectionメソッドでは.NET Framework標準の機能のみを使用して、クライアントの証明書を選択しています。各処理の詳細については、MSDNライブラリなどを参照してください。
あらかじめ証明書を指定しておく方法
サーバーからの要求に対して提示する証明書を、あらかじめ指定しておく方法です。
ローカルシステムの証明書ストアにある任意の証明書を、サーバーとの接続前にCertificatesプロパティ(クライアント証明書のコレクション)にセットしておきます。SelectionCallbackフィールドにメソッドを指定しない場合、サーバーから証明書の要求があったときには、Certificatesプロパティにセットした証明書がクライアント認証に使用されます。
 |
Certificatesプロパティに複数の証明書が存在する場合は、コレクション内の最初の証明書(Certificates(0)またはCertificates[0])がクライアント認証に使用されます。 |
Imports Dart.Mail
Imports Dart.Mail.Pop
Imports System.Net.Security
Imports System.Security.Authentication
Imports System.Security.Cryptography.X509Certificates
Private Sub SecurePopLogin()
' SSL接続の種類を指定します。
Pop1.Session.Security.Encrypt = Encrypt.Implicit
' プロトコルを指定します。
Pop1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls
' サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
Pop1.Session.Security.ValidationCallback = AddressOf remoteCertificateValidation
' POPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
Pop1.Session.RemoteEndPoint = New Dart.Mail.IPEndPoint("pop.myMailServer.com", Pop.GetDefaultPort(Pop1.Session))
Pop1.Session.Username = "myUsername"
Pop1.Session.Password = "myPassword"
' 現在のユーザーの"My"証明書ストアを参照します。
Dim store As New X509Store(StoreName.My, StoreLocation.CurrentUser)
' 証明書ストアを読み取り専用で開きます。
store.Open(OpenFlags.ReadOnly)
' ストア内の証明書をCertificatesプロパティにセットします。
Pop1.Session.Security.Certificates = store.Certificates
' POPサーバーに接続します。
Pop1.Connect()
' POPサーバーにログインし、メールの情報を取得します。
Pop1.Authenticate(True, True)
End Sub
Private Function remoteCertificateValidation(ByVal sender As Object, ByVal remoteCertificate As X509Certificate, _
ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors)
' コードの内容は前述の「SSL証明書を検証せずに接続する」
' または「SSL証明書を検証した上で接続する」を参照してください。
End Function
using Dart.Mail;
using Dart.Mail.Pop;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
private void SecurePopLogin()
{
// SSL接続の種類を指定します。
pop1.Session.Security.Encrypt = Encrypt.Implicit;
// プロトコルを指定します。
pop1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls;
// サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
pop1.Session.Security.ValidationCallback = remoteCertificateValidation;
// POPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
pop1.Session.RemoteEndPoint = new Dart.Mail.IPEndPoint("pop.myMailServer.com", Pop.GetDefaultPort(pop1.Session));
pop1.Session.Username = "myUsername";
pop1.Session.Password = "myPassword";
// 現在のユーザーの"My"証明書ストアを参照します。
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
// 証明書ストアを読み取り専用で開きます。
store.Open(OpenFlags.ReadOnly);
// ストア内の証明書をCertificatesプロパティにセットします。
pop1.Session.Security.Certificates = store.Certificates;
// POPサーバーに接続します。
pop1.Connect();
// POPサーバーにログインします。
pop1.Authenticate(true, true);
}
private bool remoteCertificateValidation(Object sender, X509Certificate remoteCertificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// コードの内容は前述の「SSL証明書を検証せずに接続する」
// または「SSL証明書を検証した上で接続する」を参照してください。
}