From 90d9f2996c10a2be090fd89be7409c81eabceb4c Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Mon, 6 Feb 2023 11:31:59 -0500 Subject: [PATCH] tpm2: add/rename functions to manage pcr selections This renames some functions to match other to/from_string() naming, and allows better management of TPML_PCR_SELECTION and TPMS_PCR_SELECTION structs. (cherry picked from commit c69bd0abdbd06ee89068227c67890358f5764c3d) Related: RHEL-16182 --- src/boot/measure.c | 4 +- .../cryptsetup-token-systemd-tpm2.c | 12 +- src/shared/tpm2-util.c | 350 +++++++++++++++--- src/shared/tpm2-util.h | 31 +- src/test/test-tpm2.c | 32 +- 5 files changed, 358 insertions(+), 71 deletions(-) diff --git a/src/boot/measure.c b/src/boot/measure.c index 65a48a01cd..86edf77c52 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -844,7 +844,9 @@ static int verb_sign(int argc, char *argv[], void *userdata) { return log_error_errno(tpmalg, "Unsupported PCR bank"); TPML_PCR_SELECTION pcr_selection; - tpm2_pcr_mask_to_selection(1 << TPM_PCR_INDEX_KERNEL_IMAGE, tpmalg, &pcr_selection); + tpm2_tpml_pcr_selection_from_mask(1 << TPM_PCR_INDEX_KERNEL_IMAGE, + tpmalg, + &pcr_selection); rc = sym_Esys_PolicyPCR( c->esys_context, diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c index e8bc091191..b5d66e389d 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c @@ -205,13 +205,13 @@ _public_ void cryptsetup_token_dump( if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON fields: %m"); - r = pcr_mask_to_string(hash_pcr_mask, &hash_pcrs_str); - if (r < 0) - return (void) crypt_log_debug_errno(cd, r, "Cannot format PCR hash mask: %m"); + hash_pcrs_str = tpm2_pcr_mask_to_string(hash_pcr_mask); + if (!hash_pcrs_str) + return (void) crypt_log_debug_errno(cd, ENOMEM, "Cannot format PCR hash mask: %m"); - r = pcr_mask_to_string(pubkey_pcr_mask, &pubkey_pcrs_str); - if (r < 0) - return (void) crypt_log_debug_errno(cd, r, "Cannot format PCR hash mask: %m"); + pubkey_pcrs_str = tpm2_pcr_mask_to_string(pubkey_pcr_mask); + if (!pubkey_pcrs_str) + return (void) crypt_log_debug_errno(cd, ENOMEM, "Cannot format PCR hash mask: %m"); r = crypt_dump_buffer_to_hex_string(blob, blob_size, &blob_str); if (r < 0) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 0cbb32f819..cf62524e34 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -458,24 +458,292 @@ static int tpm2_make_primary( return 0; } -void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret) { +/* Utility functions for TPMS_PCR_SELECTION. */ + +/* Convert a TPMS_PCR_SELECTION object to a mask. */ +void tpm2_tpms_pcr_selection_to_mask(const TPMS_PCR_SELECTION *s, uint32_t *ret) { + assert(s); + assert(s->sizeofSelect <= sizeof(s->pcrSelect)); assert(ret); - /* We only do 24bit here, as that's what PC TPMs are supposed to support */ - assert(TPM2_PCR_MASK_VALID(mask)); + uint32_t mask = 0; + for (unsigned i = 0; i < s->sizeofSelect; i++) + SET_FLAG(mask, (uint32_t)s->pcrSelect[i] << (i * 8), true); + *ret = mask; +} - *ret = (TPML_PCR_SELECTION) { - .count = 1, - .pcrSelections[0] = { - .hash = bank, - .sizeofSelect = 3, - .pcrSelect[0] = mask & 0xFF, - .pcrSelect[1] = (mask >> 8) & 0xFF, - .pcrSelect[2] = (mask >> 16) & 0xFF, +/* Convert a mask and hash alg to a TPMS_PCR_SELECTION object. */ +void tpm2_tpms_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash_alg, TPMS_PCR_SELECTION *ret) { + assert(ret); + + /* This is currently hardcoded at 24 PCRs, above. */ + if (!TPM2_PCR_MASK_VALID(mask)) + log_warning("PCR mask selections (%x) out of range, ignoring.", + mask & ~((uint32_t)TPM2_PCRS_MASK)); + + *ret = (TPMS_PCR_SELECTION){ + .hash = hash_alg, + .sizeofSelect = TPM2_PCRS_MAX / 8, + .pcrSelect[0] = mask & 0xff, + .pcrSelect[1] = (mask >> 8) & 0xff, + .pcrSelect[2] = (mask >> 16) & 0xff, + }; +} + +/* Add all PCR selections in 'b' to 'a'. Both must have the same hash alg. */ +void tpm2_tpms_pcr_selection_add(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b) { + assert(a); + assert(b); + assert(a->hash == b->hash); + + uint32_t maska, maskb; + tpm2_tpms_pcr_selection_to_mask(a, &maska); + tpm2_tpms_pcr_selection_to_mask(b, &maskb); + tpm2_tpms_pcr_selection_from_mask(maska | maskb, a->hash, a); +} + +/* Remove all PCR selections in 'b' from 'a'. Both must have the same hash alg. */ +void tpm2_tpms_pcr_selection_sub(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b) { + assert(a); + assert(b); + assert(a->hash == b->hash); + + uint32_t maska, maskb; + tpm2_tpms_pcr_selection_to_mask(a, &maska); + tpm2_tpms_pcr_selection_to_mask(b, &maskb); + tpm2_tpms_pcr_selection_from_mask(maska & ~maskb, a->hash, a); +} + +/* Move all PCR selections in 'b' to 'a'. Both must have the same hash alg. */ +void tpm2_tpms_pcr_selection_move(TPMS_PCR_SELECTION *a, TPMS_PCR_SELECTION *b) { + if (a == b) + return; + + tpm2_tpms_pcr_selection_add(a, b); + tpm2_tpms_pcr_selection_from_mask(0, b->hash, b); +} + +#define FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms) \ + _FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms, UNIQ) +#define _FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms, uniq) \ + FOREACH_PCR_IN_MASK(pcr, \ + ({ uint32_t UNIQ_T(_mask, uniq); \ + tpm2_tpms_pcr_selection_to_mask(tpms, &UNIQ_T(_mask, uniq)); \ + UNIQ_T(_mask, uniq); \ + })) + +#define FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml) \ + UNIQ_FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml, UNIQ) +#define UNIQ_FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml, uniq) \ + for (TPML_PCR_SELECTION *UNIQ_T(_tpml, uniq) = (TPML_PCR_SELECTION*)(tpml); \ + UNIQ_T(_tpml, uniq); UNIQ_T(_tpml, uniq) = NULL) \ + _FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, UNIQ_T(_tpml, uniq)) +#define _FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml) \ + for (TPMS_PCR_SELECTION *tpms = tpml->pcrSelections; \ + (uint32_t)(tpms - tpml->pcrSelections) < tpml->count; \ + tpms++) + +#define FOREACH_PCR_IN_TPML_PCR_SELECTION(pcr, tpms, tpml) \ + FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml) \ + FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms) + +char *tpm2_tpms_pcr_selection_to_string(const TPMS_PCR_SELECTION *s) { + assert(s); + + const char *algstr = strna(tpm2_hash_alg_to_string(s->hash)); + + uint32_t mask; + tpm2_tpms_pcr_selection_to_mask(s, &mask); + _cleanup_free_ char *maskstr = tpm2_pcr_mask_to_string(mask); + if (!maskstr) + return NULL; + + return strjoin(algstr, "(", maskstr, ")"); +} + +size_t tpm2_tpms_pcr_selection_weight(const TPMS_PCR_SELECTION *s) { + assert(s); + + uint32_t mask; + tpm2_tpms_pcr_selection_to_mask(s, &mask); + return (size_t)__builtin_popcount(mask); +} + +/* Utility functions for TPML_PCR_SELECTION. */ + +/* Remove the (0-based) index entry from 'l', shift all following entries, and update the count. */ +static void tpm2_tpml_pcr_selection_remove_index(TPML_PCR_SELECTION *l, uint32_t index) { + assert(l); + assert(l->count <= sizeof(l->pcrSelections)); + assert(index < l->count); + + size_t s = l->count - (index + 1); + memmove(&l->pcrSelections[index], &l->pcrSelections[index + 1], s * sizeof(l->pcrSelections[0])); + l->count--; +} + +/* Get a TPMS_PCR_SELECTION from a TPML_PCR_SELECTION for the given hash alg. Returns NULL if there is no + * entry for the hash alg. This guarantees the returned entry contains all the PCR selections for the given + * hash alg, which may require modifying the TPML_PCR_SELECTION by removing duplicate entries. */ +static TPMS_PCR_SELECTION *tpm2_tpml_pcr_selection_get_tpms_pcr_selection( + TPML_PCR_SELECTION *l, + TPMI_ALG_HASH hash_alg) { + + assert(l); + + TPMS_PCR_SELECTION *selection = NULL; + FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) + if (s->hash == hash_alg) { + selection = s; + break; + } + + if (!selection) + return NULL; + + /* Iterate backwards through the entries, removing any other entries for the hash alg. */ + for (uint32_t i = l->count - 1; i > 0; i--) { + TPMS_PCR_SELECTION *s = &l->pcrSelections[i]; + + if (selection == s) + break; + + if (s->hash == hash_alg) { + tpm2_tpms_pcr_selection_move(selection, s); + tpm2_tpml_pcr_selection_remove_index(l, i); } + } + + return selection; +} + +/* Convert a TPML_PCR_SELECTION object to a mask. Returns -ENOENT if 'hash_alg' is not in the object. */ +int tpm2_tpml_pcr_selection_to_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash_alg, uint32_t *ret) { + assert(l); + assert(ret); + + /* Make a copy, as tpm2_tpml_pcr_selection_get_tpms_pcr_selection() will modify the object if there + * are multiple entries with the requested hash alg. */ + TPML_PCR_SELECTION lcopy = *l; + + TPMS_PCR_SELECTION *s; + s = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(&lcopy, hash_alg); + if (!s) + return SYNTHETIC_ERRNO(ENOENT); + + tpm2_tpms_pcr_selection_to_mask(s, ret); + return 0; +} + +/* Convert a mask and hash alg to a TPML_PCR_SELECTION object. */ +void tpm2_tpml_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash_alg, TPML_PCR_SELECTION *ret) { + assert(ret); + + TPMS_PCR_SELECTION s; + tpm2_tpms_pcr_selection_from_mask(mask, hash_alg, &s); + + *ret = (TPML_PCR_SELECTION){ + .count = 1, + .pcrSelections[0] = s, }; } +/* Combine all duplicate (same hash alg) TPMS_PCR_SELECTION entries in 'l'. */ +static void tpm2_tpml_pcr_selection_cleanup(TPML_PCR_SELECTION *l) { + FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) + /* This removes all duplicates for s->hash. */ + (void) tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, s->hash); +} + +/* Add the PCR selections in 's' to the corresponding hash alg TPMS_PCR_SELECTION entry in 'l'. Adds a new + * TPMS_PCR_SELECTION entry for the hash alg if needed. This may modify the TPML_PCR_SELECTION by combining + * entries with the same hash alg. */ +void tpm2_tpml_pcr_selection_add_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s) { + assert(l); + assert(s); + + if (tpm2_tpms_pcr_selection_is_empty(s)) + return; + + TPMS_PCR_SELECTION *selection = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, s->hash); + if (selection) { + tpm2_tpms_pcr_selection_add(selection, s); + return; + } + + /* It's already broken if the count is higher than the array has size for. */ + assert(!(l->count > sizeof(l->pcrSelections))); + + /* If full, the cleanup should result in at least one available entry. */ + if (l->count == sizeof(l->pcrSelections)) + tpm2_tpml_pcr_selection_cleanup(l); + + assert(l->count < sizeof(l->pcrSelections)); + l->pcrSelections[l->count++] = *s; +} + +/* Remove the PCR selections in 's' from the corresponding hash alg TPMS_PCR_SELECTION entry in 'l'. This + * will combine all entries for 's->hash' in 'l'. */ +void tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s) { + assert(l); + assert(s); + + if (tpm2_tpms_pcr_selection_is_empty(s)) + return; + + TPMS_PCR_SELECTION *selection = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, s->hash); + if (selection) + tpm2_tpms_pcr_selection_sub(selection, s); +} + +/* Add all PCR selections in 'b' to 'a'. */ +void tpm2_tpml_pcr_selection_add(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b) { + assert(a); + assert(b); + + FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection_b, (TPML_PCR_SELECTION*) b) + tpm2_tpml_pcr_selection_add_tpms_pcr_selection(a, selection_b); +} + +/* Remove all PCR selections in 'b' from 'a'. */ +void tpm2_tpml_pcr_selection_sub(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b) { + assert(a); + assert(b); + + FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection_b, (TPML_PCR_SELECTION*) b) + tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(a, selection_b); +} + +char *tpm2_tpml_pcr_selection_to_string(const TPML_PCR_SELECTION *l) { + assert(l); + + _cleanup_free_ char *banks = NULL; + FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, (TPML_PCR_SELECTION*) l) { + if (tpm2_tpms_pcr_selection_is_empty(s)) + continue; + + _cleanup_free_ char *str = tpm2_tpms_pcr_selection_to_string(s); + if (!str || !strextend_with_separator(&banks, ",", str)) + return NULL; + } + + return strjoin("[", strempty(banks), "]"); +} + +size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l) { + assert(l); + assert(l->count <= sizeof(l->pcrSelections)); + + size_t weight = 0; + FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) { + size_t w = tpm2_tpms_pcr_selection_weight(s); + assert(weight <= SIZE_MAX - w); + weight += w; + } + + return weight; +} + static void tpm2_log_debug_buffer(const void *buffer, size_t size, const char *msg) { if (!DEBUG_LOGGING || !buffer || size == 0) return; @@ -562,7 +830,7 @@ static int tpm2_pcr_mask_good( * actually measure into them, or only into a suboptimal bank. If so, the PCRs should be all zero or * all 0xFF. Detect that, so that we can warn and maybe pick a better bank. */ - tpm2_pcr_mask_to_selection(mask, bank, &selection); + tpm2_tpml_pcr_selection_from_mask(mask, bank, &selection); rc = sym_Esys_PCR_Read( c->esys_context, @@ -1269,7 +1537,7 @@ static int tpm2_make_policy_session( /* Put together the PCR policy we want to use */ TPML_PCR_SELECTION pcr_selection; - tpm2_pcr_mask_to_selection(pubkey_pcr_mask, pcr_bank, &pcr_selection); + tpm2_tpml_pcr_selection_from_mask(pubkey_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection); rc = sym_Esys_PolicyPCR( c->esys_context, session->esys_handle, @@ -1372,7 +1640,7 @@ static int tpm2_make_policy_session( log_debug("Configuring hash-based PCR policy."); TPML_PCR_SELECTION pcr_selection; - tpm2_pcr_mask_to_selection(hash_pcr_mask, pcr_bank, &pcr_selection); + tpm2_tpml_pcr_selection_from_mask(hash_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection); rc = sym_Esys_PolicyPCR( c->esys_context, session->esys_handle, @@ -1989,13 +2257,28 @@ int tpm2_extend_bytes( } #endif -int tpm2_parse_pcrs(const char *s, uint32_t *ret) { - const char *p = ASSERT_PTR(s); +char *tpm2_pcr_mask_to_string(uint32_t mask) { + _cleanup_free_ char *s = NULL; + + FOREACH_PCR_IN_MASK(n, mask) + if (strextendf_with_separator(&s, "+", "%d", n) < 0) + return NULL; + + if (!s) + return strdup(""); + + return TAKE_PTR(s); +} + +int tpm2_pcr_mask_from_string(const char *arg, uint32_t *ret_mask) { uint32_t mask = 0; int r; - if (isempty(s)) { - *ret = 0; + assert(arg); + assert(ret_mask); + + if (isempty(arg)) { + *ret_mask = 0; return 0; } @@ -2004,6 +2287,7 @@ int tpm2_parse_pcrs(const char *s, uint32_t *ret) { * /etc/crypttab the "," is already used to separate options, hence a different separator is nice to * avoid escaping. */ + const char *p = arg; for (;;) { _cleanup_free_ char *pcr = NULL; unsigned n; @@ -2012,19 +2296,20 @@ int tpm2_parse_pcrs(const char *s, uint32_t *ret) { if (r == 0) break; if (r < 0) - return log_error_errno(r, "Failed to parse PCR list: %s", s); + return log_error_errno(r, "Failed to parse PCR list: %s", arg); r = safe_atou(pcr, &n); if (r < 0) return log_error_errno(r, "Failed to parse PCR number: %s", pcr); if (n >= TPM2_PCRS_MAX) return log_error_errno(SYNTHETIC_ERRNO(ERANGE), - "PCR number out of range (valid range 0…23): %u", n); + "PCR number out of range (valid range 0…%u): %u", + TPM2_PCRS_MAX - 1, n); - mask |= UINT32_C(1) << n; + SET_BIT(mask, n);; } - *ret = mask; + *ret_mask = mask; return 0; } @@ -2389,7 +2674,7 @@ int tpm2_parse_pcr_argument(const char *arg, uint32_t *mask) { return 0; } - r = tpm2_parse_pcrs(arg, &m); + r = tpm2_pcr_mask_from_string(arg, &m); if (r < 0) return r; @@ -2445,25 +2730,6 @@ int tpm2_load_pcr_public_key(const char *path, void **ret_pubkey, size_t *ret_pu return 0; } -int pcr_mask_to_string(uint32_t mask, char **ret) { - _cleanup_free_ char *buf = NULL; - int r; - - assert(ret); - - for (unsigned i = 0; i < TPM2_PCRS_MAX; i++) { - if (!(mask & (UINT32_C(1) << i))) - continue; - - r = strextendf_with_separator(&buf, "+", "%u", i); - if (r < 0) - return r; - } - - *ret = TAKE_PTR(buf); - return 0; -} - #define PBKDF2_HMAC_SHA256_ITERATIONS 10000 /* diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 07a8a89800..c2532c61c2 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -3,6 +3,7 @@ #include +#include "bitfield.h" #include "json.h" #include "macro.h" #include "sha256.h" @@ -23,6 +24,8 @@ static inline bool TPM2_PCR_MASK_VALID(uint32_t pcr_mask) { return pcr_mask <= TPM2_PCRS_MASK; } +#define FOREACH_PCR_IN_MASK(pcr, mask) BIT_FOREACH(pcr, mask) + #if HAVE_TPM2 #include @@ -92,8 +95,6 @@ Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle); DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free); #define _cleanup_tpm2_handle_ _cleanup_(tpm2_handle_freep) -void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret); - static inline void Esys_Freep(void *p) { if (*(void**) p) sym_Esys_Free(*(void**) p); @@ -104,6 +105,25 @@ int tpm2_get_good_pcr_banks_strv(Tpm2Context *c, uint32_t pcr_mask, char ***ret) int tpm2_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const void *data, size_t data_size, const void *secret, size_t secret_size); +void tpm2_tpms_pcr_selection_to_mask(const TPMS_PCR_SELECTION *s, uint32_t *ret); +void tpm2_tpms_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash, TPMS_PCR_SELECTION *ret); +void tpm2_tpms_pcr_selection_add(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b); +void tpm2_tpms_pcr_selection_sub(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b); +void tpm2_tpms_pcr_selection_move(TPMS_PCR_SELECTION *a, TPMS_PCR_SELECTION *b); +char *tpm2_tpms_pcr_selection_to_string(const TPMS_PCR_SELECTION *s); +size_t tpm2_tpms_pcr_selection_weight(const TPMS_PCR_SELECTION *s); +#define tpm2_tpms_pcr_selection_is_empty(s) (tpm2_tpms_pcr_selection_weight(s) == 0) + +int tpm2_tpml_pcr_selection_to_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t *ret); +void tpm2_tpml_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash, TPML_PCR_SELECTION *ret); +void tpm2_tpml_pcr_selection_add_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s); +void tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s); +void tpm2_tpml_pcr_selection_add(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b); +void tpm2_tpml_pcr_selection_sub(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b); +char *tpm2_tpml_pcr_selection_to_string(const TPML_PCR_SELECTION *l); +size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l); +#define tpm2_tpml_pcr_selection_is_empty(l) (tpm2_tpml_pcr_selection_weight(l) == 0) + #else /* HAVE_TPM2 */ typedef struct {} Tpm2Context; typedef struct {} Tpm2Handle; @@ -112,8 +132,6 @@ typedef struct {} Tpm2Handle; int tpm2_list_devices(void); int tpm2_find_device_auto(int log_level, char **ret); -int tpm2_parse_pcrs(const char *s, uint32_t *ret); - int tpm2_make_pcr_json_array(uint32_t pcr_mask, JsonVariant **ret); int tpm2_parse_pcr_json_array(JsonVariant *v, uint32_t *ret); @@ -155,6 +173,9 @@ int tpm2_hash_alg_from_string(const char *alg); const char *tpm2_asym_alg_to_string(uint16_t alg); int tpm2_asym_alg_from_string(const char *alg); +char *tpm2_pcr_mask_to_string(uint32_t mask); +int tpm2_pcr_mask_from_string(const char *arg, uint32_t *mask); + typedef struct { uint32_t search_pcr_mask; const char *device; @@ -179,8 +200,6 @@ int tpm2_parse_pcr_argument(const char *arg, uint32_t *mask); int tpm2_load_pcr_signature(const char *path, JsonVariant **ret); int tpm2_load_pcr_public_key(const char *path, void **ret_pubkey, size_t *ret_pubkey_size); -int pcr_mask_to_string(uint32_t mask, char **ret); - int tpm2_util_pbkdf2_hmac_sha256(const void *pass, size_t passlen, const void *salt, diff --git a/src/test/test-tpm2.c b/src/test/test-tpm2.c index 04e08490b3..23277449b5 100644 --- a/src/test/test-tpm2.c +++ b/src/test/test-tpm2.c @@ -3,29 +3,29 @@ #include "tpm2-util.h" #include "tests.h" -static void test_tpm2_parse_pcrs_one(const char *s, uint32_t mask, int ret) { +static void test_tpm2_pcr_mask_from_string_one(const char *s, uint32_t mask, int ret) { uint32_t m; - assert_se(tpm2_parse_pcrs(s, &m) == ret); + assert_se(tpm2_pcr_mask_from_string(s, &m) == ret); if (ret >= 0) assert_se(m == mask); } -TEST(tpm2_parse_pcrs) { - test_tpm2_parse_pcrs_one("", 0, 0); - test_tpm2_parse_pcrs_one("0", 1, 0); - test_tpm2_parse_pcrs_one("1", 2, 0); - test_tpm2_parse_pcrs_one("0,1", 3, 0); - test_tpm2_parse_pcrs_one("0+1", 3, 0); - test_tpm2_parse_pcrs_one("0-1", 0, -EINVAL); - test_tpm2_parse_pcrs_one("0,1,2", 7, 0); - test_tpm2_parse_pcrs_one("0+1+2", 7, 0); - test_tpm2_parse_pcrs_one("0+1,2", 7, 0); - test_tpm2_parse_pcrs_one("0,1+2", 7, 0); - test_tpm2_parse_pcrs_one("0,2", 5, 0); - test_tpm2_parse_pcrs_one("0+2", 5, 0); - test_tpm2_parse_pcrs_one("foo", 0, -EINVAL); +TEST(tpm2_mask_from_string) { + test_tpm2_pcr_mask_from_string_one("", 0, 0); + test_tpm2_pcr_mask_from_string_one("0", 1, 0); + test_tpm2_pcr_mask_from_string_one("1", 2, 0); + test_tpm2_pcr_mask_from_string_one("0,1", 3, 0); + test_tpm2_pcr_mask_from_string_one("0+1", 3, 0); + test_tpm2_pcr_mask_from_string_one("0-1", 0, -EINVAL); + test_tpm2_pcr_mask_from_string_one("0,1,2", 7, 0); + test_tpm2_pcr_mask_from_string_one("0+1+2", 7, 0); + test_tpm2_pcr_mask_from_string_one("0+1,2", 7, 0); + test_tpm2_pcr_mask_from_string_one("0,1+2", 7, 0); + test_tpm2_pcr_mask_from_string_one("0,2", 5, 0); + test_tpm2_pcr_mask_from_string_one("0+2", 5, 0); + test_tpm2_pcr_mask_from_string_one("foo", 0, -EINVAL); } TEST(tpm2_util_pbkdf2_hmac_sha256) {