Eu criei um certificado LetsEncrypt que contém dois domínios, one.example.com e two.example.com (Observe que estou ciente dos certificados curinga, mas esta questão contém vários nomes em um certificado).
O certificado tem one.example.com como CN e one.example.com e two.example.com como atributos X509v3 Subject Alternative Name.
Eu uso o certificado com nginx.
Convencionalmente, o cliente apenas verificaria se CN corresponde ao nome DNS e espero que, desde que one.example.com e two.example.com agora apontem para o mesmo servidor nginx, eu possa acessá-los por meio de ambos os nomes DNS. Mas apenas one.example.com funciona.
Posso reproduzir isso com o openssl:
openssl s_client -showcerts -servername one.example.com -connect 192.168.151.97:443
Connecting to 192.168.151.97
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=E5
verify return:1
depth=0 CN=one.example.com
verify return:1
---
Certificate chain
0 s:CN=one.example.com
i:C=US, O=Let's Encrypt, CN=E5
a:PKEY: id-ecPublicKey, 256 (bit); sigalg: ecdsa-with-SHA384
v:NotBefore: Jul 17 05:27:55 2024 GMT; NotAfter: Oct 15 05:27:54 2024 GMT
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----
1 s:C=US, O=Let's Encrypt, CN=E5
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
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----
---
Server certificate
subject=CN=one.example.com
issuer=C=US, O=Let's Encrypt, CN=E5
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2434 bytes and written 410 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
openssl s_client -showcerts -servername two.example.com -connect 192.168.151.97:443
Connecting to 192.168.151.97
CONNECTED(00000003)
402EB7DC01000000:error:0A000458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name:ssl/record/rec_layer_s3.c:907:SSL alert number 112
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 333 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
Então você pode ver que one.example.com funciona, mas two.example.com não funciona, mesmo que esteja listado como Nome alternativo do assunto.
Mesmo quando eu especifico explicitamente -servername two.example.com
, a situação não muda.
Por que os navegadores/openssl não verificam two.example.com com êxito?
De acordo com essas linhas, o openssl não pode verificar o certificado porque não há nada para verificar – o servidor não enviou um certificado, em vez disso enviou um alerta de “Nome não reconhecido”.
Isso geralmente significa que o cliente solicitou um bloco para
-servername
o qual sua configuração Nginx não possui nenhumserver{}
bloco correspondente.Normalmente, a correspondência das solicitações de indicação de nome do servidor TLS com as configurações do servidor não é feita nos próprios certificados; em vez disso, é feito com nomes configurados manualmente - em outras palavras, TLS SNI serve tanto para selecionar vhosts quanto para selecionar certificados (e alguns servidores impõem isso), portanto, quando um cliente solicita TLS SNI "two.example.com" o servidor não envia apenas qualquer certificado correspondente, mas especificamente o certificado configurado no bloco vhost correspondente.
Ambos são implementações razoáveis do TLS SNI. Se um cliente HTTP solicitasse um vhost que o servidor não configurou, um servidor HTTP poderia retornar um vhost padrão enquanto outro retornaria um erro "403/404 no such vhost", muitas vezes por motivos de segurança (por exemplo, para evitar domínios indesejados de apontando para ele) – da mesma forma, quando o cliente solicita explicitamente um certificado para um nome que não está configurado como vhost, o servidor pode assumir que ele não deve ser acessado por meio desse domínio.
(O Apache tem a mesma opção que SSLStrictSNIVHostCheck.)