From 66d2c693acb820467a7cc92fa0a5ef2aade2d9e4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 12 Dec 2024 11:01:00 +0900 Subject: [PATCH 1/4] tpm2-util: allow to control if legend and/or footer shown by tpm2_list_devices() --- src/creds/creds.c | 2 +- src/cryptenroll/cryptenroll.c | 2 +- src/measure/measure.c | 2 +- src/pcrextend/pcrextend.c | 2 +- src/repart/repart.c | 2 +- src/shared/tpm2-util.c | 6 ++++-- src/shared/tpm2-util.h | 2 +- src/tpm2-setup/tpm2-setup.c | 2 +- 8 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/creds/creds.c b/src/creds/creds.c index 7635aee37ca..866fcd63671 100644 --- a/src/creds/creds.c +++ b/src/creds/creds.c @@ -911,7 +911,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_TPM2_DEVICE: if (streq(optarg, "list")) - return tpm2_list_devices(); + return tpm2_list_devices(arg_legend, arg_quiet); arg_tpm2_device = streq(optarg, "auto") ? NULL : optarg; break; diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index 3fb58c2874b..a3ca50fd0d6 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -493,7 +493,7 @@ static int parse_argv(int argc, char *argv[]) { _cleanup_free_ char *device = NULL; if (streq(optarg, "list")) - return tpm2_list_devices(); + return tpm2_list_devices(/* legend = */ true, /* quiet = */ false); if (arg_enroll_type >= 0 || arg_tpm2_device) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/measure/measure.c b/src/measure/measure.c index e583444e0bf..22dd1831253 100644 --- a/src/measure/measure.c +++ b/src/measure/measure.c @@ -295,7 +295,7 @@ static int parse_argv(int argc, char *argv[]) { _cleanup_free_ char *device = NULL; if (streq(optarg, "list")) - return tpm2_list_devices(); + return tpm2_list_devices(/* legend = */ true, /* quiet = */ false); if (!streq(optarg, "auto")) { device = strdup(optarg); diff --git a/src/pcrextend/pcrextend.c b/src/pcrextend/pcrextend.c index 6bdb5418b53..ef4d1a1f178 100644 --- a/src/pcrextend/pcrextend.c +++ b/src/pcrextend/pcrextend.c @@ -131,7 +131,7 @@ static int parse_argv(int argc, char *argv[]) { _cleanup_free_ char *device = NULL; if (streq(optarg, "list")) - return tpm2_list_devices(); + return tpm2_list_devices(/* legend = */ true, /* quiet = */ false); if (!streq(optarg, "auto")) { device = strdup(optarg); diff --git a/src/repart/repart.c b/src/repart/repart.c index 7e6fd2a29a4..e485cd5231d 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -8160,7 +8160,7 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY * _cleanup_free_ char *device = NULL; if (streq(optarg, "list")) - return tpm2_list_devices(); + return tpm2_list_devices(/* legend = */ true, /* quiet = */ false); if (!streq(optarg, "auto")) { device = strdup(optarg); diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 36a0f906daa..252136af3e1 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -6165,7 +6165,7 @@ int tpm2_unseal_data( } #endif /* HAVE_TPM2 */ -int tpm2_list_devices(void) { +int tpm2_list_devices(bool legend, bool quiet) { #if HAVE_TPM2 _cleanup_(table_unrefp) Table *t = NULL; _cleanup_closedir_ DIR *d = NULL; @@ -6179,6 +6179,8 @@ int tpm2_list_devices(void) { if (!t) return log_oom(); + (void) table_set_header(t, legend); + d = opendir("/sys/class/tpmrm"); if (!d) { log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open /sys/class/tpmrm: %m"); @@ -6224,7 +6226,7 @@ int tpm2_list_devices(void) { } } - if (table_isempty(t)) { + if (table_isempty(t) && !quiet) { log_info("No suitable TPM2 devices found."); return 0; } diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 77cd7dbcaf7..76b4dd3cc15 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -385,7 +385,7 @@ static inline int tpm2_pcrlock_search_file(const char *path, FILE **ret_file, ch #endif /* HAVE_TPM2 */ -int tpm2_list_devices(void); +int tpm2_list_devices(bool legend, bool quiet); int tpm2_find_device_auto(char **ret); int tpm2_make_pcr_json_array(uint32_t pcr_mask, sd_json_variant **ret); diff --git a/src/tpm2-setup/tpm2-setup.c b/src/tpm2-setup/tpm2-setup.c index ee9d243d5ee..ab5bd9bff9d 100644 --- a/src/tpm2-setup/tpm2-setup.c +++ b/src/tpm2-setup/tpm2-setup.c @@ -91,7 +91,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_TPM2_DEVICE: if (streq(optarg, "list")) - return tpm2_list_devices(); + return tpm2_list_devices(/* legend = */ true, /* quiet = */ false); if (free_and_strdup(&arg_tpm2_device, streq(optarg, "auto") ? NULL : optarg) < 0) return log_oom(); From 2a92e0bc6c17bdd4cb1afbc657267c40514226d1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 12 Dec 2024 11:31:16 +0900 Subject: [PATCH 2/4] string-table: make DUMP_STRING_TABLE() returns 0 Then, we can use it as === return DUMP_STRING_TABLE(...); === --- src/basic/string-table.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/basic/string-table.h b/src/basic/string-table.h index 639443d02b3..83891eeb738 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -101,7 +101,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static) #define DUMP_STRING_TABLE(name,type,max) \ - do { \ + ({ \ flockfile(stdout); \ for (type _k = 0; _k < (max); _k++) { \ const char *_t; \ @@ -112,4 +112,5 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k fputc_unlocked('\n', stdout); \ } \ funlockfile(stdout); \ - } while (false) + 0; \ + }) From 831bbaf5cd2f4a38bc71751b55482032fc0b4186 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 12 Dec 2024 11:37:36 +0900 Subject: [PATCH 3/4] creds: support --transcode=help and --with-key=help --- man/systemd-creds.xml | 6 ++- src/creds/creds.c | 88 +++++++++++++++++++++++++++++++++---------- 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/man/systemd-creds.xml b/man/systemd-creds.xml index 8f972eeffba..e88cbb5e6f4 100644 --- a/man/systemd-creds.xml +++ b/man/systemd-creds.xml @@ -234,7 +234,8 @@ When specified with the cat or decrypt commands, transcodes the output before showing it. Takes one of base64, unbase64, hex or unhex as argument, in order - to encode/decode the credential data with Base64 or as series of hexadecimal values. + to encode/decode the credential data with Base64 or as series of hexadecimal values. The special + value help may be used to list supported transcode types. Note that this has no effect on the encrypt command, as encrypted credentials are unconditionally encoded in Base64. @@ -340,7 +341,8 @@ information). If set to auto-initrd a TPM2 key is used if a TPM2 is found. If not a fixed zero length key is used, equivalent to null mode. This option is particularly useful to generate credentials files that are encrypted/authenticated against TPM2 where - available but still work on systems lacking support for this. + available but still work on systems lacking support for this. The special value + help may be used to list supported key types. The switch is a shortcut for . Similar, is a shortcut for . diff --git a/src/creds/creds.c b/src/creds/creds.c index 866fcd63671..bf76e4acf08 100644 --- a/src/creds/creds.c +++ b/src/creds/creds.c @@ -77,7 +77,53 @@ static const char* transcode_mode_table[_TRANSCODE_MAX] = { [TRANSCODE_UNHEX] = "unhex", }; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(transcode_mode, TranscodeMode); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(transcode_mode, TranscodeMode); + +typedef enum CredKeyType { + CRED_KEY_TYPE_AUTO, + CRED_KEY_TYPE_AUTO_INITRD, + CRED_KEY_TYPE_HOST, + CRED_KEY_TYPE_TPM2, + CRED_KEY_TYPE_TPM2_PUBLIC, + CRED_KEY_TYPE_HOST_TPM2, + CRED_KEY_TYPE_TPM2_HOST, + CRED_KEY_TYPE_HOST_TPM2_PUBLIC, + CRED_KEY_TYPE_TPM2_PUBLIC_HOST, + CRED_KEY_TYPE_NULL, + CRED_KEY_TYPE_ABSENT, + _CRED_KEY_TYPE_MAX, + _CRED_KEY_TYPE_INVALID = -EINVAL, +} CredKeyType; + +static const char* cred_key_type_table[_CRED_KEY_TYPE_MAX] = { + [CRED_KEY_TYPE_AUTO] = "auto", + [CRED_KEY_TYPE_AUTO_INITRD] = "auto-initrd", + [CRED_KEY_TYPE_HOST] = "host", + [CRED_KEY_TYPE_TPM2] = "tpm2", + [CRED_KEY_TYPE_TPM2_PUBLIC] = "tpm2-with-public-key", + [CRED_KEY_TYPE_HOST_TPM2] = "host+tpm2", + [CRED_KEY_TYPE_TPM2_HOST] = "tpm2+host", + [CRED_KEY_TYPE_HOST_TPM2_PUBLIC] = "host+tpm2-with-public-key", + [CRED_KEY_TYPE_TPM2_PUBLIC_HOST] = "tpm2-with-public-key+host", + [CRED_KEY_TYPE_NULL] = "null", + [CRED_KEY_TYPE_ABSENT] = "tpm2-absent", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(cred_key_type, CredKeyType); + +static sd_id128_t cred_key_id[_CRED_KEY_TYPE_MAX] = { + [CRED_KEY_TYPE_AUTO] = _CRED_AUTO, + [CRED_KEY_TYPE_AUTO_INITRD] = _CRED_AUTO_INITRD, + [CRED_KEY_TYPE_HOST] = CRED_AES256_GCM_BY_HOST, + [CRED_KEY_TYPE_TPM2] = CRED_AES256_GCM_BY_TPM2_HMAC, + [CRED_KEY_TYPE_TPM2_PUBLIC] = CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK, + [CRED_KEY_TYPE_HOST_TPM2] = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, + [CRED_KEY_TYPE_TPM2_HOST] = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC, + [CRED_KEY_TYPE_HOST_TPM2_PUBLIC] = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, + [CRED_KEY_TYPE_TPM2_PUBLIC_HOST] = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK, + [CRED_KEY_TYPE_NULL] = CRED_AES256_GCM_BY_NULL, + [CRED_KEY_TYPE_ABSENT] = CRED_AES256_GCM_BY_NULL, +}; static int open_credential_directory( bool encrypted, @@ -849,6 +895,13 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_TRANSCODE: + if (streq(optarg, "help")) { + if (arg_legend) + puts("Supported transcode types:"); + + return DUMP_STRING_TABLE(transcode_mode, TranscodeMode, _TRANSCODE_MAX); + } + if (parse_boolean(optarg) == 0) /* If specified as "false", turn transcoding off */ arg_transcode = TRANSCODE_OFF; else { @@ -880,25 +933,22 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_WITH_KEY: - if (isempty(optarg) || streq(optarg, "auto")) - arg_with_key = _CRED_AUTO; - else if (streq(optarg, "auto-initrd")) - arg_with_key = _CRED_AUTO_INITRD; - else if (streq(optarg, "host")) - arg_with_key = CRED_AES256_GCM_BY_HOST; - else if (streq(optarg, "tpm2")) - arg_with_key = CRED_AES256_GCM_BY_TPM2_HMAC; - else if (streq(optarg, "tpm2-with-public-key")) - arg_with_key = CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK; - else if (STR_IN_SET(optarg, "host+tpm2", "tpm2+host")) - arg_with_key = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC; - else if (STR_IN_SET(optarg, "host+tpm2-with-public-key", "tpm2-with-public-key+host")) - arg_with_key = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK; - else if (STR_IN_SET(optarg, "null", "tpm2-absent")) - arg_with_key = CRED_AES256_GCM_BY_NULL; - else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown key type: %s", optarg); + if (streq(optarg, "help")) { + if (arg_legend) + puts("Supported key types:"); + return DUMP_STRING_TABLE(cred_key_type, CredKeyType, _CRED_KEY_TYPE_MAX); + } + + if (isempty(optarg)) + arg_with_key = _CRED_AUTO; + else { + CredKeyType t = cred_key_type_from_string(optarg); + if (t < 0) + return log_error_errno(t, "Failed to parse key type: %m"); + + arg_with_key = cred_key_id[t]; + } break; case 'H': From 54944339e50a0032ed913430fec1960ba094dfa2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 12 Dec 2024 11:51:36 +0900 Subject: [PATCH 4/4] bash-completion/creds: generate suggestions by systemd-creds itself Follow-ups for 783f794e89996ae7f2ae1872d65c515a672437fa. --- shell-completion/bash/systemd-creds | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shell-completion/bash/systemd-creds b/shell-completion/bash/systemd-creds index 310106b936e..c16619e94f0 100644 --- a/shell-completion/bash/systemd-creds +++ b/shell-completion/bash/systemd-creds @@ -25,10 +25,9 @@ __contains_word() { } __get_tpm2_devices() { - local i - for i in /dev/tpmrm*; do - [ -c "$i" ] && printf '%s\n' "$i" - done + local a b c + systemd-creds --no-legend --quiet --tpm2-device=list 2>/dev/null | \ + { while read -r a b c; do echo " $a"; done } } __get_creds() { @@ -129,10 +128,10 @@ _systemd_creds() { comps=$( systemd-creds --json=help 2>/dev/null ) ;; --transcode) - comps='base64 unbase64 hex unhex' + comps=$( systemd-creds --no-legend --transcode=help 2>/dev/null ) ;; --with-key) - comps='host tpm2 host+tpm2 null auto auto-initrd' + comps=$( systemd-creds --no-legend --with-key=help 2>/dev/null ) ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") )