summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2024-01-05 12:14:26 +0100
committerGitHub <noreply@github.com>2024-01-05 12:14:26 +0100
commit8ef31e1f13e29a4ee5a052cd8770120e3b16301c (patch)
tree3d314d0ec8903469e91e694f3737e64985ce8004
parentupdate TODO (diff)
parentcryptenroll: change class in provided PKCS#11 URI if necessary (diff)
downloadsystemd-8ef31e1f13e29a4ee5a052cd8770120e3b16301c.tar.xz
systemd-8ef31e1f13e29a4ee5a052cd8770120e3b16301c.zip
Merge pull request #29692 from H5117/fix_pkcs11_uri
cryptenroll: change class in provided PKCS#11 URI if necessary
-rw-r--r--man/systemd-cryptenroll.xml12
-rw-r--r--src/cryptenroll/cryptenroll-pkcs11.c46
-rw-r--r--src/shared/pkcs11-util.c4
-rw-r--r--src/shared/pkcs11-util.h2
-rwxr-xr-xtest/units/testsuite-24.sh12
5 files changed, 63 insertions, 13 deletions
diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml
index a308a2ebdc..041337ab8a 100644
--- a/man/systemd-cryptenroll.xml
+++ b/man/systemd-cryptenroll.xml
@@ -313,11 +313,13 @@
<varlistentry>
<term><option>--pkcs11-token-uri=</option><replaceable>URI</replaceable></term>
- <listitem><para>Enroll a PKCS#11 security token or smartcard (e.g. a YubiKey). Expects a PKCS#11
- smartcard URI referring to the token. Alternatively the special value <literal>auto</literal> may
- be specified, in order to automatically determine the URI of a currently plugged in security token
- (of which there must be exactly one). The special value <literal>list</literal> may be used to
- enumerate all suitable PKCS#11 tokens currently plugged in.</para>
+ <listitem><para>Enroll a PKCS#11 security token or smartcard (e.g. a YubiKey). Expects a PKCS#11 URI
+ that allows to find an X.509 certificate on the token. The URI must also be suitable to find
+ a related private key after changing the type of object in it. Alternatively the special value
+ <literal>auto</literal> may be specified, in order to automatically determine the suitable URI if
+ a single security token containing a single key pair is plugged in. The special value
+ <literal>list</literal> may be used to enumerate all suitable PKCS#11 tokens currently plugged in.
+ </para>
<para>The PKCS#11 token must contain an RSA or EC key pair which will be used to unlock a LUKS2 volume.
For RSA, a randomly generated volume key is encrypted with a public key in the token, and stored in
diff --git a/src/cryptenroll/cryptenroll-pkcs11.c b/src/cryptenroll/cryptenroll-pkcs11.c
index 7d6112e402..ea969102cb 100644
--- a/src/cryptenroll/cryptenroll-pkcs11.c
+++ b/src/cryptenroll/cryptenroll-pkcs11.c
@@ -7,6 +7,30 @@
#include "openssl-util.h"
#include "pkcs11-util.h"
+static int uri_set_private_class(const char *uri, char **ret_uri) {
+ _cleanup_(sym_p11_kit_uri_freep) P11KitUri *p11kit_uri = NULL;
+ _cleanup_free_ char *private_uri = NULL;
+ int r;
+
+ r = uri_from_string(uri, &p11kit_uri);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PKCS#11 URI '%s': %m", uri);
+
+ if (sym_p11_kit_uri_get_attribute(p11kit_uri, CKA_CLASS)) {
+ CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
+ CK_ATTRIBUTE attribute = { CKA_CLASS, &class, sizeof(class) };
+
+ if (sym_p11_kit_uri_set_attribute(p11kit_uri, &attribute) != P11_KIT_URI_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set class for URI '%s': %m", uri);
+
+ if (sym_p11_kit_uri_format(p11kit_uri, P11_KIT_URI_FOR_ANY, &private_uri) != P11_KIT_URI_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to format PKCS#11 URI: %m");
+ }
+
+ *ret_uri = TAKE_PTR(private_uri);
+ return 0;
+}
+
int enroll_pkcs11(
struct crypt_device *cd,
const void *volume_key,
@@ -16,13 +40,13 @@ int enroll_pkcs11(
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
- _cleanup_free_ char *keyslot_as_string = NULL;
+ _cleanup_free_ char *keyslot_as_string = NULL, *private_uri = NULL;
size_t decrypted_key_size, saved_key_size;
_cleanup_free_ void *saved_key = NULL;
_cleanup_(X509_freep) X509 *cert = NULL;
ssize_t base64_encoded_size;
const char *node;
- int keyslot, r;
+ int r;
assert_se(cd);
assert_se(volume_key);
@@ -49,7 +73,7 @@ int enroll_pkcs11(
if (r < 0)
return log_error_errno(r, "Failed to set minimal PBKDF: %m");
- keyslot = crypt_keyslot_add_by_volume_key(
+ int keyslot = crypt_keyslot_add_by_volume_key(
cd,
CRYPT_ANY_SLOT,
volume_key,
@@ -62,12 +86,18 @@ int enroll_pkcs11(
if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
return log_oom();
+ /* Change 'type=cert' in the provided URI to 'type=private' before storing in a LUKS2 header.
+ This allows users to use output of some PKCS#11 tools directly without modifications. */
+ r = uri_set_private_class(uri, &private_uri);
+ if (r < 0)
+ return r;
+
r = json_build(&v,
- JSON_BUILD_OBJECT(
- JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("systemd-pkcs11")),
- JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
- JSON_BUILD_PAIR("pkcs11-uri", JSON_BUILD_STRING(uri)),
- JSON_BUILD_PAIR("pkcs11-key", JSON_BUILD_BASE64(saved_key, saved_key_size))));
+ JSON_BUILD_OBJECT(
+ JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("systemd-pkcs11")),
+ JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
+ JSON_BUILD_PAIR("pkcs11-uri", JSON_BUILD_STRING(private_uri ?: uri)),
+ JSON_BUILD_PAIR("pkcs11-key", JSON_BUILD_BASE64(saved_key, saved_key_size))));
if (r < 0)
return log_error_errno(r, "Failed to prepare PKCS#11 JSON token object: %m");
diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c
index 3ff2e92b01..2f583f232e 100644
--- a/src/shared/pkcs11-util.c
+++ b/src/shared/pkcs11-util.c
@@ -50,6 +50,8 @@ const char *(*sym_p11_kit_strerror)(CK_RV rv);
int (*sym_p11_kit_uri_format)(P11KitUri *uri, P11KitUriType uri_type, char **string);
void (*sym_p11_kit_uri_free)(P11KitUri *uri);
CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attributes)(P11KitUri *uri, CK_ULONG *n_attrs);
+CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attribute)(P11KitUri *uri, CK_ATTRIBUTE_TYPE attr_type);
+int (*sym_p11_kit_uri_set_attribute)(P11KitUri *uri, CK_ATTRIBUTE_PTR attr);
CK_INFO_PTR (*sym_p11_kit_uri_get_module_info)(P11KitUri *uri);
CK_SLOT_INFO_PTR (*sym_p11_kit_uri_get_slot_info)(P11KitUri *uri);
CK_TOKEN_INFO_PTR (*sym_p11_kit_uri_get_token_info)(P11KitUri *uri);
@@ -69,6 +71,8 @@ int dlopen_p11kit(void) {
DLSYM_ARG(p11_kit_uri_format),
DLSYM_ARG(p11_kit_uri_free),
DLSYM_ARG(p11_kit_uri_get_attributes),
+ DLSYM_ARG(p11_kit_uri_get_attribute),
+ DLSYM_ARG(p11_kit_uri_set_attribute),
DLSYM_ARG(p11_kit_uri_get_module_info),
DLSYM_ARG(p11_kit_uri_get_slot_info),
DLSYM_ARG(p11_kit_uri_get_token_info),
diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h
index 2ff6997823..d901bbea91 100644
--- a/src/shared/pkcs11-util.h
+++ b/src/shared/pkcs11-util.h
@@ -26,6 +26,8 @@ extern const char *(*sym_p11_kit_strerror)(CK_RV rv);
extern int (*sym_p11_kit_uri_format)(P11KitUri *uri, P11KitUriType uri_type, char **string);
extern void (*sym_p11_kit_uri_free)(P11KitUri *uri);
extern CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attributes)(P11KitUri *uri, CK_ULONG *n_attrs);
+extern CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attribute)(P11KitUri *uri, CK_ATTRIBUTE_TYPE attr_type);
+extern int (*sym_p11_kit_uri_set_attribute)(P11KitUri *uri, CK_ATTRIBUTE_PTR attr);
extern CK_INFO_PTR (*sym_p11_kit_uri_get_module_info)(P11KitUri *uri);
extern CK_SLOT_INFO_PTR (*sym_p11_kit_uri_get_slot_info)(P11KitUri *uri);
extern CK_TOKEN_INFO_PTR (*sym_p11_kit_uri_get_token_info)(P11KitUri *uri);
diff --git a/test/units/testsuite-24.sh b/test/units/testsuite-24.sh
index eeec411e9c..4d2a718433 100755
--- a/test/units/testsuite-24.sh
+++ b/test/units/testsuite-24.sh
@@ -231,14 +231,26 @@ cryptsetup_start_and_check empty_nokey
if [[ -r /etc/softhsm2.conf ]]; then
# Test unlocking with a PKCS#11 token
export SOFTHSM2_CONF="/etc/softhsm2.conf"
+
PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=RSATestKey" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY"
cryptsetup_start_and_check empty_pkcs11_auto
cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2
cryptsetup token remove --token-id 0 "$IMAGE_EMPTY"
+
+ PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=RSATestKey;type=cert" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY"
+ cryptsetup_start_and_check empty_pkcs11_auto
+ cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2
+ cryptsetup token remove --token-id 0 "$IMAGE_EMPTY"
+
PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=ECTestKey" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY"
cryptsetup_start_and_check empty_pkcs11_auto
cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2
cryptsetup token remove --token-id 0 "$IMAGE_EMPTY"
+
+ PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=ECTestKey;type=cert" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY"
+ cryptsetup_start_and_check empty_pkcs11_auto
+ cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2
+ cryptsetup token remove --token-id 0 "$IMAGE_EMPTY"
fi
cryptsetup_start_and_check detached