Перейти к основному содержимому

Использование TLS клиента OpenSSL для тестирования HTTPS

·955 слов·5 минут
Блог о Сетях, Инфраструктуре и DevOps
Автор
Блог о Сетях, Инфраструктуре и DevOps
DevOps, Infrastructure Engineer, Expert Cyber Security

Введение
#

При диагностике проблем с HTTPS, TLS или сертификатами стандартные инструменты вроде браузера или curl часто скрывают важные детали.
Особенно это заметно при работе с виртуальными хостами, reverse proxy, Kubernetes ingress и автоматическими сертификатами.

В таких случаях оптимальным инструментом становится openssl s_client — низкоуровневый TLS-клиент, позволяющий увидеть все этапы TLS-соединения и точно определить источник проблемы.

Что такое openssl s_client
#

openssl s_client — это консольная утилита, входящая в состав OpenSSL, которая позволяет:

  • установить TCP + TLS соединение;
  • получить цепочку сертификатов сервера;
  • увидеть версию TLS и используемый cipher suite;
  • вручную отправлять HTTP-запросы поверх TLS;
  • диагностировать ошибки TLS-рукопожатия.

Фактически это «прозрачный» HTTPS-клиент без скрытой логики браузеров.

Проверка цепочки сертификатов
#

В процессе TLS-handshake сервер передаёт клиенту свою сертификатную цепочку, которая обычно включает только серверный (leaf) сертификат и промежуточные (intermediate) сертификаты.
Корневой сертификат (root CA) сервер, как правило, не отправляет — он должен уже присутствовать в доверенном хранилище клиента.

Что именно присылает сервер
#

Типичная корректная цепочка от сервера выглядит так:

  • Серверный сертификат (leaf)
  • Один или несколько промежуточных сертификатов (intermediate)

Корневой Root CA:

  • не участвует в handshake
  • не передаётся сервером
  • используется клиентом локально для проверки подписи промежуточного сертификата

В браузере
#

  • Браузеры используют собственное хранилище доверенных корневых CA.
  • Если сервер не прислал промежуточный сертификат, браузер может:
    • автоматически докачать intermediate по AIA (Authority Information Access),
    • сохранить его локально,
    • построить полную цепочку доверия:
      leaf → intermediate → root (локальный)
      
  • Поэтому сайт может открываться в браузере без ошибок, даже если серверная цепочка неполная.

В OpenSSL (openssl s_client)
#

  • OpenSSL НЕ докачивает промежуточные сертификаты.
  • Для проверки используются:
    • сертификаты, присланные сервером (leaf + intermediates),
    • локальное trust store (-CAfile или -CApath) — только для root CA.
  • Root CA не берётся из сети, а ищется локально из базового каталога OpenSSL:
openssl version -d
OPENSSLDIR:/usr/lib/ssl

По умолчанию, -CAfile /usr/lib/ssl/cert.pem (симлинк на единое системное хранилище CA: /etc/ssl/certs/ca-certificates.crt)

Важно понимать разницу:

  • Certificate chain — это цепочка, полученная от сервера
  • verify depth / Verification: OK — результат проверки с использованием локальных доверенных root CA

Если сервер:

  • не прислал промежуточный сертификат,
  • и он отсутствует локально,

OpenSSL не сможет построить цепочку и завершит проверку ошибкой:

Verify return code: 21 (unable to verify the first certificate)

В curl
#

Linux (OpenSSL / LibreSSL / GnuTLS)

  • Поведение аналогично openssl s_client:
    • используется только цепочка от сервера,
    • плюс локальные доверенные root CA,
    • промежуточные сертификаты не докачиваются автоматически.

Windows (Schannel:--ssl-backend schannel)

  • Используется системное крипто-API Windows.
  • Schannel:
    • может автоматически докачивать промежуточные сертификаты,
    • использует системное хранилище сертификатов,
    • строит цепочку доверия аналогично браузеру.

⚠️ Итог

  • Сервер не обязан и не должен отправлять root CA.
  • openssl s_client не докачивает intermediate сертификаты и использует только цепочку от сервера + локальные root CA.
  • Браузеры и Windows Schannel могут автоматически получать промежуточные сертификаты по AIA.
  • Поэтому сайт может работать в браузере, но падать в openssl s_client или curl на Linux при неполной серверной цепочке.
Лучшей практикой считается всегда настраивать сервер так, чтобы он отдавал полный chain (leaf + intermediates).

Корректное тестирование HTTPS с SNI
#

Современные HTTPS-серверы используют SNI (Server Name Indication) для обслуживания нескольких доменов на одном IP-адресе.
Без SNI сервер может вернуть неверный сертификат.

openssl s_client -connect example.com:443 
# или
openssl s_client -connect example.com:443 -servername example.com

Просмотр всех сертификатов, которые отправляет HTTPS сервер

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null

Вывод:

*Certificate chain*  
   *0 s:/CN=example.com*   
     *i:/CN=Let's Encrypt Authority X3*    
*Verify return code: 0 (ok)*   
Verify return code: 0 (ok) — цепочка сертификатов корректна

Коды проверки сертификата:

Код Значение
0 Сертификат корректен
10 Срок действия сертификата истёк
20 Неизвестный издатель
21 Невозможно проверить первый сертификат

Просмотр сертификата в читаемом виде

openssl s_client -connect example.com:443 -servername example.com | openssl x509 -noout -text

Проверка срока действия сертификата

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

Проверка поддерживаемых TLS-версий

# TLS 1.2
openssl s_client -connect example.com:443 -servername example.com -tls1_2

# TLS 1.3
openssl s_client -connect example.com:443 -servername example.com -tls1_3

Проверка cipher suite

# Вывод текущего cipher
openssl s_client -connect example.com:443 -servername example.com

# Принудительное использование cipher suite (TLS 1.2)
openssl s_client -connect example.com:443 -servername example.com -cipher 'ECDHE-RSA-AES256-GCM-SHA384'

STARTTLS для протоколов с explicit TLS
#

# SMTP
openssl s_client -starttls smtp -connect smtp.example.com:25

# IMAP
openssl s_client -starttls imap -connect imap.example.com:143

# POP3
openssl s_client -starttls pop3 -connect pop3.example.com:110

# FTP (explicit FTPS)
openssl s_client -starttls ftp -connect ftp.example.com:21

Принцип работы STARTTLS:

  • Подключение по обычному TCP к порту сервиса.
  • Отправка инициализационного handshake протокола (EHLO, CAPABILITY,..).
  • Отправка команды STARTTLS.
  • Переключение на TLS handshake.
  • Проверка цепочки сертификатов, версии TLS, cipher suite, срока действия.

Пример тестирования HTTPS
#

root@web1:~# openssl s_client -connect www.asterisker.com:443

CONNECTED(00000003)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = E8
verify return:1
depth=0 CN = asterisker.com
verify return:1
---
Certificate chain
 0 s:CN = asterisker.com
   i:C = US, O = Let's Encrypt, CN = E8
   a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA384
   v:NotBefore: Nov 25 20:50:13 2025 GMT; NotAfter: Feb 23 20:50:12 2026 GMT
 1 s:C = US, O = Let's Encrypt, CN = E8
   i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
   a:PKEY: id-ecPublicKey, 384 (bit); sigalg: RSA-SHA256
   v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDxzCCA0ygAwIBAgISBepzzJ46hVOTtMYnVzIIDlNyMAoGCCqGSM49BAMDMDIx
...
cP5Zp6Sj16QCMQC2tQMC57bmWZ2yTz79C5F3+rlRSHUKm4XsZIh60n3AADVeoYQA
TTIpOK9v5oAjCbs=
-----END CERTIFICATE-----
subject=CN = asterisker.com
issuer=C = US, O = Let's Encrypt, CN = E8
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2464 bytes and written 400 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

Пример отправки HTTP-запроса вручную
#

GET / HTTP/1.1
Host: example.com

Related

Настройка GRE over IPSec
·1039 слов·5 минут
Как устроен IPSec VPN
·768 слов·4 минут
VPN технологии на Cisco
·565 слов·3 минут