SSL-Zertifikat für VHosts

Submitted by Erik Wegner on
Body

Mit der SNI-Technik (Server Name Indication, Wikipedia) ist es möglich, unter einer IP-Adresse mehrere virtuelle Hosts zu betreiben. Da das SSL-Zertifikat die Verbindung absichert, bevor der Zieldomainnamen übertragen wird, muss das Webserver-Zertifikat für alle Domains ausgestellt sein. Daraus ergibt sich auch der Nebeneffekt, dass www.example.com, example.com und *.example.com abgesichert werden können.

Grundlage ist das Perl-Script, dass unter http://wiki.cacert.org/VhostTaskForce#Perl_version abrufbar ist.

use strict;
my $config_file = "/tmp/openssl.cnf.$$";        #Where to write the config file
my $keyname;                            #Generally, the primary FQDN
my $org_unit;                           #Organisational unit for csr, ie Web Services
my @altnames;                           #Alternate dns names for csr, ie www1.example.com, www1.example.net etc
my $altname;                            #Alternate dns names for csr, ie www1.example.com, www1.example.net etc
my $altcount = 1;                       #Can only have 16 or less alts (when submitting to Verisign)
my $altflag = 1;                        #flag for my while loop
my @config_out;                         #Populate with all info for the config file.
my $email_address;                      #email address to be tagged on the certificate
my $proc_base_name;                     #basename of the process, simply for naming conventions
my $mutual_tls = "y";                   #flag for mutual tls for client app stuff
my $home = `echo \$HOME`;               #Get user's home directory to store files in.
chomp $home;
my $random_file = "$home/.rnd";         #openssl for hpux needs a .rnd file to work
#  If config file exists, exit and alert user
if (-e $config_file) {
        `rm $config_file`;
}
if (!-e $random_file) {
        `dd bs=512 count=4 if=/dev/null of=$random_file`
        ##die ("Random file couldn't be found at $random_file\n");
}
#  Open config file to write ssl stuff out to
open (CONFIG, ">$config_file")||die "Can't open $config_file for writing\n";
# Start getting info from user
print ("Generate SSL Cert stuff for SAPI\n");
print ("FQDN/Keyname for Cert \(ie www.example.com\)\t\t:");
chomp ($keyname=);
        while ($altflag) {
                print ("Alt Names (ie www1.example.com or  for none)\t\t\t:");
                chomp($altname=);
                if ($altcount  16) {
                        if ($altname eq $keyname) {
                                print (" ****** Alternate name can not equal main keyname ******\n");
                        } elsif ($altname ne "") {
                                push (@altnames, "DNS:$altname");
                                $altcount++;
                        } else {
                                $altflag=0;
                        }
                } else {
                        $altflag=0;
                }
        }
print ("Host short name (ie imap big_srv etc)\t\t\t\t:");
chomp ($proc_base_name=);
# Start building the config file
push (@config_out, "# -------------- BEGIN custom openssl.cnf -----\n");
push (@config_out, "HOME                    = $home\n");
push (@config_out, "RANDFILE                = $random_file\n");
push (@config_out, "oid_section             = new_oids\n");
push (@config_out, "[ new_oids ]\n");
push (@config_out, "[ req ]\n");
push (@config_out, "default_bits            = 2048\n");
push (@config_out, "default_days    = 730                   # how long to certify for\n");
push (@config_out, "default_keyfile         = $home/${proc_base_name}_privatekey.pem\n");
push (@config_out, "distinguished_name      = req_distinguished_name\n");
push (@config_out, "encrypt_key             = no\n");
push (@config_out, "string_mask = nombstr\n");
push (@config_out, "req_extensions = v3_req # Extensions to add to certificate request\n");
push (@config_out, "[ req_distinguished_name ]\n");
push (@config_out, "commonName                      = Common Name (eg, YOUR name)\n");
push (@config_out, "commonName_default              = $keyname\n");
push (@config_out, "commonName_max                  = 64\n");
push (@config_out, "[ v3_req ]\n");
        if (@altnames[0] ne "") {
                $altname=join(',', @altnames);
                push (@config_out, "subjectAltName=$altname\n");
        }
push (@config_out, "# -------------- END OpsSec-provided openssl.cnf -----\n");
#  Write shit to file
print (CONFIG "@config_out");
close CONFIG;
#  Generate ssl stuff
print ("\nAttempting openssl...\n");
system ("openssl req -batch -config $config_file -newkey rsa:2048 -out $home/${proc_base_name}_csr.pem");
print ("\nwriting csr to $home/${proc_base_name}_csr.pem...\n\n");
print ("Take the contents of $home/${proc_base_name}_csr.pem and go submit them to receive an SSL ID.  When you receive your public key back, you 'should' name it something like '${proc_base_name}_server.pem'.  ");
`rm $config_file`;

Es kann mit folgenden Eingaben gefüttert werden:

www.example.com
*.example.com
example.com

example.com

Damit werden im Benutzerverzeichnis die Dateien example.com_privatekey.pem und example.com_csr.pem erzeugt. Die csr-Datei ist die Zertifikatsanforderungsdatei, die nun bei einer Zertifikatsautorität eingereicht werden kann.

Von dort erhält man ein unterschriebenes Zertifikat, dass in der Apache-Datei /etc/apache2/ssl.crt/server.crt eingetragen wird.

Der private Teil des Schlüssels wird in der Datei /etc/apache2/ssl.key/server.key abgelegt.