webdevqa.jp.net

openssl s_client -cert:クライアント証明書がサーバーに送信されたことの証明

バックグラウンド

SSLサーバーおよびクライアント証明書で保護されたAPIを使用して、サービスプロバイダーとの指さし試合に行き詰まっています。

  • CSRを生成し、パブリックCA(この場合はGoDaddy)から証明書を取得し、証明書とCAチェーンをサービスプロバイダーに提供しました。
  • 彼らはおそらくCAと私のクライアント証明書をゲートウェイにロードしたと思われます。
  • 私はopenssl s_client -connect ... -cert ... -key ...を使用して最も基本的なレベルのテストを行っています
  • プロバイダーから、ログには、要求にクライアントSSL証明書がまったく含まれていないことが示唆されていると言われます。
  • 奇妙なことに、証明書の適切なCA発行者は、SSLハンドシェイク中に提供される「受け入れ可能なクライアント証明書CA名」のリストに表示されます。
  • 参考までに、テスト用に作成して提供した自己署名証明書は、実際には正しく機能します。

サンプル(失敗した)リクエスト

[Shell ~]$ openssl s_client -connect Host:443 -cert cert_and_key.pem -key cert_and_key.pem -state -quiet
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=2 **SNIP**
verify return:1
depth=1 **SNIP**
verify return:1
depth=0 **SNIP**
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server key exchange A
SSL_connect:SSLv3 read server certificate request A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client certificate A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write certificate verify A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL3 alert read:fatal:unknown CA
SSL_connect:failed in SSLv3 read finished A
140011313276744:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:1197:SSL alert number 48
140011313276744:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:

SSL3 alert read:fatal:unknown CAエラーの私の読み取りは、サーバーが(実際に)私が提供している証明書の発行者を認識しないということです。ただし、プロバイダーはCA証明書が適切に読み込まれていることを「保証」しており、そうでないと納得することができませんでした。

質問

したがって、他の(広範な)トラブルシューティング手順を別として、私が本当に知りたいのは次のとおりです。

クライアント証明書がサーバーによって要求されただけではなく、実際にはに送信されたを最終的に示すopenssl s_clientからの出力がありますSSLハンドシェイク中のサーバー?

-state-msg-debugおよび-traceオプションを試しましたが、出力を解釈するのに必要な背景がありません。

EJPの答えは、私が提供したサンプル出力はwrite client certificate Aで十分な証拠であることを示唆していますが、この出力はコマンドラインで-certオプションが使用されたかどうかに関係なく表示されるため、証明書を示すものではありませんwas 送信済み

34
beporter

クライアント証明書がサーバーに送信されていることを確認するには、-stateフラグと-debugフラグの組み合わせからの出力を分析する必要があります。

最初にベースラインとして、実行してみてください

$ openssl s_client -connect Host:443 -state -debug

大量の出力が得られますが、関心のある行は次のようになります。

SSL_connect:SSLv3 read server done A
write to 0x211efb0 [0x21ced50] (12 bytes => 12 (0xC))
0000 - 16 03 01 00 07 0b 00 00-03                        .........
000c - <SPACES/NULS>
SSL_connect:SSLv3 write client certificate A

ここで何が起こっていますか:

  • -stateフラグは、前のセクションの終わりを表示します。

    SSL_connect:SSLv3 read server done A  
    

    これは、出力で自分の場所を見つけるためにのみ重要です。

  • -debugフラグは、次のステップで送信される未加工バイトを示しています。

    write to 0x211efb0 [0x21ced50] (12 bytes => 12 (0xC))
    0000 - 16 03 01 00 07 0b 00 00-03                        .........
    000c - <SPACES/NULS>
    
  • 最後に、-stateフラグは、-debugがちょうどエコーしたステップの結果を再度報告します。

    SSL_connect:SSLv3 write client certificate A
    

つまり、s_clientはサーバーから送信されたデータの読み取りを終了し、12バイトをサーバーに(私が想定しているように)「クライアント証明書なし」メッセージとして送信しました。


テストを繰り返しますが、今回は-certおよび-keyフラグを次のように含めます。

$ openssl s_client -connect Host:443 \
   -cert cert_and_key.pem \
   -key cert_and_key.pem  \
   -state -debug

"read server done"行と"write client certificate"行の間の出力ははるかに長くなり、クライアント証明書のバイナリ形式を表します。

SSL_connect:SSLv3 read server done A
write to 0x7bd970 [0x86d890] (1576 bytes => 1576 (0x628))
0000 - 16 03 01 06 23 0b 00 06-1f 00 06 1c 00 06 19 31   ....#..........1
(*SNIP*)
0620 - 95 ca 5e f4 2f 6c 43 11-                          ..^%/lC.
SSL_connect:SSLv3 write client certificate A

1576 bytesはそれ自体で証明書が送信されたことを示す優れた指標ですが、その上、右側の列には証明書の人間が読める部分が表示されます。CNを認識できるはずです。そしてそこにあなたの証明書の発行者の文字列。

78
beporter

これは古い質問ですが、まだ答えがあるようには見えません。この状況を複製しましたが、サーバーアプリを作成しているので、サーバー側でも何が起こるかを確認できました。クライアントは、サーバーが証明書を要求したとき、およびs_clientコマンドラインで実際の証明書への参照を持っている場合、証明書を送信します。サーバーアプリケーションは、クライアント証明書を要求し、提示されない場合は失敗するように設定されています。私が発行するコマンドラインは次のとおりです。

Yourhostname here -vvvvvvvvvv s_client -connect <hostname>:443 -cert client.pem -key cckey.pem -CAfile rootcert.pem -cipher ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH -tls1 -state

コマンドの「-cert client.pem」部分を省略すると、サーバー側でハンドシェイクが失敗し、s_clientコマンドがエラーが報告されて失敗します。 「クライアント証明書のCA名が送信されていません」というレポートは引き続き表示されますが、上記の回答があったと思います。

簡単な答えは、サーバーが、クライアントが通常の動作条件下で証明書を送信するかどうかを決定することです(s_clientは正常ではありません)。私のプロジェクトには双方向認証が必要ですが、双方向認証が行われる多くの状況に慣れていません。

証明書を明確に送信しています。サーバーは明らかにそれを拒否しています。

ここで不足している情報は、証明書が作成された正確な方法と、プロバイダーが証明書をロードした方法ですが、おそらくそれまでにすべてがまとめられています。

7
JSAnderson