GrapeCity Secure Mail for .NET 4.0J
SSLでIMAPサーバーへ接続する

すべて展開すべて展開
すべて折りたたむすべて折りたたむ
本製品は、IMAP over SSL(IMAPs)およびSTARTTLS(STLS)でのSSL通信に対応しています。

SSLを使用してIMAPサーバーとセキュアなデータのやり取りを行うには、サーバーとの接続時にMailSecurityクラスの各種プロパティを設定し、さらに同クラスのValidationCallbackフィールドにサーバーのSSL証明書を検証するためのプロシージャを指定します。その他の設定や処理は、通常の接続方法と同じです。

IMAP over SSLでSSL通信を行う場合は、EncryptプロパティをImplicit(暗黙的)モードに設定します。この場合、クライアントとサーバーの両方がセッションの間中SSLを使用するという前提で、専用のポート(一般的には993番の通信ポート)を使用して最初からSSL通信が行われます。

STARTTLSでSSL通信を行う場合は、EncryptプロパティをExplicit(明示的)モードに設定します。この場合、クライアントは通常のポート(一般的には143番の通信ポート)を使用してサーバーに接続し、STARTTLSコマンドを実行します。サーバーがこのコマンドに対応しており、肯定的な応答を返してきた場合に、その後のセッションでSSL通信が行われます。

  • SSL通信を行うには、サーバー側でSSLの設定が必要です。
  • サンプルコードの先頭にある名前空間の参照文(Visual BasicではImports、C#ではusing)は、ソースファイルの先頭に記述してください。
  • 本トピック以降のサンプルコードでは、サーバー接続設定に関するコードの記載を省略している場合があります。
SSL証明書を検証せずに接続する

SSLでサーバーに接続する、もっとも単純な方法のサンプルコードを示します。

サーバーからSSL証明書を受信したときに実行するプロシージャを、ValidationCallbackフィールドに指定します。本来このプロシージャには、証明書の妥当性をチェックし、問題がない場合はTrue、問題がある場合はFalseを戻り値として返す処理を実装します。

ただし、以下のサンプルコードではプロシージャ内で証明書の妥当性を判断していません。この場合、サーバーから受信した証明書が信頼されないものであっても、その証明書を承認してSSL通信が確立されます。

この方法は、接続先が信頼できるサーバーであることがあらかじめ分かっている場合や、テスト用サーバーに証明書作成ツール(Makecert.exe)で作成した自己証明書を置いた場合など、SSL証明書の検証を省略しても問題のない条件下のみで利用できます。

Imports Dart.Mail
Imports Dart.Mail.Imap
Imports System.Net.Security
Imports System.Security.Authentication
Imports System.Security.Cryptography.X509Certificates

Private Sub SecureImapLogin()
  ' SSL接続の種類を指定します。
  Imap1.Session.Security.Encrypt = Encrypt.Implicit
        
  ' プロトコルを指定します。
  Imap1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls
        
  ' サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
  Imap1.Session.Security.ValidationCallback = AddressOf remoteCertificateValidation

  ' IMAPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
  Imap1.Session.RemoteEndPoint = New Dart.Mail.IPEndPoint("imap.myMailServer.com", Imap.GetDefaultPort(Imap1.Session))
  Imap1.Session.Username = "myUsername"
  Imap1.Session.Password = "myPassword"

  ' IMAPサーバーに接続します。
  Imap1.Connect()
        
  ' IMAPサーバーにログインします。
  Imap1.Authenticate()
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.Imap;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

private void SecureImapLogin()
{
  // SSL接続の種類を指定します。
  imap1.Session.Security.Encrypt = Encrypt.Implicit;
        
  // プロトコルを指定します。
  imap1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls;
        
  // サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
  imap1.Session.Security.ValidationCallback = remoteCertificateValidation;

  // IMAPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
  imap1.Session.RemoteEndPoint = new Dart.Mail.IPEndPoint("imap.myMailServer.com", Imap.GetDefaultPort(imap1.Session));
  imap1.Session.Username = "myUsername";
  imap1.Session.Password = "myPassword";

  // Imapサーバーに接続します。
  imap1.Connect();
        
  // Imapサーバーにログインします。
  imap1.Authenticate();
}

private bool remoteCertificateValidation(Object sender, X509Certificate remoteCertificate,
  X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
  // SSL証明書の検証を行わず、すべての証明書に対してTrue(問題なし)を返します。
  return true;
}
SSL証明書を検証した上で接続する

前述の「SSL証明書を検証せずに接続する」方法では、サーバーのSSL証明書をすべて「問題なし」と見なしてSSL接続を行っていました。次はSSL証明書を検証した上で、SSLでサーバーに接続するサンプルコードを示します。

サーバーのSSL証明書を検証して、問題がない場合はTrue、問題がある場合はFalseを戻り値として返すプロシージャを作成し、そのプロシージャをValidationCallbackフィールドに指定します。このプロシージャはConnectメソッドの実行時に呼び出されますが、Falseが返された場合はメソッドの処理で例外が発生します。

ValidationCallbackフィールドに指定する、サーバーのSSL証明書を検証するプロシージャは、RemoteCertificateValidationCallbackデリゲート型(System.Net.Security名前空間のクラス)のプロシージャです。以下のサンプルコードでは、一例として、.NET Framework標準の機能のみを使用したremoteCertificateValidationプロシージャで、SSL証明書の検証を行っています。各処理の詳細については、MSDNライブラリなどを参照してください。

Imports Dart.Mail
Imports Dart.Mail.Imap
Imports System.Net.Security
Imports System.Security.Authentication
Imports System.Security.Cryptography.X509Certificates

Private Sub SecureImapLogin()
  ' SSL接続の種類を指定します。
  Imap1.Session.Security.Encrypt = Encrypt.Implicit
    
  ' プロトコルを指定します。
  Imap1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls
    
  ' サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
  Imap1.Session.Security.ValidationCallback = AddressOf remoteCertificateValidation

  ' IMAPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
  Imap1.Session.RemoteEndPoint = New Dart.Mail.IPEndPoint("imap.myMailServer.com", Imap.GetDefaultPort(Imap1.Session))
  Imap1.Session.Username = "myUsername"
  Imap1.Session.Password = "myPassword"

  ' IMAPサーバーに接続します。
  Imap1.Connect()
    
  ' IMAPサーバーにログインします。
  Imap1.Authenticate()
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.Imap;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

private void SecureImapLogin()
{
  // SSL接続の種類を指定します。
  imap1.Session.Security.Encrypt = Encrypt.Implicit;
    
  // プロトコルを指定します。
  imap1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls;
    
  // サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
  imap1.Session.Security.ValidationCallback = remoteCertificateValidation;

  // IMAPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
  imap1.Session.RemoteEndPoint = new Dart.Mail.IPEndPoint("imap.myMailServer.com", Imap.GetDefaultPort(imap1.Session));
  imap1.Session.Username = "myUsername";
  imap1.Session.Password = "myPassword";

  // Imapサーバーに接続します。
  imap1.Connect();
    
  // Imapサーバーにログインします。
  imap1.Authenticate();
}

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;
}
クライアント認証

セキュアなIMAPサーバーは、接続時にクライアントへ証明書を要求し、身元の証明を求める場合があります。このプロセスをクライアント認証といいます。

ユーザーが証明書を選択する方法

サーバーからクライアントへ証明書の要求があった場合に、ユーザーがローカルシステムにある任意の証明書を選択し、クライアント認証に使用する方法です。

ユーザーが選択した証明書を戻り値として返すメソッドを作成し、そのメソッドを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.Imap
Imports System.Net.Security
Imports System.Security.Authentication
Imports System.Security.Cryptography.X509Certificates

Private Sub SecureImapLogin()
  ' SSL接続の種類を指定します。
  Imap1.Session.Security.Encrypt = Encrypt.Implicit
    
  ' プロトコルを指定します。
  Imap1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls
    
  ' サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
  Imap1.Session.Security.ValidationCallback = AddressOf remoteCertificateValidation

  ' IMAPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
  Imap1.Session.RemoteEndPoint = New Dart.Mail.IPEndPoint("imap.myMailServer.com", Imap.GetDefaultPort(Imap1.Session))
  Imap1.Session.Username = "myUsername"
  Imap1.Session.Password = "myPassword"

  ' 現在のユーザーの"My"証明書ストアを参照します。
  Dim store As New X509Store(StoreName.My, StoreLocation.CurrentUser)
    
  ' 証明書ストアを読み取り専用で開きます。
  store.Open(OpenFlags.ReadOnly)
    
  ' ストア内の証明書をCertificatesプロパティにセットします。
  Imap1.Session.Security.Certificates = store.Certificates

  ' IMAPサーバーに接続します。
  Imap1.Connect()
    
  ' IMAPサーバーにログインします。
  Imap1.Authenticate()
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.Imap;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

private void SecureImapLogin()
{
  // SSL接続の種類を指定します。
  imap1.Session.Security.Encrypt = Encrypt.Implicit;
    
  // プロトコルを指定します。
  imap1.Session.Security.Protocols = System.Security.Authentication.SslProtocols.Tls;
    
  // サーバーのSSL証明書を検証する際に呼び出されるコールバック関数を指定します。
  imap1.Session.Security.ValidationCallback = remoteCertificateValidation;

  // IMAPサーバーのサーバー名、ポート番号、ユーザー名、パスワードを指定します。
  imap1.Session.RemoteEndPoint = new Dart.Mail.IPEndPoint("imap.myMailServer.com", Imap.GetDefaultPort(imap1.Session));
  imap1.Session.Username = "myUsername";
  imap1.Session.Password = "myPassword";

  // 現在のユーザーの"My"証明書ストアを参照します。
  X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    
  // 証明書ストアを読み取り専用で開きます。
  store.Open(OpenFlags.ReadOnly);
    
  // ストア内の証明書をCertificatesプロパティにセットします。
  imap1.Session.Security.Certificates = store.Certificates;

  // Imapサーバーに接続します。
  imap1.Connect();
    
  // Imapサーバーにログインします。
  imap1.Authenticate();
}

private bool remoteCertificateValidation(Object sender, X509Certificate remoteCertificate,
  X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
  // コードの内容は前述の「SSL証明書を検証せずに接続する」
  // または「SSL証明書を検証した上で接続する」を参照してください。
}

 

 


© 2003, GrapeCity inc. All rights reserved.