Sunday, 16 August 2009

Apache 2 with SSL/TLS: Part 2

In the first article of this three part series, the reader was shown how to install, configure, and troubleshoot Apache 2.0 with SSL/TLS support. Part two now discusses the recommended settings for the mod_ssl module that lets us achieve maximum security and optimal performance. The reader will also see how to create a local Certification Authority and a SSL certificate based on the free and open-source OpenSSL library.

Recommended settings for mod_ssl

In Apache 2.0.52, there are more than 30 directives that can be used to configure mod_ssl. The detailed description of all of them can be found in Apache's mod_ssl documentation. This section focuses only on the recommended settings which can improve the security or performance of SSL/TLS connections.

The list of these mod_ssl settings is shown below in Table 1.


Recommended setting or comment


Must be enabled, otherwise the main server (or virtual host) will not be using SSL/TLS


Must be enabled, otherwise users may be able to access the web content via regular HTTP requests, without using SSL/TLS, at all.



Should be set to use only TLS v1.0 and SSL v3.0. Most of current web browsers support both of them, so we can safely disable SSL v2.0.



To provide strong cryptography, this parameter should be set to use HIGH (>168 bits) and MEDIUM (128 bits) cipher suites. LOW (<56 href="">collisions . To summary, the recommended settings could be as follows:


Note that it is possible to see what ciphers suites the proposed settings can support, as follows:

openssl ciphers -v 'HIGH:MEDIUM:\!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM'


The "+StrictRequire" options should be set, otherwise the "Satisfy Any" directive may force mod_ssl to allow access to the web content, even if SSL/TLS is not used.


For startup of Apache should be set to use pseudo random device (/dev/urandom) and/or EGD (Entrophy Gathering Daemon). Before establishing every new SSL connection should be configured to use built-in source, /dev/urandom or EGD. It is not recommended to use /dev/random in both cases, because /dev/random can provide only as much entropy, as it has at certain moment.


To avoid repeating SSL handshakes for parallel HTTP requests (e.g. when web browser downloads several images at one time), SSL caching should be enabled. It should be set to use shared memory (SHM), or DBM. When setting to "none", performance of the web server may decrease significantly.


This value specifies the number of seconds, after which the entry in SSLSessionCache expires. It should be set to at least 300-600 seconds. However, the actual time should depend on the average time the users spent on visiting the web server. E.g., if the average time is around 15 minutes, then the value should be set to at least 900 (15 minutes * 60 seconds)



When not using client or proxy authentication, these options should be set to "none". They should never be set to "optional_no_ca", because it is against the idea of PKI authentication, where client, to be authenticated, must present valid certificate. "optional" may occasionally be used (depends on needs), however it may not work with all web browsers.



Should contain the maximum number of intermediate CA's. E.g. to accept only self-signed certificates it should be set to zero, for client certificates that are signed by root CA - it should be 1. And so on.


Should be disabled, if SSL/TLS proxy mechanism is not used.

Table 1. Recommended mod_ssl settings.

Our sample settings according to the above recommendations can be shown in httpd.conf as follows:

SSLEngine on

SSLOptions +StrictRequire


SSLProtocol -all +TLSv1 +SSLv3

# Support only for strong cryptography
# Support for strong and export cryptography

SSLRandomSeed startup file:/dev/urandom 1024
SSLRandomSeed connect file:/dev/urandom 1024

SSLSessionCache shm:/usr/local/apache2/logs/ssl_cache_shm
SSLSessionCacheTimeout 600

SSLVerify none
SSLProxyEngine off

In addition to above mod_ssl directives, there are also two important directives from other Apache modules (mod_log_config and mod_set_envif) that need to be setup, as shown below in Table 2.


Recommended setting / comment


To log information about SSL parameters (recommended minimum: the protocol version and chosen cipher suites) we should use the following value:

CustomLog logs/ssl_request_log \
\"%r\" %b"


To provide compatibility with older versions of MS Internet Explorer, which has got known bugs in SSL implementation (e.g. problems with keep-alive functionality, HTTP/1.1 over SSL, and SSL close notify alerts on socket connection close), the following option should be set:

SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0

The above option will cause that web server will neither use HTTP/1.1 nor keep-alive connections, and will not send SSL close notify when the web browser is MS Internet Explorer.

Table 2. Recommended mod_log and mod_set_envif settings.

The sample configuration file (httpd.conf) presented in the previous article already includes the above settings, for the reader's convenience.

Web server authentication

Thus far we were able to configure and test SSL/TLS, but our web browser was not able to check the web server's identity. In the first article we were using a web server certificate that had been created only for testing purposes, and did not contain the information required for real authentication purposes and commerce transactions.

In order for the web browser to successfully authenticate the web server, we need to create a valid web server certificate, which should contain:

  • the public key of the web server
  • validity dates (start and expiration)
  • supported cipher algorithms
  • the distinguish name (DN), which must contain fully qualified domain name of the web server known as the Common Name (CN). Optionally it may also contain some other attributes, like Country (C), State (S), Location (L), the Organization's name (O), the Organization Unit's name (OU), and more.
  • the serial number of the certificate
  • X.509v3 attributes that will tell web browsers about the type and usage of the certificate
  • URI of the CRL distribution point (if exist)
  • URI of the X.509v3 Certificate Policy (if exist)
  • name and signature of trusted Certification Authority (CA)

It is important to note that the Common Name (CN) attribute must be a fully qualified domain name (FQDN) on the web server. Otherwise, the web browsers will not be able to verify if the certificate belongs to the web server that is presenting it.

A sample web server certificate (as a text representation) has been presented below.

Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: O=Seccure, OU=Seccure Root CA
Not Before: Nov 28 01:00:20 2004 GMT
Not After : Nov 28 01:00:20 2005 GMT
Subject: O=Seccure, OU=Seccure Labs, CN=www.seccure.lab
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
Netscape Cert Type:
SSL Server
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, Netscape Server Gated Crypto,
Microsoft Server Gated Crypto
Netscape Comment:
OpenSSL Certificate for SSL Web Server
Signature Algorithm: sha1WithRSAEncryption

The examples presented in the subsequent sections of this article are based on the following values, as shown in Table 3. In order to create valid certificates, readers will need to replace these values with the names of their own company or organization.

Attribute's description


Sample value

Country code (two letters)


C = PL
State or Province


S = mazowieckie



L = Warsaw

Organization Name


O = Seccure

Organization Unit


OU = Seccure Labs

Common Name


CN = www.seccure.lab

Table 3. Sample values for a valid certificate.

The passphrase dilemma

Before creating certificates, it is important to understand the implications of a passphrase for the certificate. Should the web server's private key be encrypted or not? There are many opinions, but it is recommended that one does not protect the web server's private key using passphrase. It is not only inconvenient, but also gives a false sense of security. Why? Consider the points below.

  1. One is required to enter the passphrase after every restart of the web server, which can be quite annoying if the system needs to be restarted often (such as due to a kernel update, an electricity failure, configuration change, and so on).
  2. If an intruder manages to get the private key on the web server, it means that the web server is compromised and the intruder had had access to the web server's operating system at root level. If this is the case, the intruder could obtain the passphrase by installing keylogger, and either crash or restart the system to force administrator to enter the passphrase. Alternatively, an intruder could dump Apache's memory and find the web server's private key stored as clear text there. While it is little bit difficult, for those skilled in the art of hacking Unix it should not pose a big problem (hint: look at the pcat utility from The Coroner's Toolkit).

Therefore, the only advantage of encrypting web server's private key is that the passphrase will help protect web server's private key against script kiddies, but not against professionals who are able to compromise the server.

Creating the web server certificate

At this point we can create our web server certificate. In general, there are three types of certificates that we can use:

  1. A self-signed certificate.
  2. A certificate signed by trusted CA (most recommended).
  3. A certificate signed by a local CA.

The sections below describe in detail the methods of creating the above certificates. The final result of any method used will be just two files:

  • server.key - the private key of the web server
  • server.crt - the PEM encoded certificate that includes our web server's public key

Method 1: Self-signed certificate (for testing purposes only)

This method is recommended only for continuing our testing, or for use in small, closed environments (such as at home or in small Intranets). In order for the web browsers to be able to authenticate the web server, self-signed certificates must be installed in every web browser that needs access the web server. This can be quite inconvenient.

The web server's private/public key pair and the self-signed PEM-encoded certificate now can be created as follows:

openssl req \
-new \
-x509 \
-days 365 \
-sha1 \
-newkey rsa:1024 \
-nodes \
-keyout server.key \
-out server.crt \
-subj '/O=Seccure/OU=Seccure Labs/CN=www.seccure.lab'

The above commands will create a new (-new) certificate (-x509) that will be valid for one year (-days 365) and will be signed using the SHA1 algorithm (-sha1). The RSA private key will be 1024 bits long (-newkey rsa:1024), and will not be protected by a passphrase (-nodes). The certificate and the private/public key pair will be created in the "server.crt" and "server.key" files (-out server.crt -keyout server.key). The "-subj" parameter says that the company's name is "Seccure" (O=Seccure), the department's name is "Seccure Labs", and the web server's fully qualified domain name is "www.seccure.lab".

After creating the above certificate, we need to distribute and install it in every web browser that may connect to the web server. Otherwise, web browsers requiring a connection will not be able to verify the web server's identity. For Windows environments, this is shown below in Figure 1.

Figure 1. Installing a self-signed certificate onto a client machine.

Method 2: Certificate signed by a trusted CA (recommended method)

Creating a certificate request and signing it by a trusted CA (such as Verisign,Thawte, RSA, or others) is the most recommended way to proceed if the SSL web server is to be exposed to the Internet. Using this approach, there is no need to install certificates in each web browser, since most of them already have a number of trusted CA certificates pre-installed out-of-the-box.

Please note that each Certificate Authority has different restrictions for the Distinguish Name's attributes, to accommodate certain key lengths or international characters, and therefore prior to creating certificate requests readers need to make sure that certificate request is compliant with their particular CA's requirements. It is also recommended that one choose a CA whose signing certificate is already installed in most of web browsers (including Thawte, Verisign, and a number of others). Otherwise, the user's web browser may have problems authenticating with the web server.

The process of obtaining a signed certificate from trusted CA consists of the following steps:

  1. In the first step, we should create our web server's private/public key pair (server.key), and certificate request (request.pem), as follows:

    openssl req \
    -new \
    -sha1 \
    -newkey rsa:1024 \
    -nodes \
    -keyout server.key \
    -out request.pem \
    -subj '/O=Seccure/OU=Seccure Labs/CN=www.seccure.lab'
  2. Now we must send the certificate request (request.pem) to the CA, and then wait until it is signed and sent back to us in the form of certificate.
  3. After receiving certificate back from our trusted CA, we must make sure that it is encoded in the PEM format, and not in TXT or DER format. If the received certificate is not PEM-encoded, then we will need to convert it from whatever format we have received.

    The easiest way to check the format of the certificate is to view the certificate with a text editor. Depending on how the certificate look, it can be in one of the following formats (the typical filename extensions has been presented in the brackets):

    • PEM, Base64 encoded X.509 format (*.crt, *.pem, *.cer)

      -----BEGIN CERTIFICATE-----
      -----END CERTIFICATE-----
    • TXT + PEM format (*.crt, *.cer, *.pem, *.txt)

      Version: 3 (0x2)
      Serial Number: 1 (0x1)
      Signature Algorithm: sha1WithRSAEncryption
      Issuer: O=Seccure, OU=Seccure Root CA
      RSA Public Key: (1024 bit)
      Modulus (1024 bit):
      X509v3 extensions:
      X509v3 Basic Constraints:
      -----BEGIN CERTIFICATE-----
      -----END CERTIFICATE-----

      If your certificate was received in TXT + PEM format, here is the command to convert it to PEM:

      openssl x509 -in signed_cert.pem -out server.crt

    • DER, binary encoded X.509 (*.der, *.crt, *.cer)

      [ non-text, binary representation ]

      If your certificate was received in DER format, here is the command to convert it to PEM:

      openssl x509 -in signed_cert.der -inform DER -out server.crt
  4. Verify and test the certificate

    Before installing the certificate we should check if the received certificate is indeed valid and can be used for web server authentication purposes:

    openssl verify -CAfile /path/to/trusted_ca.crt -purpose sslserver server.crt

    Also, it is good to make sure that the certificate corresponds to our previously created web server's private key (the results of both commands below should be identical):

    openssl x509 -noout -modulus -in server.crt | openssl sha1
    openssl rsa -noout -modulus -in server.key | openssl sha1

Method 3: Certificate signed by a local CA

This third method of signing a certificate can be used in Intranets as well as all organizations that use, or plan to use, their own Certification Authority. In this case, a local CA certificate must be installed in all web browsers that connect to the secure web server.

To be able to use this method, we need to create our local CA's private/public key, as well as the CA's certificate and repository for the new keys.

Note: The local CA should be created on a separate server that is not connected to the network at all. The operating system should allow access only to authorized people, and the machine itself should be physically secured. The CA's private key is the most precious element of the entire PKI system - if this key is compromised, then all other certificates signed by this CA are considered compromised as well!

We will use the OpenSSL library to setup the environment step by step, as listed below. Of course, if we already have a local CA, we can skip this section and proceed with creating the certificate request for the web server.

  1. Prepare the directory structure for the new CA (the $SSLDIR environment variable should be added to applicable startup scripts, such as /etc/profile or /etc/rc.local):

    export SSLDIR=$HOME/ca
    mkdir $SSLDIR
    mkdir $SSLDIR/certs
    mkdir $SSLDIR/crl
    mkdir $SSLDIR/newcerts
    mkdir $SSLDIR/private
    mkdir $SSLDIR/requests
    touch $SSLDIR/index.txt
    echo "01" > $SSLDIR/serial
    chmod 700 $SSLDIR
  2. Create the main OpenSSL configuration file - $SSLDIR/openssl.cnf, with the following content (optimized for the use with SSL web servers):

    # =================================================
    # OpenSSL configuration file
    # =================================================


    [ ca ]
    default_ca = CA_default

    [ CA_default ]
    dir = $ENV::SSLDIR
    certs = $dir/certs
    new_certs_dir = $dir/newcerts
    crl_dir = $dir/crl
    database = $dir/index.txt
    private_key = $dir/private/ca.key
    certificate = $dir/ca.crt
    serial = $dir/serial
    crl = $dir/crl.pem
    RANDFILE = $dir/private/.rand
    default_days = 365
    default_crl_days = 30
    default_md = sha1
    preserve = no
    policy = policy_anything
    name_opt = ca_default
    cert_opt = ca_default

    [ policy_anything ]
    countryName = optional
    stateOrProvinceName = optional
    localityName = optional
    organizationName = optional
    organizationalUnitName = optional
    commonName = supplied
    emailAddress = optional

    [ req ]
    default_bits = 1024
    default_md = sha1
    default_keyfile = privkey.pem
    distinguished_name = req_distinguished_name
    x509_extensions = v3_ca
    string_mask = nombstr

    [ req_distinguished_name ]
    countryName = Country Name (2 letter code)
    countryName_min = 2
    countryName_max = 2
    stateOrProvinceName = State or Province Name (full name)
    localityName = Locality Name (eg, city)
    0.organizationName = Organization Name (eg, company)
    organizationalUnitName = Organizational Unit Name (eg, section)
    commonName = Common Name (eg, YOUR name)
    commonName_max = 64
    emailAddress = Email Address
    emailAddress_max = 64

    [ usr_cert ]
    basicConstraints = CA:FALSE
    # nsCaRevocationUrl = https://url-to-exposed-clr-list/crl.pem

    [ ssl_server ]
    basicConstraints = CA:FALSE
    nsCertType = server
    keyUsage = digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth, nsSGC, msSGC
    nsComment = "OpenSSL Certificate for SSL Web Server"

    [ ssl_client ]
    basicConstraints = CA:FALSE
    nsCertType = client
    keyUsage = digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth
    nsComment = "OpenSSL Certificate for SSL Client"

    [ v3_req ]
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment

    [ v3_ca ]
    basicConstraints = critical, CA:true, pathlen:0
    nsCertType = sslCA
    keyUsage = cRLSign, keyCertSign
    extendedKeyUsage = serverAuth, clientAuth
    nsComment = "OpenSSL CA Certificate"

    [ crl_ext ]
    basicConstraints = CA:FALSE
    keyUsage = digitalSignature, keyEncipherment
    nsComment = "OpenSSL generated CRL"
  3. Now create the CA's private/public key pair, and the self-signed CA's certificate:

    openssl req \
    -config $SSLDIR/openssl.cnf \
    -new \
    -x509 \
    -days 3652 \
    -sha1 \
    -newkey rsa:1024 \
    -keyout $SSLDIR/private/ca.key \
    -out $SSLDIR/ca.crt \
    -subj '/O=Seccure/OU=Seccure Root CA'

    It should be emphasized that the CA's private key (ca.key) should be protected by a hard to guess passphrase, and it should be valid for a much longer period of time than regular certificates (typically, 10-30 years, or more).

The CA's certificate "ca.crt" should be published on Intranet web pages and installed in every web browser that may possibly need to use it. A sample root CA certificate installed in Internet Explorer is shown below in Figure 2.

Figure 2. Sample root CA certificate installed in Internet Explorer.

From this point we can now use our local CA for signing/revoking certificates. In order to create the web server certificate, we should follow the below steps:

  1. Create the web server's private/public key pair (server.key), and the certificate request (request.pem). This instruction needs to be executed on the web server.

    openssl req \
    -new \
    -sha1 \
    -newkey rsa:1024 \
    -nodes \
    -keyout server.key \
    -out request.pem \
    -subj '/O=Seccure/OU=Seccure Labs/CN=www.seccure.lab'
  2. Copy the above certificate request (request.pem) into the $SSLDIR/requests directory on the CA host (using removable media, such as a USB-Drive).
  3. Sign the certificate request as follows (to be executed on the CA host only):

    openssl ca \
    -config $SSLDIR/openssl.cnf \
    -policy policy_anything \
    -extensions ssl_server \
    -out $SSLDIR/requests/signed.pem \
    -infiles $SSLDIR/requests/request.pem

    The result of the above command is a signed certificate (signed.pem) that is placed in the $SSLDIR/newcerts directory, and in the file $SSLDIR/signed.pem. It consists of both a TXT and PEM representation of the certificate. Because Apache expects a pure PEM format, we need to convert it, as follows:

    openssl x509 \
    -in $SSLDIR/requests/signed.pem \
    -out $SSLDIR/requests/server.crt
  4. Copy the signed, PEM-encoded certificate (server.crt) back to the web server machine.

At this point web server's certificate is ready to use.

For local Certificate Authorities, if the web server's certificate is compromised it is CA responsibility to revoke the certificate, and to inform users and applications that this certificate is no longer valid.

To revoke a certificate, we need to find the serial number of the certificate we want to revoke in the $SSLDIR/index.txt file. Then, we can revoke the certificate as follows:

openssl ca \
-config $SSLDIR/openssl.cnf \
-revoke $SSLDIR/newcerts/.pem

To create a CRL (Certificate Revocation List) file, we can use the following commands:

openssl ca -config $SSLDIR/openssl.cnf -gencrl -crlexts crl_ext -md sha1 -out $SSLDIR/crl.pem

The above file should be published on the CA's website, and/or distributed to users. When distributing CRLs it is also recommended that one use the Online Certificate Status Protocol (OCSP). More information about OCSP can be found in RFC 2560 .

Note that some browsers (including Firefox) accept only DER-encoded CRLs, so prior to installing crl.pem in such browsers, the file must be converted as follows:

openssl crl \
-in $SSLDIR/crl.pem \
-out $SSLDIR/revoke_certs.crl \
-outform DER

Also note that in order for the web browser to check if the web server's certificate is revoked, the option "Check for server certificate revocation" should be checked in MS Internet Explorer's Advanced Settings. This is shown below in Figures 3 and 4.

Figure 3. Configuring Internet Explorer to check for certificate revocation.

Figure 4. Internet Explorer's response to a revoked certificate.

Installing the certificate

At this point we can proceed with installing the web server's private key (server.key) and certificate (server.crt) into the Apache environment:

install -m 600 -o root -g sys server.key /usr/local/apache2/conf/ssl.key/
install -m 644 -o root -g sys server.crt /usr/local/apache2/conf/ssl.crt/

We should also make sure that the directives in Apache's configuration file are pointing to the above files (in httpd.conf):

SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt
SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server.key

The final step is to restart Apache for the changes to take an effect:

/usr/local/apache2/bin/apachectl stop
/usr/local/apache2/bin/apachectl startssl

At this point we can check to see if the SSL website is accessible from the web browsers, and if the web browsers can successfully authenticate with the web server. This time, there should be no warning messages displayed, as shown below in Figure 5.

Figure 5. Secure connection with a valid certificate.

Concluding part two

It has been shown how to configure mod_ssl, and how to create and use a web server's X.509v3 certificates. Next, in the third and final part of this article series, we will discuss client authentication via certificates, as well as common mistakes and known attacks that can threaten the security of SSL communication.


Anonymous said...

It agree

Anonymous said...

You have thought up such matchless phrase?

Anonymous said...

Lorena rocks!?!