PHP streams (openssl stream wrapper)PHP
错误信息
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 error 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 或内部别名连接
常见常见于用 IP 地址配置的数据库、LDAP 和 SMTP 连接。
通过其他名称访问 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
ssl 上下文选项 peer_name 告诉 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