18.2. ssl — ソケットオブジェクトに対する TLS/SSL ラッパー

Source code: Lib/ssl.py


このモジュールは Transport Layer Security ( “Secure Sockets Layer” という名前でよく知られています) 暗号化と、クライアントサイド、サーバサイド両方のネットワークソケットのためのピア認証の仕組みを提供しています。このモジュールは OpenSSL ライブラリを利用しています。 OpenSSL は、すべてのモダンな Unix システム、 Windows 、 Mac OS X 、その他幾つかの OpenSSL がインストールされているプラットフォームで利用できます。

注釈

OSのソケットAPIに対して実装されているので、幾つかの挙動はプラットフォーム依存になるかもしれません。インストールされているOpenSSLのバージョンの違いも挙動の違いの原因になるかもしれません。例えば、TLSv1.1, TLSv1.2 は openssl version 1.0.1 以降でのみ利用できます。

警告

セキュリティで考慮すべき点 を読まずにこのモジュールを使用しないでください。SSL のデフォルト設定はアプリケーションに十分ではないので、読まない場合はセキュリティに誤った意識を持ってしまうかもしれません。

このセクションでは、 ssl モジュールのオブジェクトと関数を解説します。 TLS, SSL, 証明書に関するより一般的な情報は、末尾にある “See Also” のセクションを参照してください。

このモジュールは ssl.SSLSocket クラスを提供します。このクラスは socket.socket クラスを継承していて、ソケットで通信されるデータをSSLで暗号化・復号するソケットに似たラッパーになります。また、このクラスは、接続の相手側からの証明書を取得する getpeercert() メソッドや、セキュア接続で使うための暗号方式を取得する cipher() メソッドのような追加のメソッドをサポートしています。

より洗練されたアプリケーションのために、 ssl.SSLContext クラスが設定と証明書の管理の助けとなるでしょう。それは SSLContext.wrap_socket() メソッドを通して SSL ソケットを作成することで引き継がれます。

バージョン 3.6 で変更: OpenSSL 0.9.8, 1.0.0, 1.0.1 は廃止されており、もはやサポートされていません。ssl モジュールは、将来的に OpenSSL 1.0.2 または 1.1.0 を必要とするようになります。

18.2.1. 関数、定数、例外

exception ssl.SSLError

(現在のところ OpenSSL ライブラリによって提供されている)下層の SSL 実装からのエラーを伝えるための例外です。このエラーは、低レベルなネットワークの上に載っている、高レベルな暗号化と認証レイヤーでの問題を通知します。このエラーは OSError のサブタイプです。 SSLError インスタンスのエラーコードとメッセージは OpenSSL ライブラリによるものです。

バージョン 3.3 で変更: SSLError は以前は socket.error のサブタイプでした。

library

エラーが起こった OpenSSL サブモジュールを示すニーモニック文字列で、 SSL, PEM, X509 などです。取り得る値は OpenSSL のバージョンに依存します。

バージョン 3.3 で追加.

reason

エラーが起こった原因を示すニーモニック文字列で、 CERTIFICATE_VERIFY_FAILED などです。取り得る値は OpenSSL のバージョンに依存します。

バージョン 3.3 で追加.

exception ssl.SSLZeroReturnError

読み出しあるいは書き込みを試みようとした際に SSL コネクションが行儀よく閉じられてしまった場合に送出される SSLError サブクラス例外です。これは下層の転送(read TCP)が閉じたことは意味しないことに注意してください。

バージョン 3.3 で追加.

exception ssl.SSLWantReadError

読み出しあるいは書き込みを試みようとした際に、リクエストが遂行される前に下層の TCP 転送で受け取る必要があるデータが不足した場合に non-blocking SSL socket によって送出される SSLError サブクラス例外です。

バージョン 3.3 で追加.

exception ssl.SSLWantWriteError

読み出しあるいは書き込みを試みようとした際に、リクエストが遂行される前に下層の TCP 転送が送信する必要があるデータが不足した場合に non-blocking SSL socket によって送出される SSLError サブクラス例外です。

バージョン 3.3 で追加.

exception ssl.SSLSyscallError

SSL ソケット上で操作を遂行しようとしていてシステムエラーが起こった場合に送出される SSLError サブクラス例外です。残念ながら元となった errno 番号を調べる簡単な方法はありません。

バージョン 3.3 で追加.

exception ssl.SSLEOFError

SSL コネクションが唐突に打ち切られた際に送出される SSLError サブクラス例外です。一般的に、このエラーが起こったら下層の転送を再利用しようと試みるべきではありません。

バージョン 3.3 で追加.

exception ssl.CertificateError

(ホスト名のミスマッチのような)証明書のエラーを通知するために送出されます。ただし、OpenSSL によって検出された場合の証明書エラーは SSLError です。

18.2.1.1. ソケットの作成

以下に示す関数は、スタンドアロンでソケットを作りたい場合に使います。Python 3.2 からは、これよりもっと柔軟な SSLContext.wrap_socket() が使えます。

ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None)

socket.socket のインスタンス sock を受け取り、 socket.socket のサブタイプである ssl.SSLSocket のインスタンスを返します。 ssl.SSLSocket は低レイヤのソケットをSSLコンテキストでラップします。 sockSOCK_STREAM ソケットでなければなりません; ほかのタイプのソケットはサポートされていません。

クライアントサイドソケットにおいて、コンテキストの生成は遅延されます。つまり、低レイヤのソケットがまだ接続されていない場合、コンテキストの生成はそのソケットの connect() メソッドが呼ばれた後に行われます。サーバサイドソケットの場合、そのソケットに接続先が居なければそれは listen 用ソケットだと判断されます。 accept() メソッドで生成されるクライアント接続に対してのサーバサイド SSLラップは自動的に行われます。 wrap_socket()SSLError を送出することがあります。

オプションの keyfilecertfile 引数は、接続のこちら側を識別するために利用される証明書を含むファイルを指定します。証明書がどのように certfile に格納されるかについてのより詳しい情報は、 証明書 を参照してください。

server_side 引数は真偽値で、このソケットがサーバサイドとクライアントサイドのどちらの動作をするのかを指定します。

cert_reqs 引数は、接続の相手側からの証明書を必要とするかどうかと、証明書が提供された場合にそれを検証(validate)するかどうかを指定します。これは次の3つの定数のどれかで無ければなりません: CERT_NONE (証明書は無視されます), CERT_OPTIONAL (必要としないが、提供された場合は検証します), CERT_REQUIRED (証明書を必要とし、検証します)。この引数が CERT_NONE 以外だった場合、 ca_certs 引数は CA 証明書ファイルを指定していなければなりません。

ca_certs ファイルは、接続の相手側から渡された証明書を検証するために使う、一連のCA証明書を結合したものを含んでいます。このファイル内にどう証明書を並べるかについての詳しい情報は 証明書 を参照してください。

ssl_version 引数は、使用するSSLプロトコルのバージョンを指定します。通常、サーバが特定のプロトコルバージョンを選択し、クライアントはサーバの選択したプロトコルを受け入れなければなりません。ほとんどのバージョンは他のバージョンと互換性がありません。この引数が指定されない場合、デフォルトは PROTOCOL_TLS になります。これは、他のバージョンとの互換性が最も高いバージョンです。

次のテーブルは、どのクライアントのバージョンがどのサーバのバージョンに接続できるかを示しています:

client / server SSLv2 SSLv3 TLS TLSv1 TLSv1.1 TLSv1.2
SSLv2 yes no no [1] no no no
SSLv3 no yes no [2] no no no
TLS (SSLv23) no [1] no [2] yes yes yes yes
TLSv1 no no yes yes no no
TLSv1.1 no no yes no yes no
TLSv1.2 no no yes no no yes

脚注

[1](1, 2)

SSLContext では、デフォルトで OP_NO_SSLv2 によりSSLv2 が無効になっています。

[2](1, 2)

SSLContext では、デフォルトで OP_NO_SSLv3 により SSLv3 が無効になっています。

注釈

どの接続が成功するかは、 OpenSSL のバージョンに依存して大きく変わります。例えば、OpenSSL 1.0.0 以前は、SSLv23 クライアントは常に SSLv2 接続を試みていました。

ciphers 引数はこの SSL オブジェクトで利用可能な暗号化アルゴリズム群を指定します。これは、 OpenSSL cipher list format 形式で書かれた文字列でなければなりません。

do_handshake_on_connect 引数は、 socket.connect() の後に自動的に SSLハンドシェイクを行うか、それともアプリケーションが明示的に SSLSocket.do_handshake() メソッドを実行するかを指定します。 SSLSocket.do_handshake() を明示的に呼びだすことで、ハンドシェイクによるソケットI/Oのブロッキング動作を制御できます。

suppress_ragged_eofs 引数は、 SSLSocket.recv() メソッドが、接続先から予期しないEOF を受け取った時に通知する方法を指定します。 True (デフォルト) の場合、下位のソケットレイヤーから予期せぬEOFエラーが来た場合、通常のEOF (空のバイト列オブジェクト)を返します。 False の場合、呼び出し元に例外を投げて通知します。

バージョン 3.2 で変更: 新しいオプション引数 ciphers

18.2.1.2. コンテキストの作成

コンビニエンス関数が、共通の目的で使用される SSLContext オブジェクトを作成するのに役立ちます。

ssl.create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)

新規の SSLContext オブジェクトを、与えられた purpose のデフォルト設定で返します。設定は ssl モジュールで選択され、通常は SSLContext のコンストラクタを直接呼び出すよりも高いセキュリティレベルを表現します。

cafile, capath, cadata は証明書の検証で信用するオプションの CA 証明書で、 SSLContext.load_verify_locations() のものと同じです。これら 3 つすべてが None であれば、この関数は代わりにシステムのデフォルトの CA 証明書を信用して選択することができます。

設定は、 PROTOCOL_TLS, OP_NO_SSLv2, RC4 と非認証暗号化スイート以外の、高度暗号化スイートを利用した OP_NO_SSLv3 です。SERVER_AUTHpurpose として渡すと、verify_modeCERT_REQUIRED に設定し、 CA 証明書をロードする (cafile, capath, cadata の少なくとも1つが与えられている場合) か、SSLContext.load_default_certs() を使用してデフォルトの CA 証明書をロードします。

注釈

プロトコル、オプション、暗号方式その他の設定は、事前に非推奨の状態にすることなく、もっと制限の強い値に変更される場合があります。これらの値は、互換性と安全性との妥当なバランスをとって決められます。

もしもあなたのアプリケーションが特定の設定を必要とする場合、 SSLContext を作って自分自身で設定を適用すべきです。

注釈

ある種の古いクライアントやサーバが接続しようと試みてきた場合に、この関数で作られた SSLContext が “Protocol or cipher suite mismatch” で始まるエラーを起こすのを目撃したらそれは、この関数が OP_NO_SSLv3 を使って除外している SSL 3.0 しかサポートしていないのでしょう。SSL 3.0 は 完璧にぶっ壊れている ことが広く知られています。それでもまだこの関数を使って、ただし SSL 3.0 接続を許可したいと望むならば、これをこのように再有効化できます:

ctx = ssl.create_default_context(Purpose.CLIENT_AUTH)
ctx.options &= ~ssl.OP_NO_SSLv3

バージョン 3.4 で追加.

バージョン 3.4.4 で変更: デフォルトの暗号設定から RC4 が除かれました。

バージョン 3.6 で変更: デフォルトの暗号化文字列に ChaCha20/Poly1305 が追加されました。

デフォルトの暗号化文字列から 3DES が除かれました。

18.2.1.3. 乱数生成

ssl.RAND_bytes(num)

暗号学的に強固な擬似乱数の num バイトを返します。擬似乱数生成器に十分なデータでシードが与えられていない場合や、現在の RANDOM メソッドに操作がサポートされていない場合は SSLError を送出します。 RAND_status() を使って擬似乱数生成器の状態をチェックできます。 RAND_add() を使って擬似乱数生成器にシードを与えることができます。

ほとんどすべてのアプリケーションでは os.urandom() が望ましいです。

暗号論的擬似乱数生成器に要求されることについては Wikipedia の記事 Cryptographically secure pseudorandom number generator (CSPRNG) (日本語版: 暗号論的擬似乱数生成器) を参照してください。

バージョン 3.3 で追加.

ssl.RAND_pseudo_bytes(num)

(bytes, is_cryptographic) タプルを返却: bytes は長さ num の擬似乱数バイト列、 is_cryptographic は、生成されたバイト列が暗号として強ければ True 。 操作が現在使われている RAND メソッドでサポートされていなければ、 SSLError が送出されます。

生成される擬似乱数バイトシーケンスは十分な長さであれば一意にはなるでしょうが、必ずしも予測不可能とは言えません。これは非暗号目的、あるいは暗号化プロトコルでの若干の用途に使われますが、普通は鍵生成などには使いません。

ほとんどすべてのアプリケーションでは os.urandom() が望ましいです。

バージョン 3.3 で追加.

バージョン 3.6 で撤廃: OpenSSL は ssl.RAND_pseudo_bytes() を廃止しました。代わりに ssl.RAND_bytes() を使用してください。

ssl.RAND_status()

SSL 擬似乱数生成器が十分なランダム性(randomness)を受け取っている時に True を、それ以外の場合は False を返します。 ssl.RAND_egd()ssl.RAND_add() を使って擬似乱数生成機にランダム性を加えることができます。

ssl.RAND_egd(path)

もしエントロピー収集デーモン(EGD=entropy-gathering daemon)が動いていて、 path がEGDへのソケットのパスだった場合、この関数はそのソケットから 256バイトのランダム性を読み込み、SSL擬似乱数生成器にそれを渡すことで、生成される暗号鍵のセキュリティを向上させることができます。これは、より良いランダム性のソースが無いシステムでのみ必要です。

エントロピー収集デーモンについては、 http://egd.sourceforge.net/http://prngd.sourceforge.net/ を参照してください。

利用出来る環境: LibreSSL および 1.1.0 を超えるバージョンの OpenSSL では利用できません。

ssl.RAND_add(bytes, entropy)

与えられた bytes をSSL擬似乱数生成器に混ぜます。 entropy 引数(float値)は、その文字列に含まれるエントロピーの下限(lower bound)です。 (なので、いつでも 0.0 を使うことができます。) エントロピーのソースについてのより詳しい情報は、 RFC 1750 を参照してください。

バージョン 3.5 で変更: 書き込み可能な bytes-like object を使用できるようになりました。

18.2.1.4. 証明書の取り扱い

ssl.match_hostname(cert, hostname)

(SSLSocket.getpeercert() が返してきたようなデコードされたフォーマットの) cert が、与えられた hostname に合致するかを検証します。HTTPS サーバの身元をチェックするために適用されるルールは RFC 2818, RFC 6125 で概説されているものです。HTTPS に加え、この関数は他の SSL ベースのプロトコル、例えば FTPS, IMAPS, POPS などのサーバの身元をチェックするのに相応しいはずです。

失敗すれば CertificateError が送出されます。成功すれば、この関数は何も返しません:

>>> cert = {'subject': ((('commonName', 'example.com'),),)}
>>> ssl.match_hostname(cert, "example.com")
>>> ssl.match_hostname(cert, "example.org")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/py3k/Lib/ssl.py", line 130, in match_hostname
ssl.CertificateError: hostname 'example.org' doesn't match 'example.com'

バージョン 3.2 で追加.

バージョン 3.3.3 で変更: この関数は RFC 6125 の section 6.4.3 に従うようになりましたので、マルチプルワイルドカード(例. *.*.com*a*.example.org) にも国際化ドメイン名 (IDN=internationalized domain name)フラグメント内部に含まれるワイルドカードのどちらにも合致しません。 www*.xn--pthon-kva.org のような IDN A-labels はまだサポートしますが、 x*.python.org はもはや xn--tda.python.org には合致しません。

バージョン 3.5 で変更: 認定書の subjectAltName フィールドで提示されている場合、IP アドレスの一致がサポートされるようになりました。

ssl.cert_time_to_seconds(cert_time)

cert_time として証明書内の “notBefore” や “notAfter” の "%b %d %H:%M:%S %Y %Z" strptime フォーマット (C locale) 日付を渡すと、エポックからの積算秒を返します。

例です。 :

>>> import ssl
>>> timestamp = ssl.cert_time_to_seconds("Jan  5 09:34:43 2018 GMT")
>>> timestamp
1515144883
>>> from datetime import datetime
>>> print(datetime.utcfromtimestamp(timestamp))
2018-01-05 09:34:43

“notBefore” や “notAfter” の日付には GMT を使わなければなりません(RFC 5280)。

バージョン 3.5 で変更: 入力文字列に指定された ‘GMT’ タイムゾーンを UTC として解釈するようになりました。以前はローカルタイムで解釈していました。また、整数を返すようになりました(入力に含まれる秒の端数を含まない)。

ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None)

SSLで保護されたサーバーのアドレス addr を (hostname, port-number) の形で受け取り、そのサーバーから証明書を取得し、それを PEMエンコードされた文字列として返します。 ssl_version が指定された場合は、サーバーに接続を試みるときにそのバージョンのSSLプロトコルを利用します。 ca_certs が指定された場合、それは wrap_socket() の同名の引数と同じフォーマットで、ルート証明書のリストを含むファイルでなければなりません。この関数はサーバー証明書をルート証明書リストに対して認証し、認証が失敗した場合にこの関数も失敗します。

バージョン 3.3 で変更: この関数はIPv6互換になりました。

バージョン 3.5 で変更: ssl_version のデフォルトが、最近のサーバへの最大限の互換性のために PROTOCOL_SSLv3 から PROTOCOL_TLS に変更されました。

ssl.DER_cert_to_PEM_cert(DER_cert_bytes)

DERエンコードされたバイト列として与えられた証明書から、 PEMエンコードされたバージョンの同じ証明書を返します。

ssl.PEM_cert_to_DER_cert(PEM_cert_string)

PEM 形式のASCII文字列として与えられた証明書から、同じ証明書をDERエンコードしたバイト列を返します。

ssl.get_default_verify_paths()

OpenSSL デフォルトの cafile, capath を指すパスを名前付きタプルで返します。パスは SSLContext.set_default_verify_paths() で使われるものと同じです。戻り値は named tuple DefaultVerifyPaths です:

  • cafile - cafile の解決済みパス、またはファイルが存在しない場合は None

  • capath - capath の解決済みパス、またはディレクトリが存在しない場合は None

  • openssl_cafile_env - cafile を指す OpenSSL の環境変数

  • openssl_cafile - OpenSSL にハードコードされた cafile のパス

  • openssl_capath_env - capath を指す OpenSSL の環境変数

  • openssl_capath - OpenSSL にハードコードされた capath のパス

利用出来る環境: LibreSSL では環境変数 openssl_cafile_envopenssl_capath_env が無視されます

バージョン 3.4 で追加.

ssl.enum_certificates(store_name)

Windows のシステム証明書ストアより証明書を抽出します。 store_nameCA, ROOT, MY のうちどれか一つでしょう。Windows は追加の証明書ストアを提供しているかもしれません。

この関数はタプル (cert_bytes, encoding_type, trust) のリストで返します。encoding_type は cert_bytes のエンコーディングを表します。X.509 ASN.1 に対する x509_asn か PKCS#7 ASN.1 データに対する pkcs_7_asn のいずれかです。trust は、証明書の目的を、OIDS を内容に持つ set として表すか、または証明書がすべての目的で信頼できるならば True です。

以下はプログラム例です:

>>> ssl.enum_certificates("CA")
[(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}),
 (b'data...', 'x509_asn', True)]

利用できる環境 : Windows.

バージョン 3.4 で追加.

ssl.enum_crls(store_name)

Windows のシステム証明書ストアより CRLs を抽出します。 store_nameCA, ROOT, MY のうちどれか一つでしょう。Windows は追加の証明書ストアを提供しているかもしれません。

この関数はタプル (cert_bytes, encoding_type, trust) のリストで返します。encoding_type は cert_bytes のエンコーディングを表します。X.509 ASN.1 に対する x509_asn か PKCS#7 ASN.1 データに対する pkcs_7_asn のいずれかです。

利用できる環境 : Windows.

バージョン 3.4 で追加.

18.2.1.5. 定数

すべての定数が enum.IntEnum コレクションまたは enum.IntFlag コレクションになりました。

バージョン 3.6 で追加.

ssl.CERT_NONE

SSLContext.verify_mode または wrap_socket()cert_reqs パラメータに使用する値です。このモード(これがデフォルトです)では、ソケット接続先からの証明書やその認証を必要としません。接続先から証明書を受け取っても検証は試みられません。

このドキュメントの下の方の、 セキュリティで考慮すべき点 に関する議論を参照してください。

ssl.CERT_OPTIONAL

SSLContext.verify_mode または wrap_socket()cert_reqs パラメータに使用する値です。このモードでは、ソケット接続先からの証明書やその認証を必要としませんが、証明書が提供されれば検証が試みられ、検証失敗時には SSLError が送出されます。

この設定では、正当なCA証明書のセットを SSLContext.load_verify_locations() または wrap_socket()ca_certs パラメータのどちらかに渡す必要があります。

ssl.CERT_REQUIRED

SSLContext.verify_mode または wrap_socket()cert_reqs パラメータに使用する値です。このモードでは、ソケット接続先からの証明書やその認証を必要とされ、証明書が提供されないかその検証失敗時には SSLError が送出されます。

この設定では、正当なCA証明書のセットを SSLContext.load_verify_locations() または wrap_socket()ca_certs パラメータのどちらかに渡す必要があります。

class ssl.VerifyMode

CERT_* 定数の enum.IntEnum コレクションです。

バージョン 3.6 で追加.

ssl.VERIFY_DEFAULT

SSLContext.verify_flags に渡せる値です。このモードでは、証明書失効リスト(CRLs)はチェックされません。デフォルトでは OpenSSL は CRLs を必要ともしませんし検証にも使いません。

バージョン 3.4 で追加.

ssl.VERIFY_CRL_CHECK_LEAF

SSLContext.verify_flags に渡せる値です。このモードでは、接続先の証明書のチェックのみで仲介の CA 証明書はチェックしません。接続先証明書の発行者(その CA の直接の祖先)によって署名された妥当な CRL が必要です。 SSLContext.load_verify_locations が相応しいものをロードしていなければ、検証は失敗するでしょう。

バージョン 3.4 で追加.

ssl.VERIFY_CRL_CHECK_CHAIN

SSLContext.verify_flags に渡せる値です。このモードでは、接続先の証明書チェイン内のすべての証明書についての CRLs がチェックされます。

バージョン 3.4 で追加.

ssl.VERIFY_X509_STRICT

SSLContext.verify_flags に渡せる値で、壊れた X.509 証明書に対するワークアラウンドを無効にします。

バージョン 3.4 で追加.

ssl.VERIFY_X509_TRUSTED_FIRST

SSLContext.verify_flags に渡せる値です。OpenSSL に対し、証明書検証のために信頼チェインを構築する際、信頼できる証明書を選ぶように指示します。これはデフォルトで有効にされています。

バージョン 3.4.4 で追加.

class ssl.VerifyFlags

VERIFY_* 定数の enum.IntFlag コレクションです。

バージョン 3.6 で追加.

ssl.PROTOCOL_TLS

クライアントとサーバの両方がサポートするプロトコルバージョンのうち、最も大きなものを選択します。名前に反して、このオプションは “SSL” と “TLS” プロトコルのいずれも選択する場合があります。

バージョン 3.6 で追加.

ssl.PROTOCOL_TLS_CLIENT

PROTOCOL_SSLv23 のような最高のプロトコルバージョンを自動的にネゴシエートしますが、クライアントサイドの SSLSocket 接続しかサポートしません。このプロトコルでは、デフォルトで CERT_REQUIREDcheck_hostname が有効になっています。

バージョン 3.6 で追加.

ssl.PROTOCOL_TLS_SERVER

PROTOCOL_SSLv23 のような最高のプロトコルバージョンを自動的にネゴシエートしますが、サーバサイドの SSLSocket 接続しかサポートしません。

バージョン 3.6 で追加.

ssl.PROTOCOL_SSLv23

data:PROTOCOL_TLS のエイリアスです。

バージョン 3.6 で撤廃: 代わりに PROTOCOL_TLS を使用してください。

ssl.PROTOCOL_SSLv2

チャンネル暗号化プロトコルとして SSL バージョン2を選択します。

このプロトコルは、 OpenSSL が OPENSSL_NO_SSL2 フラグが有効な状態でコンパイルされている場合には利用できません。

警告

SSL version 2 は非セキュアです。このプロトコルは強く非推奨です。

バージョン 3.6 で撤廃: OpenSSL は SSLv2 へのサポートを打切りました。

ssl.PROTOCOL_SSLv3

チャンネル暗号化プロトコルとしてSSLバージョン3を選択します。

このプロトコルは、 OpenSSL が OPENSSL_NO_SSLv3 フラグが有効な状態でコンパイルされている場合には利用できません。

警告

SSL version 3 は非セキュアです。このプロトコルは強く非推奨です。

バージョン 3.6 で撤廃: OpenSSL は全てのバージョン固有のプロトコルを廃止しました。デフォルトプロトコルの PROTOCOL_TLSOP_NO_SSLv3 などのフラグをつけて使用してください。

ssl.PROTOCOL_TLSv1

チャンネル暗号化プロトコルとしてTLSバージョン1.0を選択します。

バージョン 3.6 で撤廃: OpenSSL は全てのバージョン固有のプロトコルを廃止しました。デフォルトプロトコルの PROTOCOL_TLSOP_NO_SSLv3 などのフラグをつけて使用してください。

ssl.PROTOCOL_TLSv1_1

チャンネル暗号化プロトコルとしてTLSバージョン1.1を選択します。 openssl version 1.0.1+ のみで利用可能です。

バージョン 3.4 で追加.

バージョン 3.6 で撤廃: OpenSSL は全てのバージョン固有のプロトコルを廃止しました。デフォルトプロトコルの PROTOCOL_TLSOP_NO_SSLv3 などのフラグをつけて使用してください。

ssl.PROTOCOL_TLSv1_2

チャンネル暗号化プロトコルとしてTLSバージョン1.2を選択します。これは最も現代的で、接続の両サイドが利用できる場合は、たぶん最も安全な選択肢です。 openssl version 1.0.1+ のみで利用可能です。

バージョン 3.4 で追加.

バージョン 3.6 で撤廃: OpenSSL は全てのバージョン固有のプロトコルを廃止しました。デフォルトプロトコルの PROTOCOL_TLSOP_NO_SSLv3 などのフラグをつけて使用してください。

ssl.OP_ALL

相手にする SSL 実装のさまざまなバグを回避するためのワークアラウンドを有効にします。このオプションはデフォルトで有効です。これを有効にする場合 OpenSSL 用の同じ意味のフラグ SSL_OP_ALL をセットする必要はありません。

バージョン 3.2 で追加.

ssl.OP_NO_SSLv2

SSLv2 接続が行われないようにします。このオプションは PROTOCOL_TLS と組み合わされている場合にのみ適用されます。ピアがプロトコルバージョンとして SSLv2 を選択しないようにします。

バージョン 3.2 で追加.

バージョン 3.6 で撤廃: SSLv2 は非推奨です

ssl.OP_NO_SSLv3

SSLv3 接続が行われないようにします。このオプションは PROTOCOL_TLS と組み合わされている場合にのみ適用されます。ピアがプロトコルバージョンとして SSLv3 を選択しないようにします。

バージョン 3.2 で追加.

バージョン 3.6 で撤廃: SSLv3 は非推奨です

ssl.OP_NO_TLSv1

TLSv1 接続が行われないようにします。このオプションは PROTOCOL_TLS と組み合わされている場合にのみ適用されます。ピアがプロトコルバージョンとして TLSv1 を選択しないようにします。

バージョン 3.2 で追加.

ssl.OP_NO_TLSv1_1

TLSv1.1 接続が行われないようにします。このオプションは PROTOCOL_TLS と組み合わされている場合にのみ適用されます。ピアがプロトコルバージョンとして TLSv1.1 を選択しないようにします。openssl バージョン 1.0.1 以降でのみ利用できます。

バージョン 3.4 で追加.

ssl.OP_NO_TLSv1_2

TLSv1.2 接続が行われないようにします。このオプションは PROTOCOL_TLS と組み合わされている場合にのみ適用されます。ピアがプロトコルバージョンとして TLSv1.2 を選択しないようにします。openssl バージョン 1.0.1 以降でのみ利用できます。

バージョン 3.4 で追加.

ssl.OP_CIPHER_SERVER_PREFERENCE

暗号の優先順位として、クライアントのものではなくサーバのものを使います。このオプションはクライアントソケットと SSLv2 のサーバソケットでは効果はありません。

バージョン 3.3 で追加.

ssl.OP_SINGLE_DH_USE

SSL セッションを区別するのに同じ DH 鍵を再利用しないようにします。これはセキュリティを向上させますが、より多くの計算機リソースを必要とします。このオプションはサーバソケットに適用されます。

バージョン 3.3 で追加.

ssl.OP_SINGLE_ECDH_USE

SSL セッションを区別するのに同じ ECDH 鍵を再利用しないようにします。これはセキュリティを向上させますが、より多くの計算機リソースを必要とします。このオプションはサーバソケットに適用されます。

バージョン 3.3 で追加.

ssl.OP_NO_COMPRESSION

SSL チャネルでの圧縮を無効にします。これはアプリケーションのプロトコルが自身の圧縮方法をサポートする場合に有用です。

このオプションは OpenSSL 1.0.0以降のみで使用できます。

バージョン 3.3 で追加.

class ssl.Options

OP_* 定数の enum.IntFlag コレクションです。

ssl.OP_NO_TICKET

クライアントサイドがセッションチケットをリクエストしないようにします。

バージョン 3.6 で追加.

ssl.HAS_ALPN

OpenSSL ライブラリが、組み込みで RFC 7301 で記述されている Application-Layer Protocol Negotiation TLS 拡張をサポートしているかどうか。

バージョン 3.5 で追加.

ssl.HAS_ECDH

OpenSSL ライブラリが、組み込みの楕円曲線ディフィー・ヘルマン鍵共有をサポートしているかどうか。これは、ディストリビュータが明示的に無効にしていない限りは、真であるはずです。

バージョン 3.3 で追加.

ssl.HAS_SNI

OpenSSL ライブラリが、組み込みで (RFC 4366 で記述されている) Server Name Indication 拡張をサポートしているかどうか。

バージョン 3.2 で追加.

ssl.HAS_NPN

OpenSSL ライブラリが、組み込みで、NPN draft specification で記述されている Next Protocol Negotiation をサポートしているかどうか。 true であれば、サポートしたいプロトコルを SSLContext.set_npn_protocols() メソッドで提示することができます。

バージョン 3.3 で追加.

ssl.CHANNEL_BINDING_TYPES

サポートされている TLS のチャネルバインディングのタイプのリスト。リスト内の文字列は SSLSocket.get_channel_binding() の引数に渡せます。

バージョン 3.3 で追加.

ssl.OPENSSL_VERSION

インタプリタによってロードされた OpenSSL ライブラリのバージョン文字列:

>>> ssl.OPENSSL_VERSION
'OpenSSL 1.0.2k  26 Jan 2017'

バージョン 3.2 で追加.

ssl.OPENSSL_VERSION_INFO

OpenSSL ライブラリのバージョン情報を表す5つの整数のタプル:

>>> ssl.OPENSSL_VERSION_INFO
(1, 0, 2, 11, 15)

バージョン 3.2 で追加.

ssl.OPENSSL_VERSION_NUMBER

1つの整数の形式の、 OpenSSL ライブラリの生のバージョン番号:

>>> ssl.OPENSSL_VERSION_NUMBER
268443839
>>> hex(ssl.OPENSSL_VERSION_NUMBER)
'0x100020bf'

バージョン 3.2 で追加.

ssl.ALERT_DESCRIPTION_HANDSHAKE_FAILURE
ssl.ALERT_DESCRIPTION_INTERNAL_ERROR
ALERT_DESCRIPTION_*

RFC 5246 その他からのアラートの種類です。 IANA TLS Alert Registry にはこのリストとその意味が定義された RFC へのリファレンスが含まれています。

SSLContext.set_servername_callback() でのコールバック関数の戻り値として使われます。

バージョン 3.4 で追加.

class ssl.AlertDescription

ALERT_DESCRIPTION_* 定数の enum.IntEnum コレクションです。

バージョン 3.6 で追加.

Purpose.SERVER_AUTH

create_default_context()SSLContext.load_default_certs() に渡すオプションです。この値はコンテキストが Web サーバの認証に使われることを示します (ですので、クライアントサイドのソケットを作るのに使うことになるでしょう)。

バージョン 3.4 で追加.

Purpose.CLIENT_AUTH

create_default_context()SSLContext.load_default_certs() に渡すオプションです。この値はコンテキストが Web クライアントの認証に使われることを示します (ですので、サーバサイドのソケットを作るのに使うことになるでしょう)。

バージョン 3.4 で追加.

class ssl.SSLErrorNumber

SSL_ERROR_* 定数の enum.IntEnum コレクションです。

バージョン 3.6 で追加.

18.2.2. SSL ソケット

class ssl.SSLSocket(socket.socket)

SSL ソケットは socket オブジェクト の以下のメソッドを提供します:

SSL(およびTLS)プロトコルは TCP の上に独自の枠組みを持っているので、SSLソケットの抽象化は、いくつかの点で通常の OSレベルのソケットの仕様から逸脱することがあります。特に ノンブロッキングソケットについての注釈 を参照してください。

通常、 SSLSocket は直接作成されるのではなく、 SSLContext.wrap_socket() メソッドを使用して作成されます。

バージョン 3.5 で変更: sendfile() メソッドが追加されました。

バージョン 3.5 で変更: shutdown() は、バイトが送受信されるたびにソケットのタイムアウトをリセットしません。ソケットのタイムアウトは、シャットダウンの最大合計時間になりました。

バージョン 3.6 で撤廃: SSLSocket インスタンスを直接作成することは非推奨です。ソケットをラップするために SSLContext.wrap_socket() を使用してください。

SSL ソケットには、以下に示す追加のメソッドと属性もあります:

SSLSocket.read(len=1024, buffer=None)

SSL ソケットからデータの len バイトまでを読み出し、読み出した結果を bytes インスタンスで返します。 buffer を指定すると、結果は代わりに buffer に読み込まれ、読み込んだバイト数を返します。

ソケットが non-blocking で読み出しがブロックすると、 SSLWantReadError もしくは SSLWantWriteError が送出されます。

再ネゴシエーションがいつでも可能なので、 read() の呼び出しは書き込み操作も引き起こしえます。

バージョン 3.5 で変更: ソケットのタイムアウトは、バイトが送受信されるたびにリセットされません。ソケットのタイムアウトは、最大 len バイトを読むのにかかる最大合計時間になりました。

バージョン 3.6 で撤廃: read() の代わりに recv() を使用してください。

SSLSocket.write(buf)

buf を SSL ソケットに書き込み、書き込んだバイト数を返します。 buf 引数はバッファインターフェイスをサポートするオブジェクトでなければなりません。

ソケットが non-blocking で書き込みがブロックすると、 SSLWantReadError もしくは SSLWantWriteError が送出されます。

再ネゴシエーションがいつでも可能なので、 write() の呼び出しは読み出し操作も引き起こしえます。

バージョン 3.5 で変更: ソケットのタイムアウトは、バイトが送受信されるたびにリセットされません。ソケットのタイムアウトは、buf を書き込むのにかかる最大合計時間になりました。

バージョン 3.6 で撤廃: write() の代わりに send() を使用してください。

注釈

read(), write() メソッドは下位レベルのメソッドであり、暗号化されていないアプリケーションレベルのデータを読み書きし、それを復号/暗号化して暗号化された書き込みレベルのデータにします。これらのメソッドはアクティブな SSL 接続つまり、ハンドシェイクが完了していて、 SSLSocket.unwrap() が呼ばれていないことを必要とします。

通常はこれらのメソッドの代わりに recv()send() のようなソケット API メソッドを使うべきです。

SSLSocket.do_handshake()

SSL セットアップのハンドシェイクを実行します。

バージョン 3.4 で変更: ソケットの context の属性 check_hostname が真の場合に、ハンドシェイクメソッドが match_hostname() を実行するようになりました。

バージョン 3.5 で変更: ソケットのタイムアウトは、バイトが送受信されるたびにリセットされません。ソケットのタイムアウトは、ハンドシェイクにかかる最大合計時間になりました。

SSLSocket.getpeercert(binary_form=False)

接続先に証明書が無い場合、 None を返します。SSL ハンドシェイクがまだ行われていない場合は、 ValueError が送出されます。

binary_formFalse で接続先から証明書を取得した場合、このメソッドは dict のインスタンスを返します。証明書が認証されていない場合、辞書は空です。証明書が認証されていた場合いくつかのキーを持った辞書を返し、 subject (証明書が発行された principal), issuer (証明書を発行した principal) を含みます。証明書が Subject Alternative Name 拡張(RFC 3280 を参照)のインスタンスを格納していた場合、 subjectAltName キーも辞書に含まれます。

subject, issuer フィールドは、証明書のそれぞれのフィールドについてのデータ構造で与えられる RDN (relative distinguishued name) のシーケンスを格納したタプルで、各 RDN は name-value ペアのシーケンスです。現実世界での例をお見せします:

{'issuer': ((('countryName', 'IL'),),
            (('organizationName', 'StartCom Ltd.'),),
            (('organizationalUnitName',
              'Secure Digital Certificate Signing'),),
            (('commonName',
              'StartCom Class 2 Primary Intermediate Server CA'),)),
 'notAfter': 'Nov 22 08:15:19 2013 GMT',
 'notBefore': 'Nov 21 03:09:52 2011 GMT',
 'serialNumber': '95F0',
 'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),),
             (('countryName', 'US'),),
             (('stateOrProvinceName', 'California'),),
             (('localityName', 'San Francisco'),),
             (('organizationName', 'Electronic Frontier Foundation, Inc.'),),
             (('commonName', '*.eff.org'),),
             (('emailAddress', 'hostmaster@eff.org'),)),
 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')),
 'version': 3}

注釈

特定のサービスのために証明書の検証がしたければ、 match_hostname() 関数を使うことができます。

binary_form 引数が True だった場合、証明書が渡されていればこのメソッドはDERエンコードされた証明書全体をバイト列として返し、接続先が証明書を提示しなかった場合は None を返します。接続先が証明書を提供するかどうかは SSL ソケットの役割に依存します:

  • クライアント SSL ソケットでは、認証が要求されているかどうかに関わらず、サーバは常に証明書を提供します。

  • サーバ SSL ソケットでは、クライアントはサーバによって認証が要求されている場合にのみ証明書を提供します。したがって、 (CERT_OPTIONALCERT_REQUIRED ではなく) CERT_NONE を使用した場合 getpeercert()None を返します。

バージョン 3.2 で変更: 返される辞書に issuer, notBefore のような追加アイテムを含むようになりました。

バージョン 3.4 で変更: ハンドシェイクが済んでいなければ ValueError を投げるようになりました。返される辞書に crlDistributionPoints, caIssuers, OCSP URI のような X509v3 拡張アイテムを含むようになりました。

SSLSocket.cipher()

利用されている暗号の名前、その暗号の利用を定義しているSSLプロトコルのバージョン、利用されている鍵のbit長の3つの値を含むタプルを返します。もし接続が確立されていない場合、 None を返します。

SSLSocket.shared_ciphers()

ハンドシェイク中にクライアントにより共有される暗号方式のリストを返します。返されるリストの各要素は 3つの値を含むタプルで、その値はそれぞれ、暗号方式の名前、その暗号の利用を定義している SSL プロトコルのバージョン、暗号で使用される秘密鍵のビット長です。接続が確立されていないか、ソケットがクライアントソケットである場合、meth:~SSLSocket.shared_ciphersNone を返します。

バージョン 3.5 で追加.

SSLSocket.compression()

使われている圧縮アルゴリズムを文字列で返します。接続が圧縮されていなければ None を返します。

上位レベルのプロトコルが自身で圧縮メカニズムをサポートする場合、SSL レベルでの圧縮を OP_NO_COMPRESSION を使って無効にできます。

バージョン 3.3 で追加.

SSLSocket.get_channel_binding(cb_type="tls-unique")

現在の接続におけるチャネルバインディングのデータを取得します。未接続あるいはハンドシェイクが完了していなければ None を返します。

cb_type パラメータにより、望みのチャネルバインディングのタイプを選択できます。チャネルバインディングのタイプの妥当なものは CHANNEL_BINDING_TYPES でリストされています。現在のところは RFC 5929 で定義されている ‘tls-unique’ のみがサポートされています。未サポートのチャネルバインディングのタイプが要求された場合、 ValueError を送出します。

バージョン 3.3 で追加.

SSLSocket.selected_alpn_protocol()

TLS ハンドシェイクで選択されたプロトコルを返します。 SSLContext.set_alpn_protocols() が呼ばれていない場合、相手側が ALPN をサポートしていない場合、クライアントが提案したプロトコルのどれもソケットがサポートしない場合、あるいはハンドシェイクがまだ行われていない場合には、 None が返されます。

バージョン 3.5 で追加.

SSLSocket.selected_npn_protocol()

TLS/SSL ハンドシェイクで選択された上位レベルのプロトコルを返します。 SSLContext.set_npn_protocols() が呼ばれていない場合、相手側が NPN をサポートしていない場合、あるいはハンドシェイクがまだ行われていない場合には、 None が返されます。

バージョン 3.3 で追加.

SSLSocket.unwrap()

SSLシャットダウンハンドシェイクを実行します。これは下位レイヤーのソケットからTLSレイヤーを取り除き、下位レイヤーのソケットオブジェクトを返します。これは暗号化されたオペレーションから暗号化されていない接続に移行するときに利用されます。以降の通信には、オリジナルのソケットではなくこのメソッドが返したソケットのみを利用するべきです。

SSLSocket.version()

コネクションによって実際にネゴシエイトされた SSL プロトコルバージョンを文字列で、または、セキュアなコネクションが確立していなければ None を返します。これを書いている時点では、 "SSLv2", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" などが返ります。最新の OpenSSL はもっと色々な値を定義しているかもしれません。

バージョン 3.5 で追加.

SSLSocket.pending()

接続において既に復号済みで読み出し可能で保留になっているバイト列の数を返します。

SSLSocket.context

この SSL ソケットに結び付けられた SSLContext オブジェクトです。SSL ソケットが (SSLContext.wrap_socket() ではなく)トップレベルの wrap_socket() 関数を使って作られた場合、これはこの SSL ソケットのために作られたカスタムコンテキストオブジェクトです。

バージョン 3.2 で追加.

SSLSocket.server_side

サーバサイドのソケットに対して True 、クライアントサイドのソケットに対して False となる真偽値です。

バージョン 3.2 で追加.

SSLSocket.server_hostname

サーバのホスト名: str 型、またはサーバサイドのソケットの場合とコンストラクタで hostname が指定されなかった場合は None

バージョン 3.2 で追加.

SSLSocket.session

この SSL 接続に対する SSLSession です。このセッションは、TLS ハンドシェイクの実行後、クライアントサイドとサーバサイドのソケットで使用できます。クライアントソケットでは、このセッションを do_handshake() が呼ばれる前に設定して、セッションを再利用できます。

バージョン 3.6 で追加.

SSLSocket.session_reused

バージョン 3.6 で追加.

18.2.3. SSL コンテキスト

バージョン 3.2 で追加.

SSL コンテキストは、SSL 構成オプション、証明書(群)や秘密鍵(群)などのような、一回の SSL 接続よりも長生きするさまざまなデータを保持します。これはサーバサイドソケットの SSL セッションのキャッシュも管理し、同じクライアントからの繰り返しの接続時の速度向上に一役買います。

class ssl.SSLContext(protocol=PROTOCOL_TLS)

新しい SSL コンテキストを作成します。 protocol にはこのモジュールで定義されている PROTOCOL_* 定数のうち一つを指定しなければなりません。最大限の互換性とデフォルト値のためには、現時点での推奨は PROTOCOL_TLS です。

参考

create_default_context()ssl モジュールに、目的に合ったセキュリティ設定を選ばせます。

バージョン 3.6 で変更: このコンテキストは、安全性の高いデフォルト値で作成されます。デフォルト設定されるオプションは、 OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE, OP_NO_SSLv2 (PROTOCOL_SSLv2 以外), OP_NO_SSLv3 (PROTOCOL_SSLv3 以外) です。初期の暗号方式スイートリストには HIGH 暗号のみが含まれており、 NULL 暗号および MD5 暗号は含まれません (PROTOCOL_SSLv2 以外)。

SSLContext オブジェクトは以下のメソッドと属性を持っています:

SSLContext.cert_store_stats()

ロードされた X.509 証明書の数、CA 証明書で活性の X.509 証明書の数、証明書失効リストの数、についての統計情報を辞書として取得します。

一つの CA と他の一つの証明書を持ったコンテキストでの例です:

>>> context.cert_store_stats()
{'crl': 0, 'x509_ca': 1, 'x509': 2}

バージョン 3.4 で追加.

SSLContext.load_cert_chain(certfile, keyfile=None, password=None)

秘密鍵と対応する証明書をロードします。 certfile は、証明書と、証明書認証で必要とされる任意の数の CA 証明書を含む、PEM フォーマットの単一ファイルへのパスでなければなりません。 keyfile 文字列を指定する場合、秘密鍵が含まれるファイルを指すものでなければなりません。指定しない場合、秘密鍵も certfile から取得されます。 certfile への証明書の格納についての詳細は、 証明書 の議論を参照してください。

password 引数に、秘密鍵を復号するためのパスワードを返す関数を与えることができます。その関数は秘密鍵が暗号化されていて、なおかつパスワードが必要な場合にのみ呼び出されます。その関数は引数なしで呼び出され、string, bytes, または bytearray を返さなければなりません。戻り値が string の場合は鍵を復号化するのに使う前に UTF-8 でエンコードされます。string の代わりに bytes や bytearray を返した場合は password 引数に直接供給されます。秘密鍵が暗号化されていなかったりパスワードを必要としない場合は、指定は無視されます。

password が与えられず、そしてパスワードが必要な場合には、OpenSSL 組み込みのパスワード問い合わせメカニズムが、ユーザに対話的にパスワードを問い合わせます。

秘密鍵が証明書に合致しなければ、 SSLError が送出されます。

バージョン 3.3 で変更: 新しいオプション引数 password

SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)

デフォルトの場所から “認証局” (CA=certification authority) 証明書ファイル一式をロードします。Windows では、CA 証明書はシステム記憶域の CAROOT からロードします。それ以外のシステムでは、この関数は SSLContext.set_default_verify_paths() を呼び出します。将来的にはこのメソッドは、他の場所からも CA 証明書をロードするかもしれません。

purpose フラグでどの種類の CA 証明書をロードするかを指定します。デフォルトの Purpose.SERVER_AUTH は TLS web サーバの認証のために活性かつ信頼された証明書をロードします(クライアントサイドのソケット)。 Purpose.CLIENT_AUTH はクライアント証明書の正当性検証をサーバサイドで行うための CA 証明書をロードします。

バージョン 3.4 で追加.

SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None)

verify_modeCERT_NONE でない場合に接続先の証明書ファイルの正当性検証に使われる “認証局” (CA=certification authority) 証明書ファイル一式をロードします。少なくとも cafilecapath のどちらかは指定しなければなりません。

このメソッドは PEM または DER フォーマットの証明書失効リスト (CRLs=certification revocation lists)もロードできます。CRLs のために使うには、 SSLContext.verify_flags を適切に設定しなければなりません。

cafile を指定する場合は、PEM フォーマットで CA 証明書が結合されたファイルへのパスを指定してください。このファイル内で証明書をどのように編成すれば良いのかについての詳しい情報については、 証明書 の議論を参照してください。

capath を指定する場合は、PEM フォーマットの CA 証明書が含まれる、OpenSSL specific layout に従ったディレクトリへのパスを指定してください。

cadata オブジェクトを指定する場合は、PEM エンコードの証明書一つ以上の ASCII 文字列か、DER エンコードの証明書の bytes-like object オブジェクトのどちらかを指定してください。PEM エンコードの証明書の周囲の余分な行は無視されますが、少なくとも一つの証明書が含まれている必要があります。

バージョン 3.4 で変更: 新しいオプション引数 cadata

SSLContext.get_ca_certs(binary_form=False)

ロードされた “認証局” (CA=certification authority) 証明書のリストを取得します。 binary_form 引数が False である場合、リストのそれぞれのエントリは SSLSocket.getpeercert() が出力するような辞書になります。True である場合、このメソッドは、DER エンコード形式の証明書のリストを返します。返却されるリストには、 SSL 接続によって証明書がリクエストおよびロードされない限り、 capath からの証明書は含まれません。

注釈

capath ディレクトリ内の証明書は一度でも使われない限りはロードされません。

バージョン 3.4 で追加.

SSLContext.get_ciphers()

有効な暗号化のリストを取得します。リストは暗号化優先度順に並びます。SSLContext.set_ciphers() を参照してください。

以下はプログラム例です:

>>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
>>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
>>> ctx.get_ciphers()  # OpenSSL 1.0.x
[{'alg_bits': 256,
  'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(256) Mac=AEAD',
  'id': 50380848,
  'name': 'ECDHE-RSA-AES256-GCM-SHA384',
  'protocol': 'TLSv1/SSLv3',
  'strength_bits': 256},
 {'alg_bits': 128,
  'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(128) Mac=AEAD',
  'id': 50380847,
  'name': 'ECDHE-RSA-AES128-GCM-SHA256',
  'protocol': 'TLSv1/SSLv3',
  'strength_bits': 128}]
OpenSSL 1.1 以降では、暗号化辞書に以下のフィールドが追加されました。
>>> ctx.get_ciphers()  # OpenSSL 1.1+
[{'aead': True,
  'alg_bits': 256,
  'auth': 'auth-rsa',
  'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(256) Mac=AEAD',
  'digest': None,
  'id': 50380848,
  'kea': 'kx-ecdhe',
  'name': 'ECDHE-RSA-AES256-GCM-SHA384',
  'protocol': 'TLSv1.2',
  'strength_bits': 256,
  'symmetric': 'aes-256-gcm'},
 {'aead': True,
  'alg_bits': 128,
  'auth': 'auth-rsa',
  'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                 'Enc=AESGCM(128) Mac=AEAD',
  'digest': None,
  'id': 50380847,
  'kea': 'kx-ecdhe',
  'name': 'ECDHE-RSA-AES128-GCM-SHA256',
  'protocol': 'TLSv1.2',
  'strength_bits': 128,
  'symmetric': 'aes-128-gcm'}]

利用可能な環境: OpenSSL 1.0.2+

バージョン 3.6 で追加.

SSLContext.set_default_verify_paths()

デフォルトの “認証局” (CA=certification authority) 証明書を、OpenSSL ライブラリがビルドされた際に定義されたファイルシステム上のパスからロードします。残念ながらこのメソッドが成功したかどうかを知るための簡単な方法はありません: 証明書が見つからなくてもエラーは返りません。OpenSSL ライブラリがオペレーティングシステムの一部として提供されている際にはどうやら適切に構成できるようですが。

SSLContext.set_ciphers(ciphers)

このコンテキストによって作られるソケットで利用できる暗号を設定します。 OpenSSL cipher list format に書かれている形式の文字列でなければなりません。 (OpenSSL のコンパイル時オプションや他の設定がそれらすべての暗号の使用を禁止しているなどの理由で) どの暗号も選べない場合、 SSLError が送出されます。

注釈

接続時に SSL ソケットの SSLSocket.cipher() メソッドが、現在選択されているその暗号を使います。

SSLContext.set_alpn_protocols(protocols)

SSL/TLS ハンドシェイク時にソケットが提示すべきプロトコルを指定します。 ['http/1.1', 'spdy/2'] のような推奨順に並べた ASCII 文字列のリストでなければなりません。プロトコルの選択は RFC 7301 に従いハンドシェイク中に行われます。ハンドシェイクが正常に終了した後、 SSLSocket.selected_alpn_protocol() メソッドは合意されたプロトコルを返します。

このメソッドは HAS_ALPN が偽の場合 NotImplementedError を送出します。

両者が ALPN をサポートしているが、使用するプロトコルで合意できない場合、OpenSSL 1.1.0+ はハンドシェイクを中断し、 SSLError を送出します。

バージョン 3.5 で追加.

SSLContext.set_npn_protocols(protocols)

SSL/TLS ハンドシェイク時にソケットが提示すべきプロトコルを指定します。 ['http/1.1', 'spdy/2'] のような推奨順に並べた文字列のリストでなければなりません。プロトコルの選択は NPN draft specification に従いハンドシェイク中に行われます。ハンドシェイクが正常に終了した後、 SSLSocket.selected_alpn_protocol() メソッドは合意されたプロトコルを返します。

このメソッドは HAS_NPN が偽の場合 NotImplementedError を送出します。

バージョン 3.3 で追加.

SSLContext.set_servername_callback(server_name_callback)

TLS クライアントがサーバ名表示を指定した際の、SSL/TLS サーバによって TLS Client Hello ハンドシェイクメッセージが受け取られたあとで呼び出されるコールバック関数を登録します。サーバ名表示メカニズムは RFC 6066 セクション 3 - Server Name Indication で述べられています。

SSLContext ごとに一つだけコールバックをセットできます。 server_name_callbackNone にすればコールバックは無効になります。この関数を続けて呼ぶと、以前に登録されたコールバックを上書きします。

コールバック関数 server_name_callback は 3 つの引数で呼び出されます; 最初の引数は ssl.SSLSocket です。2 つ目の引数は、クライアントが相手をしようと意図しているサーバ名を表す文字列 (または TLS Client Hello がサーバ名を含まない場合は None) です。そして 3 つ目の引数はオリジナルの SSLContext です。サーバ名引数は IDNA デコードされたサーバ名です。

このコールバックの典型的な利用方法は、 ssl.SSLSocketSSLSocket.context 属性を、サーバ名に合致する証明書チェインを持つ新しい SSLContext オブジェクトに変更することです。

TLS 接続の初期ネゴシエーションのフェーズなので、 SSLSocket.selected_alpn_protocol(), SSLSocket.context のような限られたメソッドと属性のみ使えます。 SSLSocket.getpeercert(), SSLSocket.getpeercert(), SSLSocket.cipher(), SSLSocket.compress() メソッドは TLS 接続が TLS Client Hello よりも先に進行していることを必要としますから、これらは意味のある値を返しませんし、安全に呼び出すこともできません。

TLS ネゴシエーションを継続させるならば、 server_name_callback 関数は None を返さなければなりません。TLS が失敗することを必要とするなら、 constant ALERT_DESCRIPTION_* を返してください。ここにない値を返すと、致命エラー ALERT_DESCRIPTION_INTERNAL_ERROR を引き起こします。

サーバ名に対する IDNA デコードのエラーがあれば、TLS 接続はクライアントに対する TLS の致命的アラートメッセージ ALERT_DESCRIPTION_INTERNAL_ERROR とともに終了します。

server_name_callback 関数が例外を送出した場合、TLS 接続は TLS の致命的アラートメッセージ ALERT_DESCRIPTION_HANDSHAKE_FAILURE とともに終了します。

このメソッドは OpenSSL ライブラリが OPENSSL_NO_TLSEXT を定義してビルドされている場合、 NotImplementedError を送出します。

バージョン 3.4 で追加.

SSLContext.load_dh_params(dhfile)

ディフィー・ヘルマン(DH)鍵交換のための鍵生成パラメータをロードします。DH 鍵交換を用いることは、(サーバ、クライアントともに)計算機リソースに高い処理負荷をかけますがセキュリティを向上させます。 dhfile パラメータは PEM フォーマットの DH パラメータを含んだファイルへのパスでなければなりません。

この設定はクライアントソケットには適用されません。さらにセキュリティを改善するのに OP_SINGLE_DH_USE オプションも利用できます。

バージョン 3.3 で追加.

SSLContext.set_ecdh_curve(curve_name)

楕円曲線ディフィー・ヘルマン(ECDH)鍵交換の曲線名を指定します。ECDH はもとの DH に較べて、ほぼ間違いなく同程度に安全である一方で、顕著に高速です。 curve_name パラメータは既知の楕円曲線を表す文字列でなければなりません。例えば prime256v1 が広くサポートされている曲線です。

この設定はクライアントソケットには適用されません。さらにセキュリティを改善するのに OP_SINGLE_ECDH_USE オプションも利用できます。

このメソッドは HAS_ECDHFalse の場合は利用できません。

バージョン 3.3 で追加.

参考

SSL/TLS & Perfect Forward Secrecy
Vincent Bernat.
SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)

既存の Python ソケット sock をラップして ssl.SSLSocket オブジェクトを返します。 sockSOCK_STREAM ソケットでなければなりません; ほかのタイプのソケットはサポートされていません。

返される SSL ソケットは、コンテキスト、その設定と証明書に関連付けられます。パラメータ server_side, do_handshake_on_connect, suppress_ragged_eofs はトップレベルの関数 wrap_socket() のものと同じ意味です。

クライアントからの接続では、 server_hostname で接続先サービスのホスト名を指定できます。これは HTTP バーチャルホストにかなり似て、シングルサーバで複数の SSL ベースのサービスを別々の証明書でホストしているようなサーバに対して使えます。 server_side が True の場合に server_hostname を指定すると ValueError を送出します。

session, session を参照してください。

バージョン 3.5 で変更: OpenSSL が SNI をサポートしなくても server_hostname を許容するようになりました。

バージョン 3.6 で変更: session 引数が追加されました。

SSLContext.wrap_bio(incoming, outgoing, server_side=False, server_hostname=None, session=None)

BIO オブジェクトの incomingoutgoing をラップすることで、新しい SSLObject インスタンスを作成します。SSL ルーティンは、入力 BIO からの入力データを読み取り、出力 BIO にデータを書き出します。

server_sideserver_hostnamesession 引数は、 SSLContext.wrap_socket() での意味と同じ意味を持ちます。

バージョン 3.6 で変更: session 引数が追加されました。

SSLContext.session_stats()

このコンテキストによって作られた、または管理されている SSL セッションについての統計情報を取得します。 piece of information のそれぞれの名前にそれらが持つ数値をマッピングした辞書を返します。例えば、以下は、コンテキスト作成以降のセッションキャッシュのキャッシュヒットとキャッシュミスの総計です。

>>> stats = context.session_stats()
>>> stats['hits'], stats['misses']
(0, 0)
SSLContext.check_hostname

SSLSocket.do_handshake() 呼び出し時に、 match_hostname() を使って接続先証明書のホスト名の合致を見るかどうか。コンテキストの verify_mode には CERT_OPTIONALCERT_REQUIRED をセットしなければなりません。また wrap_socket() にはホスト名の合致をみるための server_hostname を渡さなければなりません。

以下はプログラム例です:

import socket, ssl

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_default_certs()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com')
ssl_sock.connect(('www.verisign.com', 443))

バージョン 3.4 で追加.

注釈

この機能にはOpenSSL0.9.8f以降が必要です。

SSLContext.options

このコンテキストで有効になっている SSL オプションを表す整数。デフォルトの値は OP_ALL ですが、 OP_NO_SSLv2 のような他の値をビット OR 演算で指定できます。

注釈

OpenSSL の 0.9.8m より古いバージョンを使う場合、値はセットはできますがクリアができません。オプションを (対応するビットをリセットすることで) クリアしようとすると ValueError が送出されます。

バージョン 3.6 で変更: SSLContext.options は次のように Options のフラグを返します。

>>> ssl.create_default_context().options
<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>
SSLContext.protocol

コンテキストの構築時に選択されたプロトコルバージョン。この属性は読み取り専用です。

SSLContext.verify_flags

証明書の検証操作のためのフラグです。 VERIFY_CRL_CHECK_LEAF などのフラグをビット OR 演算でセットできます。デフォルトでは OpenSSL は証明書失効リスト (CRLs) を必要としませんし検証にも使いません。openssl version 0.9.8+ でのみ利用可能です。

バージョン 3.4 で追加.

バージョン 3.6 で変更: SSLContext.verify_flags は次のように VerifyFlags のフラグを返します。

>>> ssl.create_default_context().verify_flags
<VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
SSLContext.verify_mode

接続先の証明書の検証を試みるかどうか、また、検証が失敗した場合にどのように振舞うべきかを制御します。この属性は CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED のうちどれか一つでなければなりません。

バージョン 3.6 で変更: SSLContext.verify_mode は次のように VerifyMode enum (列挙) を返します。

>>> ssl.create_default_context().verify_mode
<VerifyMode.CERT_REQUIRED: 2>

18.2.4. 証明書

証明書を大まかに説明すると、公開鍵/秘密鍵システムの一種です。このシステムでは、各 principal (これはマシン、人、組織などです) は、ユニークな2つの暗号鍵を割り当てられます。1つは公開され、 公開鍵(public key) と呼ばれます。もう一方は秘密にされ、 秘密鍵(private key) と呼ばれます。 2つの鍵は関連しており、片方の鍵で暗号化したメッセージは、もう片方の鍵 のみ で復号できます。

証明書は2つの principal の情報を含んでいます。証明書は subject 名とその公開鍵を含んでいます。また、もう一つの principal である 発行者(issuer) からの、 subject が本人であることと、その公開鍵が正しいことの宣言(statement)を含んでいます。発行者からの宣言は、その発行者の秘密鍵で署名されています。発行者の秘密鍵は発行者しか知りませんが、誰もがその発行者の公開鍵を利用して宣言を復号し、証明書内の別の情報と比較することで認証することができます。証明書はまた、その証明書が有効である期限に関する情報も含んでいます。この期限は “notBefore” と “notAfter” と呼ばれる2つのフィールドで表現されています。

Python において証明書を利用する場合、クライアントもサーバーも自分を証明するために証明書を利用することができます。ネットワーク接続の相手側に証明書の提示を要求する事ができ、そのクライアントやサーバーが認証を必要とするならその証明書を認証することができます。認証が失敗した場合、接続は例外を発生させます。認証は下位層のOpenSSLフレームワークが自動的に行います。アプリケーションは認証機構について意識する必要はありません。しかし、アプリケーションは認証プロセスのために幾つかの証明書を提供する必要があるかもしれません。

Python は証明書を格納したファイルを利用します。そのファイルは “PEM” (RFC 1422 参照) フォーマットという、ヘッダー行とフッター行の間にbase-64エンコードされた形をとっている必要があります。

-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----

18.2.4.1. 証明書チェイン

Pythonが利用する証明書を格納したファイルは、ときには 証明書チェイン(certificate chain) と呼ばれる証明書のシーケンスを格納します。このチェインの先頭には、まずクライアントやサーバーである principal の証明書を置き、それ以降には、その証明書の発行者(issuer)の証明書などを続け、最後に証明対象(subject)と発行者が同じ 自己署名(self-signed) 証明書で終わります。この最後の証明書は ルート証明書(root certificate と呼ばれます。これらの証明書チェインは単純に1つの証明書ファイルに結合してください。例えば、3つの証明書からなる証明書チェインがある場合、私たちのサーバーの証明書から、私たちのサーバーに署名した認証局の証明書、そして認証局の証明書を発行した機関のルート証明書と続きます:

-----BEGIN CERTIFICATE-----
... (certificate for your server)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the certificate for the CA)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (the root certificate for the CA's issuer)...
-----END CERTIFICATE-----

18.2.4.2. CA 証明書

もし相手から送られてきた証明書の認証をしたい場合、信頼している各発行者の証明書チェインが入った “CA certs” ファイルを提供する必要があります。繰り返しますが、このファイルは単純に、各チェインを結合しただけのものです。認証のために、Pythonはそのファイルの中の最初にマッチしたチェインを利用します。SSLContext.load_default_certs() を呼び出すことでプラットフォームの証明書ファイルも使われますが、これは create_default_context() によって自動的に行われます。

18.2.4.3. 秘密鍵と証明書の組み合わせ

多くの場合、証明書と同じファイルに秘密鍵も格納されています。この場合、 SSLContext.load_cert_chain(), wrap_socket() には certfile 引数だけが必要とされます。秘密鍵が証明書ファイルに格納されている場合、秘密鍵は証明書チェインの最初の証明書よりも先にないといけません。

-----BEGIN RSA PRIVATE KEY-----
... (private key in base64 encoding) ...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----

18.2.4.4. 自己署名証明書

SSL暗号化接続サービスを提供するサーバーを建てる場合、適切な証明書を取得するには、認証局から買うなどの幾つかの方法があります。また、自己署名証明書を作るケースもあります。 OpenSSLを使って自己署名証明書を作るには、次のようにします。

% openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem
Generating a 1024 bit RSA private key
.......++++++
.............................++++++
writing new private key to 'cert.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MyState
Locality Name (eg, city) []:Some City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc.
Organizational Unit Name (eg, section) []:My Group
Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com
Email Address []:ops@myserver.mygroup.myorganization.com
%

自己署名証明書の欠点は、それ自身がルート証明書であり、他の人はその証明書を持っていない (そして信頼しない)ことです。

18.2.5. 使用例

18.2.5.1. SSLサポートをテストする

インストールされているPythonがSSLをサポートしているかどうかをテストするために、ユーザーコードは次のイディオムを利用することができます。

try:
    import ssl
except ImportError:
    pass
else:
    ...  # do something that requires SSL support

18.2.5.2. クライアントサイドの処理

この例では、自動的に証明書の検証を行うことを含む望ましいセキュリティ設定でクライアントソケットの SSL コンテキストを作ります:

>>> context = ssl.create_default_context()

自分自身でセキュリティ設定を調整したい場合、コンテキストを一から作ることはできます (ただし、正しくない設定をしてしまいがちなことに注意してください):

>>> context = ssl.SSLContext(ssl.PROTOCOL_TLS)
>>> context.verify_mode = ssl.CERT_REQUIRED
>>> context.check_hostname = True
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")

(このスニペットはすべての CA 証明書が /etc/ssl/certs/ca-bundle.crt にバンドルされていることを仮定しています; もし違っていればエラーになりますので、適宜修正してください)

サーバへの接続にこのコンテキストを使うと、 CERT_REQUIRED でサーバの証明書の検証が行われます: サーバの証明書が CA 証明書のいずれかに署名されていて、その署名が正しいことを保障します。

>>> conn = context.wrap_socket(socket.socket(socket.AF_INET),
...                            server_hostname="www.python.org")
>>> conn.connect(("www.python.org", 443))

そして証明書を持ってくることができます:

>>> cert = conn.getpeercert()

証明書が、期待しているサービス (つまり、 HTTPS ホスト www.python.org) の身元を特定していることを視覚的に点検してみましょう:

>>> pprint.pprint(cert)
{'OCSP': ('http://ocsp.digicert.com',),
 'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',),
 'crlDistributionPoints': ('http://crl3.digicert.com/sha2-ev-server-g1.crl',
                           'http://crl4.digicert.com/sha2-ev-server-g1.crl'),
 'issuer': ((('countryName', 'US'),),
            (('organizationName', 'DigiCert Inc'),),
            (('organizationalUnitName', 'www.digicert.com'),),
            (('commonName', 'DigiCert SHA2 Extended Validation Server CA'),)),
 'notAfter': 'Sep  9 12:00:00 2016 GMT',
 'notBefore': 'Sep  5 00:00:00 2014 GMT',
 'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26',
 'subject': ((('businessCategory', 'Private Organization'),),
             (('1.3.6.1.4.1.311.60.2.1.3', 'US'),),
             (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),),
             (('serialNumber', '3359300'),),
             (('streetAddress', '16 Allen Rd'),),
             (('postalCode', '03894-4801'),),
             (('countryName', 'US'),),
             (('stateOrProvinceName', 'NH'),),
             (('localityName', 'Wolfeboro,'),),
             (('organizationName', 'Python Software Foundation'),),
             (('commonName', 'www.python.org'),)),
 'subjectAltName': (('DNS', 'www.python.org'),
                    ('DNS', 'python.org'),
                    ('DNS', 'pypi.python.org'),
                    ('DNS', 'docs.python.org'),
                    ('DNS', 'testpypi.python.org'),
                    ('DNS', 'bugs.python.org'),
                    ('DNS', 'wiki.python.org'),
                    ('DNS', 'hg.python.org'),
                    ('DNS', 'mail.python.org'),
                    ('DNS', 'packaging.python.org'),
                    ('DNS', 'pythonhosted.org'),
                    ('DNS', 'www.pythonhosted.org'),
                    ('DNS', 'test.pythonhosted.org'),
                    ('DNS', 'us.pycon.org'),
                    ('DNS', 'id.python.org')),
 'version': 3}

SSL チャネルは今や確立されて証明書が検証されているので、サーバとのお喋りを続けることができます:

>>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")
>>> pprint.pprint(conn.recv(1024).split(b"\r\n"))
[b'HTTP/1.1 200 OK',
 b'Date: Sat, 18 Oct 2014 18:27:20 GMT',
 b'Server: nginx',
 b'Content-Type: text/html; charset=utf-8',
 b'X-Frame-Options: SAMEORIGIN',
 b'Content-Length: 45679',
 b'Accept-Ranges: bytes',
 b'Via: 1.1 varnish',
 b'Age: 2188',
 b'X-Served-By: cache-lcy1134-LCY',
 b'X-Cache: HIT',
 b'X-Cache-Hits: 11',
 b'Vary: Cookie',
 b'Strict-Transport-Security: max-age=63072000; includeSubDomains',
 b'Connection: close',
 b'',
 b'']

このドキュメントの下の方の、 セキュリティで考慮すべき点 に関する議論を参照してください。

18.2.5.3. サーバサイドの処理

サーバサイドの処理では、通常、サーバー証明書と秘密鍵がそれぞれファイルに格納された形で必要です。最初に秘密鍵と証明書が保持されたコンテキストを作成し、クライアントがあなたの信憑性をチェックできるようにします。そののちにソケットを開き、ポートにバインドし、そのソケットの listen() を呼び、クライアントからの接続を待ちます。

import socket, ssl

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile")

bindsocket = socket.socket()
bindsocket.bind(('myaddr.mydomain.com', 10023))
bindsocket.listen(5)

クライアントが接続してきた場合、 accept() を呼んで新しいソケットを作成し、接続のためにサーバサイドの SSL ソケットを、コンテキストの SSLContext.wrap_socket() メソッドで作ります:

while True:
    newsocket, fromaddr = bindsocket.accept()
    connstream = context.wrap_socket(newsocket, server_side=True)
    try:
        deal_with_client(connstream)
    finally:
        connstream.shutdown(socket.SHUT_RDWR)
        connstream.close()

そして、 connstream からデータを読み、クライアントと切断する(あるいはクライアントが切断してくる)まで何か処理をします。

def deal_with_client(connstream):
    data = connstream.recv(1024)
    # empty data means the client is finished with us
    while data:
        if not do_something(connstream, data):
            # we'll assume do_something returns False
            # when we're finished with client
            break
        data = connstream.recv(1024)
    # finished with client

そして新しいクライアント接続のために listen に戻ります。 (もちろん現実のサーバは、おそらく個々のクライアント接続ごとに別のスレッドで処理するか、ソケットを ノンブロッキングモード にし、イベントループを使うでしょう。)

18.2.6. ノンブロッキングソケットについての注意事項

SSL ソケットはノンブロッキングモードにおいては、普通のソケットとは少し違った振る舞いをします。ですのでノンブロッキングソケットとともに使う場合、いくつか気をつけなければならない事項があります:

  • ほとんどの SSLSocket のメソッドは I/O 操作がブロックすると BlockingIOError ではなく SSLWantWriteErrorSSLWantReadError のどちらかを送出します。 SSLWantReadError は下層のソケットで読み出しが必要な場合に送出され、 SSLWantWriteError は下層のソケットで書き込みが必要な場合に送出されます。SSL ソケットに対して 書き込み を試みると下層のソケットから最初に 読み出す 必要があるかもしれず、SSL ソケットに対して 読み出し を試みると下層のソケットに先に 書き込む 必要があるかもしれないことに注意してください。

    バージョン 3.5 で変更: 以前の Python バージョンでは、 SSLSocket.send() メソッドは SSLWantWriteError または SSLWantReadError を送出するのではなく、ゼロを返していました。

  • select() 呼び出しは OS レベルでのソケットが読み出し可能(または書き込み可能)になったことを教えてくれますが、上位の SSL レイヤーでの十分なデータがあることを意味するわけではありません。例えば、SSL フレームの一部が届いただけかもしれません。ですから、 SSLSocket.recv()SSLSocket.send() の失敗を処理することに備え、ほかの select() 呼び出し後にリトライしなければなりません。

  • 反対に、SSL レイヤーは独自の枠組みを持っているため、select() が気付かない読み出し可能なデータを SSL ソケットが持っている場合があります。したがって、入手可能な可能性のあるデータをすべて引き出すために最初に SSLSocket.recv() を呼び出し、次にそれでもまだ必要な場合にだけ select() 呼び出しでブロックすべきです。

    (当然のことながら、ほかのプリミティブ、例えば poll()selectors モジュール内のものを使う際にも似た但し書きが付きます)

  • SSL ハンドシェイクそのものがノンブロッキングになります: SSLSocket.do_handshake() メソッドは成功するまでリトライしなければなりません。 select() を用いてソケットの準備が整うのを待つためには、およそ以下のようにします:

    while True:
        try:
            sock.do_handshake()
            break
        except ssl.SSLWantReadError:
            select.select([sock], [], [])
        except ssl.SSLWantWriteError:
            select.select([], [sock], [])
    

参考

asyncio モジュールは ノンブロッキング SSL ソケット をサポートし、より高いレベルの API を提供しています。 selectors モジュールを使ってイベントを poll し、 SSLWantWriteError, SSLWantReadError, BlockingIOError 例外を処理します。SSL ハンドシェイクも非同期に実行します。

18.2.7. メモリ BIO サポート

バージョン 3.5 で追加.

Python 2.6 で SSL モジュールが導入されて以降、SSLSocket クラスは、以下の互いに関連するが別々の機能を提供してきました。

  • SSL プロトコル処理

  • ネットワーク IO

ネットワーク IO API は、socket.socket が提供するものと同じです。SSLSocket も、そのクラスから継承しています。これにより、SSL ソケットは標準のソケットをそっくりそのまま置き換えるものとして使用できるため、既存のアプリケーションを SSL に対応させるのが非常に簡単になります。

SSL プロトコルの処理とネットワーク IO を組み合わせた場合、通常は問題なく動作しますが、問題が発生する場合があります。一例を挙げると、非同期 IO フレームワークが別の多重化モデルを使用する場合、これは socket.socket と内部 OpenSSL ソケット IO ルーティンが想定する「ファイル記述子上の select/poll」モデル(準備状態ベース)とは異なります。これは、このモデルが非効率的になる Windows などのプラットフォームに主に該当します。そのため、スコープを限定した SSLSocket の変種、 SSLObject が提供されています。

class ssl.SSLObject

ネットワーク IO メソッドを含まない SSL プロトコルインスタンスを表す、スコープを限定した SSLSocket の変種です。一般的にこ、のクラスを使用するのは、メモリバッファを通じて SSL のための非同期 IO を実装するフレームワーク作成者です。

このクラスは、OpenSSL が実装する低水準 SSL オブジェクトの上にインターフェイスを実装します。このオブジェクトは SSL 接続の状態をキャプチャしますが、ネットワーク IO 自体は提供しません。IO は、OpenSSL の IO 抽象レイヤである別の「BIO」オブジェクトを通じて実行する必要があります。

SSLObject インスタンスは、 wrap_bio() メソッドを使用して作成できます。このメソッドは、SSLObject インスタンスを作成し、2 つの BIO に束縛します。incoming BIO は、Python から SSL プロトコルインスタンスにデータを渡すために使用され、outgoing BIO は、データを反対向きに渡すために使用されます。

次のメソッドがサポートされています:

SSLSocket と比較すると、このオブジェクトでは以下の機能が不足しています。

  • recv()send() などのメソッドを含む、あらゆるネットワーク IO。

  • do_handshake_on_connect 機構はありません。必ず手動で do_handshake() を呼んで、ハンドシェイクを開始する必要があります。

  • suppress_ragged_eofs は処理されません。プロトコルに違反するファイル末尾状態は、 SSLEOFError 例外を通じて報告されます。

  • unwrap() メソッドの呼び出しは、下層のソケットを返す SSL ソケットとは異なり、何も返しません。

  • SSLContext.set_servername_callback() に渡される server_name_callback コールバックは、1 つ目の引数として SSLSocket インスタンスではなく SSLObject インスタンスを受け取ります。

SSLObject の使用に関する注意:

  • SSLObject 上のすべての IO は non-blocking です。例えば、read() は入力 BIO が持つデータよりも多くのデータを必要とする場合、SSLWantReadError を送出します。

  • wrap_socket() に対して存在するような、モジュールレベルの wrap_bio() 呼び出しは存在しません。SSLObject は、常に SSLContext を経由して作成されます。

SSLObject は、メモリバッファを使用して外界と通信します。MemoryBIO クラスは、以下のように OpenSSL メモリ BIO (Basic IO) オブジェクトをラップし、この目的に使用できるメモリバッファを提供します。

class ssl.MemoryBIO

Python と SSL プロトコルインスタンス間でデータをやり取りするために使用できるメモリバッファ。

pending

現在メモリバッファ中にあるバイト数を返します。

eof

メモリ BIOが現在ファイルの末尾にあるかを表す真偽値です。

read(n=-1)

メモリバッファから最大 n 読み取ります。n が指定されていないか、負値の場合、すべてのバイトが返されます。

write(buf)

buf からメモリ BIO にバイトを書き込みます。buf 引数は、バッファプロトコルをサポートするオブジェクトでなければなりません。

戻り値は、書き込まれるバイト数であり、常に buf の長さと等しくなります。

write_eof()

EOF マーカーをメモリ BIO に書き込みます。このメソッドが呼び出された後に write() を呼ぶことはできません。eof 属性は、バッファ内のすべてのデータが読み出された後に True になります。

18.2.8. SSL セッション

バージョン 3.6 で追加.

class ssl.SSLSession

session が使用するセッションオブジェクトです。

id
time
timeout
ticket_lifetime_hint
has_ticket

18.2.9. セキュリティで考慮すべき点

18.2.9.1. 最善のデフォルト値

クライアントでの使用 では、セキュリティポリシーによる特殊な要件がない限りは、 create_default_context() 関数を使用して SSL コンテキストを作成することを強くお勧めします。この関数は、システムの信頼済み CA 証明書をロードし、証明書の検証とホスト名のチェックを有効化し、十分にセキュアなプロトコルと暗号を選択しようとします。

例として、 smtplib.SMTP クラスを使用して SMTP サーバーに対して信頼できるセキュアな接続を行う方法を以下に示します:

>>> import ssl, smtplib
>>> smtp = smtplib.SMTP("mail.python.org", port=587)
>>> context = ssl.create_default_context()
>>> smtp.starttls(context=context)
(220, b'2.0.0 Ready to start TLS')

接続にクライアントの証明書が必要な場合、 SSLContext.load_cert_chain() によって追加できます。

対照的に、自分自身で SSLContext クラスのコンストラクタを呼び出すことによって SSL コンテキストを作ると、デフォルトでは証明書検証もホスト名チェックも有効になりません。自分で設定を行う場合は、十分なセキュリティレベルを達成するために、以下のパラグラフをお読みください。

18.2.9.2. 手動での設定

18.2.9.2.1. 証明書の検証

SSLContext のコンストラクタを直接呼び出した場合、 CERT_NONE がデフォルトとして使われます。これは接続先の身元特定をしないので安全ではありませんし、特にクライアントモードでは大抵相手となるサーバの信憑性を保障したいでしょう。ですから、クライアントモードでは CERT_REQUIRED を強くお勧めします。ですが、それだけでは不十分です; SSLSocket.getpeercert() を呼び出してサーバ証明書が望んだサービスと合致するかのチェックもしなければなりません。多くのプロトコルとアプリケーションにとって、サービスはホスト名で特定されます; この場合、 match_hostname() が使えます。これらの共通的なチェックは SSLContext.check_hostname が有効な場合、自動的に行われます。

サーバモードにおいて、(より上位のレベルでの認証メカニズムではなく) SSL レイヤーを使ってあなたのクライアントを認証したいならば、 CERT_REQUIRED を指定して同じようにクライアントの証明書を検証すべきでしょう。

注釈

クライアントモードでは anonymous ciphers が有効(デフォルトでは無効)でない限り、 CERT_OPTIONALCERT_REQUIRED は同じ意味になります。

18.2.9.2.2. プロトコルのバージョン

SSL バージョン 2 と 3 は安全性に欠けると考えられており、使用するのは危険です。クライアントとサーバ間の互換性を最大限に確保したい場合、プロトコルバージョンとして PROTOCOL_TLS_CLIENT または PROTOCOL_TLS_SERVER を使用してください。 SSLv2 と SSLv3 はデフォルトで無効になっています。

>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
>>> client_context.options |= ssl.OP_NO_TLSv1
>>> client_context.options |= ssl.OP_NO_TLSv1_1

上記で作成した SSL コンテキストは、TLSv1.2 以降 (システムでサポートされている場合) でのサーバへの接続のみを許可します。PROTOCOL_TLS_CLIENT は、デフォルトで証明書の検証とホスト名のチェックを意味します。コンテキスト中に証明書をロードする必要があります。

18.2.9.2.3. 暗号の選択

高度なセキュリティが要求されている場合、SSL セッションのネゴシエーションで有効になる暗号の微調整が SSLContext.set_ciphers() によって可能です。Python 3.2.3 以降、 ssl モジュールではデフォルトで特定の弱い暗号化が無効になっていますが、暗号方式の選択をさらに厳しく制限したい場合もあるでしょう。OpenSSL ドキュメントの cipher list format を注意深く読んでください。与えられた暗号方式リストによって有効になる暗号方式をチェックするには、SSLContext.get_ciphers() メソッドまたは openssl ciphers コマンドをシステム上で実行してください。

18.2.9.3. マルチプロセス化

(例えば multiprocessingconcurrent.futures を使って、)マルチプロセスアプリケーションの一部としてこのモジュールを使う場合、OpenSSL の内部の乱数発生器は fork したプロセスを適切に処理しないことに気を付けて下さい。SSL の機能を os.fork() とともに使う場合、アプリケーションは親プロセスの PRNG 状態を変更しなければなりません。 RAND_add(), RAND_bytes(), RAND_pseudo_bytes() のいずれかの呼び出し成功があれば十分です。