Add CAcert SSL Certificates to Support Multiple Domains on a SuSE 10.0 / Plesk 8.0 Server

I would like to host multiple domains and subdomains on my server and be able to use SSL encryption with some of them. Typically, you need to have one certificate for each domain, and you can only have one certificate per IP address, because the SSL protocol is negotiated based on the IP address before the browser sends the host name.

Free Certificates from CAcert

Certificates usually cost money, for each domain and subdomain, renewable every year. Enter CAcert: this non-profit organization provides free certificates based on a Web of Trust approach, similar to PGP/GPG. CAcert is working to get its root certificate included in more and more browsers, but it still has a long way to go, and it may never succeed in getting into MSIE. If you can live with that, CAcert is a great choice.

Creating a Certificate Request for Multiple Domains

The information in this section is taken from here and boiled down to what you need. Save the following shell script as CAcert-csr.sh:

#!/bin/sh
# 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
# Mon Apl 09 14:34:56 CET 2005 - hs - Added some comments, create DH file
 
# 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, used for the file name (ie. imap big_srv www2 / example): "
read HOST
printf "FQDN/CommonName (ie. www.example.com / example.com) : "
read COMMONNAME
 
echo "Type SubjectAltNames for the certificate, one per line. Enter a blank line to finish"
echo "(probably want to repeat FQDN here!)"
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
openssl gendh 512 >$HOME/${HOST}_dh.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

Run this shell script to create a private key and a certificate request. The "Short Hostname" (first prompt) is just a file name; I recommend using a name that identifies the host, purpose, and date. The "FQDN/CommonName" (second prompt) will be used to identify your certificate on the CAcert website. On the next prompt(s) you can specify any number of domains and subdomains (like example.com, www.example.com, and/or *.example.com (*.example.com does not cover example.com!)).

Register each domain with cacert.org and finally create the server certificate by pasting the certificate request into the entry field at cacert.org.

Inserting the New Certificate into Plesk

Download the CAcert root certificate (and the class 3 intermediate certificate if you've created a class 3 certificate) in PEM format.

In Plesk go to Server|Certificates|Create, enter a name for the new certificate, e.g. something like "CAcert-YYYY-MM-DD", paste

  • the private key
  • the certificate from CAcert
  • the CAcert root certificate (followed by the class 3 intermediate certificate if applicable)

into the three entry fields, and click the [Send Text] button.

Plesk will add the new certificate and display it with the three required icons. You don't need the CSR within Plesk. Now go to Server|IP Addresses and select the new certificate for the IP address(es) you want. This makes the web server use the new certificate.

Certificates for Email

Plesk uses other certificates for email:

SMTP / qmail
/var/qmail/control/servercert.pem
POP3
/usr/share/courier-imap/pop3d.pem
IMAP
/usr/share/courier-imap/imapd.pem

These files combine the private key, certificate, CA root certificate(s), and the Diffie-Hellmann Parameters in composite files (simple concatenation). They start out as Plesk certificates, and if you want to use your own certificates, you can replace them. Isn't it nice to get free multi-site certificates from CAcert.org?

The SMTP certificate (including the private key!) needs to be world-readable, so you want to create a separate one just for that purpose. It should list the mail server (MTA) name as well as all the names of the domain-specific SMTP hosts.

A Certificate for qpsmtpd

If you've replaced qmail-smptd with qpsmtpd as your SMTP server, you can enable TLS support with the tls plugin — just add

tls ../ssl/qpsmtpd-server.crt ../ssl/qpsmtpd-server.key ../ssl/qpsmtpd-ca.crt

to your plugins file, and create and deploy the files.

The Bigger Picture

I started out separating SMTP (mail.example.com) and POP3 (pop.example.com) to make it easier to migrate email accounts from one server to another, but it turns out that moving a mail server can be done in one piece, and I currently don't see any benefit in this separation.

On the contrary, if you use two different server names and different certificates from a certificate authority (CA) whose root certificate may not be installed in the client email program, then you'll have to ask your users to accept not one but two certificates. That's a lot to ask...

For now I will keep the separate server names, but I'm installing copies of a combined certificate covering mail.example.com, pop.example.com, imap.example.com as well as variants for each hosted domain for SMTP, POP3, and IMAP. Fortunately, CAcert supports creating such combined certificates, which allows this flexibility.

CAcert Root Certificates

The CAcert root certificates are available at

Trouble with qmail

Later, after updating the certificates, I suddenly started to get timeout messages, because qmail was unable to send mail to some 5 to 10% of the recipients:


TLS connect failed: error:140943F2:SSL routines:SSL3_READ_BYTES:sslv3 alert unexpected message; connected to xx.xx.xx.xx.
I'm not going to try again; this message has been in the queue too long.

Indeed, these messages started coming in for mails that had been queued one week (!) earlier. What a nasty surprise. It turned out that there was a mismatch of the pieces that went into qmail's certificate. Fixing the /var/qmail/control/servercert.pem file cured the issue and the blocked messages started to go out over the course of a day.