-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Plain dm-crypt unlocking via PKCS#11 with systemd-cryptsetup fails with an encrypted keyfile #38291
Description
systemd version the issue has been seen with
257.7
Used distribution
Gentoo
Linux kernel version used
6.12.21-gentoo
CPU architectures issue was seen on
x86_64
Component
systemd-cryptsetup
Expected behaviour you didn't see
Expected successful "unlocking" via PKCS#11 of a plain dm-crypt device when the passphrase is read from an encrypted key file. This seems like it should be a supported use case in that it fits with the 1st mechanism listed in the description section of the systemd-cryptsetup man page, albeit specifically for plain mode.
The following entry in /etc/crypttab was used:
enc0 /tmp/<encrypted-volume> /tmp/<encrypted-keyfile> noauto,nofail,plain,
cipher=aes-xts-plain64,hash=sha512,size=512,
token-timeout=5,pkcs11-uri=<private-key-uri>
/tmp/<encrypted-volume> is an encrypted file with a valid filesystem in it, set up in advance using cryptsetup in plain mode with a the base64 encoding of "foobar" as the passphrase.
/tmp/<encrypted-keyfile> contains the cipher-text of "foobar", encrypted by openssl-rsautl using a 4096-bit RSA public key generated on an OpenPGP card.
<private-key-uri> references the corresponding private key on the security token, adapted from the URI reported by pkcs11-tool --list-objects.
Unexpected behaviour you saw
The corresponding (generated) systemd-cryptsetup unit fails to start. The logs indicate it wasn't able to decrypt the key file:
Jul 16 11:35:11 <hostname> systemd[1]: Starting Cryptography Setup for enc0...
Jul 16 11:35:11 <hostname> systemd-cryptsetup[3001801]: Set cipher aes, mode xts-plain64, key size 512 bits for device
/tmp/<encrypted-volume>.
Jul 16 11:35:14 <hostname> systemd-cryptsetup[3001801]: Successfully logged into security token 'OpenPGP card (User PIN)'.
Jul 16 11:35:14 <hostname> systemd-cryptsetup[3001801]: Failed to decrypt key on security token: The operation failed
Jul 16 11:35:14 <hostname> systemd[1]: systemd-cryptsetup@enc0.service: Main process exited, code=exited, status=1/FAILURE
Jul 16 11:35:14 <hostname> systemd[1]: systemd-cryptsetup@enc0.service: Failed with result 'exit-code'.
Jul 16 11:35:14 <hostname> systemd[1]: Failed to start Cryptography Setup for enc0
Turning on debug=3 in /etc/opensc.conf and comparing the resulting OpenSC log output from both systemd-cryptsetup and pkcs11-tool (both are using opensc-pkcs11.so) reveals what seems to be the problem:
<much redacted noise>
...
[opensc-pkcs11] reader-pcsc.c:328:pcsc_transmit:
Outgoing APDU (74 bytes):
00 2A 80 86 00 00 41 00 74 C4 59 F9 E3 21 49 05 .*....A.t.Y..!I.
95 EB 18 1F 71 86 AD 89 3F DE D8 A8 58 FF 8C D7 ....q...?...X...
42 2D C3 08 E7 B7 60 38 97 DB 96 83 42 62 89 60 B-....`8....Bb.`
94 6C D9 B3 33 A3 B4 BD 98 3C BA C7 00 F0 57 5E .l..3....<....W^
A8 3D 90 70 E0 11 ED FC 02 00 .=.p......
[opensc-pkcs11] reader-pcsc.c:245:pcsc_internal_transmit: called
[opensc-pkcs11] reader-pcsc.c:337:pcsc_transmit:
Incoming APDU (2 bytes):
69 85 i.
[opensc-pkcs11] apdu.c:382:sc_single_transmit: returning with: 0 (Success)
[opensc-pkcs11] apdu.c:539:sc_transmit: returning with: 0 (Success)
[opensc-pkcs11] card.c:523:sc_unlock: called
[opensc-pkcs11] iso7816.c:128:iso7816_check_sw: Conditions of use not satisfied
[opensc-pkcs11] card-openpgp.c:2486:pgp_decipher: Card returned error: -1209 (Not allowed)
[opensc-pkcs11] sec.c:50:sc_decipher: returning with: -1209 (Not allowed)
[opensc-pkcs11] card.c:523:sc_unlock: called
[opensc-pkcs11] pkcs15-sec.c:169:use_key: returning with: -1209 (Not allowed)
[opensc-pkcs11] pkcs15-sec.c:313:sc_pkcs15_decipher: use_key() failed: -1209 (Not allowed)
[opensc-pkcs11] card.c:523:sc_unlock: called
[opensc-pkcs11] reader-pcsc.c:734:pcsc_unlock: called
[opensc-pkcs11] framework-pkcs15.c:4626:pkcs15_prkey_decrypt: Decryption complete.
The above outgoing APDU seen in the systemd-cryptsetup case is much shorter than that sent by pkcs11-tool. It appears that systemd-cryptsetup has passed only the first 64-bytes of the encrypted key file the OpenSC library. The security token has then returned the status bytes 0x69 0x85, which in the OpenPGP card specification does indeed mean "Condition of use not satisfied" (as logged). That's a pretty unhelpful message, but I'd hazard a guess that the token wants 512-bytes for a 4096-bit RSA key.
Best I can tell, this is actually documented behaviour, as per the explanation of keyfile-size= in the crypttab man page, which says "this option is ignored in plain mode" and the block cipher key size is used instead. That would seem to make sense when the key is directly stored in the key file, but seems incompatible with security tokens using cryptosystems with expanded ciphertexts.
For what it's worth, things work fine in LUKS mode with systemd-cryptenroll and the exact same key files and PKCS#11 URI.
Steps to reproduce the problem
Approximate steps to reproduce:
- Choose a test passphrase
- Base64 encrypt the passphrase into a plaintext key file
- Create a plain dm-crypt mapping using /etc/crypttab and the above plaintext key file (no security token)
- Start systemd-cryptsetup and create some valid data in the resulting device, then stop systemd-cryptsetup
- Encrypt the test passphrase using RSA, or some other cryptosystem supported by the token
- Modify the crypttab entry from step 3 to point to the encrypted keyfile and add the token URI
- Do the daemon-reload dance to reload crypttab
- Start systemd-cryptsetup, authenticate with the token when prompted.
If the ciphertext in the encrypted keyfile is longer than the dm-crypt block cipher then unlocking the plain dm-crypt volume fails.