Thursday, March 13, 2008

Using SSL with a Wildcard Certificate on Multiple Apache Sites

It is possible to set up multiple virtual SSL-encrypted hosts (sites) in apache, but did you know it's possible for them all to use port 443 and the same IP address? Wildcard certificates help make it happen.
Setting up SSL virtual hosts in linux (specifically RHEL and CentOS, but the steps are similar in other distros) isn't hard, and--to correct a common misperception--it is possible to have multiple SSL virtual hosts running under apache using host headers. To be clear: you don't have to use separate IP addresses or different port numbers in order to have multiple SSL sites under apache.
In short, the process involves creating multiple SSL virtual hosts, each with its own host header (ServerName in apache parlance), and adding the same wildcard SSL certificate to each of the sites. There are a variety of ways to create a certificate, and you can see many of them discussed with a simple Google search. In our case, we'll use genkey from crypto-utils. Feel free to use any utility you'd like


Install Crypto-Utils

Crypto-utils is a package that contains a lot of programs for dealing with certificates and keys; it makes things a lot easier.
yum install crypto-utils

Generate the new key

Then simply run the genkey application:
genkey --days 3650 *.servername.com
You'll notice in the above example we set it to last for 10 years (why should it expire?) and contain the server name servername.com. Of course, you'd want to put the correct server name there.
The program will prompt you for some details; note that you'll not want to have the private key encrypted; that requires a password when you start apache, which isn't terribly convenient.
Genkey will create a file called *.servername.cert and *.servername.key in /etc/pki/tls/certs and /etc/pki/tls/private, respectively. These directories, I believe, are specific to RHEL (and CENTOS) 5; EL 4 and other distros use different directories. You'll want to rename these files when the process is complete: genkey creates the cert and key with the name you typed in, which means it'll be a filename with a * in it. That's no good, so when it's done, go to those directories and change the filename to wildcard.servername.cert and wildcard.servername.key.
When you've done that, your certificate is complete, and you're ready to set up your sites.
As an aside: it's not necessary that you use self-signed certificates. In fact, if you're setting this up for a production environment, you will want to use a commercially-provided certificate from a company such as GeoTrust, Verisign, or any of the myriad of certificate companies out there.

Edit ssl.conf

Now we add our virtual hosts (sites). Again, this directory location may be different for your distro.
vim /etc/httpd/conf.d/ssl.conf
If we were just installing this certificate for the default site, we'd just change the SSLCertificateFile and SSLCertificateKeyFile to point to the new files created in /etc/pki/tls/certs and /etc/pki/tls/private respectively.
But because we're creating (or adding certificates to) two new sites we'll have to change the SSLCertificateFile and SSLCertificateKeyFile not only in the default site, but add our additional sites as well. The following will create two additional sites called "testssl1" and "testssl2." They'll go right after the default <VirtualHost> </VirtualHost> section
NameVirtualHost *
<VirtualHost * >
SSLEngine on SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
ServerAdmin webmaster@example.com
DocumentRoot /var/www/html/testssl1
ServerName testssl1.example.com
ErrorLog /var/log/httpd/testssl_error_log
CustomLog /var/log/httpd/testssl_access_log common
SSLCertificateFile /etc/pki/tls/certs/wildcard.example.com.cert
SSLCertificateKeyFile /etc/pki/tls/private/wildcard.example.com.key
</virtualhost>

<virtualhost *>
SSLEngine on SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
ServerAdmin webmaster@example.com
DocumentRoot /var/www/html/testssl2
ServerName testssl2.example.com

ErrorLog /var/log/httpd/testssl_error_log
CustomLog /var/log/httpd/testssl_access_log common
SSLCertificateFile /etc/pki/tls/certs/wildcard.example.com.cert
SSLCertificateKeyFile /etc/pki/tls/private/wildcard.example.com.key
</virtualhost>

If you'd prefer simply to replace the default :443 site, simply comment out the entire section between the first <VirtualHost> </VirtualHost> section.
Note that there's a lot that can go wrong with the settings in this file, but, unlike using wildcard certificates, there is--happily--a lot of information on the web about troubleshooting this file.

Restart Apache

service httpd restart

8 comments:

  1. It doesn't work and I don't know how it possibly can.
    Maybe there were some changes in mod_ssl or openssl itself since 2008.

    For instance:
    Starting httpd: Syntax error (...)
    VirtualHost directive requires additional arguments [FAILED]

    However, even if you add required arguments
    VirtualHost *:443
    it still won't work.
    [warn] _default_ VirtualHost overlap on port 443, the first has precedence

    AFAIK there is currently no way for mod_ssl to determine server name before using some vhost.
    It's due to the fact that certificates are defined per vhost and since traffic is encrypted, apache cannot get "Host" HTTP header from browser to choose proper vhost first.

    The only solution that I know of is to use different IPs or different ports.

    Regards,
    Andrew.

    ReplyDelete
  2. Ok. I take back what I've said in my previous comment.
    It actually worked!
    You still need to correct VirtualHost directive to:
    <VirtualHost server_ip:443>
    Moreover you need to add on top the directive:
    NameVirtualHost server_ip:443
    which was the reason it didn't work for me before.

    Sorry for my mistake.
    Regards,
    Andrew.

    ReplyDelete
  3. Hi, Andrew,
    I appreciate the comment! You're right that, at least with CENTOS (and RHEL) 6, the config I'd posted didn't work. I've added the namevirtualhost and virtualhost wildcard name settings that are necessary to make it work. I appreciate your follow-up, too: I was just about to post that I'd re-done this configuration with a current CENTOS 6 box, and it does, in fact, work.

    The way it's able to figure out which virtual directory it's going to is that we're using the same certificate for both sites. Otherwise, you're right: there's no way for the web server to know which virtual directory is being requested until it can decrypt the header. Since we're using the same cert for each virtual directory, the server doesn't have to determine which certificate to use, and it's able to decrypt the header and direct the traffic appropriately.

    Again, really appreciate your feedback! -Lane

    ReplyDelete
  4. Luis Fernando AlenJanuary 13, 2012 at 7:32 AM

    Let me see if I got it straight.

    When the server receives an encrypted request (https) on port 443, it uses the cert/key to decrypt this request and get the actual HTTP part of it. This way Apache can choose the proper virtual host to handle the request by checking the HTTP 'Host' header.

    By using different certificates, the server can't determine which one to use for the request and therefore won't be able to decrypt it and get the HTTP 'Host' header.

    Is that correct?

    ReplyDelete
  5. Hi, Luis,
    Yes: that's right. Apache uses the port number to identify which certificate to use to decrypt the HTTPS traffic, and then it has access to the (now unencrypted) host header information so it can determine to which virtual host it needs to direct the traffic.

    ReplyDelete
  6. Luis Fernando AlenJanuary 13, 2012 at 1:33 PM

    Thanks, Lane.

    This post was very helpful.

    Keep up with the good work =]

    ReplyDelete
  7. You can use multiple wildcard ssl certs in 1 ucc ssl cert if you are only able to use 1 ip address (see https://answers.ssl.com/2903/can-use-wildcard-ssl-certificates-with-multi-domain-ucc-certs)

    Also, in ubuntu, the ssl certs are stored at /opt/ssl/certs (for trusted CA certs) and /opt/ssl/private (for your sites)

    ReplyDelete
  8. I have gone through your entire self signed creation of WildCard SSL process step by step and its really incredible installation solution. Thanks for sharing with us. Apart from this we also would like to bring update you that we would like to add your entire in our SSL education blog where your blog will help other users in the process of self signed WildCard creation.

    Thawte WildCard SSL | GeoTrust WildCard SSL

    ReplyDelete

Thanks for leaving a comment!