Bug 65591

Summary: Standard + non-standard SSL port + name-based vhosts + SNI: Port number disregarded when selecting certificate?
Product: Apache httpd-2 Reporter: Björn Wiberg <bjorn.wiberg>
Component: mod_sslAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: NEW ---    
Severity: normal    
Priority: P2    
Version: 2.4.6   
Target Milestone: ---   
Hardware: PC   
OS: Linux   

Description Björn Wiberg 2021-09-22 13:51:38 UTC
It appears that when using both a standard (443) and a non-standard (8443) SSL port together with name-based virtual hosts and SNI, Apache does not consider the port number when selecting which certificate to serve to the client if multiple vhosts have equal ServerNames (but different ports).

Instead, Apache appears to serve the certificate from the first listed vhost with a matching ServerName, regardless of the port number.

Furthermore, ServerAliases appear not to be considered when determining which vhost will serve the actual web content.


Consider the following configuration. Two default vhosts to catch "unexpected" requests, followed by two "real" vhosts serving the actual web content:

Listen 443 https
Listen 8443 https

<VirtualHost *:443>
  ServerName default_vhost_ssl

  SSLEngine on
  SSLCertificateFile /etc/pki/tls/certs/idp-frontend.crt
  SSLCertificateKeyFile /etc/pki/tls/private/idp-frontend.key
  SSLCertificateChainFile /etc/pki/tls/certs/idp-frontend.chain

  <Location "/">
    Options None
    Require all denied
  </Location>
</VirtualHost>

<VirtualHost *:8443>
  ServerName default_vhost_ssl_8443

  SSLEngine on
  SSLCertificateFile /opt/shibboleth-idp/credentials/idp-backchannel.crt
  SSLCertificateKeyFile /opt/shibboleth-idp/credentials/idp-backchannel.key
  # no SSLCertificateChainFile as the certificate is self-signed

  <Location "/">
    Options None
    Require all denied
  </Location>
</VirtualHost>

<VirtualHost *:443>
  ServerName myservice.com

  SSLEngine on
  SSLCertificateFile /etc/pki/tls/certs/idp-frontend.crt
  SSLCertificateKeyFile /etc/pki/tls/private/idp-frontend.key
  SSLCertificateChainFile /etc/pki/tls/certs/idp-frontend.chain
</VirtualHost>

<VirtualHost *:8443>
  ServerName myservice.com

  SSLEngine on
  SSLCertificateFile /opt/shibboleth-idp/credentials/idp-backchannel.crt
  SSLCertificateKeyFile /opt/shibboleth-idp/credentials/idp-backchannel.key
  # no SSLCertificateChainFile as the certificate is self-signed
</VirtualHost>

Testing with:

openssl s_client -connect myservice.com:8443 -no_ssl2 -no_ssl3 -debug -servername 'myservice.com' < /dev/null

...appears to yield the idp-frontend.crt certificate (incorrect), but no certificate chain (correct).

I would have expected Apache to serve the idp-backchannel.crt certificate and no certificate chain. I would definitely not have expected to get the wrong certificate but the correct (no) certificate chain.

Is this expected behavior, or could there perhaps be some kind of bug in the vhost/certificate selection process when using SNI?


Adjusting the ServerName in the "real" (last) 8443 vhost to:

  ServerName myservice.com:8443

...as per https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23 will instead cause the SNI name (which is "myservice.com") not to match the ServerName, causing Apache to select the default 8443 vhost, so not serving any "real" content any longer (yielding 404s to the client).

Trying to add a ServerAlias in the "real" (last) 8443 vhost to overcome this:

  ServerName myservice.com
  ServerAlias myservice.com:8443

...appears not to work. Apache appears to only consider ServerNames when determining which vhost will serve the web content when using SNI.

The only easy work-around for this that I can think of would be to skip having a default 8443 vhost.