Key Knowledge Areas:

  • Understand SSL, TLS, including protocol versions and ciphers
  • Configure Apache HTTPD with mod_ssl to provide HTTPS service, including SNI and HSTS
  • Configure Apache HTTPD with mod_ssl to serve certificate chains and adjust the cipher configuration (no cipher-specific knowledge)
  • Configure Apache HTTPD with mod_ssl to authenticate users using certificates
  • Configure Apache HTTPD with mod_ssl to provide OCSP stapling
  • Use OpenSSL for SSL/TLS client and server tests

Partial list of the used files, terms and utilities:

  • httpd.conf
  • mod_ssl
  • openssl (including relevant subcommands)

Files

httpd.conf

httpd.conf is the main configuration file for the Apache HTTP Server

Utilities

mod_ssl

mod_ssl is a module for the Apache HTTP Server that provides SSL v3 and TLS v1.x support

HTTPS

LoadModule ssl_module modules/mod_ssl.so

Listen 443

<VirtualHost _default_:443>
SSLEngine on

SSLCertificateFile "/usr/local/apache2/conf/server.crt"

SSLCertificateKeyFile "/usr/local/apache2/conf/server.key"

#SSLCertificateChainFile "/usr/local/apache2/conf/server-ca.crt"

#SSLCACertificatePath "/usr/local/apache2/conf/ssl.crt"
#SSLCACertificateFile "/usr/local/apache2/conf/ssl.crt/ca-bundle.crt"

#SSLCARevocationPath "/usr/local/apache2/conf/ssl.crl"
#SSLCARevocationFile "/usr/local/apache2/conf/ssl.crl/ca-bundle.crl"
#SSLCARevocationCheck chain

#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/usr/local/apache2/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>

</VirtualHost>

SNI

From the wiki:

# Listen for virtual host requests on all IP addresses
NameVirtualHost *:443

# Go ahead and accept connections for these vhosts
# from non-SNI clients
SSLStrictSNIVHostCheck off

<VirtualHost *:443>
  # Because this virtual host is defined first, it will
  # be used as the default if the hostname is not received
  # in the SSL handshake, e.g. if the browser doesn't support
  # SNI.
  DocumentRoot /www/example1
  ServerName www.example.net

  # Other directives here

</VirtualHost>

<VirtualHost *:443>
  DocumentRoot /www/example2
  ServerName www.example2.org

  # Other directives here

</VirtualHost>

HSTS

HTTP Strict Transport Security is configured by defining a header:

LoadModule headers_module modules/mod_headers.so

<VirtualHost _default_:443>
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</VirtualHost>

certificate chain

SSLCertificateChainFile: One file containing the issuing CA for the server’s certificate and can range up to the root CA.

SSLCertificateChainFile "/usr/local/apache2/conf/server-ca.crt"

Note: From version 2.4.8 onwards the chain can alternatively be defined through the SSLCertificateFile directive, where a single file would contain the chain sorted from leaf to root.

cipher configuration

Cipher suites

SSLHonorCipherOrder on

# be liberal in general
SSLCipherSuite ALL:!aNULL:RC4+RSA:+HIGH:+MEDIUM:+LOW:+EXP:+eNULL

<Location "/strong/area">
  # but https://hostname/strong/area/ and below
  # requires strong ciphers
  SSLCipherSuite HIGH:!aNULL:!MD5
</Location>

authenticate users using certificates (mutual TLS)

Authenticating clients using certificates is commonly called mutual TLS.

secure a particular route with certificate authentication, but allow unauthenticated access to the rest:

SSLVerifyClient none
SSLCACertificateFile "conf/ssl.crt/ca.crt"

<Location "/secure/area">
  SSLVerifyClient require
  SSLVerifyDepth 1
</Location>

match clients which are part of a common hierarchy which is encoded into the DN:

SSLVerifyClient      none
SSLCACertificateFile "conf/ssl.crt/ca.crt"
SSLCACertificatePath "conf/ssl.crt"

<Directory "/usr/local/apache2/htdocs/secure/area">
  SSLVerifyClient      require
  SSLVerifyDepth       5
  SSLOptions           +FakeBasicAuth
  SSLRequireSSL
  SSLRequire       %{SSL_CLIENT_S_DN_O}  eq "Snake Oil, Ltd." \
               and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"}
</Directory>

OCSP stapling

Online Certificate Status Protocol (OCSP) describes a mechanism that reports the current revocation status of certificates. It can be used instead of a Certificate Revocation List (CRL). This is beneficial for clients because they no longer need to download the full CRL, but can instead directly query the validity of a single entry. For the certificate authorities (CA) that provide OCSP this adds significant load. To mitigate the load from OCSP queries to an extent, the OCSP results can be cached by the server and provided to the client (OCSP stapling). This reduces load on the CA and saves the client a request to the CA.

minimal configuration:

# global scope
SSLUseStapling On
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

recommended production use:

# Do not pass OCSP responder errors to clients:
SSLStaplingReturnResponderErrors off

# Reduce the OCSP responder timeout from the default 10s:
SSLStaplingResponderTimeout 4

# Cache valid OCSP responses for 48 hours (default: 1 hour).
# This reduces load on OCSP responders and avoids transient
# errors caused by frequent queries:
SSLStaplingStandardCacheTimeout 172800

# Retry failed OCSP queries after 60 seconds instead of the
# default 600s:
SSLStaplingErrorCacheTimeout 60

openssl

client test

Use OpenSSL s_server to set up a SSL/TLS server to which clients can connect.

Example IPv4 server on port 8443, without a server certificate::

openssl s_server -4 -nocert -port 8443

Client response:

$ openssl s_client -connect 127.0.0.1:8443
Connecting to 127.0.0.1
CONNECTED(00000003)
402740D2CA7F0000:error:0A000410:SSL routines:ssl3_read_bytes:ssl/tls alert handshake failure:ssl/record/rec_layer_s3.c:914:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 302 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

Example server on port 8443, with a status response on HTTP GET requests:

openssl s_server -cert leaf.crt -cert_chain chain.crt -key leaf.key -port 8443 -www

Client response:

$ curl -k https://127.0.0.1:8443/
<HTML><BODY BGCOLOR="#ffffff">
<pre>

s_server -cert leaf.crt -cert_chain chain.crt -key leaf.key -port 8443 -www
This TLS version forbids renegotiation.
Ciphers supported in s_server binary
TLSv1.3    :TLS_AES_256_GCM_SHA384    TLSv1.3    :TLS_CHACHA20_POLY1305_SHA256
TLSv1.3    :TLS_AES_128_GCM_SHA256    TLSv1.3    :TLS_AES_128_CCM_SHA256
TLSv1.2    :ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2    :ECDHE-RSA-AES256-GCM-SHA384
TLSv1.2    :ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2    :ECDHE-RSA-CHACHA20-POLY1305
TLSv1.2    :ECDHE-ECDSA-AES256-CCM    TLSv1.2    :ECDHE-ECDSA-AES128-GCM-SHA256
TLSv1.2    :ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2    :ECDHE-ECDSA-AES128-CCM
TLSv1.2    :ECDHE-ECDSA-AES128-SHA256 TLSv1.2    :ECDHE-RSA-AES128-SHA256
TLSv1.0    :ECDHE-ECDSA-AES256-SHA    TLSv1.0    :ECDHE-RSA-AES256-SHA
TLSv1.0    :ECDHE-ECDSA-AES128-SHA    TLSv1.0    :ECDHE-RSA-AES128-SHA
TLSv1.2    :AES256-GCM-SHA384         TLSv1.2    :AES256-CCM
TLSv1.2    :AES128-GCM-SHA256         TLSv1.2    :AES128-CCM
TLSv1.2    :AES256-SHA256             TLSv1.2    :AES128-SHA256
SSLv3      :AES256-SHA                SSLv3      :AES128-SHA
TLSv1.2    :DHE-RSA-AES256-GCM-SHA384 TLSv1.2    :DHE-RSA-CHACHA20-POLY1305
TLSv1.2    :DHE-RSA-AES256-CCM        TLSv1.2    :DHE-RSA-AES128-GCM-SHA256
TLSv1.2    :DHE-RSA-AES128-CCM        TLSv1.2    :DHE-RSA-AES256-SHA256
TLSv1.2    :DHE-RSA-AES128-SHA256     SSLv3      :DHE-RSA-AES256-SHA
SSLv3      :DHE-RSA-AES128-SHA        TLSv1.2    :PSK-AES256-GCM-SHA384
TLSv1.2    :PSK-CHACHA20-POLY1305     TLSv1.2    :PSK-AES256-CCM
TLSv1.2    :PSK-AES128-GCM-SHA256     TLSv1.2    :PSK-AES128-CCM
SSLv3      :PSK-AES256-CBC-SHA        TLSv1.0    :PSK-AES128-CBC-SHA256
SSLv3      :PSK-AES128-CBC-SHA        TLSv1.2    :DHE-PSK-AES256-GCM-SHA384
TLSv1.2    :DHE-PSK-CHACHA20-POLY1305 TLSv1.2    :DHE-PSK-AES256-CCM
TLSv1.2    :DHE-PSK-AES128-GCM-SHA256 TLSv1.2    :DHE-PSK-AES128-CCM
SSLv3      :DHE-PSK-AES256-CBC-SHA    TLSv1.0    :DHE-PSK-AES128-CBC-SHA256
SSLv3      :DHE-PSK-AES128-CBC-SHA    TLSv1.2    :ECDHE-PSK-CHACHA20-POLY1305
TLSv1.0    :ECDHE-PSK-AES256-CBC-SHA  TLSv1.0    :ECDHE-PSK-AES128-CBC-SHA256
TLSv1.0    :ECDHE-PSK-AES128-CBC-SHA  TLSv1.2    :RSA-PSK-AES256-GCM-SHA384
TLSv1.2    :RSA-PSK-CHACHA20-POLY1305 TLSv1.2    :RSA-PSK-AES128-GCM-SHA256
SSLv3      :RSA-PSK-AES256-CBC-SHA    TLSv1.0    :RSA-PSK-AES128-CBC-SHA256
SSLv3      :RSA-PSK-AES128-CBC-SHA
---
Ciphers common between both SSL end points:
TLS_AES_256_GCM_SHA384     TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256
TLS_AES_128_CCM_SHA256     ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM
ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM
ECDHE-ECDSA-AES128-SHA256  ECDHE-RSA-AES128-SHA256    ECDHE-ECDSA-AES256-SHA
ECDHE-RSA-AES256-SHA       ECDHE-ECDSA-AES128-SHA     ECDHE-RSA-AES128-SHA
AES256-GCM-SHA384          AES256-CCM                 AES128-GCM-SHA256
AES128-CCM                 AES256-SHA256              AES128-SHA256
AES256-SHA                 AES128-SHA                 DHE-RSA-AES256-GCM-SHA384
DHE-RSA-CHACHA20-POLY1305  DHE-RSA-AES256-CCM         DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES128-CCM         DHE-RSA-AES256-SHA256      DHE-RSA-AES128-SHA256
DHE-RSA-AES256-SHA         DHE-RSA-AES128-SHA
Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
Shared Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
Supported groups: x25519:secp256r1:x448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192
Shared groups: x25519:secp256r1:x448:secp521r1:secp384r1:ffdhe2048:ffdhe3072:ffdhe4096:ffdhe6144:ffdhe8192
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 8575D2B03276B807ABD391B0F9FF5051734519FB57E737E6F5EE6202B27CD948
    Session-ID-ctx: 01000000
    Resumption PSK: EC8544258DC9310B44C5E3EB054955C04F3C5B4730FFED57B080120E53F07203A34C7A60E3D6E7DF067A51907070A911
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1778279645
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0
---
   0 items in the session cache
   0 client connects (SSL_connect())
   0 client renegotiates (SSL_connect())
   0 client connects that finished
   3 server accepts (SSL_accept())
   0 server renegotiates (SSL_accept())
   2 server accepts that finished
   0 session cache hits
   0 session cache misses
   0 session cache timeouts
   0 callback cache hits
   0 cache full overflows (128 allowed)
---
no client certificate available
</pre></BODY></HTML>

server test

Use OpenSSL s_client to test client connections to SSL/TLS servers. There are options for protocol, client certificate, server certificate verification, network characteristics, etc.

Example:

openssl s_client -connect imaps.example.net:993

Note: Add -debug argument to print message payloads.

Notes

SNI

Server Name Indication (SNI) is a Transport Layer Security (TLS) extension which provides virtual hosting capability to HTTPS connections. During the initial handshake the client communicates the virtual domain it desires to reach through the Client Hello message. This data allows the host to select the matching certificate, usually out of a pool of certificates, and use that to complete the TLS handshake. A privacy flaw in this setup is that the virtual domain of otherwise encrypted HTTPS traffic can be learned by inspecting the plain text handshake packets.

ECH

Encrypted Client Hello (ECH) is a TLS 1.3 extension which encrypts the Client Hello message using a public key that has been distributed to the web browser beforehand. By encrypting the Client Hello message its contents are inaccessible for monitoring in transit.

HSTS

HTTP Strict Transport Security (HSTS) is a policy mechanism that informs the web browser that a host is to be reached through HTTPS for the given period. The web browser persists this requirement and updates any HTTP requests to HTTPS before submitting them, for the given period.