From a07d1bca74753375225a9546d202dfad5aeef2e2 Mon Sep 17 00:00:00 2001 From: Marc Hartmayer Date: Tue, 1 Aug 2023 14:12:25 +0000 Subject: [PATCH] pvattest: Add `--output` option to `verify` subcommand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other tools may need to process the configuration-unique id. Provide a machine readable format by writing to a YAML file containing a `cuid` entry and optionally an `add` entry. New CLI options `--format` and `--output` are introduced for this. Currently, only the output format `yaml` is supported. Reviewed-by: Jan Höppner Signed-off-by: Steffen Eiden Signed-off-by: Marc Hartmayer Signed-off-by: Jan Höppner --- CHANGELOG.md | 1 + pvattest/man/pvattest-verify.1 | 15 +++++++++++++++ pvattest/src/argparse.c | 31 +++++++++++++++++++++++++++++- pvattest/src/argparse.h | 3 +++ pvattest/src/pvattest.c | 35 ++++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58f1af24..98e9de77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Release history for s390-tools (MIT version) Changes of existing tools: - genprotimg: add support for add-secret requests - dbginfo.sh: global IFS variable + - pvattest: add yaml-output for verify command Bug Fixes: diff --git a/pvattest/man/pvattest-verify.1 b/pvattest/man/pvattest-verify.1 index 9ea13fbe..3b235702 100644 --- a/pvattest/man/pvattest-verify.1 +++ b/pvattest/man/pvattest-verify.1 @@ -24,12 +24,27 @@ Show help options \fBFILE\fP specifies the attestation result as input. .TP .B +\fB-o\fP, \fB--ouput\fP=\fBFILE\fP +\fBFILE\fP specifies the output for the verification result. +.TP +.B \fB--hdr\fP=\fBFILE\fP Specify the header of the guest image. Exactly one is required. .TP .B \fB-a\fP, \fB--arpk\fP=\fBFILE\fP Use \fBFILE\fP to specify the GCM-AES256 key to decrypt the attestation request. Delete this key after verification. +.TP +.B +\fB--format\fP=\fByaml\fP +Define the output format. +Default value: 'yaml' + +Possible values: +.RS 4 +- \fByaml\fP: Use YAML format +.RE + .TP .B \fB-V\fP, \fB--verbose\fP diff --git a/pvattest/src/argparse.c b/pvattest/src/argparse.c index 06bf90f8..fe5662f9 100644 --- a/pvattest/src/argparse.c +++ b/pvattest/src/argparse.c @@ -49,8 +49,10 @@ static pvattest_config_t pvattest_config = { }, .verify = { .input_path = NULL, + .output_path = NULL, .hdr_path = NULL, .arp_key_in_path = NULL, + .output_fmt = VERIFY_FMT_YAML, }, }; typedef gboolean (*verify_options_fn_t)(GError **); @@ -329,6 +331,15 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error) .description = "Use FILE to specify the user data.\n", .arg_description = "FILE", \ } +#define _entry__verify_format(__indent) \ + { \ + .long_name = "format", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \ + .arg = G_OPTION_ARG_CALLBACK, .arg_data = &set_verify_output_format, \ + .description = "Define the output format.\n" __indent \ + "Defaults to 'yaml'. (possible values: 'yaml')\n", \ + .arg_description = "FORMAT", \ + } + static gboolean increase_log_lvl(G_GNUC_UNUSED const char *option_name, G_GNUC_UNUSED const char *value, G_GNUC_UNUSED void *data, G_GNUC_UNUSED GError **error) @@ -337,6 +348,20 @@ static gboolean increase_log_lvl(G_GNUC_UNUSED const char *option_name, return TRUE; } +static gboolean set_verify_output_format(const char *option_name, const char *value, + G_GNUC_UNUSED void *data, GError **error) +{ + if (!g_strcmp0(value, "yaml")) { + pvattest_config.verify.output_fmt = VERIFY_FMT_YAML; + } else { + g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + _("Found value '%s' for option '%s', but only 'yaml' is allowed."), + value, option_name); + return FALSE; + } + return TRUE; +} + static gboolean create_set_paf(G_GNUC_UNUSED const char *option_name, const char *value, G_GNUC_UNUSED void *data, GError **error) { @@ -445,13 +470,16 @@ static gboolean verify_perform(GError **error) } /************************* VERIFY OPTIONS ************************************/ -#define verify_indent " " +#define verify_indent " " static GOptionEntry verify_options[] = { _entry_input(&pvattest_config.verify.input_path, "attestation result", verify_indent), + _entry_output(&pvattest_config.verify.output_path, + "verification result.\n" verify_indent "(optional)", verify_indent), _entry_guest_hdr(&pvattest_config.verify.hdr_path, verify_indent), _entry_att_prot_key_load(&pvattest_config.verify.arp_key_in_path, verify_indent), _entry_verbose(verify_indent), + _entry__verify_format(verify_indent), { NULL }, }; @@ -631,6 +659,7 @@ static void pvattest_parse_clear_verify_config(pvattest_verify_config_t *config) if (!config) return; g_free(config->input_path); + g_free(config->output_path); g_free(config->hdr_path); g_free(config->arp_key_in_path); } diff --git a/pvattest/src/argparse.h b/pvattest/src/argparse.h index 1c1bbd39..307772b2 100644 --- a/pvattest/src/argparse.h +++ b/pvattest/src/argparse.h @@ -60,10 +60,13 @@ typedef struct { enum verify_output_format { VERIFY_FMT_HUMAN, + VERIFY_FMT_YAML, }; typedef struct { char *input_path; + char *output_path; + enum verify_output_format output_fmt; char *hdr_path; char *arp_key_in_path; } pvattest_verify_config_t; diff --git a/pvattest/src/pvattest.c b/pvattest/src/pvattest.c index 7c7449c0..f42f1d97 100644 --- a/pvattest/src/pvattest.c +++ b/pvattest/src/pvattest.c @@ -280,6 +280,24 @@ static int fprint_verify_result(FILE *stream, const enum verify_output_format fm return -1; } break; + case VERIFY_FMT_YAML: + if (fprintf(stream, "cuid: ") < 0) + return -1; + if (pvattest_hexdump(stream, config_uid, 0L, "'0x", FALSE) < 0) + return -1; + if (fprintf(stream, _("'\n")) < 0) + return -1; + + if (additional_data) { + if (fprintf(stream, "add: ") < 0) + return -1; + + if (pvattest_hexdump(stream, additional_data, 0x0L, "'0x", FALSE) < 0) + return -1; + if (fprintf(stream, _("'\n")) < 0) + return -1; + } + break; default: g_assert_not_reached(); break; @@ -363,6 +381,23 @@ static int do_verify(const pvattest_verify_config_t *verify_config, const int ap goto err_exit; } } + + /* Write to file */ + if (verify_config->output_path) { + g_autoptr(FILE) output = pv_file_open(verify_config->output_path, "wx", &error); + + if (!output) { + err_prefix = "Failed to write output"; + goto err_exit; + } + if (fprint_verify_result(output, verify_config->output_fmt, config_uid, + additional_data) < 0) { + g_set_error(&error, PV_GLIB_HELPER_ERROR, PV_GLIB_HELPER_FILE_ERROR, + "'%s': %s", verify_config->output_path, g_strerror(errno)); + err_prefix = "Failed to write output"; + goto err_exit; + } + } return EXIT_SUCCESS; err_exit: