Сообщение об ошибке
Peer certificate subjectAltName did not match expected name `api.example.com'
Также выводится как
- Warning: file_get_contents(): Peer certificate subjectAltName did not match expected name `api.example.com'
PHP обрамляет ожидаемое имя обратным апострофом перед ним и обычным апострофом после него. Для сертификатов без расширения SAN вместо этого выводится «Peer certificate CN=`…' did not match expected CN=`…'». Клиенты на основе ext-curl (Guzzle) выдают в той же ситуации ошибку cURL 60 с текстом «no alternative certificate subject name matches target hostname».
PHP streams (openssl stream wrapper) — verify_peer_name check
Что это означает
Цепочка сертификатов прошла проверку, но ни одно из альтернативных имён субъекта (SAN) сертификата не совпадает с именем, которое ожидал PHP (хостом из URL или параметром контекста peer_name). Обёртка потоков PHP сама выполняет эту проверку после рукопожатия и отклоняет соединение, после чего выводит «Failed to enable crypto».
Почему это происходит
Имени хоста нет в сертификате
частоВ URL указано имя, для которого сертификат не выпускался.
Подключение по IP или внутреннему псевдониму
частоЧасто встречается у подключений к базам данных, LDAP и SMTP, в настройках которых указаны IP-адреса.
К SMTP-релеям обращаются под другим именем
иногдаБиблиотеки отправки почты, в настройках которых указан «localhost» или псевдоним провайдера, тогда как сервер предъявляет сертификат для своего публичного имени.
Как исправить
- 1.
Сравните список SAN с хостом
В сообщении указан ожидаемый хост, а записи SAN сертификата показывают, какие имена он покрывает.
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -ext subjectAltName - 2.
Задайте peer_name при подключении по адресу
Параметр peer_name контекста ssl указывает PHP, какое имя проверять, когда сокет подключается по IP-адресу.
php // Connect to an address but verify the certificate's real name $context = stream_context_create(['ssl' => ['peer_name' => 'mail.example.com']]); $socket = stream_socket_client('tls://10.0.0.25:465', $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $context); - 3.
Указывайте в DSN имя хоста из сертификата
Указывайте в настройках библиотек отправки почты и клиентов то имя, которое содержит сертификат сервера.
text # Mail libraries (PHPMailer, Symfony Mailer): use the SMTP host name from the certificate MAILER_DSN=smtp://user:pass@mail.example.com:587
Связанные ошибки
SSL operation failed with code 1. OpenSSL Error messages:PHP streams (file_get_contents, fopen, stream_socket_client, SoapClient, mail libraries)curl: (60) SSL: no alternative certificate subject name matches target hostname…curl (OpenSSL backend)x509: certificate is valid for example.com, not api.example.comGo crypto/x509