このドキュメンテーションは、MicroPython の最新開発ブランチのためのものです。 リリースバージョンでは利用できない機能に言及することがあります。

特定のリリースのドキュメントをお探しの場合は、左側のドロップダウンメニューを使って、 望みのバージョンを選択します。

ssl -- SSL/TLS モジュール

このモジュールは、該当する CPython モジュールのサブセットを実装しています。 詳しくはオリジナルの CPython ドキュメンテーションを参照してください: ssl.

このモジュールは Transport Layer Security (以前は “Secure Sockets Layer” とと呼ばれていて、今でもこの名称で呼ばれることが多々あります)による暗号化とクライアント側とサーバー側のネットワークソケットのピア認証機能へのアクセスを提供します。

関数

ssl.wrap_socket(sock, server_side=False, key=None, cert=None, cert_reqs=CERT_NONE, cadata=None, server_hostname=None, do_handshake=True)

指定した sock をラップし、新しいラップ済ソケットオブジェクトを返します。この関数内ではまず SSLContext を作成し、そのコンテキストオブジェクト上で SSLContext.wrap_socket メソッドを呼び出しています。引数 sock, server_side, server_hostname は呼び出すメソッドにそのまま渡されます。引数 do_handshakedo_handshake_on_connect として渡されます。残りの引数は次のように動作します:

  • cert_reqs はピア(サーバーまたはクライアント)が有効な証明書を提示しなければならないかを指定します。 mbedtls ベースのポートでは ssl.CERT_NONEssl.CERT_OPTIONAL が証明書を検証せず、 ssl.CERT_REQUIRED だけが証明書を検証します。

  • cadata は、ピアの証明書を検証するためのCA証明書チェーン(DERフォーマット)をバイト列オブジェクトにしたものです。現在のところ、単一のDERエンコードされた証明書のみをサポートします。

特定の MicroPython ポート のモジュールの実装によっては、 上記のキーワード引数の一部またはすべてがサポートされていない可能性があります。

クラス SSLContext

class ssl.SSLContext(protocol, /)

新しい SSLContext のインスタンスを作成します。 protocol 引数は PROTOCOL_* 定数のいずれかでなければなりません。

SSLContext.load_cert_chain(certfile, keyfile)

秘密鍵とそれに対応する証明書をロードします。 certfile は証明書のファイルパスを示す文字列です。 keyfile は秘密鍵のファイルパスを示す文字列です。

CPython との違い

MicroPythonの拡張機能: certfile および keyfile には、文字列の代わりにバイト列オブジェクトで指定でき、その場合は実際の証明書/秘密鍵データとして解釈されます。

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

ピアの証明書を検証するための CA 証明書チェーンをロードします。 cafile は CA 証明書のファイルパスです。 cadata は CA 証明書を含むバイト列オブジェクトです。これらの引数のうち、どちらか一方だけを指定してください。

SSLContext.get_ciphers()

有効な暗号スイートのリストを取得し、それを文字列のリストとして返します。

SSLContext.set_ciphers(ciphers)

このコンテキストで作成されたソケットに対して利用可能な暗号スイートを設定します。 ciphers には IANA の暗号スイート形式 である文字列のリストを指定してください。

SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None, client_id=None)

stream sock (通常は SOCK_STREAM タイプの socket.socket インスタンス)を引数としてとり、基本となるストリームをラップした ssl.SSLSocket インスタンスを返します。返されるオブジェクトには read(), write() のような通常の stream インスタンスのインタフェースメソッドがあります。

  • server_side にはラップするソケットがサーバ側かクライアント側かを指定します。サーバー側の SSL ソケットは、非 SSL リスニングサーバーソケットの accept() から返される通常のソケットから作成する必要があります。

  • do_handshake_on_connect は、ハンドシェイクが wrap_socket の一部として実行されるか、最初の読み書きの一部として実行するよう延期するかを決定します。ブロッキングソケットの場合はハンドシェイクをすぐに実行するのが標準です。非ブロッキングソケットの場合(つまり wrap_socket に渡した sock が非ブロッキングモードの場合)、ハンドシェイクは一般的に延期すべきです。さもなければ wrap_socket がハンドシェイクの完了までブロックするからです。AXTLS では、ハンドシェイクは最初の読み書きまで延期できますが、その後は完了するまでブロックされることに注意してください。

  • server_hostname はクライアントとして使用するためのもので、受信したサーバー証明書と照合するためのホスト名を指定します。また、これはサーバー名表示(SNI: Server Name Indication)としても使われ、サーバーが適切な証明書を提示できるようにします。

  • client_id は MicroPython 固有の拡張引数であり、DTLS サーバーを実装する場合にのみ使われます。詳細については DTLS サポート を参照してください。

警告

ssl モジュールの実装によってはサーバー証明書の検証が行われないため、中間者攻撃を受けやすい SSL 接続になってしまいます。

CPython の wrap_socketSSLSocket オブジェクトを返します。このオブジェクトには sendrecv などソケットのための典型的なメソッドがあります。MicroPython の wrap_socket は CPython の SSLObject に類似のオブジェクトを返しますが、ソケットメソッドはありません。

SSLContext.verify_mode

ピア証明書の検証の動作を設定/取得します。 CERT_* 定数のいずれかにしなければなりません。

注釈

ssl.CERT_REQUIRED には、デバイスの日付/時刻が適切に設定されている必要があります。たとえば mpremote rtc --setntptime を使って設定できます。また、クライアント側の場合は server_hostname が指定されている必要があります。

例外

ssl.SSLError

この例外は存在しません。代わりにベースクラスの OSError が使われます。

DTLS サポート

CPython との違い

これは MicroPython 拡張です。

たいていのポートにおいて、このモジュールは DTLS のクライアントモードとサーバーモードをサポートしており、 SSLContextprotocol 引数として PROTOCOL_DTLS_CLIENTPROTOCOL_DTLS_SERVER 定数を指定できます。

この場合、基盤となるソケットはデータグラムソケット(afsocket.AF_INETtypesocket.SOCK_DGRAM を指定した socket.socket でオープンしたソケットのようなもの)として動作する必要があります。

DTLS は mbedTLS を使うポートでのみサポートされており、デフォルトではたいていのビルドオプションで有効になってます。ビルドオプションで MBEDTLS_SSL_PROTO_DTLS を 0 にすることにより無効にできます。

DTLS サーバーのサポート

MicroPython における DTLS サーバーのサポートは、DTLS 1.2 で要求される "Hello Verify" に対応するように構成されています。これは DTLS クライアントにとっては透過的ですが、MicroPython で DTLS サーバーを実装する際には次の点に注意が必要です:

  • サーバーは SSLContext.wrap_socket() を呼び出す際に、追加の引数 client_id を渡す必要があります。この ID は、クライアントを識別するトランスポート固有の識別子であり、 bytes オブジェクト(または同等のもの)でなければなりません。

    最も簡単な方法は socket.recv_from() によって返される (client_ip, client_port) のタプルをバイト列に変換することです。つまり、以下のようになります:

    _, client_addr = sock.recvfrom(1, socket.MSG_PEEK)
    sock.connect(client_addr)  # Connect back to the client
    sock = ssl_ctx.wrap_socket(sock, server_side=True,
                               client_id=repr(client_addr).encode())
    
  • クライアントが最初に接続してきたとき、サーバー側で wrap_socket を呼び出すと、 OSError エラー "Hello Verify Required" が発生して失敗します。これは、DTLS の "Hello Verify" クッキーがまだクライアント側で認識されていないためです。同じクライアントが2回目に接続してくると wrap_socket が成功します。

  • "Hello Verify" のための DTLS クッキーは SSLContext オブジェクトに関連付けられているため、同じクライアントからの再接続には同じ SSLContext オブジェクトを使って wrap_socket を呼び出す必要があります。クッキーの実装にはタイムアウト機構が含まれており、接続するクライアント数に関係なくメモリ使用量は一定なので、サーバーの存続期間中ずっと同じ SSLContext オブジェクトを使い続けても問題ありません。

定数

ssl.PROTOCOL_TLS_CLIENT
ssl.PROTOCOL_TLS_SERVER
ssl.PROTOCOL_DTLS_CLIENT(when DTLS support is enabled)
ssl.PROTOCOL_DTLS_SERVER(when DTLS support is enabled)

protocol パラメーターでサポートされる値です。

ssl.CERT_NONE
ssl.CERT_OPTIONAL
ssl.CERT_REQUIRED

cert_reqs パラメーターと "SSLContext.verify_mode 属性でサポートされる値です。