BIND9 has native pkcs11 support which is usually available in separate packages. But that does not work for smartcard. Your HSM would need to support every crypto function. We want to use OpenSSL engine to do everything except the few things that the smartcard holds secret inside (signing things with a key that can't come out). So don't bother with the bind pkcs11 packages.
This took too long to figure out because of a bug in libp11. I guess other software doesn't check whether the key has the private flag set. I would keep getting something like:
dnssec-signzone: fatal: cannot sign zone with non-private dnskey Kexample.test.+005+38895
This needs libp11 >= 0.4.11 as noted here: https://gitlab.isc.org/isc-projects/bind9/-/wikis/BIND-9-PKCS11
Incorporating that change is what gave me the problems I think. Here are some options once you have a pkcs11.so from new libp11. Somewhat in increasing betterness..
Overwrite the system one. This probably won't survive if your distro patches something else in the file. I also don't like overwriting package controlled files. But Debian 10 has it in /usr/lib/x86_64-linux-gnu/engines-1.1 and CentOS 7 has it in /usr/lib64/engines-1.1 if you'd like to try that.
Just call the engine something else and put it in the engine dir. That requires editing PKCS11_ENGINE_ID in libp11/src/eng_front.c before you compile. Here I just add the short commit ID to the end. You should use vi and an easier name.
mute@local:~/dns/libp11$ version=$(git log --pretty=format:'%h' -n 1); printf %s\\n "/define PKCS11_ENGINE_ID/s/pkcs11/pkcs11-$version" w q | ed -s src/eng_front.c #define PKCS11_ENGINE_ID "pkcs11-4084f83" ... make and sudo ... root@local:/usr/lib/x86_64-linux-gnu/engines-1.1# cp /home/mute/dns/libp11/src/.libs/pkcs11.so pkcs11-4084f83.so root@local:/usr/lib/x86_64-linux-gnu/engines-1.1# openssl engine pkcs11-4084f83 -c (pkcs11-4084f83) pkcs11 engine [RSA, rsaEncryption, id-ecPublicKey]
Edit system openssl.cnf to redefine the pkcs11 engine. Probably a great solution... Details in libp11 README: https://github.com/OpenSC/libp11/blob/master/README.md
Copy the system openssl.cnf to somewhere else and export OPENSSL_CONF to point to it. Very minimal one just for dnssec-signzone:
openssl_conf = bind_conf [bind_conf] engines = engine_sect [engine_sect] pkcs11 = pkcs11_sect [pkcs11_sect] dynamic_path = /home/mute/dns/libp11/src/.libs/pkcs11.so MODULE_PATH = /usr/lib/x86_64-linux-gnu/p11-kit-proxy.so init = 0
export OPENSSL_ENGINES=/home/mute/dns/libp11/src/.libs and put your newer library there. This is what I'm going with.
No matter what, you will still need the openssl.conf entry with a MODULE_PATH if you don't configure libp11 with ./configure --with-pkcs11-module=p11-kit-proxy
Now that that is fixed .. The overall method to store KSK offline, and ZSK in file on system is as so:
Find your YubiKey token ID. You may see it twice if you have loaded their driver. Using the entire string is not necessary. You can get away with "pkcs11:token=ksk" (using opensc driver) or "pkcs11:token=YubiKey%20PIV%20%237792984" if you have loaded libykcs11.so. "ksk" is just the CN of my first cert so your token may be different.
mute@local:~$ p11tool --list-token-urls pkcs11:model=p11-kit-trust;manufacturer=PKCS%2311%20Kit;serial=1;token=System%20Trust pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=dc6e8bb5b47e7aa8;token=ksk pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=7792984;token=YubiKey%20PIV%20%237792984
Find the key you wish to use. I used the PIV AUTH (9a, id=%01) in opensc driver, but CARD AUTH (9e, id=%04) seems to work as well if you've loaded ykcs11. You will want to pass the --login parameter when asking about privkeys otherwise you won't get good results. For dnssec-signzone it MUST have the CKA_PRIVATE flag.
mute@local:~$ p11tool --list-privkeys "pkcs11:token=ksk" Object 0: URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=dc6e8bb5b47e7aa8;token=ksk;id=%04;object=CARD%20AUTH%20key;type=private Token 'ksk' with URL 'pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=dc6e8bb5b47e7aa8;token=ksk' requires user PIN Enter PIN: Type: Private key (RSA-2048) Label: CARD AUTH key Flags: CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; ID: 04 mute@local:~$ p11tool --list-privkeys "pkcs11:token=ksk" --login Token 'ksk' with URL 'pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=dc6e8bb5b47e7aa8;token=ksk' requires user PIN Enter PIN: Object 0: URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=dc6e8bb5b47e7aa8;token=ksk;id=%01;object=PIV%20AUTH%20key;type=private Type: Private key (RSA-2048) Label: PIV AUTH key Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; ID: 01 Object 1: URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=dc6e8bb5b47e7aa8;token=ksk;id=%04;object=CARD%20AUTH%20key;type=private Type: Private key (RSA-2048) Label: CARD AUTH key Flags: CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; ID: 04 mute@local:~/dns$ p11tool --list-privkeys "pkcs11:token=YubiKey%20PIV%20%237792984" No matching objects found mute@local:~/dns$ p11tool --list-privkeys "pkcs11:token=YubiKey%20PIV%20%237792984" --login Token 'YubiKey PIV #7792984' with URL 'pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=7792984;token=YubiKey%20PIV%20%237792984' requires user PIN Enter PIN: Object 0: URL: pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=7792984;token=YubiKey%20PIV%20%237792984;id=%01;object=Private%20key%20for%20PIV%20Authentication;type=private Type: Private key (RSA-2048) Label: Private key for PIV Authentication Flags: CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; ID: 01 Object 1: URL: pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=7792984;token=YubiKey%20PIV%20%237792984;id=%04;object=Private%20key%20for%20Card%20Authentication;type=private Type: Private key (RSA-2048) Label: Private key for Card Authentication Flags: CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; ID: 04 Object 2: URL: pkcs11:model=YubiKey%20YK4;manufacturer=Yubico%20%28www.yubico.com%29;serial=7792984;token=YubiKey%20PIV%20%237792984;id=%19;object=Private%20key%20for%20PIV%20Attestation;type=private Type: Private key (RSA-2048) Label: Private key for PIV Attestation Flags: CKA_PRIVATE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; ID: 19
Create the KSK key from the label, generate ZSK to file, and sign the zone. I am not going to show both URL anymore, just the built-in opensc one (it's shorter, and built-in, and works).
mute@local:~/dns$ dnssec-keyfromlabel -E pkcs11-4084f83 -a rsasha256 -l 'pkcs11:token=ksk;id=%01' -f KSK example.org Enter PKCS#11 token PIN for ksk: Kexample.org.+008+65005 mute@local:~/dns$ dnssec-keygen -E pkcs11-4084f83 -a rsasha256 -b 1024 example.org Generating key pair....+++++ .....+++++ Enter PKCS#11 token PIN for ksk: Kexample.org.+008+10734 mute@local:~/dns$ OPENSSL_CONF=openssl.conf dnssec-signzone -E pkcs11-4084f83 -S example.org Enter PKCS#11 token PIN for ksk: Fetching ZSK 10734/RSASHA256 from key repository. Fetching KSK 65005/RSASHA256 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.org.signed
And that's it. Really just the 2 issues that made this so hard was (1) making sure fixed pkcs11 engine was loaded and (2) making sure I logged in to find private keys. Two days wasted!
Comments