xref: /netbsd-src/external/mpl/bind/dist/doc/arm/pkcs11.inc.rst (revision 9689912e6b171cbda866ec33f15ae94a04e2c02d)
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 accesses PKCS#11 libraries via OpenSSL extensions. The extension for
27OpenSSL 3 and newer is `pkcs11-provider`_; for older OpenSSL versions,
28engine_pkcs11 from the `OpenSC`_ project can be used.
29
30.. _`pkcs11-provider`: https://github.com/latchset/pkcs11-provider
31.. _OpenSC: https://github.com/OpenSC/libp11
32
33In both cases the extension is dynamically loaded into OpenSSL and the HSM is
34operated indirectly; any cryptographic operations not supported by the HSM can
35be carried out by OpenSSL instead.
36
37Prerequisites
38^^^^^^^^^^^^^
39
40See the documentation provided by the HSM vendor for information about
41installing, initializing, testing, and troubleshooting the HSM.
42
43Building SoftHSMv2
44^^^^^^^^^^^^^^^^^^
45
46SoftHSMv2, the latest development version of SoftHSM, is available from
47https://github.com/opendnssec/SoftHSMv2. It is a software library
48developed by the OpenDNSSEC project (https://www.opendnssec.org) which
49provides a PKCS#11 interface to a virtual HSM, implemented in the form
50of an SQLite3 database on the local filesystem. It provides less security
51than a true HSM, but it allows users to experiment with native PKCS#11
52when an HSM is not available. SoftHSMv2 can be configured to use either
53OpenSSL or the Botan library to perform cryptographic functions, but
54when using it for native PKCS#11 in BIND, OpenSSL is required.
55
56By default, the SoftHSMv2 configuration file is ``prefix/etc/softhsm2.conf``
57(where ``prefix`` is configured at compile time). This location can be
58overridden by the SOFTHSM2_CONF environment variable. The SoftHSMv2
59cryptographic store must be installed and initialized before using it
60with BIND.
61
62::
63
64   $  cd SoftHSMv2
65   $  configure --with-crypto-backend=openssl --prefix=/opt/pkcs11/usr
66   $  make
67   $  make install
68   $  /opt/pkcs11/usr/bin/softhsm-util --init-token 0 --slot 0 --label softhsmv2
69
70OpenSSL 1.x.x With engine_pkcs11
71^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
72
73OpenSSL engine-based PKCS#11 uses the engine_pkcs11 OpenSSL engine from the libp11 project.
74
75engine_pkcs11 tries to fit the PKCS#11 API within the engine API of OpenSSL.
76That is, it provides a gateway between PKCS#11 modules and the OpenSSL engine
77API.  One has to register the engine with OpenSSL and one has to provide the
78path to the PKCS#11 module which should be gatewayed to. This can be done by
79editing the OpenSSL configuration file, by engine specific controls, or by using
80the p11-kit proxy module.
81
82It is recommended, that libp11 >= 0.4.12 is used.
83
84For more detailed instructions, including examples, we recommend reading:
85
86https://gitlab.isc.org/isc-projects/bind9/-/wikis/BIND-9-PKCS11
87
88When using engine_pkcs11, be sure to pass the `-E pkcs11` argument to all BIND
89binaries that potentially use the keys, to activate the engine support.
90
91Even though OpenSSL 3 has compatibility support for Engine API, its use is not
92recommended due to bugs in OpenSSL and libp11.
93
94It is not possible to generate new keys via engine_pkcs11, so its use
95is not recommended in a ``dnssec-policy`` setup. However, it is
96possible to put previously generated keys in the ``key-directory`` and let the
97key manager select those keys when a key rollover is started.
98
99Configuring engine_pkcs11
100^^^^^^^^^^^^^^^^^^^^^^^^^
101
102The canonical documentation for configuring engine_pkcs11 is in the
103`libp11/README.md`_ file, but a sample working configuration is included
104here for the user's convenience:
105
106.. _`libp11/README.md`: https://github.com/OpenSC/libp11/blob/master/README.md#pkcs-11-module-configuration
107
108In our example, we use a custom copy of OpenSSL configuration,
109driven by an environment variable called OPENSSL_CONF.
110First, copy the global OpenSSL configuration (often found in
111``etc/ssl/openssl.conf``) and customize it to use engine_pkcs11.
112
113::
114
115   cp /etc/ssl/openssl.cnf /opt/bind9/etc/openssl.cnf
116
117Then, export the environment variable:
118
119::
120
121   export OPENSSL_CONF=/opt/bind9/etc/openssl.cnf
122
123Then add the following line at the top of the file, before any sections (in square
124brackets) are defined:
125
126::
127
128   openssl_conf = openssl_init
129
130Make sure there are no other 'openssl_conf = ...' lines in the file.
131
132Add the following lines at the bottom of the file:
133
134::
135
136   [openssl_init]
137   engines=engine_section
138
139   [engine_section]
140   pkcs11 = pkcs11_section
141
142   [pkcs11_section]
143   engine_id = pkcs11
144   dynamic_path = <PATHTO>/pkcs11.so
145   MODULE_PATH = <FULL_PATH_TO_HSM_MODULE>
146   # if automatic logging to the token is needed, PIN can be specified as below
147   #PIN = 1234
148   init = 0
149
150Enabling the OpenSSL Engine in BIND Commands
151^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
152
153When using OpenSSL Engine-based PKCS#11, the "engine" to be used by OpenSSL can be
154specified in :iscman:`named` and in all of the BIND ``dnssec-*`` tools by using the ``-E
155<engine>`` command-line option. This engine name matches the ``engine_id`` in the
156``openssl.cnf`` created in previous section.
157
158The zone signing commences as usual, with only one small difference: we need to
159provide the name of the OpenSSL engine using the -E command-line option.
160
161::
162
163   dnssec-signzone -E pkcs11 -S -o example.net example.net
164
165
166OpenSSL 3 With pkcs11-provider
167^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
168
169OpenSSL provider-based PKCS#11 uses the pkcs11-provider project.
170
171pkcs11-provider tries to fit the PKCS#11 API within the Provider API of OpenSSL;
172that is, it provides a gateway between PKCS#11 modules and the OpenSSL Provider
173API. The engine must be registered with OpenSSL and the
174path to the PKCS#11 module gateway must be provided. This can be done by
175editing the OpenSSL configuration file, by engine-specific controls, or by using
176the p11-kit proxy module.
177
178The pkcs11-provider git commit
1792e8c26b4157fd21422c66f0b4d7b26cf8c320570 from October 2, 2023 or later must be used.
180
181BIND support for pkcs11-provider is built in; with pcks11-provider, the -E command-line option
182explained above should not be used.
183
184Configuring pkcs11-provider
185^^^^^^^^^^^^^^^^^^^^^^^^^^^
186
187The canonical documentation for configuring pkcs11-provider is in the
188`provider-pkcs11.7`_ manual page, but a copy of a working configuration is
189provided here for convenience:
190
191.. _`provider-pkcs11.7`: https://github.com/latchset/pkcs11-provider/blob/main/docs/provider-pkcs11.7.md
192
193In this example, we use a custom copy of OpenSSL configuration,
194driven by an environment variable called OPENSSL_CONF. First, copy the
195global OpenSSL configuration (often found in
196``etc/ssl/openssl.conf``) and customize it to use pkcs11-provider.
197
198::
199
200   cp /etc/ssl/openssl.cnf /opt/bind9/etc/openssl.cnf
201
202Next, export the environment variable:
203
204::
205
206   export OPENSSL_CONF=/opt/bind9/etc/openssl.cnf
207
208Then add the following line at the top of the file, before any sections (in square
209brackets) are defined:
210
211::
212
213   openssl_conf = openssl_init
214
215Make sure there are no other 'openssl_conf = ...' lines in the file.
216
217Add the following lines at the bottom of the file:
218
219::
220
221   [openssl_init]
222   providers = provider_init
223
224   [provider_init]
225   default = default_init
226   pkcs11 = pkcs11_init
227
228   [default_init]
229   activate = 1
230
231   [pkcs11_init]
232   module = <PATHTO>/pkcs11.so
233   pkcs11-module-path = <FULL_PATH_TO_HSM_MODULE>
234   # bind uses the digest+sign api. this is broken with the default load behaviour,
235   # but works with early load. see: https://github.com/latchset/pkcs11-provider/issues/266
236   pkcs11-module-load-behavior = early
237   # no-deinit quirk is needed if you use softhsm2
238   #pkcs11-module-quirks = no-deinit
239   # if automatic logging to the token is needed, PIN can be specified as below
240   # the file referenced should contain just the PIN
241   #pkcs11-module-token-pin = file:/etc/pki/pin.txt
242   activate = 1
243
244Key Generation
245^^^^^^^^^^^^^^
246
247HSM keys can now be created and used.  We are assuming that
248BIND 9 is already installed, either from a package or from the sources, and the
249tools are readily available in the ``$PATH``.
250
251For generating the keys, we are going to use ``pkcs11-tool`` available from the
252OpenSC suite.  On both DEB-based and RPM-based distributions, the package is
253called opensc.
254
255We need to generate at least two RSA keys:
256
257::
258
259   pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type rsa:2048 --label example.net-ksk --pin <PIN>
260   pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type rsa:2048 --label example.net-zsk --pin <PIN>
261
262Remember that each key should have unique label and we are going to use that
263label to reference the private key.
264
265Convert the RSA keys stored in the HSM into a format that BIND 9 understands.
266The :iscman:`dnssec-keyfromlabel` tool from BIND 9 can link the raw keys stored in the
267HSM with the ``K<zone>+<alg>+<id>`` files.
268
269The OpenSSL engine name (``pkcs11``) must be provided if using the engine and
270the algorithm (``RSASHA256``). The key is referenced with the PKCS#11 URI scheme; it
271can contain the PKCS#11 token label (we assume that it has been initialized as bind9),
272the PKCS#11 object label (called "label" when generating the keys using ``pkcs11-tool``),
273and the HSM PIN. Refer to :rfc:`7512` for the full PKCS#11 URI specification.
274
275Convert the KSK:
276
277::
278
279   dnssec-keyfromlabel -E pkcs11 -a RSASHA256 -l "pkcs11:token=bind9;object=example.net-ksk;pin-value=0000" -f KSK example.net
280
281and ZSK:
282
283::
284
285   dnssec-keyfromlabel -E pkcs11 -a RSASHA256 -l "pkcs11:token=bind9;object=example.net-zsk;pin-value=0000" example.net
286
287NOTE: a PIN stored on disk can be used by specifying ``pin-source=<path_to>/<file>``, e.g:
288
289::
290
291   (umask 0700 && echo -n 0000 > /opt/bind9/etc/pin.txt)
292
293and then use in the label specification:
294
295::
296
297   pin-source=/opt/bind9/etc/pin.txt
298
299Confirm that there is one KSK and one ZSK present in the current directory:
300
301::
302
303   ls -l K*
304
305The output should look like this (the second number will be different):
306
307::
308
309   Kexample.net.+008+31729.key
310   Kexample.net.+008+31729.private
311   Kexample.net.+008+42231.key
312   Kexample.net.+008+42231.private
313
314A note on generating ECDSA keys: there is a bug in libp11 when looking up a key.
315That function compares keys only on their ID, not the label, so when looking up
316a key it returns the first key, rather than the matching key. To work around
317this when creating ECDSA keys, specify a unique ID:
318
319::
320
321   ksk=$(echo "example.net-ksk" | openssl sha1 -r | awk '{print $1}')
322   zsk=$(echo "example.net-zsk" | openssl sha1 -r | awk '{print $1}')
323   pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type EC:prime256v1 --id $ksk --label example.net-ksk --pin <PIN>
324   pkcs11-tool --module <FULL_PATH_TO_HSM_MODULE> -l -k --key-type EC:prime256v1 --id $zsk --label example.net-zsk --pin <PIN>
325
326
327Running :iscman:`named` With Automatic Zone Re-signing
328^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
329
330The zone can also be signed automatically by :iscman:`named`. Again, we need to provide
331the name of the OpenSSL engine using the :option:`-E <named -E>` command-line option,
332if using OpenSSL 1.x.x with engine_pkcs11; this is not needed when using OpenSSL 3.x.x providers.
333
334::
335
336   named -E pkcs11 -c named.conf
337
338The logs should have lines like:
339
340::
341
342   Fetching example.net/RSASHA256/31729 (KSK) from key repository.
343   DNSKEY example.net/RSASHA256/31729 (KSK) is now published
344   DNSKEY example.net/RSA256SHA256/31729 (KSK) is now active
345   Fetching example.net/RSASHA256/42231 (ZSK) from key repository.
346   DNSKEY example.net/RSASHA256/42231 (ZSK) is now published
347   DNSKEY example.net/RSA256SHA256/42231 (ZSK) is now active
348
349For :iscman:`named` to dynamically re-sign zones using HSM keys,
350and/or to sign new records inserted via nsupdate, :iscman:`named` must
351have access to the HSM PIN. In OpenSSL-based PKCS#11, this is
352accomplished by placing the PIN into the ``openssl.cnf`` file (in the above
353examples, ``/opt/pkcs11/usr/ssl/openssl.cnf``).
354
355See OpenSSL extension-specific documentation for instructions on configuring the PIN on
356the global level; doing so allows the ``dnssec-\*`` tools to access the HSM without
357PIN entry. (The ``pkcs11-\*`` tools access the HSM directly, not via OpenSSL,
358so a PIN is still required to use them.)
359