OpenSSL 1.1.1: Apache HTTP Server setup with the PKCS#11 libp11 engine
The libp11 engine is a library designed to call from within OpenSSL certain cryptographic functions provided by a PKCS#11 API (for example, functions implemented by an HSM or a smart card).
One way to connect OpenSSL with PKCS#11 is via the libp11 engine provided by the OpenSC project. This engine makes the operations provided by a specific PKCS#11 token available to OpenSSL. It makes it easier to use PKCS#11 in applications without having to program against the PKCS#11 API called Cryptoki.
This use case describes how to create and use a secure RSA or EC signing key for the Apache HTTP Server. It solves the problem that the server’s private key is vulnerable when being stored in an operating system’s file system or computer memory. The setup uses mod_ssl and OpenSSL libp11 engine, which is part of the OpenSC project. The engine uses openCryptoki via its PKCS#11 interface. In openCryptoki, the CCA and the EP11 token both support the secure key functionality. Figure 1 shows the overall setup.

Hardware prerequisites
Hardware prerequisites are a cryptographic coprocessor either configured in CCA mode or in EP11 mode with a valid master key setup.
Software prerequisites
- OpenSSL
- the p11tool as part of the GnuTLS utilities
- the libp11 engine (0.4.10 or later)
- the Apache HTTP Server and mod_ssl provided by the OpenSC project.
Sample setup on Red Hat Enterprise Linux
The following describes the setup on Red Hat Enterprise Linux with OpenSSL 1.1.1. Install the CCA and EP11 host libraries:
# rpm -ivh ep11-host-3.0.1-1.s390x.rpm
# rpm -ivh ep11-host-devel-3.0.1-1.s390x.rpm
# rpm -ivh csulcca-6.0.13-10.s390x.rpm
You can obtain the host libraries from the following URL:
Linux on Z software
Installation:
Install the following packages:
# yum -y install "opencryptoki*"
# yum -y install gnutls-utils
# yum -y install "libp11*"
# yum -y install "httpd*" mod_ssl
Configuration:
Perform the following configuration steps:
- Configure the p11tool to work with openCryptoki: The p11tool needs to know where the openCryptoki
PKCS#11 module is located. This is configured by
creating a new plain text file in /etc/pkcs11/modules. You can call this file
opencryptoki.module, for example. The file contains one single line:
module: /usr/lib64/opencryptoki/PKCS11_API.so
After creating the file, you can display available openCryptoki tokens and token URLs. In PKCS#11, tokens and key objects are identified by Uniform Resource Identifiers (URIs) specified in RFC7512. The p11tool refers to URIs as URLs.
# p11tool --list-tokens # p11tool --list-token-urls pkcs11:model=IBM%20CCA%20Token;manufacturer=IBM%20Corp.;serial=123;token=ccatok pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184;token=ep11tok ...
- Configure the libp11 engine: Apply the
following changes in the openssl.cnf file:
[openssl_init] engines = engine_section ssl_conf = ssl_module ... [engine_section] pkcs11 = pkcs11_section [pkcs11_section] engine_id = pkcs11 dynamic_path = /usr/lib64/engines-3/libpkcs11.so MODULE_PATH = /usr/lib64/opencryptoki/PKCS11_API.so init = 0
Note: The statementinit = 0
means that the engine is not globally active but will be activated by applications explicitly, in this case by the Apache HTTP Server (httpd) and not by OpenSSL.With these changes to the openssl.cnf file, you can check if the engine is active in OpenSSL:
# openssl engine -c (dynamic) Dynamic engine loading support (pkcs11) pkcs11 engine [RSA, rsaEncryption, id-ecPublicKey]
- Generate a new secure RSA key: As the token URL is part of many subsequently used
p11tool commands, put it into a variable:
It can then be referenced as# url="pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184;token=ep11tok"
"$url"
:# p11tool --login --generate-rsa --bits 2048 --outfile /etc/ssl/ep11rsa.key --label ep11rsa "$url"
Note: In the output file ep11rsa.key, only the public key is stored, which, however, is not used furthermore.After generating the RSA key, you can list it. The output shows two key objects: the public key and the private key. In the following, you need the private key URL.
# p11tool --login --list-all "$url" Token 'ep11tok' with URL 'pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184;token=ep11tok' requires user PIN Enter PIN: Object 0: URL: pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184; token=ep11tok;id=%35%80%33%7B%3A%20%1A%39%41%3F%60%B4%EA%42%FE%02%E6%F8%39%5F; object=ep11rsa;type=private Type: Private key (RSA-2048) Label: ep11rsa Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_EXTRACTABLE; CKA_SENSITIVE; ID: 35:80:33:7b:3a:20:1a:39:41:3f:60:b4:ea:42:fe:02:e6:f8:39:5f Object 1: URL: pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184; token=ep11tok;id=%35%80%33%7B%3A%20%1A%39%41%3F%60%B4%EA%42%FE%02%E6%F8%39%5F; object=ep11rsa;type=public Type: Public key (RSA-2048) Label: ep11rsa Flags: CKA_WRAP/UNWRAP; ID: 35:80:33:7b:3a:20:1a:39:41:3f:60:b4:ea:42:fe:02:e6:f8:39:5f
- Create the secure key certificate: This step creates a TLS certificate, signed by the
secure RSA key.
# key="pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184; token=ep11tok;id=%35%80%33%7B%3A%20%1A%39%41%3F%60%B4%EA%42%FE%02%E6%F8%39%5F; object=ep11rsa;type=private" /* must be all in one line */ # openssl req -x509 -new -engine pkcs11 -keyform engine -subj "/C=DE/ST=BW/L=Boeblingen/O=IBM R&D/OU=Linux on Z/CN=ep11rsa cert" -key "$key" -out /etc/ssl/ep11rsa.crt /* must be all in one line */
The certificate is now stored in /etc/ssl/ep11rsa.crt.
Note: Place the certificate file at an appropriate location so that the Apache HTTP Server is allowed to access it. - Configure the Apache web server: On Red Hat Enterprise Linux, the Apache configuration is
located in /etc/httpd/. Here, change file
/etc/httpd/conf.d/ssl.conf as follows:
Specify your certificate file ep11rsa.crt for parameter SSLCertificateFile and specify the RSA key URL for parameter SSLCertificateKeyFile.
Note: Enclose the key URL in double quotes:SSLCertificateFile /etc/ssl/ep11rsa.crt SSLCertificateKeyFile "pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184;token=ep11tok; id=%35%80%33%7B%3A%20%1A%39%41%3F%60%B4%EA%42%FE%02%E6%F8%39%5F; object=ep11rsa;type=private"
Testing
You can now immediately test the setup using the OpenSSL utilities s_server and s_client. This test verifies the correct key and certificate setup, but does not involve the Apache web server.
Test with s_server / s_client:
# openssl s_server -engine pkcs11 -keyform engine \
-key "$key" -cert /etc/ssl/ep11rsa.crt \
-debug -msg \
-accept 443 -tls1_2 -www
Engine "pkcs11" set.
Enter PKCS#11 token PIN for ep11tok:
Using default temp DH parameters
ACCEPT ...
>>> TLS 1.2, Handshake [length 0010], Finished
14 00 00 0c c9 29 9d 4b de 21 82 03 58 74 fa 26
write to 0x2aa22939a50 [0x2aa22a0b7a0] (242 bytes => 242 (0xF2))
The s_server is now in a listening state and you can use the s_client to connect to the s_server:
# openssl s_client -debug -msg -connect <ip_address>:443
...
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: C3699D42DE586D9209078A9115A3D2A1214CF14E5E035A33E8BC47FED66C2D24
Session-ID-ctx:
Master-Key: 9BE04...D7753FF1838FE6FE7128CFF82DA0F04EB4699
...
A successful connection shows the protocol and used TLS cipher suite.
Test with Apache web server
You can use the httpd -X parameter to start Apache single-threaded. You are prompted for the user PIN of the openCryptoki EP11 token:
# httpd -X
Apache/2.4.51 mod_ssl (Pass Phrase Dialog)
A pass phrase is required to access the private key.
Private key t3545012.lnxne.boe:443 (pkcs11:model=EP11;manufacturer=IBM;serial=93AABEC895428184;token=ep11tok;
id=%35%80%33%7B%3A%20%1A%39%41%3F%60%B4%EA%42%FE%02%E6%F8%39%5F;object=ep11rsa;type=private)
Enter PKCS#11 token PIN for ep11tok:
After starting httpd, use s_client to connect to the web server.
# openssl s_client -debug -msg -connect t3545012:443
...
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384 ...
Again, a successful connection shows the protocol and TLS cipher suite.
Starting Apache multi-threaded, is usually done via the systemctl command:
# systemctl start httpd
If you use the systemctl command in this way, your are not prompted for the PIN of the openCryptoki EP11 token. Instead, you must provide the PIN within the PKCS11 URL. You can either specify the PIN directly using the pin-value option, or by using the pin-source option pointing to a file that contains the PIN. The first alternative is quite insecure, because the PIN is in clear text in the configuration file. For the second alternative, you can protect the file by access controls.
Example for pin-value
SSLCertificateKeyFile "pkcs11:model=EP11; ..... ?pin-value=11223344"
Example for pin-source
SSLCertificateKeyFile "pkcs11:model=EP11; ..... ?pin-source=file:/<path_to_pin-file>"