#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"
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;
+}
#include <sys/types.h>
+#include "cryptsetup-util.h"
#include "log.h"
#include "time-util.h"
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
+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);
+
#else
static inline int decrypt_pkcs11_key(
"PKCS#11 Token support not available.");
}
+static inline 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) {
+
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "PKCS#11 Token support not available.");
+}
+
#endif
static uint64_t arg_skip = 0;
static usec_t arg_timeout = USEC_INFINITY;
static char *arg_pkcs11_uri = NULL;
+static bool arg_pkcs11_uri_auto = false;
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
} else if ((val = startswith(option, "pkcs11-uri="))) {
- if (!pkcs11_uri_valid(val))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing");
+ if (streq(val, "auto")) {
+ arg_pkcs11_uri = mfree(arg_pkcs11_uri);
+ arg_pkcs11_uri_auto = true;
+ } else {
+ if (!pkcs11_uri_valid(val))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing");
- r = free_and_strdup(&arg_pkcs11_uri, val);
- if (r < 0)
- return log_oom();
+ r = free_and_strdup(&arg_pkcs11_uri, val);
+ if (r < 0)
+ return log_oom();
+
+ arg_pkcs11_uri_auto = false;
+ }
} else if ((val = startswith(option, "try-empty-password="))) {
assert(name);
assert(key_file || key_data || !strv_isempty(passwords));
- if (arg_pkcs11_uri)
+ if (arg_pkcs11_uri || arg_pkcs11_uri_auto)
/* Ask for a regular password */
return log_error_errno(SYNTHETIC_ERRNO(EAGAIN),
"Sorry, but tcrypt devices are currently not supported in conjunction with pkcs11 support.");
crypt_get_volume_key_size(cd)*8,
crypt_get_device_name(cd));
- if (arg_pkcs11_uri) {
+ if (arg_pkcs11_uri || arg_pkcs11_uri_auto) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
+ _cleanup_free_ char *friendly = NULL, *discovered_uri = NULL;
+ size_t decrypted_key_size = 0, discovered_key_size = 0;
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
- _cleanup_free_ char *friendly = NULL;
- size_t decrypted_key_size = 0;
+ _cleanup_free_ void *discovered_key = NULL;
+ int keyslot = arg_key_slot;
+ const char *uri;
+
+ if (arg_pkcs11_uri_auto) {
+ r = find_pkcs11_auto_data(cd, &discovered_uri, &discovered_key, &discovered_key_size, &keyslot);
+ if (IN_SET(r, -ENOTUNIQ, -ENXIO))
+ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+ "Automatic PKCS#11 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking.");
+ if (r < 0)
+ return r;
+
+ key_data = discovered_key;
+ key_data_size = discovered_key_size;
+ uri = discovered_uri;
+ } else
+ uri = arg_pkcs11_uri;
if (!key_file && !key_data)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
r = decrypt_pkcs11_key(
name,
friendly,
- arg_pkcs11_uri,
+ uri,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
until,
return r;
log_notice("Security token %s not present for unlocking volume %s, please plug it in.",
- arg_pkcs11_uri, friendly);
+ uri, friendly);
/* Let's immediately rescan in case the token appeared in the time we needed
* to create and configure the monitor */
if (r < 0)
return log_oom();
- r = crypt_activate_by_passphrase(cd, name, arg_key_slot, base64_encoded, strlen(base64_encoded), flags);
+ r = crypt_activate_by_passphrase(cd, name, keyslot, base64_encoded, strlen(base64_encoded), flags);
}
if (r == -EPERM) {
log_error_errno(r, "Failed to activate with PKCS#11 decrypted key. (Key incorrect?)");
* 5. We enquire the user for a password
*/
- if (!key_file && !key_data && !arg_pkcs11_uri) {
+ if (!key_file && !key_data && !arg_pkcs11_uri && !arg_pkcs11_uri_auto) {
if (arg_try_empty_password) {
/* Hmm, let's try an empty password now, but only once */
key_data = erase_and_free(key_data);
key_data_size = 0;
arg_pkcs11_uri = mfree(arg_pkcs11_uri);
+ arg_pkcs11_uri_auto = false;
}
if (arg_tries != 0 && tries >= arg_tries)