For Development HEAD DRAFTSearch (procedure/syntax/module):

12.54 rfc.tls - トランスポート・レイヤ・セキュリティ

Module: rfc.tls

このモジュールはTCPソケット上のセキュアな接続を処理します。 rfc.httpで、https接続を実現するのに使われています (rfc.http - HTTPクライアント参照)。

TLS subsystems

実行中のGaucheがTLSをサポートしているかどうかは機能識別子 gauche.net.tlsで判別できます。 機能識別子については機能条件式を参照してください。

GaucheはTLS実装としてMbedTLS(https://tls.mbed.org/)を使っています。 以前は複数のTLSサブシステムをサポートしていたので、ライブラリは複数のサブシステムを 切り替えて使えるようになっています。将来また別のTLSサブシステムをサポートするかもしれません。

Class: <tls>

{rfc.tls} TLS実装のベースクラスです。このクラスのインスタンスを使って、 セキュアなコネクションを張って通信ができます。 通常、具体的なサブクラスを気にする必要はありません。

このクラスは<connection>を継承します (gauche.connection - コネクションフレームワーク参照)。

Class: <mbed-tls>

{rfc.tls} MbedTLSサブシステムを実装しているクラスです。

Parameter: default-tls-class

{rfc.tls} デフォルトのTLSサブシステムです。現在のバージョンでは、 これは<mbed-tls>クラスか#fです。 #fは、GaucheがTLSをサポートしていないことを示します。

TLS共通の操作

Function: make-tls initargs …

{rfc.tls} 新たなTLSインスタンスを作って返します。インスタンスの具体的なクラスは default-tls-classの値が使われます。 TLSインスタンスはtls-connectに渡すことでクライアントとして使ったり、 tls-bindtls-acceptに渡すことでサーバーとして使うことができます。 以下のそれぞれのサブセクションを参照してください。

引数はTLSクラスに渡されるキーワード-値リストでなければなりません。 以下のキーワード引数が認識されます。

:server-name

TLS Server Name Indication拡張に使うサーバー名を指定します。 一般的には、TLSオブジェクトをクライアントとして使う場合に接続先サーバ名を渡します。 サーバとして使う場合は必要ありません。

:skip-verification

クライアントのみ。この引数が真の値の場合、接続時の証明書の認証を省略します。 これは危険な動作なので、実験目的以外では使わないでください。

Function: tls-close tls

{rfc.tls} TLSコネクションを閉じます。通信相手は接続が閉じられたことを知ります。 tlsがひとたびクローズされるとそれはもう使うことができません。

tlsに対しconnection-closeを呼び出すことでも同じ動作になります (gauche.connection - コネクションフレームワーク参照)。

Function: tls-input-port tls
Function: tls-output-port tls

{rfc.tls} tlsが接続状態にある時、これらは相手と通信するための入力ポートと出力ポートを それぞれ返します。

tlsが接続状態に無い時にこれらを呼ぶと#fが返されます。

tlsに対しconnection-input-portおよび connection-output-portを呼び出すことでも同じ動作になります (gauche.connection - コネクションフレームワーク参照)。

Function: tls-poll tls rw :optional timeout

{rfc.tls} tlsが読み込みもしくは書き込み可能になるまで待ちます。tlsは既に bindされているか接続されていなければなりません。そうでない場合は直ちに()が 返されます。

rwはシンボルreadwriteの組み合わせのリストで、 待つべき条件を指定します。timeout引数は、 時刻を指定する<time>オブジェクトか、 現在からの経過時間を秒で指定する実数値か、 タイムアウトしないことを指示する#fです。省略時は#fが使われます。

戻り値は満たされた条件のリストです。例えばrw引数に (read)もしくは(read write)を指定して、tlsが読み込み可能になったら (read)が返されます。条件が満たされる前にタイムアウトした場合は()が 返されます。

Function: tls-debug-level-set! level

{rfc.tls} これはトラブルシューティング用のAPIです。 TLSサブシステムのグローバルなデバッグログレベルをlevelに設定します。level は0(ログなし、デフォルト)から9(ログ最大)までの正確な整数です。

実際のログ段階の細かさは各TLSサブシステムにより、0-9のレベルがサブシステムのサポートする 段階へとマップされます。いくらか試行して適切な値を見つけてください。

TLSクライアント

クライアントとしてサーバにTLS接続する場合、 サーバの認証を適切に行うために、CA証明書が必要です。 Gaucheは自前でCA証明書を持っておらず、デフォルトでシステムのCA証明書バンドルを利用します。 Unixベースのシステムでは、いくつかのよくあるパスを探索します。 例えばLinuxディストリビューションならca-certificatesやそれに類する パッケージをインストールしておくと良いでしょう。 OSXではopensslをHomebrewでインストールしておくのをおすすめします。 WindowsではWincrypt API経由でシステムの証明書ストアを使います。

デフォルトのコンフィグレーションでは、Gaucheは初期化時にシステムのCA証明書バンドルを探し、 見つかればそれを使うようになっています。かわりとなるCA証明書バンドルのパスを指定したり、 接続毎に独自の証明書を与えることもできます。

もし、何らかの理由で、システム全体で使えるCA証明書バンドルがインストールできない場合、 独自にCurlのCA証明書バンドルをhttps://curl.haxx.se/ca/cacert.pemから ダウンロードしてGaucheのインストールディレクトリに置いておくことができます。 便利なスクリプトが用意してあります。 Gaucheをインストールした後、次のコマンドを実行してください。

gosh tools/get-cacert

curlがシステムにインストールされている必要があります。また、Gaucheをインストールする時に root権限で行ったのであれば、このコマンドがCA証明書バンドルをインストールする時に sudoのパスワードを尋ねるでしょう。

もしこの方法を取ることに決めたなら、時々このコマンドを実行してCA証明書バンドルを 最新版に更新するのを忘れないようにしてください。 CA証明書は期限が切れたり無効化されることがあります。

Parameter: tls-ca-bundle-path :optional path

{rfc.tls} CA証明書バンドルのパスを保持しています。値は、CA証明書バンドルファイルの パス名、シンボルsystem、あるいは#fのいずれかです。

この値がsystemの場合、Gaucheはシステムのデフォルトの証明書バンドルを 使おうとします。もしそれが見つからなければ接続時にエラーが報告されます。

この値が#fの場合、CA証明書は自動的にロードされないので、 tls-load-objectを使って自分で適切な証明書をロードしてやる必要があります。 (このオプションは<ax-tls>のみ有効です。 <mbed-tls>を使う場合は、必ず有効なCA証明書バンドルが必要です。)

デフォルトのコンフィグレーションでは、Gaucheはrfc.tlsモジュール初期化時に システムのCA証明書バンドルが使えるかどうか調べて、使えるならtls-ca-bundle-pathの 初期値をsystemに、使えないなら#fにセットします。 したがって、デフォルトのコンフィグレーションで使っている限り、 この値がsystemであればシステムのCA証明書を使えると考えて良いでしょう。

このデフォルトの振る舞いはconfigure時に--with-ca-bundleオプションで 変えられます。使っているGaucheのコンフィグレーションが変えられているかどうかは、 gauche-config --reconfigureコマンドを実行して--with-ca-bundle オプションがあるかどうかを見ればわかります。

Function: tls-connect tls host port :optional proto

{rfc.tls} クライアントとして、指定されたサーバにTLSで接続します。

tls引数はまだ接続されていないTLSオブジェクトでなければなりません。 hostportは文字列で、それぞれサーバのホスト名とポートを指定します。 ホスト名についてはドメイン名のほか、IP表記が使えます (例: "127.0.0.1""[::1]")。 ポートについては整数のポート番号も名前による指定(例: "https")も使えます。 proto引数はシンボルtcpudpのどちらかでなければならず、 省略時はtcpとみなされます (udpを指定した場合はTLSのかわりにDTLSが使われることになりますが、 今はDTLSを実用的に使うために必要なAPIがいくつか未実装です。)

サーバにコンタクトできたら、この手続きはサーバ証明書を入手して CA証明書を使ってバリデーションを試みます。 バリデーションが失敗したらエラーが投げられます。正しく接続を確立するには、 有効なCA証明書ストアがパラメータtls-ca-bundle-pathで指定されていなければ なりません。

接続が確立してTLSハンドシェイクが成功したら、 引数に渡したtlsオブジェクトはconnected状態になり、 相手とデータをやりとりすることができます。

TLSサーバー

TLSコネクションをサーバとして使うには、秘密鍵、サーバ証明書、および中間証明書を 用意する必要があります。これらはクライアントからのTLS接続を受け付ける前に 読み込まれている必要があります。

Function: tls-load-certificate tls path

{rfc.tls} pathで示されるファイルに格納されたサーバ証明書を読み込みます。 ファイル中に複数の証明書を含めることができます。また、この関数は複数回呼び出せて、 tlsに中間証明書を追加してゆくことができます。

Function: tls-load-private-key tls path password

{rfc.tls} pathで示されるファイルに格納されたサーバの秘密鍵を読み出して登録します。 秘密鍵が暗号化されている場合はpasswordにパスワードを指定します。 秘密鍵が暗号されていない場合はpassword#fを渡します。

Function: tls-bind tls host port :optional proto

{rfc.tls} TLS接続のサーバー側エンドポイントを作ります。

tls引数はまだ接続もbindもされていないTLSオブジェクトでなければなりません。 host引数は文字列のホスト名か#fです。 port引数は整数のポート番号か文字列によるポート名です。 protoにはシンボルtcpudpを渡します。 省略時はtcpが仮定されます。 (NB: udpサーバー (DTLS) を使うにはいくつか追加のAPIサポートが 必要なので、今のところDTLSは使えません)。

socket-bindと同じように、portに0を指定することで、 空いているポート番号をシステムに選んでもらうことができます。 実際にどのポートにバインドされたかは (sockaddr-port (connection-self-address tls)) でわかります。

Function: tls-accept tls

{rfc.tls} 引数のtlsは、tls-bindでバインドされたTLSオブジェクトでなければなりません。 サーバ証明書と秘密鍵はtls-load-certificateおよびtls-load-private-key によってtlsにロードされていなければなりません。

この手続きはクライアントの接続要求を待ちます。接続要求が来たら、 サーバ証明書をクライアントに提示し、TLSハンドシェークを行います。 全てが成功すれば、クライアントに接続された新たなtlsオブジェクトを作って返します。

コネクションメソッド

<tls>クラスはコネクションフレームワークを実装しているので、 以下のメソッドがtlsオブジェクトに対して使えます。特に最初の2つは 下位にあるコネクションのIPアドレスを得るのに使えます。

connection-self-address (c <tls)
connection-peer-address (c <tls>)
connection-input-port (c <tls>)
connection-output-port (c <tls>)
connection-close (c <tls>)


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT