--- title: "PKCS#11 in BIND 9" slug: "bind-9-pkcs11" description: "The PKCS#11 support in BIND 9 comes in two flavors: native and OpenSSL-based. This page describes the OpenSSL-based method." tags: ["dnssec", "pkcs11"] updated: 2023-12-04T13:58:26Z published: 2023-12-04T13:58:26Z canonical: "kb.isc.org/bind-9-pkcs11" --- > ## Documentation Index > Fetch the complete documentation index at: https://kb.isc.org/llms.txt > Use this file to discover all available pages before exploring further. # PKCS#11 in BIND 9 ## 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](https://github.com/latchset/pkcs11-provider/), but it doesn't work with SoftHSM 2 because of a [bug(s)](https://github.com/opendnssec/SoftHSMv2/issues) 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](https://www.softhsm.org) 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](https://github.com/OpenSC/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](https://github.com/OpenSC/libp11/blob/master/README.md#pkcs-11-module-configuration), 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](https://github.com/OpenSC/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 ```