summaryrefslogtreecommitdiffstats
path: root/src/cryptsetup/cryptsetup-pkcs11.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-11-25 11:10:29 +0100
committerLennart Poettering <lennart@poettering.net>2020-12-17 19:59:24 +0100
commitb997d1115bf21b58dd876e02ce095bc483e3c875 (patch)
tree7506621680c4de90499611f5967ab78390dd6824 /src/cryptsetup/cryptsetup-pkcs11.c
parentcryptsetup: be more careful with erasing key material from memory (diff)
downloadsystemd-b997d1115bf21b58dd876e02ce095bc483e3c875.tar.xz
systemd-b997d1115bf21b58dd876e02ce095bc483e3c875.zip
cryptsetup: read PKCS#11 key and token info from LUKS2 metadata
Optionally, embedd PKCS#11 token URI and encrypted key in LUKS2 JSON metadata header. That way it becomes very easy to unlock properly set up PKCS#11-enabled LUKS2 volumes, a simple /etc/crypttab line like the following suffices: mytest /dev/disk/by-partuuid/41c1df55-e628-4dbb-8492-bc69d81e172e - pkcs11-uri=auto Such a line declares that unlocking via PKCS#11 shall be attempted, and the token URI and the encrypted key shall be read from the LUKS2 header. An external key file for the encrypted PKCS#11 key is hence no longer necessary, nor is specifying the precise URI to use.
Diffstat (limited to 'src/cryptsetup/cryptsetup-pkcs11.c')
-rw-r--r--src/cryptsetup/cryptsetup-pkcs11.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c
index b645ff28e0..93cf7c64b3 100644
--- a/src/cryptsetup/cryptsetup-pkcs11.c
+++ b/src/cryptsetup/cryptsetup-pkcs11.c
@@ -14,8 +14,11 @@
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
+#include "hexdecoct.h"
+#include "json.h"
#include "macro.h"
#include "memory-util.h"
+#include "parse-util.h"
#include "pkcs11-util.h"
#include "random-util.h"
#include "stat-util.h"
@@ -156,3 +159,80 @@ int decrypt_pkcs11_key(
return 0;
}
+
+int find_pkcs11_auto_data(
+ struct crypt_device *cd,
+ char **ret_uri,
+ void **ret_encrypted_key,
+ size_t *ret_encrypted_key_size,
+ int *ret_keyslot) {
+
+ _cleanup_free_ char *uri = NULL;
+ _cleanup_free_ void *key = NULL;
+ int r, keyslot = -1;
+ size_t key_size = 0;
+
+ assert(cd);
+ assert(ret_uri);
+ assert(ret_encrypted_key);
+ assert(ret_encrypted_key_size);
+ assert(ret_keyslot);
+
+ /* Loads PKCS#11 metadata from LUKS2 JSON token headers. */
+
+ for (int token = 0; token < LUKS2_TOKENS_MAX; token++) {
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+ JsonVariant *w;
+
+ r = cryptsetup_get_token_as_json(cd, token, "systemd-pkcs11", &v);
+ if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
+ continue;
+ if (r < 0)
+ return log_error_errno(r, "Failed to read JSON token data off disk: %m");
+
+ if (uri)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
+ "Multiple PKCS#11 tokens enrolled, cannot automatically determine token.");
+
+ w = json_variant_by_key(v, "pkcs11-uri");
+ if (!w || !json_variant_is_string(w))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "PKCS#11 token data lacks 'pkcs11-uri' field.");
+
+ uri = strdup(json_variant_string(w));
+ if (!uri)
+ return log_oom();
+
+ if (!pkcs11_uri_valid(uri))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "PKCS#11 token data contains invalid PKCS#11 URI.");
+
+ w = json_variant_by_key(v, "pkcs11-key");
+ if (!w || !json_variant_is_string(w))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "PKCS#11 token data lacks 'pkcs11-key' field.");
+
+ assert(!key);
+ assert(key_size == 0);
+ r = unbase64mem(json_variant_string(w), (size_t) -1, &key, &key_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode base64 encoded key.");
+
+ assert(keyslot < 0);
+ keyslot = cryptsetup_get_keyslot_from_token(v);
+ if (keyslot < 0)
+ return log_error_errno(keyslot, "Failed to extract keyslot index from PKCS#11 JSON data: %m");
+ }
+
+ if (!uri)
+ return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
+ "No valid PKCS#11 token data found.");
+
+ log_info("Automatically discovered security PKCS#11 token '%s' unlocks volume.", uri);
+
+ *ret_uri = TAKE_PTR(uri);
+ *ret_encrypted_key = TAKE_PTR(key);
+ *ret_encrypted_key_size = key_size;
+ *ret_keyslot = keyslot;
+ return 0;
+}