VMime Book 日本語訳 第6章 6-7

VMime Book 日本語訳 第6章 6-7
2020-07-01 K.OHWADA

原文
VMime Book: A Developer’s Guide To VMime
https://www.vmime.org/public/documentation/book/vmime-book.pdf

全体目次

第6章 メッセージングサービスの操作

ページ内 目次
6.7 TLS / SSLを使用した安全な接続
6.7.1 はじめに
6.7.2 安全な接続の設定
6.7.2.1 保護されたポートへの接続
6.7.2.2 STARTTLSの使用
6.7.3 証明書の検証
6.7.3.1 仕組み
6.7.3.2 デフォルトの証明書ベリファイアの使用
6.7.3.3 独自の証明書検証ツールの作成
6.7.4 SSL / TLSプロパティ

第6章 メッセージングサービスの操作

Working with Messaging Services

6.7 TLS / SSLを使用した安全な接続

Secured connection using TLS/SSL

6.7.1 はじめに

Introduction

VMimeでTLSサポートを有効にしている場合は、セキュリティで保護された接続を使用するようにメッセージングサービスを構成できます。

RFC-2246からの引用-TLS1.0プロトコル仕様: 「TLSプロトコルは、インターネットを介した通信プライバシーを提供します。 このプロトコルにより、クライアント/サーバーアプリケーションは、盗聴、改ざん、またはメッセージの偽造を防止するように設計された方法で通信できます。」

TLSには次の利点があります。

  • 認証 (authentication): サーバーのIDを確認できます。

  • プライバシー (privacy) : クライアントとサーバー間のデータ送信は、接続の途中で誰かが読み取ることはできません。

  • 整合性 (integrity): クライアントとサーバー間で転送される元のデータは、攻撃者が検出せずに変更することはできません。

注:
SSLTLSの違いは何ですか?
SSLは、Netscapeによって設計されたプロトコルです。 TLSは標準プロトコルであり、SSLプロトコルのバージョン3に部分的に基づいています。 2つのプロトコルは相互運用可能ではありませんが、TLSはSSL3に戻るメカニズムをサポートしています。

VMimeは、セキュリティで保護された接続を使用するための2つの可能性を提供します。

  • 特別なポート (a special port)(IMAPではなくIMAPSなど)でリッスンしているサーバーに接続できます。 これはSSLの従来の使用法ですが、現在は非推奨です。

  • デフォルトのポートでリッスンしているサーバーに接続してから、セキュリティで保護された接続を開始します。 これはSTARTTLSです。

6.7.2 安全な接続の設定

Setting up a secured connection

6.7.2.1 保護されたポートへの接続

Connecting to a “secured” port

従来のSSL / TLSの方法を使用するには、プロトコルの「S」バージョンを使用してサーバーに接続します(たとえば、imapの代わりにimaps)。 これは現在、SMTPPOP3、およびIMAPで使用できます。

vmime::shared ptr <vmime::net::store> store = theSession−>getStore(vmime:: utility :: url(”imaps://example.org”));

6.7.2.2 STARTTLSの使用

Using STARTTLS

STARTTLSメソッドを使用してサービスがセキュリティで保護されたセッションを開始できるようにするには、connection.tlsプロパティを設定するだけです。

theService−>setProperty(”connection. tls”, true);

注:
何らかの理由でセキュリティで保護された接続を開始できない場合、デフォルトの動作は通常の接続でフォールバックします。 STARTTLSが失敗した場合にconnect()を失敗させるには、connection.tls.requiredをtrueに設定します。

6.7.3 証明書の検証

Certificate verification

6.7.3.1 仕組み

How it works

前の例を試した場合、certificateExceptionがスローされた可能性があります。 これは、VMimeのデフォルトの証明書検証ツールが証明書を検証できなかったため、信頼できなかったためです。 基本的に、TLSを使用してサーバーに接続すると、サーバーは証明書チェーンと呼ばれる証明書のリストで応答します(通常、証明書のタイプはX.5093です)。 証明書チェーンは、最初の証明書がサブジェクト証明書、2番目がサブジェクトの発行者1、3番目が発行者の発行者というように順序付けられます。 サーバーが信頼できるかどうかを判断するには、各証明書が有効である(つまり、信頼されている)ことを確認する必要があります。 X.509と証明書の検証の詳細については、関連するウィキペディアの記事を参照してください。 See http://wikipedia.org/wiki/Public_key_certificate

6.7.3.2 デフォルトの証明書ベリファイアの使用

Using the default certificate verifier

デフォルトの証明書ベリファイアは、信頼されているルート(CA)およびユーザー証明書のリストを維持します。 デフォルトでは、リストは空です。したがって、ベリファイアを使用する前に初期化する必要があります。

使用されるアルゴリズムは非常に単純です。 See http://wikipedia.org/wiki/Certification_path_validation_algorithm

  • 1.チェーン内のすべての証明書について、証明書が次の人によって発行されたことを確認します チェーン内の証明書。

  • 2.チェーン内のすべての証明書について、証明書が現時点で有効であることを確認します。

  • 3.最初の証明書のサブジェクト名がサーバーのホスト名と一致することを確認します。

  • 4.サブジェクトの証明書が信頼できるかどうかを判断します。

  • 最初に、チェーンの最後の証明書が、信頼できるサードパーティ(ルートCA)によって発行されたことを確認します。

  • 発行者証明書をルートCAに対して検証できない場合は、サブジェクトの証明書を信頼できる証明書(ユーザーが信頼することを決定した証明書)と比較します。

まず、既存のX.509証明書をロードするためのコードが必要です。

リスト6.13:ファイルからのX.509証明書の読み取り
Reading a X.509 certificate from a file

vmime: : shared ptr <vmime: : security : : cert : : X509Certificate> loadX509CertificateFromFile(const std::string& path)
{
vmime:: utility ::inputStreamAdapter is(certFile);
vmime: : shared ptr <vmime: : security::cert ::X509Certificate> cert ;
cert = vmime::security::cert::X509Certificate::import(is); return cert;
}

次に、loadX509CertificateFromFile関数を使用して証明書をロードし、証明書検証ツールを初期化します。

リスト6.14:デフォルトの証明書ベリファイアの使用
Using the default certificate verifier

vmime::shared ptr <vmime::security : : cert ::defaultCertificateVerifier> vrf = vmime::make shared <vmime::security::cert::defaultCertificateVerifier>();

// Load root CAs (such as Verisign or Thawte)
std::vector <vmime::shared ptr <vmime::security::cert::X509Certificate>> rootCAs;
rootCAs.push back(loadX509CertificateFromFile("/path/to/root−ca1.cer"); rootCAs.push back(loadX509CertificateFromFile("/path/to/root−ca2.cer"); rootCAs.push back(loadX509CertificateFromFile("/path/to/root−ca3.cer");
vrf->setX509RootCAs(rootCAs);

// Then, load certificates that the user explicitely chose to trust
std ::vector <vmime::shared ptr <vmime::security::cert::X509Certificate> > trusted;
 trusted.push_back(loadX509CertificateFromFile("/path/to/trusted−site1.cer");
trusted.push_back(loadX509CertificateFromFile("/path/to/trusted−site2.cer);
vrf−>setX509TrustedCerts(trusted);

6.7.3.3 独自の証明書検証ツールの作成

Writing your own certificate verifier

証明書に対してより複雑な検証を行う必要がある場合は、独自の検証者を作成する必要があります。 ベリファイアは、vmime :: security :: cert :: certificateVerifierクラスから継承し、メソッドverify()を実装する必要があります。 次に、指定された証明書チェーンが信頼できる場合は、関数から戻るか、certificateExceptionをスローします。

次の例は、ユーザーの決定に依存するインタラクティブな証明書ベリファイアを実装する方法を示しています(これは明らかに重大なセキュリティ問題であるため、本番アプリケーションでは使用しないでください)。

リスト6.15:カスタム証明書ベリファイア
A custom certificate verifier

class myCertVerifier : public vmime::security::cert::certificateVerifier {
public :
void verify(vmime::shared ptr <certificateChain> certs) {
// Obtain the subject’s certificate
vmime::shared ptr <vmime::security::cert::certificate> cert = chain−>getAt(0);
std::cout << std::endl;
std::couts << "Server sent a ' " << c e r t −>getType() <<  " ' "
<< "certificate." << std::endl;
std::cout <<  "Do you want to accept this certificate? (Y/n) " ;
std::cout.flush();
std::string answer;
std::getline(std::cin, answer);
if (answer.length() != 0 && (answer[0] == 'Y'  || answer[0] == 'y' ) ) return;
// OK, we trust the certificate

// Don’t trust this certificate
throw vmime::security::cert::certificateException(); 
} };

注:
本番コードでは、ユーザーの決定を覚えておくとよいでしょう。 信頼する証明書とそうでない証明書。基本的なキャッシュの実装については、Example6を参照してください。

最後に、サービスで独自の証明書ベリファイアを使用するには、次のように記述します

theService−>setCertificateVerifier(vmime::make shared <myCertVerifier>());

6.7.4 SSL / TLSプロパティ

SSL/TLS Properties

動作をカスタマイズしたり、TLS / SSL接続でいくつかのオプションを設定したりする場合は、TLSPropertiesオブジェクトを使用して、それをサービスセッションに渡すことができます。 TLS / SSLオプションは、セッションでサービスを作成する前(つまり、セッションでgetStore()またはgetTransport()を呼び出す前)に設定する必要があります。設定しないと、使用されません。

次の例は、TLSの暗号スイート設定を設定する方法を示しています。

リスト6.16:TLS暗号スイートプリファレンスの設定
Setting TLS cipher suite preferences

vmime::shared ptr <vmime::net::session> sess = /∗ ... ∗/;
vmime::shared ptr <vmime::net:: tls ::TLSProperties> tlsProps = vmime::make shared <vmime::net:: tls ::TLSProperties>();
// for OpenSSL
t l s P r o p s −> s e t C i p h e r S t r i n g ( ” H I G H : ! A D H : @ S T R E N G T H ” ) ; 
// forGNUTLS
t l s P r o p s−>s e t C i p h e r S t r i n g ( ”NORMAL:%SSL3 RECORD VERSION” ) ; 
sess−>setTLSProperties(tlsProps);

暗号スイートの文字列の形式と意味は、基盤となるTLSライブラリ(OpenSSLまたはGNU TLS)によって異なることに注意してください。

一般的なセキュリティモードにマップする事前定義された定数を使用して、暗号スイートの設定を設定することもできます。

リスト6.17:事前定義されたモードを使用したTLS暗号スイート設定の設定
Setting TLS cipher suite preferences using predefined modes

sess−>setCipherSuite(vmime::net:: tls ::TLSProperties::CIPHERSUITEHIGH);

次の定数を使用できます。

定数 意味
CIPHERSUITE_HIGH 高暗号化暗号スイート(> 128ビット)
CIPHERSUITE_MEDIUM 中程度の暗号化暗号スイート(> = 128ビット)
CIPHERSUITE_LOW 低暗号化暗号スイート(> = 64ビット)
CIPHERSUITE_DEFAULT デフォルトの暗号スイート