6

Я запускаю curl на сервере с поддержкой sni с помощью следующей команды

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

Однако я не получаю правильный сертификат, в котором общее имя (CN) установлено как example.com (следовательно, проверка сертификата не удалась). Я знаю, что конфигурация 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

РЕДАКТИРОВАТЬ: я забыл упомянуть, что нет записи DNS на карте example.com к 1.2.3.4. На самом деле это часть моей работы, которую я сделал в 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

2 ответа2

22

Наконец-то нашел ответ после обращения к этому.

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

Заголовок хоста не имеет ничего общего с SNI. Чтобы использовать SNI, вы должны использовать имя хоста в URL, т.е. использовать https://example.com/ вместо http://1.2.3.4/ (и, конечно, использовать https:// не http://).

Более подробная информация: SNI отправляет имя хоста в TLS-рукопожатии (ClientHello). Затем сервер выбирает правильный сертификат на основе этой информации. Только после успешного установления соединения TLS он отправит HTTP-запрос, который содержит указанный вами заголовок Host.

Относительно вашего редактирования / комментариев:

  • Интересно, как вы успешно зашли на сайт через браузер, если для хоста нет записи DNS. Если браузер не знает имя хоста, он также не может использовать SNI.
  • Если вы добавите отображение хоста /ip в /etc/hosts оно будет работать при доступе к https://example.com с помощью curl, поскольку вы знаете, что у вас есть имя хоста для SNI и соответствующий IP-адрес для соединения TCP.
  • Ваш рубиновый код устанавливает ssl_client.hostname. Это не то же самое, что HTTP-заголовок хоста, который вы установили с помощью curl.
  • Я не вижу опцию для curl, где вы могли бы установить имя хоста для TLS SNI и IP для TCP-соединения независимо.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .