Closed1

Erlang/OTP 26.2.1 で ssl ライブラリで TLS 1.3 と TLS 1.2 を指定して mTLS を利用すると接続できない場合がある

voluntasvoluntas

https://github.com/erlang/otp/pull/7997 にて修正されました。


まとめ

  1. クライアント証明書には sha384WithRSAEncryption のものを利用する
  2. Erlang/OTP 26.2.1 で ssl:connect 利用時に versions に 'tlsv1.3' と 'tlsv1.2' を使用する
  3. サーバー側が TLS 1.2 を選択する
  4. サーバー側が Certicicate Request の署名アルゴリズム一覧に rsa_pkcs1 のみで rsa_pss_rsae を指定してこない
  5. Erlang/OTP の ssl は TLS 1.2 が選択されても、Client Hello で送った TLS 1.3 の署名アルゴリズム一覧を利用する
  6. Erlang/OTP の ssl は TLS 1.2 では署名アルゴリズム sha384WithRSAEncryption は {sha384, rsa} として判断する
  7. そのため TLS 1.3 での rsa_pkcs1_sha384 に引っかからず空振りする
  8. サーバー側が送ってきた署名アルゴリズムに一致する証明書が見つからないため Certificate が空で送られる

というバグ。

再現

一定条件で Erlang/OTP の ssl:connect を利用して OpenSSL s_server に接続をすると発生する。

Erlang/OTP 26.2.1

  • 検証時の最新版、いつからこの問題があったかは不明
  • ssl:connect を利用する
    • certfile と keyfile を指定して mTLS を利用する
    • versions に tlsv1.3 と tlsv1.2 を指定する

OpenSSL s_server

  • -client_sigalgs で rsa_pkcs1_sha384 を指定する
  • -Verify 1 を指定して mTLS を有効にする
  • Certificate Request を送るようになる
  • -tls1_2 を指定して TLS 1.2 を強制する

クライアント証明書

  • Public Key Algorithm: rsaEncryption
  • Signature Algorithm: sha384WithRSAEncryption

発生する問題

サーバーが Certificate Request を送ってきてるのに、クライアントが送り返す Certificate が空になる。

詳細

サーバーが Certificate Request の署名アルゴリズム一覧に rsa_pss_rsae_sha384 が含まれていると動作する

  • rsa_pss_rsae_sha384 の場合は証明書は送る
  • rsa_pss_pss_sha384 や rsa_pkcs1_sha384 の場合は証明書は送らない

Erlang/OTP の ssl では TLS 1.3 と TLS 1.2 では保持している署名アルゴリズム一覧の形式が異なる。

Erlang/OTP 26 [erts-14.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Eshell V14.2 (press Ctrl+G to abort, type help(). for help)
1> ssl:signature_algs(default, 'tlsv1.3').
[eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512,
 ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256,
 rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256,
 rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256,
 rsa_pkcs1_sha512,rsa_pkcs1_sha384,rsa_pkcs1_sha256,
 {sha512,ecdsa},
 {sha384,ecdsa},
 {sha256,ecdsa}]
2> ssl:signature_algs(default, 'tlsv1.2').
[{sha512,ecdsa},
 rsa_pss_pss_sha512,rsa_pss_rsae_sha512,
 {sha512,rsa},
 {sha384,ecdsa},
 rsa_pss_pss_sha384,rsa_pss_rsae_sha384,
 {sha384,rsa},
 {sha256,ecdsa},
 rsa_pss_pss_sha256,rsa_pss_rsae_sha256,
 {sha256,rsa}]

Erlang/OTP の ssl は TLS 1.3 と TLS 1.2 の両方をしていすると TLS 1.3 の署名アルゴリズムを使い続ける

TLS 1.2 が選択されても、TLS 1.3 の署名アルゴリズム一覧をクライアント証明書の判定に利用してしまい、本来あるべき {sha384, rsa} が見つからず、Certificate を空で送る。

おそらくバックポート側のコードがバグってる。この辺。
https://github.com/erlang/otp/blob/OTP-26.2.1/lib/ssl/src/ssl_handshake.erl#L1708-L1756

Erlang/OTP 側には報告済

スゴイ伝えるのが難しかった。
https://github.com/erlang/otp/issues/7978

このスクラップは2024/01/05にクローズされました