diff options
author | Lennart Poettering <lennart@poettering.net> | 2020-11-25 11:10:29 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2020-12-17 19:59:24 +0100 |
commit | b997d1115bf21b58dd876e02ce095bc483e3c875 (patch) | |
tree | 7506621680c4de90499611f5967ab78390dd6824 /src/cryptsetup/cryptsetup-pkcs11.c | |
parent | cryptsetup: be more careful with erasing key material from memory (diff) | |
download | systemd-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.c | 80 |
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; +} |