pvattest: Add --output option to verify subcommand

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 <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Marc Hartmayer
2023-08-01 14:12:25 +00:00
committed by Jan Höppner
parent 5e1ef90962
commit a07d1bca74
5 changed files with 84 additions and 1 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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: