]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cryptsetup: handle more gracefully if "keyslots" LUKS2 JSON header field is invalid
authorLennart Poettering <lennart@poettering.net>
Tue, 28 Sep 2021 10:11:53 +0000 (12:11 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 28 Sep 2021 14:47:08 +0000 (16:47 +0200)
The field is not owned by us (even though is in our JSON objects) but by
the LUKS2 spec. Hence let's handle this a bit more gracefully: let's not
get confused by it, just warn and skip over it.

Fixes: #20847
src/cryptenroll/cryptenroll-tpm2.c
src/cryptsetup/cryptsetup-fido2.c
src/cryptsetup/cryptsetup-pkcs11.c
src/cryptsetup/cryptsetup-tpm2.c

index 23deeed272d6f205fcb347dc4521256be7e9a043..801014af11da55f5ad3102dfa20a8c052a9fd1fd 100644 (file)
@@ -34,8 +34,12 @@ static int search_policy_hash(
                         return log_error_errno(r, "Failed to read JSON token data off disk: %m");
 
                 keyslot = cryptsetup_get_keyslot_from_token(v);
-                if (keyslot < 0)
-                        return log_error_errno(keyslot, "Failed to determine keyslot of JSON token: %m");
+                if (keyslot < 0) {
+                        /* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
+                         * us, but by the LUKS2 spec */
+                        log_warning_errno(keyslot, "Failed to determine keyslot of JSON token %i, skipping: %m", token);
+                        continue;
+                }
 
                 w = json_variant_by_key(v, "tpm2-policy-hash");
                 if (!w || !json_variant_is_string(w))
index 74b6bff1aa0484e5f7d0ca92097607defbcfd80d..3a870016d31202aaaf948069b10898c02d125c75 100644 (file)
@@ -133,6 +133,7 @@ int find_fido2_auto_data(
         for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token ++) {
                 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
                 JsonVariant *w;
+                int ks;
 
                 r = cryptsetup_get_token_as_json(cd, token, "systemd-fido2", &v);
                 if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
@@ -140,10 +141,21 @@ int find_fido2_auto_data(
                 if (r < 0)
                         return log_error_errno(r, "Failed to read JSON token data off disk: %m");
 
+                ks = cryptsetup_get_keyslot_from_token(v);
+                if (ks < 0) {
+                        /* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
+                         * us, but by the LUKS2 spec */
+                        log_warning_errno(ks, "Failed to extract keyslot index from FIDO2 JSON data token %i, skipping: %m", token);
+                        continue;
+                }
+
                 if (cid)
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
                                                "Multiple FIDO2 tokens enrolled, cannot automatically determine token.");
 
+                assert(keyslot < 0);
+                keyslot = ks;
+
                 w = json_variant_by_key(v, "fido2-credential");
                 if (!w || !json_variant_is_string(w))
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -165,11 +177,6 @@ int find_fido2_auto_data(
                 if (r < 0)
                         return log_error_errno(r, "Failed to decode base64 encoded salt.");
 
-                assert(keyslot < 0);
-                keyslot = cryptsetup_get_keyslot_from_token(v);
-                if (keyslot < 0)
-                        return log_error_errno(keyslot, "Failed to extract keyslot index from FIDO2 JSON data: %m");
-
                 w = json_variant_by_key(v, "fido2-rp");
                 if (w) {
                         /* The "rp" field is optional. */
index 31960de5970dd2a936ec0a31be89faa7f0a351eb..f991389aa5b5cf026e3c6c44b03e25a30eb64511 100644 (file)
@@ -111,6 +111,7 @@ int find_pkcs11_auto_data(
         for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
                 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
                 JsonVariant *w;
+                int ks;
 
                 r = cryptsetup_get_token_as_json(cd, token, "systemd-pkcs11", &v);
                 if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
@@ -118,10 +119,21 @@ int find_pkcs11_auto_data(
                 if (r < 0)
                         return log_error_errno(r, "Failed to read JSON token data off disk: %m");
 
+                ks = cryptsetup_get_keyslot_from_token(v);
+                if (ks < 0) {
+                        /* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
+                         * us, but by the LUKS2 spec */
+                        log_warning_errno(ks, "Failed to extract keyslot index from PKCS#11 JSON data token %i, skipping: %m", token);
+                        continue;
+                }
+
                 if (uri)
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
                                                "Multiple PKCS#11 tokens enrolled, cannot automatically determine token.");
 
+                assert(keyslot < 0);
+                keyslot = ks;
+
                 w = json_variant_by_key(v, "pkcs11-uri");
                 if (!w || !json_variant_is_string(w))
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -145,11 +157,6 @@ int find_pkcs11_auto_data(
                 r = unbase64mem(json_variant_string(w), SIZE_MAX, &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)
index 4d95dacca5a744a35f14111cfaf2547bb28bf033..8757212969169d3518918f867027bf9bcd57ead1 100644 (file)
@@ -93,6 +93,7 @@ int find_tpm2_auto_data(
         for (token = start_token; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
                 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
                 JsonVariant *w, *e;
+                int ks;
 
                 r = cryptsetup_get_token_as_json(cd, token, "systemd-tpm2", &v);
                 if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
@@ -100,6 +101,14 @@ int find_tpm2_auto_data(
                 if (r < 0)
                         return log_error_errno(r, "Failed to read JSON token data off disk: %m");
 
+                ks = cryptsetup_get_keyslot_from_token(v);
+                if (ks < 0) {
+                        /* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
+                         * us, but by the LUKS2 spec */
+                        log_warning_errno(ks, "Failed to extract keyslot index from TPM2 JSON data token %i, skipping: %m", token);
+                        continue;
+                }
+
                 w = json_variant_by_key(v, "tpm2-pcrs");
                 if (!w || !json_variant_is_array(w))
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -125,6 +134,9 @@ int find_tpm2_auto_data(
                     search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */
                         continue;
 
+                assert(keyslot < 0);
+                keyslot = ks;
+
                 assert(pcr_bank == UINT16_MAX);
                 assert(primary_alg == TPM2_ALG_ECC);
 
@@ -184,11 +196,6 @@ int find_tpm2_auto_data(
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                "Invalid base64 data in 'tpm2-policy-hash' field.");
 
-                assert(keyslot < 0);
-                keyslot = cryptsetup_get_keyslot_from_token(v);
-                if (keyslot < 0)
-                        return log_error_errno(keyslot, "Failed to extract keyslot index from TPM2 JSON data: %m");
-
                 break;
         }