rontolisp:tls-connect
(rontolisp:tls-connect host port)
(rontolisp:tls-connect host port :insecure value)
host/port へブロッキング TCP 接続を開き、TLS ハンドシェイクを行って
双方向ストリームハンドルを返します —
rontolisp:tcp-connect の暗号化版です。ハンドルは
ファイルストリームと同じハンドル空間にあるため、標準のストリーム関数がそのまま
使えます: read-line、write-line、
read-byte、write-byte、
close。プレーンなソケットと同様、書き込みは即座に送信され、相手が
接続を閉じると read-line は nil を返します。
サーバー証明書は JDK デフォルトのトラストストアで検証され、ホスト名も検証されます
(HTTPS 方式のエンドポイント識別)。そのため、信頼されていない証明書やホスト名の
一致しない証明書を持つサーバーへの接続はエラーを通知します。自己署名証明書を
信頼するには、標準の javax.net.ssl.trustStore /
javax.net.ssl.trustStorePassword システムプロパティで独自のトラストストアを
指定してください。これらは呼び出しのたびに再読み込みされます。
:insecure に nil 以外の value を渡すと、両方の検証を無効化します —
証明書チェーンを無条件に受け入れ、ホスト名も検証しません。これは自己署名サーバー
に対する開発用途を想定したものです。中間者攻撃に対する保護がすべて失われるため、
実運用のエンドポイントには決して使わないでください。:insecure nil はオプションを
省略した場合(検証あり)と同じです。
以下の例は TLS 上で HTTP/1.1 を手書きで話します(リクエスト行は CRLF で終わる
必要があるため、キャリッジリターンを明示的に付加しています。レスポンス側の CR は
read-line が取り除きます)。実際の HTTPS リクエストには
rontolisp:fetch を使ってください — tls-connect は
任意の TLS でラップされたプロトコルのためのものです:
(let ((sock (rontolisp:tls-connect "example.com" 443))
(cr (princ-to-string (code-char 13))))
(write-line (concatenate 'string "GET / HTTP/1.1" cr) sock)
(write-line (concatenate 'string "Host: example.com" cr) sock)
(write-line (concatenate 'string "Connection: close" cr) sock)
(write-line cr sock)
(print (read-line sock)) ; "HTTP/1.1 200 OK"
(close sock))
バックエンドのサポート
- インタープリタと JVM: JDK の TLS スタック(
SSLSocket)を使います。hostにはホスト名または IP リテラルを指定できます。接続やハンドシェイクの 失敗(ポート拒否、信頼されていない証明書、ホスト名の不一致)はエラーを通知 します。 - WASM: 現時点では非サポート —
tls-connectは Preview 1 と--componentのどちらのモードでもコンパイルエラーです。component モードのクライアントは wasmtime の実験的なwasi:tls@0.3.0-draftインターフェイス上に構築できますが、このインターフェイスは不安定です (semver の保証なし)。安定するまではインタープリタか JVM バックエンドを使ってください。 - ブラウザプレイグラウンド: 非サポート — ブラウザのサンドボックスには生の
TCP ソケットがないため、
tls-connectはエラーを通知します。
制限事項
:insecureはすべてを無効化するオプトアウトです(証明書ごとのピン留めは できません)。検証を有効にしたまま特定の追加証明書を信頼するには、代わりに トラストストアのシステムプロパティを使ってください。TLS のサーバー側はrontolisp:tls-listenを参照してください。read(S 式リーダー)はソケットハンドルでは動きません。行またはバイトで 読み取り、明示的にパースしてください(例:read-from-string)。