Python 2.7.9は、SSL証明書の検証に関してより厳密になりました。驚くばかり!
以前に動作していたプログラムにCERTIFICATE_VERIFY_FAILEDエラーが表示されるようになったことは驚くことではありません。しかし、証明書の検証を完全に無効にすることなく、それらを機能させることはできません。
1つのプログラムは、urllib2を使用してhttps経由でAmazon S3に接続していました。
ルートCA証明書を「verisign.pem」というファイルにダウンロードして、これを試してみます。
import urllib2, ssl
context = ssl.create_default_context()
context.load_verify_locations(cafile = "./verisign.pem")
print context.get_ca_certs()
urllib2.urlopen("https://bucket.s3.amazonaws.com/", context=context)
ルートCAが4行目で正しく印刷されていても、CERTIFICATE_VERIFY_FAILEDエラーが表示されます。
opensslはこのサーバーに正常に接続できます。実際、CA証明書を取得するために使用したコマンドは次のとおりです。
openssl s_client -showcerts -connect bucket.s3.amazonaws.com:443 < /dev/null
チェーン内の最後の証明書を取得し、それをPEMファイルに入れました。opensslで問題なく読み取れます。これは、次のものを含むVerisign証明書です。
Serial number: 35:97:31:87:f3:87:3a:07:32:7e:ce:58:0c:9b:7e:da
Subject key identifier: 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33
SHA1 fingerprint: F4:A8:0A:0C:D1:E6:CF:19:0B:8C:BC:6F:BC:99:17:11:D4:82:C9:D0
検証を有効にしてこれを機能させる方法はありますか?
問題の原因に関するコメントを要約し、実際の問題をより詳細に説明するには:
OpenSSLクライアントの信頼チェーンを確認すると、次の結果が得られます。
[0] 54:7D:B3:AC:BF:... /CN=*.s3.amazonaws.com
[1] 5D:EB:8F:33:9E:... /CN=VeriSign Class 3 Secure Server CA - G3
[2] F4:A8:0A:0C:D1:... /CN=VeriSign Class 3 Public Primary Certification Authority - G5
[OT] A1:DB:63:93:91:... /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
最初の証明書[0]は、サーバーによって送信されたリーフ証明書です。次の証明書[1]および[2]は、サーバーによって送信されるチェーン証明書です。最後の証明書[OT]は信頼されたルート証明書であり、サーバーによって送信されませんが、信頼されたCAのローカルストレージにあります。チェーン内の各証明書は次の証明書によって署名され、最後の証明書[OT]が信頼されているため、信頼チェーンは完了しています。
ブラウザで代わりにトラストチェーンを確認すると(例:Google Chrome NSSライブラリを使用))、次のチェーンを取得します。
[0] 54:7D:B3:AC:BF:... /CN=*.s3.amazonaws.com
[1] 5D:EB:8F:33:9E:... /CN=VeriSign Class 3 Secure Server CA - G3
[NT] 4E:B6:D5:78:49:... /CN=VeriSign Class 3 Public Primary Certification Authority - G5
ここでは、[0]と[1]がサーバーによって再度送信されますが、[NT]は信頼されたルート証明書です。これはサブジェクトからはチェーン証明書とまったく同じように見えますが[2]、指紋は証明書が異なると言います。証明書[2]と[NT]を詳しく見ると、証明書内の公開鍵が同じであるため、[2]と[NT]の両方を使用して[ 1]したがって、信頼チェーンを構築するために使用できます。
つまり、サーバーはすべての場合に同じ証明書チェーンを送信しますが、信頼されたルート証明書までチェーンを検証する方法は複数あります。これを行う方法は、SSLライブラリと既知の信頼されたルート証明書に依存します。
[0] (*.s3.amazonaws.com)
|
[1] (Verisign G3) --------------------------\
| |
/------------------ [2] (Verisign G5 F4:A8:0A:0C:D1...) |
| |
| certificates sent by server |
.....|...............................................................|................
| locally trusted root certificates |
| |
[OT] Public Primary Certification Authority [NT] Verisign G5 4E:B6:D5:78:49
OpenSSL library Google Chrome (NSS library)
ただし、検証が失敗した理由は疑問のままです。あなたがしたことは、ブラウザ(Verisign G5 4E:B6:D5:78:49)で使用される信頼されたルート証明書をOpenSSLと一緒に取得することでした。ただし、ブラウザ(NSS)とOpenSSLでの検証はわずかに異なります。
この微妙な違いにより、OpenSSLはチェーン[0]、[1]、[2]をルート証明書[NT]に対して検証できません。この証明書はチェーン[2]の最新の要素に署名せず、代わりに[1] 。サーバーが[0]、[1]のチェーンのみを送信する場合、検証は成功します。
これは 長い既知のバグ であり、 パッチ が存在します。OpenSSL1.0.2でX509_V_FLAG_TRUSTED_FIRST
オプション。