I analyzed this issue a bit more.
As a rule, it is impossible to host more than one SSL virtual host on the same IP address and port. This is because Apache needs to know the name of the host in order to choose the correct certificate to setup the encryption layer. But the name of the host being requested is contained only in the HTTP request headers, which are part of the encrypted content. It is therefore not available until after the encryption is already negotiated. This means that the correct certificate cannot be selected, and clients will receive certificate mismatch warnings and be vulnerable to man-in-the-middle attacks.
In reality, Apache will allow you to configure name-based SSL virtual hosts, but it will always use the configuration from the first-listed virtual host (on the selected IP address and port) to setup the encryption layer. In reality, Apache will allow you to configure name-based SSL virtual hosts, but it will always use the configuration from the first-listed virtual host (on the selected IP address and port) to setup the encryption layer. In certain specific circumstances, it is acceptable to use a single SSL configuration for several virtual hosts. In particular, this will work if the SSL certificate applies to all the virtual hosts. ...
Update: Corion has since published this code on GitHub, please consider that the most current version: https://github.com/Corion/Perlmonks-Maintenance/blob/master/scripts/perlmonks-server-check.pl
#!/usr/bin/env perl
use warnings;
use strict;
use Data::Dump;
use Net::DNS;
use LWP::UserAgent;
require LWP::Protocol::https; # make sure this is installed
use Class::Method::Modifiers qw/around/;
my @ADDRS = qw/
perlmonks.org www.perlmonks.org css.perlmonks.org
perlmonks.com www.perlmonks.com css.perlmonks.com
perlmonks.net www.perlmonks.net css.perlmonks.net
perlmonks.pairsite.com /;
my $DNS = { # As of 2018-06-17:
"css.perlmonks.com" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"css.perlmonks.net" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"css.perlmonks.org" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"perlmonks.com" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"perlmonks.net" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"perlmonks.org" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"perlmonks.pairsite.com" => ["209.197.123.153"],
"www.perlmonks.com" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"www.perlmonks.net" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
"www.perlmonks.org" => ["209.197.123.153", "216.92.34.251", "66
+.39.54.27"],
};
if (0) {
$DNS={};
my $resolver = new Net::DNS::Resolver(recurse => 1, debug => 0);
for my $addr (@ADDRS) {
# figure out the authoritative server
$resolver->nameservers('8.8.8.8');
my $packet = $resolver->send($addr, 'SOA');
my @server = map {$_->mname} grep {$_->type eq 'SOA'}
$packet->answer;
die "@server" unless @server==1;
$packet = $resolver->send($server[0], 'A');
my @nameservers = map {$_->address} grep {$_->type eq 'A'}
$packet->answer;
die "@server" unless @nameservers;
# query the authoritative server
$resolver->nameservers(@nameservers);
$packet = $resolver->send($addr, 'A');
my @ips = sort map {$_->address} grep {$_->type eq 'A'}
$packet->answer;
printf "%23s %-35s %s\n", $addr,
"(\@$server[0]/@nameservers)", join ' ', @ips;
$DNS->{$addr} = \@ips;
}
dd $DNS;
}
our $force_peeraddr;
around 'LWP::Protocol::http::_extra_sock_opts' => sub {
my $orig = shift;
die unless wantarray;
my @rv = $orig->(@_);
push @rv, PeerAddr => $force_peeraddr if defined $force_peeraddr;
return @rv;
};
around 'LWP::Protocol::https::_get_sock_info' => sub {
my $orig = shift;
my ($self, $res, $sock) = @_;
my $cert = $sock->get_peer_certificate;
my @san = $cert->peer_certificate('subjectAltNames');
while (@san) {
my ($type_id, $value) = splice @san, 0, 2;
$res->push_header("Client-SSL-Cert-SubjectAltName"
=> "$type_id: $value");
}
$orig->(@_);
};
my %certs;
my $ua = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0 } );
for my $addr (sort keys %$DNS) {
for my $host (sort @{ $DNS->{$addr} }) {
warn "Requesting $addr from $host...\n";
local $force_peeraddr = $host;
my $res = $ua->get("https://$addr");
die $res->status_line unless $res->is_success;
my @peer = $res->header("client-peer");
die "@peer" unless @peer==1 && $peer[0] eq "$host:443";
my @issuer = $res->header("client-ssl-cert-issuer");
my @subject = $res->header("client-ssl-cert-subject");
my @san = $res->header("client-ssl-cert-subjectaltname");
my $certstr = "Issuer: @issuer\nSubject: @subject\n"
."Subject Alt Names: @san\n";
push @{ $certs{$certstr} }, "$host $addr";
}
}
for my $cert (sort keys %certs) {
print "##### Certificate #####\n", $cert, "### Served by:\n";
printf "%15s %s\n", @$_ for map {[split]} @{ $certs{$cert} };
}
__END__
# As of 2018-06-17:
##### Certificate #####
Issuer: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
Subject: /CN=perlmonks.org
Subject Alt Names: 2: css.perlmonks.com 2: css.perlmonks.net 2: css.pe
+rlmonks.org 2: perlmonks.com 2: perlmonks.net 2: perlmonks.org 2: www
+.perlmonks.com 2: www.perlmonks.net 2: www.perlmonks.org
### Served by:
216.92.34.251 css.perlmonks.com
66.39.54.27 css.perlmonks.com
216.92.34.251 css.perlmonks.net
66.39.54.27 css.perlmonks.net
216.92.34.251 css.perlmonks.org
66.39.54.27 css.perlmonks.org
216.92.34.251 perlmonks.com
66.39.54.27 perlmonks.com
216.92.34.251 perlmonks.net
66.39.54.27 perlmonks.net
216.92.34.251 perlmonks.org
66.39.54.27 perlmonks.org
216.92.34.251 www.perlmonks.com
66.39.54.27 www.perlmonks.com
216.92.34.251 www.perlmonks.net
66.39.54.27 www.perlmonks.net
216.92.34.251 www.perlmonks.org
66.39.54.27 www.perlmonks.org
##### Certificate #####
Issuer: /C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=U
+SERTrust RSA Organization Validation Secure Server CA
Subject: /C=US/postalCode=15203/ST=Pennsylvania/L=Pittsburgh/street=Su
+ite 510/street=2403 Sidney Street/O=pair Networks, Inc./OU=Provided b
+y pair Networks/OU=PairWildcardSSL $250,000/CN=*.pairsite.com
Subject Alt Names: 2: *.pairsite.com 2: pairsite.com
### Served by:
209.197.123.153 css.perlmonks.com
209.197.123.153 css.perlmonks.net
209.197.123.153 css.perlmonks.org
209.197.123.153 perlmonks.com
209.197.123.153 perlmonks.net
209.197.123.153 perlmonks.org
209.197.123.153 perlmonks.pairsite.com
209.197.123.153 www.perlmonks.com
209.197.123.153 www.perlmonks.net
209.197.123.153 www.perlmonks.org