]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tpm2-util: refuse hash algorithm/value specification when we only parse a mask
authorLennart Poettering <lennart@poettering.net>
Sun, 22 Dec 2024 17:32:09 +0000 (18:32 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 3 Jan 2025 09:44:26 +0000 (10:44 +0100)
tpm2_parse_pcr_argument_to_mask() is supposed to parse a PCR mask
string, and uses the full blown tpm2_parse_pcr_argument() call at its
core, which parses more than just a mask, i.e. values and algorithms
too. Which is very confusing at times, because commands such as
"systemd-cryptenroll --tpm2-device=auto
--tpm2-public-key-pcrs=1:sha1=09dbdbc7f6cdd8029cc90b57a915c19a0ac21bce"
are very confusing, since they suggest enrollment with a specific
algorithm and has value, but this is not in fact what happens: both are
entirely ignored.

That this was accepted this way was more an accident than intended,
which is already visible in the fact that extensive test case entirely
ignores the fact that strings like this are accepted.

src/shared/tpm2-util.c
src/test/test-tpm2.c

index f9a805964a7a67e2fec98523e12806e976d36b53..29d9dbbe2e5d88c52660e5c22a9b963addf80beb 100644 (file)
@@ -8090,14 +8090,15 @@ int tpm2_parse_pcr_argument_append(const char *arg, Tpm2PCRValue **pcr_values, s
 #endif
 }
 
-/* Same as tpm2_parse_pcr_argument() but converts the pcr values to a pcr mask. If more than one hash
- * algorithm is included in the pcr values array this results in error. This retains the previous behavior of
- * tpm2_parse_pcr_argument() of clearing the mask if 'arg' is empty, replacing the mask if it is set to
- * UINT32_MAX, and or-ing the mask otherwise. */
 int tpm2_parse_pcr_argument_to_mask(const char *arg, uint32_t *mask) {
 #if HAVE_TPM2
         int r;
 
+       /* Same as tpm2_parse_pcr_argument() but converts the pcr values to a pcr mask. If a hash algorithm or
+        * hash value is specified an error is generated (after all we only return the mask here, nothing
+        * else). This retains the previous behavior of tpm2_parse_pcr_argument() of clearing the mask if
+        * 'arg' is empty, replacing the mask if it is set to UINT32_MAX, and or-ing the mask otherwise. */
+
         assert(arg);
         assert(mask);
 
@@ -8113,6 +8114,15 @@ int tpm2_parse_pcr_argument_to_mask(const char *arg, uint32_t *mask) {
                 return 0;
         }
 
+        FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
+                if (v->hash != 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Not expecting hash algorithm specification in PCR mask value, refusing: %s", arg);
+                if (v->value.size != 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Not expecting hash value specification in PCR mask value, refusing: %s", arg);
+        }
+
         uint32_t new_mask;
         r = tpm2_pcr_values_to_mask(pcr_values, n_pcr_values, /* algorithm= */ 0, &new_mask);
         if (r < 0)
index e4f1f861b4736ae24b468165783ec6f966098c2c..31ef6192b2924049f7c19ce493829153b25794c6 100644 (file)
@@ -556,8 +556,13 @@ static void check_parse_pcr_argument(
 
                 assert_se(tpm2_pcr_values_to_mask(expected_values, n_expected_values, expected_values[0].hash, &expected_mask) == 0);
 
-                assert_se(tpm2_parse_pcr_argument_to_mask(arg, &mask) == 0);
-                assert_se(mask == expected_mask);
+                _cleanup_free_ Tpm2PCRValue *arg_pcr_values = NULL;
+                size_t n_arg_pcr_values = 0;
+                assert_se(tpm2_parse_pcr_argument(arg, &arg_pcr_values, &n_arg_pcr_values) >= 0);
+                uint32_t mask2 = UINT32_MAX;
+                assert_se(tpm2_pcr_values_to_mask(arg_pcr_values, n_arg_pcr_values, /* algorithm= */ 0, &mask2) >= 0);
+
+                assert_se((mask == UINT32_MAX ? mask2 : (mask|mask2)) == expected_mask);
         }
 
         size_t old_n_values = n_values;
@@ -701,6 +706,10 @@ TEST(parse_pcr_argument) {
         check_parse_pcr_argument_to_mask("sysexts+17+23", 0x822000);
         check_parse_pcr_argument_to_mask("6+boot-loader-code,44", -EINVAL);
         check_parse_pcr_argument_to_mask("debug+24", -EINVAL);
+        check_parse_pcr_argument_to_mask("5:sha1=f013d66c7f6817d08b7eb2a93e6d0440c1f3e7f8", -EINVAL);
+        check_parse_pcr_argument_to_mask("0:sha256=f013d66c7f6817d08b7eb2a93e6d0440c1f3e7f8", -EINVAL);
+        check_parse_pcr_argument_to_mask("5:sha1=f013d66c7f6817d08b7eb2a93e6d0440c1f3e7f8,3", -EINVAL);
+        check_parse_pcr_argument_to_mask("3,0:sha256=f013d66c7f6817d08b7eb2a93e6d0440c1f3e7f8", -EINVAL);
 }
 
 static const TPMT_PUBLIC test_rsa_template = {