PKCS#11 in BIND 9
  • 04 Dec 2023
  • 5 Minutes to read
  • Contributors
  • Dark
    Light
  • PDF

PKCS#11 in BIND 9

  • Dark
    Light
  • PDF

Article Summary

Background

The PKCS#11 support in BIND 9 comes in two flavors:

  1. The native PKCS#11 that interfaces directly with the HSM provided library via the PKCS#11 API. This allows BIND 9 to interact directly with the PKCS#11 provider for the public key cryptography (DNSSEC).

  2. The OpenSSL-based PKCS#11 interfaces with the PKCS#11 provider indirectly via the pkcs11 engine provided by the OpenSC project.

This page describes the second method as it is more universal and doesn't require BIND 9 to be recompiled.

OpenSSL-based PKCS#11

Engines deprecated in OpenSSL 3.x

The OpenSSL Engines were being replaces with OpenSSL Providers in OpenSSL 3.x and thus the described method works only with OpenSSL 1.1.x. There is a PKCS#11 Provider, but it doesn't work with SoftHSM 2 because of a bug(s) in SoftHSM 2 causing segmentation faults when used with PKCS#11 Provider.

engine_pkcs11 tries to fit the PKCS#11 API within the engine API of OpenSSL. It provides a gateway between PKCS#11 modules and the OpenSSL engine API. One has to register the engine with OpenSSL and one has to provide the path to the PKCS#11 module which should be gatewayed to. This can be done by editing the OpenSSL configuration file, by engine specific controls, or by using the p11-kit proxy module.

In this document, we'll describe how to compile, install and configure
engine_pkcs11 to be used with BIND 9. For simplicity, we use SoftHSM2 as a PKCS#11 provider.

We'll assume that the installation path for BIND 9 is /opt/bind9.

Installation

Installing SoftHSM2

SoftHSM2 can be either installed as a package or installed from the source. The installation from the source is beyond the scope of this document. On DEB-based Linux distributions, the package is called softhsm2, on RPM-based Linux distributions, the package is called just softhsm.

Installing engine_pkcs11

The engines_pkcs11 module has be merged into libp11 library. To use engines_pkcs11 with BIND 9, you either need libp11 (>= 0.4.11) which contains necessary fixes, or use the version from the master branch of the upstream repository. In this document, we'll show you how to use the most current version of the engines_pkcs11. We assume that you have a working build environment for BIND 9 and git installed.

  1. Clone current version of libp11 sources:
git clone https://github.com/OpenSC/libp11.git
  1. Bootstrap and compile:
cd libp11
./bootstrap
./configure --with-enginesdir=/opt/bind9/engines
  1. After the compilation successfully finished, install the engines_pkcs11:
make install

The output should like something like this:

Making install in src
 mkdir -p '/opt/bind9/engines'
 /bin/sh ../libtool   --mode=install install -c   pkcs11.la '/opt/bind9/engines'
libtool: install: install -c .libs/pkcs11.dylib /opt/bind9/engines/pkcs11.dylib
libtool: install: install -c .libs/pkcs11.lai /opt/bind9/engines/pkcs11.la
[...]

Configuration

Configuring SoftHSM2

We are going to create a private BIND 9 storage for SoftHSM2, but you might want to keep the one installed by your package provider.

  1. The location of the SoftHSM2 can be overriden with SOFTHSM2_CONF
    environment variable. Make sure that you export this variable to your
    workspace before launching any further commands:
export SOFTHSM2_CONF=/opt/bind9/etc/softhsm2.conf
  1. Now, we need to prepare a pristine configuration:
mkdir -m 0700 -p /opt/bind9/lib/tokens
echo "directories.tokendir = /opt/bind9/lib/tokens" > "${SOFTHSM2_CONF}"
echo "objectstore.backend = file" >> "${SOFTHSM2_CONF}"
echo "log.level = DEBUG" >> "${SOFTHSM2_CONF}"
  1. And initialize slot for BIND 9:
softhsm2-util --init-token --free --pin 0000 --so-pin 0000 --label "bind9"

You should customize the pin, so-pin and label values, but please make sure you use correct values when copying the examples below.

Configuring OpenSSL to use engine_pkcs11

The canonical documentation for configuring engine_pkcs11 is in the
libp11/README.md, but here's copy of working configuration with SoftHSM2 for your convenience:

  1. We are going to use our own custom copy of the OpenSSL configuration, driven by an environment variable, this time called OPENSSL_CONF. We are going to copy the global OpenSSL configuration (often found in etc/ssl/openssl.conf) and customize it to use engines_pkcs11.
cp /etc/ssl/openssl.cnf /opt/bind9/etc/openssl.cnf

and export the environment variable:

export OPENSSL_CONF=/opt/bind9/etc/openssl.cnf
  1. Now add following line at the top of file, before any sections (in square brackets) are defined:
openssl_conf = openssl_init

Make sure there are no other openssl_conf = ... lines in the file.

  1. Add following lines at the bottom of the file:
[openssl_init]
engines=engine_section

[engine_section]
pkcs11 = pkcs11_section

[pkcs11_section]
engine_id = pkcs11
dynamic_path = /opt/bind9/engines/pkcs11.so
MODULE_PATH = /usr/lib/softhsm/libsofthsm2.so
init = 0

Key Generation

We are going to assume that you already have a BIND 9 installed, either from a package, or from the sources, and the tools are readily available in the $PATH.

For generating the keys, we are going to use pkcs11-tool available from the OpenSC suite. On both DEB-based and RPM-based distributions, the package is called opensc.

  1. Now we need to generate at least two RSA keys:
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l -k --key-type rsa:1280 --label example.net-ksk --pin 0000
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l -k --key-type rsa:1280 --label example.net-zsk --pin 0000

Remember that each key should have unique label and we are going to use that label to reference the private key.

  1. Convert the RSA keys stored in the HSM into a format that BIND 9 understands.
    The dnssec-keyfromlabel tool from BIND 9 can link the raw keys stored in the HSM with the K<zone>+<alg>+<id> files. You'll need to provide the OpenSSL engine name (pkcs11), the algorithm (RSASHA256) and the PKCS#11 label that specify the token (we initialized it as bind9), the name of the PKCS#11 object (called label when generating the keys using pkcs11-tool) and the HSM PIN.
dnssec-keyfromlabel -E pkcs11 -a RSASHA256 -l "token=bind9;object=example.net-ksk;pin-value=0000" -f KSK example.net

and ZSK:

dnssec-keyfromlabel -E pkcs11 -a RSASHA256 -l "token=bind9;object=example.net-zsk;pin-value=0000" example.net

NOTE: you can use PIN stored on disk, by specifying pin-source=<path_to>/<file>, f.e.:

(umask 0077 && echo -n 0000 > /opt/bind9/etc/pin.txt)

and then use in the label specification:

pin-source=/opt/bind9/etc/pin.txt
  1. Confirm that you have one KSK and one ZSK present in the current directory:
ls -l K*

The output should look like this (the second number will be different):

Kexample.net.+008+31729.key
Kexample.net.+008+31729.private
Kexample.net.+008+42231.key
Kexample.net.+008+42231.private

Sign the zone as usual

The zone signing commences as usual, with only one small difference. Again, we need to provide name of the OpenSSL engine using the -E command line option.

dnssec-signzone -E pkcs11 -S -o example.net example.net

and the output should like the usual thing:

Fetching example.net/RSASHA256/31729 (KSK) from key repository.
Fetching example.net/RSASHA256/42231 (ZSK) from key repository.
Verifying the zone using the following algorithms: RSASHA256.
Zone fully signed:
Algorithm: RSASHA256: KSKs: 1 active, 0 stand-by, 0 revoked
                      ZSKs: 1 active, 0 stand-by, 0 revoked
example.db.signed