return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" PROJECT_VERSION_FULL " (" GIT_VERSION ")";
}
-static int log_debug_open_error(struct crypt_device *cd, int r) {
+static int log_debug_open_error(struct crypt_device *cd, int token, int r) {
if (r == -EAGAIN)
return crypt_log_debug_errno(cd, r, "TPM2 device not found.");
- if (r == -ENOSTR)
- return crypt_log_debug_errno(cd, r, "No matching TPM2 token data found.");
+ if (r == -ENOSTR) {
+ /* Remap to -EPERM so libcryptsetup's CRYPT_ANY_TOKEN loop keeps iterating. */
+ (void) crypt_log_debug_errno(cd, r, "Token %d: no matching TPM2 token data found.", token);
+ return -EPERM;
+ }
+ if (IN_SET(r, -EREMCHG, -EREMOTE)) {
+ /* Remap as above. Note: For now without -EUCLEAN because currently the only error it
+ * reports won't be solved by moving to another token. */
+ (void) crypt_log_debug_errno(cd, r, "Token %d: TPM policy does not match current system state, skipping.", token);
+ return -EPERM;
+ }
- return crypt_log_debug_errno(cd, r, TOKEN_NAME " open failed: %m.");
+ return crypt_log_debug_errno(cd, r, "Token %d: open failed: %m.", token);
}
_public_ int cryptsetup_token_open_pin(
params = *(systemd_tpm2_plugin_params *)usrptr;
r = sd_json_parse(json, SD_JSON_PARSE_MUST_BE_OBJECT, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL);
- if (r < 0)
- return crypt_log_debug_errno(cd, r, "Failed to parse token JSON data: %m");
+ if (r < 0) {
+ /* Remap to -EPERM so libcryptsetup keeps iterating past a broken token. */
+ (void) crypt_log_debug_errno(cd, r, "Token %d: failed to parse JSON data: %m", token);
+ return -EPERM;
+ }
struct iovec *blobs = NULL, *policy_hash = NULL;
size_t n_blobs = 0, n_policy_hash = 0;
&pcrlock_nv,
&flags);
if (r < 0)
- return log_debug_open_error(cd, r);
+ return log_debug_open_error(cd, token, r);
- if (params.search_pcr_mask != UINT32_MAX && hash_pcr_mask != params.search_pcr_mask)
- return crypt_log_debug_errno(cd, ENXIO, "PCR mask doesn't match expectation (%" PRIu32 " vs. %" PRIu32 ")", hash_pcr_mask, params.search_pcr_mask);
+ if (params.search_pcr_mask != UINT32_MAX && hash_pcr_mask != params.search_pcr_mask) {
+ /* Remap to -EPERM so libcryptsetup keeps iterating to the next token. */
+ crypt_log_debug(cd, "Token %d: PCR mask doesn't match expectation (%" PRIu32 " vs. %" PRIu32 ")", token, hash_pcr_mask, params.search_pcr_mask);
+ return -EPERM;
+ }
r = acquire_luks2_key(
params.device,
flags,
&decrypted_key);
if (r < 0)
- return log_debug_open_error(cd, r);
+ return log_debug_open_error(cd, token, r);
/* Before using this key as passphrase we base64 encode it, for compat with homed */
base64_encoded_size = base64mem(decrypted_key.iov_base, decrypted_key.iov_len, &base64_encoded);
if (base64_encoded_size < 0)
- return log_debug_open_error(cd, base64_encoded_size);
+ return log_debug_open_error(cd, token, base64_encoded_size);
/* free'd automatically by libcryptsetup */
*ret_password = TAKE_PTR(base64_encoded);
int dlopen_tpm2(int log_level);
+/* tpm2_unseal() returns a bunch of different errors for various flavours of PCR issues, let's group them.
+ * Kept outside the HAVE_TPM2 guard as callers switch on these errnos even in builds without TPM2. */
+#define ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r) IN_SET(r, -EREMCHG, -ENOANO, -EUCLEAN, -EPERM)
+
+/* Errors that mean the tried TPM2 token does not match the boot state, be it due to wrong PCR state, a
+ * different PCR signing key/policy, or even a different TPM. The caller should keep trying other tokens. */
+#define ERRNO_IS_NEG_TPM2_TOKEN_MISMATCH(r) IN_SET(r, -EREMCHG, -ENOANO, -EPERM, -ENOSTR, -EREMOTE)
+
#if HAVE_TPM2
#ifndef SYSTEMD_CFLAGS_MARKER_TPM2
# error "missing tpm2_cflags in meson dependency."
int tpm2_seal(Tpm2Context *c, uint32_t seal_key_handle, const TPM2B_DIGEST policy_hash[], size_t n_policy, const char *pin, struct iovec *ret_secret, struct iovec **ret_blobs, size_t *ret_n_blobs, uint16_t *ret_primary_alg, struct iovec *ret_srk);
int tpm2_unseal(Tpm2Context *c, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, const char *pubkey_policy_ref, uint32_t pubkey_pcr_mask, sd_json_variant *signature, const char *pin, const Tpm2PCRLockPolicy *pcrlock_policy, uint16_t primary_alg, const struct iovec blobs[], size_t n_blobs, const struct iovec known_policy_hash[], size_t n_known_policy_hash, const struct iovec *srk, struct iovec *ret_secret);
-/* tpm2_unseal() returns a bunch of different errors for various flavours of PCR issues, let's group them */
-#define ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r) IN_SET(r, -EREMCHG, -ENOANO, -EUCLEAN, -EPERM)
-
#if HAVE_OPENSSL
int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret);
int tpm2_tpm2b_public_from_openssl_pkey(const EVP_PKEY *pkey, TPM2B_PUBLIC *ret);