Using Elliptic Curve Cryptography with Apache

This document describes how to build an Apache 2.2.11 web server with support for Elliptic Curve Cryptography (ECC) cipher suites (RFC 4492) using OpenSSL 1.0.0-beta2.

These instructions were tested on a MacBook Pro (Intel processor) running Mac OS X 10.5.6 but should apply to other flavors of UNIX with little or no modification. You should also be able to use a subsequent release of OpenSSL available from the daily snapshot repository.

Step 1: Initial Setup

Create an installation directory and set an environment variable $MY_INSTALL_ROOT to point to it. The syntax of the declaration is shell specific and following example works for bash:

% mkdir absolute_path_to_installation_directory
% export MY_INSTALL_ROOT=absolute_path_to_installation_directory
          

Step 2: Building OpenSSL

  1. Download openssl-1.0.0-beta2 (or similar) from the OpenSSL Tarballs page. Unpack it inside $MY_INSTALL_ROOT and set an environment variable to point to the OpenSSL directory.
    % cd $MY_INSTALL_ROOT
    % gunzip openssl-1.0.0-beta2.tar.gz
    % tar xvf openssl-1.0.0-beta2.tar
    % export MY_OPENSSL=$MY_INSTALL_ROOT/openssl-1.0.0-beta2
                      
  2. Build and test OpenSSL
    % cd $MY_OPENSSL
    % ./config
    % make
    % make test
                      
  3. OpenSSL versions 0.9.8 and later include ECC code contributed by Sun Labs. This functionality is enabled by default which is why we didn't need to do anything special.

Step 3: Building Apache 2.2.11 with OpenSSL

  1. Download Apache httpd-2.2.11.tar.gz from the Apache Software Foundation, save it to $MY_INSTALL_ROOT and create an installation directory for Apache.
    % cd $MY_INSTALL_ROOT
    % gunzip httpd-2.2.11.tar.gz
    % tar xvf httpd-2.2.11.tar
    
    % mkdir $MY_INSTALL_ROOT/Apache-Install
                      
  2. [NOTE: This step may not be necessary if you are using a version of Apache released after Mar 2, 2009. Apache 2.2.11 was released in Dec 2008 before this patch had been checked in.]

    Download and apply the patch posted for Apache Issue# 45521. Without this patch, attempts to build Apache with OpenSSL 0.9.9 or later result in compile time errors (error: 'STACK' undeclared). Here we assume the patch was saved in $MY_INSTALL_ROOT/modssl_openssl_099.diff.txt. It can be applied using the GNU patch tool:

    % cd $MY_INSTALL_ROOT/httpd-2.2.11
    % patch -p 0 -i $MY_INSTALL_ROOT/modssl_openssl_099.diff.txt
                      
  3. Apache is linked to OpenSSL through the mod_ssl module. This module is included in httpd-2.2.11 but needs to be patched to expose the elliptic curve cryptography capabilities in OpenSSL. Download and apply the patch posted for Apache Issue# 40132. Here, we assume the patch was saved in $MY_INSTALL_ROOT/enable-ecc-apache2.2.11-with-openssl-1.0.0-beta2-20090505121706.txt
    % cd $MY_INSTALL_ROOT/httpd-2.2.11
    % patch -p 1 -i $MY_INSTALL_ROOT/enable-ecc-apache2.2.11-with-openssl-1.0.0-beta2-20090505121706.txt
                      
  4. Configure, compile and install Apache.
    % ./configure --prefix=$MY_INSTALL_ROOT/Apache-Install/ --enable-ssl --enable-so --with-ssl=$MY_OPENSSL
    % make
    % make install
                      
    NOTE: I encountered 'undefined symbol' errors during the 'make' step on my MacBook Pro because the linker was unable to find ECC-enabled versions of libcrypto.a and libssl.a. I got around the problem by adding the full path corresponding to $MY_INSTALL_ROOT/openssl-1.0.0-beta2 to the definition of my LD_LIBRARY_PATH environment variable, copying libcrypto.a and libssl.a from openssl-1.0.0-beta2 to a new subfolder under it called lib and making sure that there were no other versions of libcrypto and libssl in other paths passed to the linker via the -L option.

Step 4: Generating Certificates

We need appropriate digital certificates to test the Apache web server with ECC and RSA cipher suites,

  1. These can be generated using scripts in the demos/ssltest-ecc subdirectory of an OpenSSL distribution. We recommend modifying those scripts as follows before use:
    • In RSAcertgen.sh, ECC-RSAcertgen.sh and ECCcertgen.sh, edit the "distinguished name" (DN) field to insert the server's hostname in the CN component. Otherwise, the browser will complain of a certificate name mismatch error during the SSL handshake.
    • Replace occurrences of 'sect163r1', 'secp160r1' and 'secp160r2' in ECC-RSAcertgen.sh and ECCcertgen.sh with 'secp256r1' because both Firefox (version 2.0 or later) and Internet Explorer (version 7.0 or later) support this elliptic curve.
  2. An RSA certificate can be generated with OpenSSL and installed as follows:
    % cd $MY_OPENSSL/demos/ssltest-ecc
    % ./RSAcertgen.sh
    % cp Certs/rsa1024TestServer.cert.pem $MY_INSTALL_ROOT/Apache-Install/conf/server.crt
    % cp Certs/rsa1024TestServer.key.pem $MY_INSTALL_ROOT/Apache-Install/conf/server.key
                      
  3. Likewise, ECC certificates can be generated and installed.
    % ./ECCcertgen.sh
    % cp Certs/secp256r1TestServer.cert.pem $MY_INSTALL_ROOT/Apache-Install/conf/server-ecc.crt
    % cp Certs/secp256r1TestServer.key.pem $MY_INSTALL_ROOT/Apache-Install/conf/server-ecc.key
                      
    This creates an ECDSA-signed ECC certificate which can be used for ECDH-ECDSA ciphers (see RFC 4492). Alternatively, you can create an RSA-signed ECC certificate for use with ECDH-RSA ciphers:
    % ./ECC-RSAcertgen.sh
    % cp Certs/secp256r1-rsaTestServer.cert.pem $MY_INSTALL_ROOT/Apache-Install/conf/server-ecc.crt
    % cp Certs/secp256r1-rsaTestServer.key.pem $MY_INSTALL_ROOT/Apache-Install/conf/server-ecc.key
                      
    NOTE: OpenSSL does not currently allow a server to be configured with multiple ECC certificates simultaneously.

Step 5: Configuring Apache

  1. Running Apache on the default HTTP port (80) requires superuser privileges so you may wish to run it on an unprivileged port like 8080. The following lines in $MY_INSTALL_ROOT/Apache-Install/conf/httpd.conf may have to be modified (replace 80 with 8080 and www.example.com with the server's name):
    Listen 80
    
    ServerName www.example.com:80
                      
    Uncomment the following line in httpd.conf
    #Include conf/extra/httpd-ssl.conf
                      
  2. The default HTTPS port (443) also requires special privileges so you may wish to run it on an unprivileged port 8443 (say). The following lines in $MY_INSTALL_ROOT/Apache-Install/conf/extra/httpd-ssl.conf may have to be modified (replace 443 with 8443, _default_ and www.example.com with the server's name):
    Listen 443
    
    <VirtualHost _default_:443>
    
    ServerName www.example.com:443
                      
    Edit the line beginning with SSLCipherSuite if you wish to disable any ECC ciphers. Here, we leave it unchanged.
    SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
                      
    NOTE: ECC cipher suites are now part of ALL and ECCdraft is no longer a valid cipher suite descriptor.

  3. Uncomment the following lines in $MY_INSTALL_ROOT/Apache-Install/conf/extra/httpd-ssl.conf to enable the newly generated ECC certificate (these lines should have been added by the ECC patch)
    #SSLCertificateFile $MY_INSTALL_ROOT/Apache-Install/conf/server-ecc.crt
    
    #SSLCertificateKeyFile $MY_INSTALL_ROOT/Apache-Install/conf/server-ecc.key
                      

Step 6: Testing Apache

  1. Start up the Apache web server:
    % $MY_INSTALL_ROOT/Apache-Install/bin/apachectl start
                      
  2. Connect to it via the OpenSSL s_client application:
    % $MY_OPENSSL/apps/openssl s_client -connect <server's name>:8443 -cipher
    ECDH-ECDSA-AES128-SHA
                      
  3. Upon successful installation, this command should show an output similar to the following:
    % openssl s_client -connect localhost:8443 -cipher ECDH-ECDSA-AES128-SHA
    CONNECTED(00000003)
    depth=0 /C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Labs/CN=localhost
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 /C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Labs/CN=localhost
    verify error:num=27:certificate not trusted
    verify return:1
    depth=0 /C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Labs/CN=localhost
    verify error:num=21:unable to verify the first certificate
    verify return:1
    ---
    Certificate chain
     0 s:/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Labs/CN=localhost
       i:/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Labs/CN=Test
       CA (Elliptic curve secp256r1)
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIB/DCCAaMCCQD2f6mKkn+reTAJBgcqhkjOPQQBMIGTMQswCQYDVQQGEwJVUzEL
    MAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAdBgNVBAoMFlN1
    biBNaWNyb3N5c3RlbXMsIEluYy4xETAPBgNVBAsMCFN1biBMYWJzMSswKQYDVQQD
    DCJUZXN0IENBIChFbGxpcHRpYyBjdXJ2ZSBzZWNwMjU2cjEpMB4XDTA5MDUwNjA0
    MTQ1OFoXDTEzMDYxNDA0MTQ1OFowejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB
    MRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MR8wHQYDVQQKDBZTdW4gTWljcm9zeXN0
    ZW1zLCBJbmMuMREwDwYDVQQLDAhTdW4gTGFiczESMBAGA1UEAwwJbG9jYWxob3N0
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER22G9my4gSiUDOtzPRLS2NupE+bL
    ixozwjYblT3eHQpyoKOcAVOuBwdJGYGQ6SoYXJLraPelt+hm3KZOzlcCbTAJBgcq
    hkjOPQQBA0gAMEUCIHn7pSs203XFEdUxl3yCvXAVKYeFyqpoaDSgFOXtJbcaAiEA
    xbxlnIbxJD1CPWUK+DIqhoiJQrsot2N/dXoUkfpD4qg=
    -----END CERTIFICATE-----
    subject=/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Labs/CN=localhost
    issuer=/C=US/ST=CA/L=Mountain View/O=Sun Microsystems, Inc./OU=Sun Labs/CN=Test
    CA (Elliptic curve secp256r1)
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 863 bytes and written 254 bytes
    ---
    New, TLSv1/SSLv3, Cipher is ECDH-ECDSA-AES128-SHA
    Server public key is 256 bit
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : ECDH-ECDSA-AES128-SHA
        Session-ID:
        Session-ID-ctx:
        Master-Key: AAEFD525FBE4186520FDC783F175F928C66FF045B843A35FB29DD06F48F45D54
        7BD0D7C1904BFFAFAE91537D0DA77718
        Key-Arg   : None
        PSK identity: None
        PSK identity hint: None
        TLS session ticket:
        0000 - cf f6 a4 73 e9 f2 4a 1f-fb 12 b0 45 80 e6 ea 11   ...s..J....E....
        0010 - 3d bd b4 f4 d0 7e 47 bf-e3 a8 a4 20 f6 00 8b d6   =....~G.... ....
        0020 - 33 73 65 1f 36 a9 d9 cf-41 40 e6 d5 95 65 9c 76   3se.6...A@...e.v
        0030 - 10 9c 50 09 11 a1 fd a6-81 74 4a 70 e5 15 2b bb   ..P......tJp..+.
        0040 - e3 4e 5c 7e 18 dc 5b ba-6a 91 d6 43 8c be 91 91   .N\~..[.j..C....
        0050 - fb 65 06 1d f8 e0 bc b6-c1 55 b5 1c a3 61 4f cc   .e.......U...aO.
        0060 - 5a 08 ea 43 de 94 ec 9e-a3 c5 2e 6e 9d f6 9d 9a   Z..C.......n....
        0070 - a6 f7 4f b7 fd 9a 88 4e-f4 5f ef 5c 3a 41 04 e6   ..O....N._.\:A..
        0080 - d7 52 51 fa f1 1a c3 e1-62 27 9f 37 f3 11 2c d4   .RQ.....b'.7..,.
        0090 - 83 f8 a5 a8 2a 24 db b7-73 6d 3f c0 ff aa 95 8b   ....*$..sm?.....
        00a0 - 7a 59 e6 45 75 e9 2c 8f-74 0e b3 4a 2a 72 0f 9f   zY.Eu.,.t..J*r..
        00b0 - 6a 14 b0 52 a0 e9 5b c4-7b 02 16 05 5b f8 94 ca   j..R..[.{...[...
    
        Start Time: 1241583503
        Timeout   : 300 (sec)
        Verify return code: 21 (unable to verify the first certificate)
    ---
                      
    In addition, a test page can be retrieved by typing
    GET / HTTP/1.0
                      
    and hitting the Enter key twice
  4. You can also connect to the Apache server from Firefox by pointing it to https://<server's name>:8443/. Our Apache server is configured with a certificate from a made-up certificate authority. Firefox will recognize this fact and complain (Error code: sec_error_unknown_issuer). You can add an exception for your server to allow the connection to proceed. If all goes well, you should eventually see "It works!" in the browser window. Choose Tools->Page Info, select the "Security" tab, click on "View Certificate" followed by "Details" to look at the certificate fields. For example, scroll down and look at the Algorithm Identifier and Algorithm Identifier under Subject Public Key Info. You should see "Elliptic Curve Public Key" and "ANSI X9.62 elliptic curve prime256v1 (aka secp256r1, NIST P-256)" respectively indicating that the connection used an ECC ciphersuite.

    The truly adventurous can point Firefox to the URL about:config and type security.ssl3.ec in the Filter field to list all supported ECC cipher suites. Each cipher suite can then be individually enabled/disabled by double clicking its name.