Currently the different browsers, servers and CAs all implement different and incompatible ways to use SSL certificates for several VHosts on the same server.
The VHost SSL Taskforce tries to find an agreement between those ways, and publish that as an RFC afterwards, so that all the software vendors can agree on one way.
Stop Press! Read all about it:
httpd 2.2.12 is released, including SNI support. http://www.apache.org/dist/httpd/CHANGES_2.2.12 |
mod_ssl: Add server name indication support (RFC 4366) and better support for name based virtual hosts with SSL. |
PR 34607 [Peter Sylvester <peter.sylvester edelweb.fr>, Kaspar Brand <asfbugz velox.ch>, Guenter Knauf, Joe Orton, Ruediger Pluem] |
Let's see if it works!
pay attention please : this is much a discussion of what is working and what is *not* working
short : most of the browsers support 1 CN + multiple SAN
Contents
- 1. Way: SubjectAltName Only
- 2. Way: Multiple CommonNames in the same certificate
- 3. Way: Certificate with 1 Common Name + 2 Subject Alt Names
- 4. Way: Multiple certificates in the certificate chain/graph
- 5. Way: TLS "server name indication".
- Discussion
- Interoperability Test
- Useless ways
- Easy way to generate CSRs with subjectAltNames
- Web server configuration
- See Also
- Comments
1. Way: SubjectAltName Only
- This is the official way, according to the RFC 2818. This was my discussion with Eric Rescorla (the author of the RFC) on the topic:
> Hi Eric, > > I would like to know your position regarding Multiple SSL/TLS Vhosts on the > same machine with the same IP Adress. (Name-based). > > In RFC 2818 you have written: > > Matching is performed using the matching rules specified by > [RFC2459]. If more than one identity of a given type is present in > the certificate (e.g., more than one dNSName name, a match in any one > of the set is considered acceptable.) Names may contain the wildcard > character * which is considered to match any single domain name > component or component fragment. E.g., *.a.com matches foo.a.com but > not bar.foo.a.com. f*.com matches foo.com but not bar.com. > > I would interpret it as if the solution for the problem is to have several > identities (dNSName lines) in one certificate for the different DNS Names, > and that the Browser has to accept any of them: > > dNSName: www.customer1.at > dNSName: www.customer2.com > dNSName: www.customer3.de > > Is that a correct interpretation? That's certainly one possibility, and it's the only one that will work with Name Based Virtual Hosts without the domain name extension (not yet widely deployed)
How can I generate a certificate for that?
Add the following into your openssl.cnf:
[ req_distinguished_name ] 0.subjectAltName =Alternativer Name 1 0.subjectAltName_default =DNS:www.welservice.com 1.subjectAltName =Alternativer Name 2 1.subjectAltName_default =DNS:sig.cacert.at
This example will generate a Subject like this:
Subject: C=CH, ST=Zurich, L=Zurich, CN=www.example.com/subjectAltName=DNS:www.example.com
which will IMHO not work.
After studing of "RFC 2459 - Section 4.2.1.7: Subject Alternative Name" and crossreferencing to the result of isakmpd's certpatch(8) the following should work:
Subject: C=CH, ST=Zurich, L=Zurich, CN=www.example.com ... Requested Extensions: X509v3 Subject Alternative Name: DNS:www.example.com
To accomplish such an CSR the following entries are needed in the openssl.cnf (please note: I only added the relevant parts for this Attribute)
[ req ] req_extensions = v3_req [ v3_req ] subjectAltName = DNS:www.example.com
There's also the possibility to mark this Extension "critical" by
subjectAltName = critical,DNS:www.example.com
IMHO multiple alternative Names are accomplished by
subjectAltName = DNS:www.example.com, DNS:www2.example.com
Currently, CSRs created in this way, will not show a subjectAltName on the cacert.org confirmation page to submit the CSR, so it is assumed that the CA will not honor the Extension Request
The following text should explain the meaning of "critical"
- When an implementation processing a certificate does not recognize an extension, if the criticality flag is FALSE, it may ignore that extension. If the criticality flag is TRUE, unrecognized extensions shall cause the structure to be considered invalid, i.e. in a certificate, an unrecognized critical extension would cause validation of a signature using that certificate to fail. When a certificate-using implementation recognizes and is able to process an extension, then the certificate-using implementation shall process the extension regardless of the value of the criticality flag. Note that any extension that is flagged non-critical will cause inconsistent behaviour between certificate-using systems that will process the extension and certificate-using systems that do not recognize the extension and will ignore it.
How does such a certificate look like?
Host: 212.55.212.241 (provided by jcl) https://host1.way1.vhosts.cacert.org/ https://host2.way1.vhosts.cacert.org/
Robert Trebula: The hosts above have only subjectAltName set in their certificates. They do not have any Common Name. To make this work in Mozilla Firefox, just add one of the domain names as Common Name. For example see https://hq.sk/ = https://hq.alert.sk/
ThorstenGlaser: the certificate on the above host is expired
DuaneSmith: It is unclear if the "SubjectAltName only" way even works given the statement "it is assumed the CA will not honor the Extension Request".
NicolavonThadden: I'm not sure whether they have changed anything, but the CN+SLA way shows the SLA on the CAcert confirmation page. My certificate created this way includes the SLA so they honor it.
2. Way: Multiple CommonNames in the same certificate
How can I generate a certificate for that?
Add the following into your openssl.cnf:
[ req_distinguished_name ] 0.commonName = Common Name (eg, YOUR name) 0.commonName_default = www.domain1.com 0.commonName_max = 64 1.commonName = Common Name (eg, YOUR name) 1.commonName_default = www.domain2.org 1.commonName_max = 64
How does such a certificate look like?
openssl x509 -in server.crt -text Certificate: Data: Version: 3 (0x2) Serial Number: 63209 (0xf6e9) Signature Algorithm: md5WithRSAEncryption Issuer: O=Root CA, OU=http://www.cacert.org, CN=CA Cert Signing Authority/emailAddress=support@cacert.org Validity Not Before: Mar 6 03:06:42 2005 GMT Not After : Mar 6 03:06:42 2007 GMT Subject: CN=www.domain1.com, CN=www.domain2.com
Host: 212.55.212.242 (provided by jcl) https://host1.way2.vhosts.cacert.org/ https://host2.way2.vhosts.cacert.org/
ThorstenGlaser: the certificate on the above host is expired
3. Way: Certificate with 1 Common Name + 2 Subject Alt Names
Host: 212.55.212.243 (provided by jcl) https://host1.way3.vhosts.cacert.org/ https://host2.way3.vhosts.cacert.org/
ThorstenGlaser: the certificate on the above host is expired
4. Way: Multiple certificates in the certificate chain/graph
Host: 212.55.212.244 (provided by jcl) https://host1.way4.vhosts.cacert.org/ https://host2.way4.vhosts.cacert.org/
ThorstenGlaser: the certificate on the above host is expired
5. Way: TLS "server name indication".
There is a TLS extension called "server name indication" (SNI). See RFC 4366, subsection 3.1 for the specification. Paul querna has an easy explanation how this works. wikipedia on SNI has a wider discussion.
SNI requires a SSL3/TLS compatible client request to work (http://www.mail-archive.com/mozilla-crypto%40mozilla.org/msg06633.html) but doing this with a SSL2 server will cause the connection to hang which may slow down client adoption.
Server support
mod_gnutls supports TLS Server Name Indication since version 0.20 (04/25/2005).
mod_ssl does support SNI (2.2.11 onwards - July 2009). The release of OpenSSL 1.0.0, will include initial support for SNI (or 0.9.8 with enable-tlsext set at compile time).
mod_nss does not support TLS SNI because the nss library does not support it in server mode (NSS Bug 360421).
LIGHTTPD supports SNI since version 1.4.24 released 2009-10-25 (ticket: http://trac.lighttpd.net/trac/ticket/386).
nginx does support SNI (0.5.23+, Jun 2007) when compiled with OpenSSL with SNI support.
Ubuntu implementation proposal: https://blueprints.launchpad.net/ubuntu/+spec/apache-tls-sni
Clients
Opera support this since 7.60 Technical Preview 1: http://my.opera.com/community/dev/tp/760/tls11/info/
Microsoft Internet Explorer supports it as of IE7 Beta 2 (only for Windows Vista, not for Windows XP): http://blogs.msdn.com/ie/archive/2005/10/22/483795.aspx
Firefox does support it since Firefox 2.0 (bug 116169). Support in the underlying nss library client is present since 2006, see bug 116168 for details.
Konqueror supports SNI since 4.9.1 (bug 122433)
Safari: A webkit bug on OpenDarwin was filed (http://nikolasco.livejournal.com/343541.html) but closed invalid as this has to be implemented in Apple's libfoundation (OpenDarwin Bug 9502, not accessible any more due to OpenDarwin's shutdown). The Apple Radar bug number for this should be 4591827, but this bug is not accessible by the general public so the status of it remains unkown.
w3m: Feature request with patch filed (Item #2682457)
Android (see Android issue 12908): integrated Webbrowser supports SNI since version 3, SNI in Java-Applications is supported since Android 2.3, Opera Mobile on Android supports it, Firefox Mobile (Beta) supports it. The integrated Webbrowser in still widely used Android versions 2.x does not support SNI.
Test sites
Host: 212.55.212.245 (provided by jcl) https://host1.way5.vhosts.cacert.org/ https://host2.way5.vhosts.cacert.org/ (not operational 31 August 2009)
ThorstenGlaser: the certificate on the above host is expired
Discussion
Here, all related parties (Software vendors, ...) are invited to comment on pros/cons of the different ways.
Legal
A message from our legal department: In the situation of ISPs hosting WebShops of their customers, it is necessary to have a bind the Vhosts to the different customers, so that they are liable for what they do. Having one certificate with all the names in it would give legal problems to the ISP. (author can be contacted through sourcerer)
Interoperability Test
Vendor/App |
Several CNs |
Regexp |
Several Cert |
TLS SNI |
CN+SubjAltNames |
|
Testsystem1 |
na |
|||||
Testsystem2 |
na |
|||||
CAcert |
Yes |
No |
No |
? |
Yes |
Yes |
Firefox |
Yes |
No |
Yes |
? |
Version 2.0 |
Yes |
Konqueror |
Yes |
Yes |
No |
? |
No |
Yes |
IE |
Yes |
Yes |
No |
? |
Version 7.0 |
Yes |
Opera |
Yes |
No |
? |
? |
Yes |
Yes |
Safari |
? |
Yes |
? |
? |
No |
Yes |
Java/JSSE |
ERR |
N+Y |
? |
? |
? |
Y+Y |
Lynx |
Yes |
Yes |
? |
host is down |
No |
Yes |
w3m |
? |
? |
Yes? (*.domain.tld) |
? |
No |
? |
2 - Patch attached to https://bugzilla.mozilla.org/show_bug.cgi?id=116169
MathiasErtl: At least on my lynx (Version 2.8.6rel.4 with libwww-FM 2.14, SSL-MM 1.4.1, GNUTLS 2.0.4) the client complains about a server using the CN+SubjectAltName (when accessing some of the alt-names). Subversion works great, perhaps it should be added to this list?
References
Relevant RFCs:
About the Depreciation of commonNames
Currently there is confusion over how CAcert issues certificates, namely people expecting certificates with multiple commonNames (CNs) to be signed by CAcert, however testing in the past has shown that certificates issued with multiple CNs only works in MS IE, other browsers that follow RFCs more strictly ignore all CNs after the first one. More recently it's been claimed that The Bat! works correctly with multiple CNs, but does not recognise subjectAltNames (SANs) at all.
The reason for this is because CNs were never part of any formal document released by any recognised standards body and RFCs that have been released (RFC 2459, 2818, 3280, 4513) that touch the topic of hostnames in certificates only mention that CNs have been depreciated in favour of SANs.
CNs came about but never standardised when Netscape was developing SSL2 and became a widely used de-facto standard, however with the release of RFC 2459 SANs became recognised as a standard and their use has been encouraged ever since.
While RFC 2818 deals with HTTP over TLS, this is one of many RFCs that reinforces the sentiments of RFC 2459. Opinions have been expressed that part of the intent of authors in writing RFCs 2459 and 2818 were to hasten the demise of CNs in certificates.
Useless ways
Multiple CommonNames and a wildcard first CommonName in the same certificate
How can I generate a certificate for that?
Add the following into your openssl.cnf:
[ req_distinguished_name ] 0.commonName = Common Name (eg, YOUR name) 0.commonName_default = *.*.* 0.commonName_max = 64 1.commonName = Common Name (eg, YOUR name) 1.commonName_default = www.domain1.com 1.commonName_max = 64 2.commonName = Common Name (eg, YOUR name) 2.commonName_default = www.domain2.org 2.commonName_max = 64
How does such a certificate look like?
openssl x509 -in server.crt -text Certificate: Data: Version: 3 (0x2) Serial Number: 63209 (0xf6e9) Signature Algorithm: md5WithRSAEncryption Issuer: O=Root CA, OU=http://www.cacert.org, CN=CA Cert Signing Authority/emailAddress=support@cacert.org Validity Not Before: Mar 6 03:06:42 2005 GMT Not After : Mar 6 03:06:42 2007 GMT Subject: CN=*.*.*, CN=www.domain1.com, CN=www.domain2.org
Why is that way useless?
Because it is insecure. With a *.*.* wildcard certificate, you could impersonate www.amazon.com, www.paypal.com and everyone else you want with one certificate.
misc
CN+SubjAltNames:
GNU Wget 1.10.2 doesn't work (only uses the CN) ; see the related :
Lynx Version 2.8.5rel.1 doesn't work (only uses the CN)
Easy way to generate CSRs with subjectAltNames
A few contributed scripts:
Shell Script
download shell script
# csr.sh: Certificate Signing Request Generator # Copyright(c) 2005 Evaldo Gardenali <evaldo@gardenali.biz> # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # ChangeLog: # Mon May 23 00:14:37 BRT 2005 - evaldo - Initial Release # be safe about permissions LASTUMASK=`umask` umask 077 # OpenSSL for HPUX needs a random file RANDOMFILE=$HOME/.rnd # create a config file for openssl CONFIG=`mktemp -q /tmp/openssl-conf.XXXXXXXX` if [ ! $? -eq 0 ]; then echo "Could not create temporary config file. exiting" exit 1 fi echo "Private Key and Certificate Signing Request Generator" echo "This script was designed to suit the request format needed by" echo "the CAcert Certificate Authority. www.CAcert.org" echo printf "Short Hostname (ie. imap big_srv www2): " read HOST printf "FQDN/CommonName (ie. www.example.com) : " read COMMONNAME echo "Type SubjectAltNames for the certificate, one per line. Enter a blank line to finish" SAN=1 # bogus value to begin the loop SANAMES="" # sanitize while [ ! "$SAN" = "" ]; do printf "SubjectAltName: DNS:" read SAN if [ "$SAN" = "" ]; then break; fi # end of input if [ "$SANAMES" = "" ]; then SANAMES="DNS:$SAN" else SANAMES="$SANAMES,DNS:$SAN" fi done # Config File Generation cat <<EOF > $CONFIG # -------------- BEGIN custom openssl.cnf ----- HOME = $HOME EOF if [ "`uname -s`" = "HP-UX" ]; then echo " RANDFILE = $RANDOMFILE" >> $CONFIG fi cat <<EOF >> $CONFIG oid_section = new_oids [ new_oids ] [ req ] default_days = 730 # how long to certify for default_keyfile = $HOME/${HOST}_privatekey.pem distinguished_name = req_distinguished_name encrypt_key = no string_mask = nombstr EOF if [ ! "$SANAMES" = "" ]; then echo "req_extensions = v3_req # Extensions to add to certificate request" >> $CONFIG fi cat <<EOF >> $CONFIG [ req_distinguished_name ] commonName = Common Name (eg, YOUR name) commonName_default = $COMMONNAME commonName_max = 64 [ v3_req ] EOF if [ ! "$SANAMES" = "" ]; then echo "subjectAltName=$SANAMES" >> $CONFIG fi echo "# -------------- END custom openssl.cnf -----" >> $CONFIG echo "Running OpenSSL..." openssl req -batch -config $CONFIG -newkey rsa:2048 -out $HOME/${HOST}_csr.pem echo "Copy the following Certificate Request and paste into CAcert website to obtain a Certificate." echo "When you receive your certificate, you 'should' name it something like ${HOST}_server.pem" echo cat $HOME/${HOST}_csr.pem echo echo The Certificate request is also available in $HOME/${HOST}_csr.pem echo The Private Key is stored in $HOME/${HOST}_privatekey.pem echo rm $CONFIG #restore umask umask $LASTUMASK
pt_BR version of this script can be found on br.cacert.org
Perl version
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=<STDIN>); while ($altflag) { print ("Alt Names (ie www1.example.com or <return> for none)\t\t\t:"); chomp($altname=<STDIN>); 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=<STDIN>); # 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`;
Web server configuration
See VhostsApache for information about setting up the ApacheServer to serve multiple HTTPS sites using one IP address and one cert.
See Also
RFC 2817
Upgrading to TLS Within HTTP/1.1 - This memo explains how to use the Upgrade mechanism in HTTP/1.1 to initiate Transport Layer Security (TLS) over an existing TCP connection. This allows unsecured and secured HTTP traffic to share the same well known port (in this case, http: at 80 rather than https: at 443). It also enables "virtual hosting", so a single HTTP + TLS server can disambiguate traffic intended for several hostnames at a single IP address.
This is used specifically by some network attached printers, for print jobs over https, today.
However there doesn't seem to be any plans to support RFC2817 in browsers such as Mozilla Firefox. See: https://bugzilla.mozilla.org/show_bug.cgi?id=276813
This RFC has been implemented by the Apache HTTP Server project in version 2.2. For additional references and discussion, see: http://www.google.com/search?q=rfc2817+site%3Aapache.org
RFC 3546
mod_gnutls http://www.outoforder.cc/projects/apache/mod_gnutls/ uses the GnuTLS library to provide SSL v3, TLS 1.0 and TLS 1.1 encryption for Apache HTTPD and it has support for Server Name Indication: https://sni.corelands.com/
RFC 2595
The only RFC that adresses wildcards in server certificates that I have found. I admit I have not searched very thoroughly, if you know other RFCs addressing the subject please add them here.
Some thoughts and compiled facts on wildcard certificates can be found on WildcardCertificates.
Comments
Taken from https://www.financialcryptography.com/mt/archives/000463.html:
... "so far the work-around seems to be that you issue a cert that includes all the names of all the sites. Which means there is now no certificate-based independence between administrative sites - definately a kludge."
- Has anyone try wild card SSL certificate with Microsoft Internet Explorer and form submission ? It does not work for me, and I am using Explorer 5 or later.
Me too. I tried it with IE6 and it failed with "CommonName field was blank" error. Then I switched to Firefox and everything went OK.
Certificates with a subjectAltName do not work with Sun Java System Web Server 7.0U1 - the server will refuse to install such a certificate ("Error decoding the certificate."). RiverTarnell