1.. Copyright (C) Internet Systems Consortium, Inc. ("ISC") 2.. 3.. SPDX-License-Identifier: MPL-2.0 4.. 5.. This Source Code Form is subject to the terms of the Mozilla Public 6.. License, v. 2.0. If a copy of the MPL was not distributed with this 7.. file, you can obtain one at https://mozilla.org/MPL/2.0/. 8.. 9.. See the COPYRIGHT file distributed with this work for additional 10.. information regarding copyright ownership. 11 12.. _pkcs11: 13 14PKCS#11 (Cryptoki) Support 15~~~~~~~~~~~~~~~~~~~~~~~~~~ 16 17Public Key Cryptography Standard #11 (PKCS#11) defines a 18platform-independent API for the control of hardware security modules 19(HSMs) and other cryptographic support devices. 20 21PKCS#11 uses a "provider library": a dynamically loadable 22library which provides a low-level PKCS#11 interface to drive the HSM 23hardware. The PKCS#11 provider library comes from the HSM vendor, and it 24is specific to the HSM to be controlled. 25 26BIND 9 uses engine_pkcs11 for PKCS#11. engine_pkcs11 is an OpenSSL 27engine which is part of the `OpenSC`_ project. The engine is dynamically 28loaded into OpenSSL and the HSM is operated indirectly; any 29cryptographic operations not supported by the HSM can be carried out by 30OpenSSL instead. 31 32.. _OpenSC: https://github.com/OpenSC/libp11 33 34Prerequisites 35^^^^^^^^^^^^^ 36 37See the documentation provided by the HSM vendor for information about 38installing, initializing, testing, and troubleshooting the HSM. 39 40Building SoftHSMv2 41^^^^^^^^^^^^^^^^^^ 42 43SoftHSMv2, the latest development version of SoftHSM, is available from 44https://github.com/opendnssec/SoftHSMv2. It is a software library 45developed by the OpenDNSSEC project (https://www.opendnssec.org) which 46provides a PKCS#11 interface to a virtual HSM, implemented in the form 47of an SQLite3 database on the local filesystem. It provides less security 48than a true HSM, but it allows users to experiment with native PKCS#11 49when an HSM is not available. SoftHSMv2 can be configured to use either 50OpenSSL or the Botan library to perform cryptographic functions, but 51when using it for native PKCS#11 in BIND, OpenSSL is required. 52 53By default, the SoftHSMv2 configuration file is ``prefix/etc/softhsm2.conf`` 54(where ``prefix`` is configured at compile time). This location can be 55overridden by the SOFTHSM2_CONF environment variable. The SoftHSMv2 56cryptographic store must be installed and initialized before using it 57with BIND. 58 59:: 60 61 $ cd SoftHSMv2 62 $ configure --with-crypto-backend=openssl --prefix=/opt/pkcs11/usr 63 $ make 64 $ make install 65 $ /opt/pkcs11/usr/bin/softhsm-util --init-token 0 --slot 0 --label softhsmv2 66 67OpenSSL-based PKCS#11 68^^^^^^^^^^^^^^^^^^^^^ 69 70OpenSSL-based PKCS#11 uses engine_pkcs11 OpenSSL engine from libp11 project. 71 72engine_pkcs11 tries to fit the PKCS#11 API within the engine API of OpenSSL. 73That is, it provides a gateway between PKCS#11 modules and the OpenSSL engine 74API. One has to register the engine with OpenSSL and one has to provide the 75path to the PKCS#11 module which should be gatewayed to. This can be done by 76editing the OpenSSL configuration file, by engine specific controls, or by using 77the p11-kit proxy module. 78 79It is recommended, that libp11 >= 0.4.12 is used. 80 81For more detailed howto including the examples, we recommend reading: 82 83https://gitlab.isc.org/isc-projects/bind9/-/wikis/BIND-9-PKCS11 84 85Using the HSM 86^^^^^^^^^^^^^ 87 88The canonical documentation for configuring engine_pkcs11 is in the 89`libp11/README.md`_, but here's copy of working configuration for 90your convenience: 91 92.. _`libp11/README.md`: https://github.com/OpenSC/libp11/blob/master/README.md#pkcs-11-module-configuration 93 94We are going to use our own custom copy of OpenSSL configuration, again it's 95driven by an environment variable, this time called OPENSSL_CONF. We are 96going to copy the global OpenSSL configuration (often found in 97``etc/ssl/openssl.conf``) and customize it to use engines_pkcs11. 98 99:: 100 101 cp /etc/ssl/openssl.cnf /opt/bind9/etc/openssl.cnf 102 103and export the environment variable: 104 105:: 106 107 export OPENSSL_CONF=/opt/bind9/etc/openssl.cnf 108 109Now add following line at the top of file, before any sections (in square 110brackets) are defined: 111 112:: 113 114 openssl_conf = openssl_init 115 116And make sure there are no other 'openssl_conf = ...' lines in the file. 117 118Add following lines at the bottom of the file: 119 120:: 121 122 [openssl_init] 123 engines=engine_section 124 125 [engine_section] 126 pkcs11 = pkcs11_section 127 128 [pkcs11_section] 129 engine_id = pkcs11 130 dynamic_path = <PATHTO>/pkcs11.so 131 MODULE_PATH = <FULL_PATH_TO_HSM_MODULE> 132 init = 0 133 134Key Generation 135^^^^^^^^^^^^^^ 136 137HSM keys can now be created and used. We are going to assume that you already 138have a BIND 9 installed, either from a package, or from the sources, and the 139tools are readily available in the ``$PATH``. 140 141For generating the keys, we are going to use ``pkcs11-tool`` available from the 142OpenSC suite. On both DEB-based and RPM-based distributions, the package is 143called opensc. 144 145We need to generate at least two RSA keys: 146 147:: 148 149 pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type rsa:2048 --label example.net-ksk --pin <PIN> 150 pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type rsa:2048 --label example.net-zsk --pin <PIN> 151 152Remember that each key should have unique label and we are going to use that 153label to reference the private key. 154 155Convert the RSA keys stored in the HSM into a format that BIND 9 understands. 156The :iscman:`dnssec-keyfromlabel` tool from BIND 9 can link the raw keys stored in the 157HSM with the ``K<zone>+<alg>+<id>`` files. You'll need to provide the OpenSSL 158engine name (``pkcs11``), the algorithm (``RSASHA256``) and the PKCS#11 label 159that specify the token (we asume that it has been initialized as bind9), the 160name of the PKCS#11 object (called label when generating the keys using 161``pkcs11-tool``) and the HSM PIN. 162 163Convert the KSK: 164 165:: 166 167 dnssec-keyfromlabel -E pkcs11 -a RSASHA256 -l "token=bind9;object=example.net-ksk;pin-value=0000" -f KSK example.net 168 169and ZSK: 170 171:: 172 173 dnssec-keyfromlabel -E pkcs11 -a RSASHA256 -l "token=bind9;object=example.net-zsk;pin-value=0000" example.net 174 175NOTE: you can use PIN stored on disk, by specifying ``pin-source=<path_to>/<file>``, f.e.: 176 177:: 178 179 (umask 0700 && echo -n 0000 > /opt/bind9/etc/pin.txt) 180 181and then use in the label specification: 182 183:: 184 185 pin-source=/opt/bind9/etc/pin.txt 186 187Confirm that you have one KSK and one ZSK present in the current directory: 188 189:: 190 191 ls -l K* 192 193The output should look like this (the second number will be different): 194 195:: 196 197 Kexample.net.+008+31729.key 198 Kexample.net.+008+31729.private 199 Kexample.net.+008+42231.key 200 Kexample.net.+008+42231.private 201 202A note on generating ECDSA keys: there is a bug in libp11 when looking up a key, 203that function compares keys only on their ID, not the label. So when looking up 204a key it returns the first key, rather than the matching key. The workaround for 205this is when creating ECDSA keys, you should specify a unique ID: 206 207:: 208 209 ksk=$(echo "example.net-ksk" | openssl sha1 -r | awk '{print $1}') 210 zsk=$(echo "example.net-zsk" | openssl sha1 -r | awk '{print $1}') 211 pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type EC:prime256v1 --id $ksk --label example.net-ksk --pin <PIN> 212 pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type EC:prime256v1 --id $zsk --label example.net-zsk --pin <PIN> 213 214 215Specifying the Engine on the Command Line 216^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 217 218When using OpenSSL-based PKCS#11, the "engine" to be used by OpenSSL can be 219specified in :iscman:`named` and all of the BIND ``dnssec-*`` tools by using the ``-E 220<engine>`` command line option. Specifying the engine is generally not necessary 221unless a different OpenSSL engine is used. 222 223The zone signing commences as usual, with only one small difference. We need to 224provide the name of the OpenSSL engine using the -E command line option. 225 226:: 227 228 dnssec-signzone -E pkcs11 -S -o example.net example.net 229 230Running :iscman:`named` With Automatic Zone Re-signing 231^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 232 233The zone can also be signed automatically by named. Again, we need to provide 234the name of the OpenSSL engine using the :option:`-E <named -E>` command line option. 235 236:: 237 238 named -E pkcs11 -c named.conf 239 240and the logs should have lines like: 241 242:: 243 244 Fetching example.net/RSASHA256/31729 (KSK) from key repository. 245 DNSKEY example.net/RSASHA256/31729 (KSK) is now published 246 DNSKEY example.net/RSA256SHA256/31729 (KSK) is now active 247 Fetching example.net/RSASHA256/42231 (ZSK) from key repository. 248 DNSKEY example.net/RSASHA256/42231 (ZSK) is now published 249 DNSKEY example.net/RSA256SHA256/42231 (ZSK) is now active 250 251For :iscman:`named` to dynamically re-sign zones using HSM keys, 252and/or to sign new records inserted via nsupdate, :iscman:`named` must 253have access to the HSM PIN. In OpenSSL-based PKCS#11, this is 254accomplished by placing the PIN into the ``openssl.cnf`` file (in the above 255examples, ``/opt/pkcs11/usr/ssl/openssl.cnf``). 256 257The location of the openssl.cnf file can be overridden by setting the 258``OPENSSL_CONF`` environment variable before running :iscman:`named`. 259 260Here is a sample ``openssl.cnf``: 261 262:: 263 264 openssl_conf = openssl_def 265 [ openssl_def ] 266 engines = engine_section 267 [ engine_section ] 268 pkcs11 = pkcs11_section 269 [ pkcs11_section ] 270 PIN = <PLACE PIN HERE> 271 272This also allows the ``dnssec-\*`` tools to access the HSM without PIN 273entry. (The ``pkcs11-\*`` tools access the HSM directly, not via OpenSSL, so 274a PIN is still required to use them.) 275