web-dev-qa-db-ja.com

curlおよびsni対応サーバー

次のコマンドでsni対応サーバーに対してcurlを実行しています

curl --cacert CustomCA.crt -H "Host: example.com" https://1.2.3.4/foo

ただし、共通名(CN)がexample.comとして設定されているため、正しい証明書を取得できません(そのため、証明書の検証に失敗しました)。 Webブラウザからアクセスすると正しい証明書が配信されるので、SNI構成が正しく行われていることがわかります。念のため、私の現在の環境は

> curl --version
curl 7.35.0 (x86_64-pc-linux-gnu) libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3
Protocols: dict file ftp ftps Gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smtp smtps telnet tftp 
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP 
> lsb_release -a
LSB Version:    core-2.0-AMD64:core-2.0-noarch:core-3.0-AMD64:core-3.0-noarch:core-3.1-AMD64:core-3.1-noarch:core-3.2-AMD64:core-3.2-noarch:core-4.0-AMD64:core-4.0-noarch:core-4.1-AMD64:core-4.1-noarch:security-4.0-AMD64:security-4.0-noarch:security-4.1-AMD64:security-4.1-noarch
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.1 LTS
Release:        14.04
Codename:       trusty

編集:example.comを1.2.3.4にマップするDNSエントリがないことを言及するのを忘れていました。これは実際には私の作業の一部であり、Rubyで次のように実行しました。

  context = OpenSSL::SSL::SSLContext.new
  context.ca_file = 'CustomCA.crt'
  context.verify_mode = OpenSSL::SSL::VERIFY_PEER

  tcp_client = TCPSocket.new('1.2.3.4', 443)
  ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client, context)
  ssl_client.hostname = 'example.com'
  ssl_client.connect
  cert = OpenSSL::X509::Certificate.new(ssl_client.peer_cert)
  cert_ca = OpenSSL::X509::Certificate.new(File.read(ca_path))
  ssl_client.sysclose
  tcp_client.close

Curlを使用してこのようなものを再作成する方法を考えているところです。

そして.../etc/hostsの自分のコピーを編集することで、コマンドは適切に動作します

1.2.3.4 example.com

何故ですか?

編集2:opensslを介してそれを行う

openssl s_client -connect 1.2.3.4:443 -servername example.com
6
Jeffrey04

HostヘッダーはSNIとは関係ありません。 SNIを使用するには、URLでホスト名を使用する必要があります。つまり、_https://example.com/_ではなく_http://1.2.3.4/_を使用します(もちろん、http://ではなくhttps://を使用します)。

詳細:SNIはTLSハンドシェイク(ClientHello)内でホスト名を送信します。次に、サーバーはこの情報に基づいて正しい証明書を選択します。 TLS接続が正常に確立された後にのみ、指定したホストヘッダーを含むHTTP要求が送信されます。

編集/コメントについて:

  • ホストのDNSエントリがない場合、ブラウザーでサイトに正常にアクセスできたのでしょうか。ブラウザがホスト名を知らない場合、SNIも使用できません。
  • Host/ipマッピングを_/etc/hosts_に追加すると、curlで_https://example.com_にアクセスするときに機能します。SNIのホスト名とTCP =接続。
  • あなたのRubyコードはssl_client.hostnameを設定します。これは、curlで設定したHTTPホストヘッダーと同じではありません。
  • TCP接続に個別にTLS SNIとIPのホスト名を設定できるcurlのオプションが表示されません。
6
Steffen Ullrich

this を参照した後、最後に答えが見つかりました。

curl --cacert CustomCA.crt --resolve example.com:443:1.2.3.4 https://example.com/foo
24
Jeffrey04