s390-tools/s390-tools-02-zkey-Add-the--pvsecrets-list-command.patch
Nikolay Gueorguiev 7869bc9d34 - Applied additional patches ( jsc#PED-9561 ( jsc#IBM-1447 ) )
* s390-tools-01-zkey-Add-support-for-retrieving-a-list-of-ultravisor-secrets.patch
  * s390-tools-02-zkey-Add-the--pvsecrets-list-command.patch
  * s390-tools-03-zkey-Add-PVSECRETS-AES-key-type.patch
  * s390-tools-04-zkey-Add-the-pvsecrets-import-command.patch
  * s390-tools-05-zkey-Reject-key-generation-and-APQN-association-for-PVSECRET-AES-keys.patch
  * s390-tools-06-zkey-Reject-re-enciphering-of-PVSECRET-AES-keys.patch
  * s390-tools-07-zkey-Support-validation-of-key-of-type-PVSECRET-AES.patch
- Revendored vendor.tar.gz

OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=245
2025-01-30 08:40:14 +00:00

824 lines
25 KiB
Diff

From 5ce79ea667ea946e6591fe898db13becad018667 Mon Sep 17 00:00:00 2001
From: Ingo Franzki <ifranzki@linux.ibm.com>
Date: Thu, 15 Feb 2024 11:22:04 +0100
Subject: [PATCH] zkey: Add the 'pvsecrets list' command
The 'pvsecrets list' command lists the available protected virtualization
secrets. By default, only those pvsecret types are listed, that can be used
with zkey. If option '--all/-a' is specified, then all pvsecret types are
listed. Nevertheless, pvsecret types not supported by zkey can not be used
with zkey.
This command only works when running in a secure execution guest.
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jorg Schmidbauer <jschmidb@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
zkey/pvsecrets.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++
zkey/pvsecrets.h | 4 +
zkey/zkey.1 | 91 ++++++++++-
zkey/zkey.c | 135 +++++++++++++++-
4 files changed, 619 insertions(+), 4 deletions(-)
diff --git a/zkey/pvsecrets.c b/zkey/pvsecrets.c
index 2874fdf1..7f28feba 100644
--- a/zkey/pvsecrets.c
+++ b/zkey/pvsecrets.c
@@ -7,6 +7,7 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
+#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -17,14 +18,60 @@
#include <sys/types.h>
#include <unistd.h>
+#include <openssl/sha.h>
+
#include "lib/util_base.h"
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_panic.h"
#include "lib/util_path.h"
+#include "lib/util_rec.h"
#include "pvsecrets.h"
+struct pvsecret_type_info {
+ u16 type;
+ const char *name;
+ bool zkey_usage;
+};
+
+static const struct pvsecret_type_info pvsecret_type_info[] = {
+ { .type = UV_SECRET_TYPE_NULL, .name = "NULL",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_AP_ASSOCIATION, .name = "AP-ASSOCIATION",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_PLAIN_TEXT, .name = "PLAIN-TEXT",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_AES_128, .name = "AES-128",
+ .zkey_usage = true },
+ { .type = UV_SECRET_TYPE_AES_192, .name = "AES-192",
+ .zkey_usage = true },
+ { .type = UV_SECRET_TYPE_AES_256, .name = "AES-256",
+ .zkey_usage = true },
+ { .type = UV_SECRET_TYPE_AES_XTS_128, .name = "AES-XTS-128",
+ .zkey_usage = true },
+ { .type = UV_SECRET_TYPE_AES_XTS_256, .name = "AES-XTS-256",
+ .zkey_usage = true },
+ { .type = UV_SECRET_TYPE_HMAC_SHA_256, .name = "HMAC-SHA-256",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_HMAC_SHA_512, .name = "HMAC-SHA-512",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_ECDSA_P256, .name = "ECDSA-P256",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_ECDSA_P384, .name = "ECDSA-P384",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_ECDSA_P521, .name = "ECDSA-P521",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_EDDSA_ED25519, .name = "EDDSA-ED25519",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_EDDSA_ED448, .name = "EDDSA-ED448",
+ .zkey_usage = false },
+ { .type = UV_SECRET_TYPE_INVALID, }
+};
+
+#define PVSECRETS_REC_ID "Secret ID"
+#define PVSECRETS_REC_TYPE "Type"
+
#define pr_verbose(verbose, fmt...) do { \
if (verbose) \
warnx(fmt); \
@@ -159,3 +206,349 @@ static int uv_list_secrets(int uv_fd, int (*cb)(u16 idx, u16 type, u32 len,
return rc;
}
+
+/**
+ * Returns true if the secret type is supported by zkey
+ *
+ * @param type the secret type
+ *
+ * @returns true if the type is supported, false otherwise
+ */
+static bool is_pvsecret_type_supported(u16 type)
+{
+ unsigned int i;
+
+ for (i = 0; pvsecret_type_info[i].type != UV_SECRET_TYPE_INVALID; i++) {
+ if (pvsecret_type_info[i].type == type)
+ return pvsecret_type_info[i].zkey_usage;
+ }
+
+ return false;
+}
+
+/**
+ * Returns the secret type name for the specified secret type
+ *
+ * @param type the secret type
+ *
+ * @returns a constant string containing the type name
+ */
+static const char *get_pvsecret_type_name(u16 type)
+{
+ unsigned int i;
+
+ for (i = 0; pvsecret_type_info[i].type != UV_SECRET_TYPE_INVALID; i++) {
+ if (pvsecret_type_info[i].type == type)
+ return pvsecret_type_info[i].name;
+ }
+
+ return "[UNKNOWN]";
+}
+
+/**
+ * Returns the secret type for the specified type name
+ *
+ * @param name the secret type name
+ *
+ * @returns the secret type or UV_SECRET_TYPE_INVALID if unknown.
+ */
+static u16 get_pvsecret_type_by_name(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; pvsecret_type_info[i].type != UV_SECRET_TYPE_INVALID; i++) {
+ if (strcasecmp(pvsecret_type_info[i].name, name) == 0)
+ return pvsecret_type_info[i].type;
+ }
+
+ return UV_SECRET_TYPE_INVALID;
+}
+
+/**
+ * Parses a 32 byte hex string into a 32 byte binary secret ID
+ *
+ * @param id_str the hex string to parse
+ * @param id the output buffer to store the secret ID
+ *
+ * @returns 0 for success or a negative errno in case of an error
+ */
+static int parse_secret_id_str(const char *id_str,
+ unsigned char id[UV_SECRET_ID_LEN])
+{
+ char hex[3] = { 0 };
+ unsigned long val;
+ unsigned int i;
+ char *endptr;
+
+ util_assert(id_str != NULL, "Internal error: id_str is NULL");
+ util_assert(id != NULL, "Internal error: id is NULL");
+
+ if (strncasecmp(id_str, "0x", 2) == 0)
+ id_str += 2;
+
+ if (strlen(id_str) != UV_SECRET_ID_LEN * 2)
+ return -EINVAL;
+
+ for (i = 0; i < UV_SECRET_ID_LEN; i++) {
+ hex[0] = id_str[i * 2];
+ hex[1] = id_str[i * 2 + 1];
+
+ errno = 0;
+ val = strtoul(hex, &endptr, 16);
+ if (errno != 0 || *endptr != '\0' || val > 0xff)
+ return -EINVAL;
+
+ id[i] = val;
+ }
+
+ return 0;
+}
+
+/**
+ * Get the 32 byte binary secret ID from the secret name by calculating the
+ * SHA-256 has from the name.
+ *
+ * @param name the name of the secret
+ * @param id the output buffer to store the secret ID
+ *
+ * @returns 0 for success or a negative errno in case of an error
+ */
+static int get_secret_id_from_name(const char *name,
+ unsigned char id[UV_SECRET_ID_LEN])
+{
+ util_assert(name != NULL, "Internal error: id_str is NULL");
+ util_assert(id != NULL, "Internal error: id is NULL");
+ util_assert(UV_SECRET_ID_LEN == SHA256_DIGEST_LENGTH,
+ "Internal error: UV_SECRET_ID_LEN != SHA256_DIGEST_LENGTH");
+
+ if (SHA256((const unsigned char *)name, strlen(name), id) != id)
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * Gets the binary 32 byte secret id from either a hex string or a secret name.
+ *
+ * @param hex the secret id as hex string. Can be NULL.
+ * @param name the secret name. Can be NULL. If the id
+ * parameter is non-NULL, then this parameter is
+ * ignored.
+ * @param id Output: the 32 byte binary secret id.
+ * @param id_str Output: the secret id in printable ascii chars
+ * form, if name is non-NULL and the name length is
+ * less than UV_SECRET_ID_LEN.
+ *
+ * @returns 0 on success, a negative errno in case of an error.
+ * If neither the hex string nor the secret name is specified, 1 is returned,
+ * and the id parameter is not modified.
+ */
+static int get_secret_id_from_hex_or_name(const char *hex, const char *name,
+ unsigned char id[UV_SECRET_ID_LEN],
+ char id_name[UV_SECRET_ID_LEN])
+{
+ int rc;
+
+ util_assert(id != NULL, "Internal error: id is NULL");
+
+ if (hex != NULL) {
+ rc = parse_secret_id_str(hex, id);
+ if (rc != 0) {
+ warnx("Invalid pvsecret id specified: '%s'", hex);
+ return rc;
+ }
+
+ return 0;
+ }
+
+ if (name != NULL) {
+ rc = get_secret_id_from_name(name, id);
+ if (rc != 0) {
+ warnx("Failed to get the ID from pvsecret name: '%s'",
+ name);
+ return rc;
+ }
+
+ if (strlen(name) < UV_SECRET_ID_LEN) {
+ strncpy(id_name, name, UV_SECRET_ID_LEN);
+ id_name[UV_SECRET_ID_LEN - 1] = '\0';
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Checks if the secret id is printable. To be printable, all characters up to
+ * the first zero byte must be printable. All bytes after the first zero byte
+ * must be all zero. There must be at least one zero byte as the very last byte
+ * of the id.
+ *
+ * @param id the ID of the secret
+ * @param name Output: the id in the printable form and enclosed
+ * in single quotes if the id is printable. The max
+ * length of the name buffer is UV_SECRET_ID_LEN + 2:
+ * A starting quote, up to UV_SECRET_ID_LEN-1 chars,
+ * an ending quote and a zero termination byte.
+ *
+ * @returns true if the id is printable, false otherwise.
+ */
+static bool is_printable_name(const u8 id[UV_SECRET_ID_LEN],
+ char name[UV_SECRET_ID_LEN + 2])
+{
+ bool end_found = false, printable_name = false;
+ unsigned int i;
+
+ name[0] = '\'';
+ for (i = 0; i < UV_SECRET_ID_LEN; i++) {
+ if (!end_found) {
+ if (id[i] == '\0') {
+ name[1 + i] = '\'';
+ end_found = true;
+ } else if (isprint(id[i])) {
+ name[1 + i] = id[i];
+ printable_name = true;
+ } else {
+ printable_name = false;
+ end_found = true;
+ }
+ } else if (id[i] != '\0') {
+ printable_name = false;
+ }
+ }
+ if (!end_found)
+ printable_name = false;
+
+ return printable_name;
+}
+
+struct list_secrets_data {
+ struct util_rec *rec;
+ bool all;
+ bool hex;
+ u16 type_filter;
+ bool id_filter;
+ char name[UV_SECRET_ID_LEN];
+ unsigned char id[UV_SECRET_ID_LEN];
+ unsigned int matched;
+};
+
+/**
+ * Callback used with pvsecrets_list function. Called for each secret.
+ *
+ * @param idx the index of the secret
+ * @param type the type of the secret
+ * @param id the ID of the secret
+ * @param cb_private callback private data
+ *
+ * @returns 0 on success, a negative errno in case of an error
+ */
+static int pvsecrets_list_cb(u16 UNUSED(idx), u16 type, u32 UNUSED(len),
+ const u8 id[UV_SECRET_ID_LEN], void *cb_private)
+{
+ struct list_secrets_data *list_data = cb_private;
+ char name[2 + UV_SECRET_ID_LEN] = { 0 };
+ char hex[2 * UV_SECRET_ID_LEN + 1] = { 0 };
+ unsigned int i;
+
+ if (!list_data->all && !is_pvsecret_type_supported(type))
+ return 0;
+
+ if (list_data->type_filter != 0 && type != list_data->type_filter)
+ return 0;
+
+ if (list_data->id_filter &&
+ memcmp(id, list_data->name, UV_SECRET_ID_LEN) != 0 &&
+ memcmp(id, list_data->id, UV_SECRET_ID_LEN) != 0)
+ return 0;
+
+ for (i = 0; i < UV_SECRET_ID_LEN; i++)
+ sprintf(&hex[i * 2], "%02x", id[i]);
+
+ if (!list_data->hex && is_printable_name(id, name))
+ util_rec_set(list_data->rec, PVSECRETS_REC_ID, name);
+ else
+ util_rec_set(list_data->rec, PVSECRETS_REC_ID, hex);
+ util_rec_set(list_data->rec, PVSECRETS_REC_TYPE,
+ get_pvsecret_type_name(type));
+
+ if (list_data->matched == 0)
+ util_rec_print_hdr(list_data->rec);
+
+ util_rec_print(list_data->rec);
+
+ list_data->matched++;
+
+ return 0;
+}
+
+/**
+ * Lists protected virtualization secrets.
+ *
+ * @param uv_fd the file descriptor of the ultravisor device
+ * @param all if true, all secret types are listed
+ * @param hex if true, list the secret ID in hex, even if the
+ * secret ID would be printable
+ * @param type_filter only display secrets of the specified secret type.
+ * Can be NULL.
+ * @param secret_id the secret id to list. Can be NULL.
+ * @param secret_name the secret name to list. Can be NULL. If the id
+ * parameter is non-NULL, then this parameter is
+ * ignored.
+ * @param verbose if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error
+ */
+int pvsecrets_list(int uv_fd, bool all, bool hex, const char *type_filter,
+ const char *secret_id, const char *secret_name,
+ bool verbose)
+{
+ struct list_secrets_data list_data = { 0 };
+ int rc;
+
+ util_assert(uv_fd != -1, "Internal error: uv_fd is -1");
+
+ list_data.all = all;
+ list_data.hex = hex;
+ list_data.type_filter = UV_SECRET_TYPE_INVALID;
+
+ if (type_filter != NULL) {
+ list_data.type_filter = get_pvsecret_type_by_name(type_filter);
+ if (list_data.type_filter == UV_SECRET_TYPE_INVALID) {
+ warnx("Invalid pvsecret type specified: %s",
+ type_filter);
+ return -EINVAL;
+ }
+ }
+
+ if (secret_id != NULL || secret_name != NULL) {
+ rc = get_secret_id_from_hex_or_name(secret_id, secret_name,
+ list_data.id,
+ list_data.name);
+ if (rc < 0)
+ return rc;
+
+ list_data.id_filter = true;
+ }
+
+ list_data.rec = util_rec_new_wide("-");
+ util_rec_def(list_data.rec, PVSECRETS_REC_ID, UTIL_REC_ALIGN_LEFT,
+ UV_SECRET_ID_LEN * 2, PVSECRETS_REC_ID);
+ util_rec_def(list_data.rec, PVSECRETS_REC_TYPE, UTIL_REC_ALIGN_LEFT,
+ 12, PVSECRETS_REC_TYPE);
+
+ rc = uv_list_secrets(uv_fd, pvsecrets_list_cb, &list_data, verbose);
+ if (rc != 0) {
+ warnx("Failed to list protected virtualization secrets: %s",
+ strerror(-rc));
+ }
+
+ util_rec_free(list_data.rec);
+
+ if (list_data.matched == 0)
+ rc = -ENOENT;
+
+ return rc;
+}
diff --git a/zkey/pvsecrets.h b/zkey/pvsecrets.h
index 2667e859..6acebfdd 100644
--- a/zkey/pvsecrets.h
+++ b/zkey/pvsecrets.h
@@ -86,4 +86,8 @@ struct uvio_list_secrets {
int uv_open_device(bool verbose);
+int pvsecrets_list(int uv_fd, bool all, bool hex, const char *type_filter,
+ const char *secret_id, const char *secret_name,
+ bool verbose);
+
#endif
diff --git a/zkey/zkey.1 b/zkey/zkey.1
index 8c5a09a7..4386629f 100644
--- a/zkey/zkey.1
+++ b/zkey/zkey.1
@@ -1,8 +1,8 @@
-.\" Copyright IBM Corp. 2017, 2020
+.\" Copyright IBM Corp. 2017, 2024
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
-.TH ZKEY 1 "July 2020" "s390-tools"
+.TH ZKEY 1 "February 2024" "s390-tools"
.SH NAME
zkey \- Manage secure AES keys
.
@@ -1162,6 +1162,54 @@ fails. Use option \fB\-\-no\-volume\-check\fP to omit the volume check, and
refresh the keys even if the associated volume(s) do not exist.
.
.
+.SH COMMANDS FOR PROTECTED VIRTUALIZATION
+.
+Use the \fBpvsecrets\fP command to work with protected virtualization (PV)
+secrets. Protected virtualization secrets can be made available to a secure
+execution guest and can be used only within that guest.
+The \fBpvsecrets\fP command provides subcommands for protected
+virtualization specific operations. Use \fBzkey pvsecrets \-\-help\fP to show
+the available subcommands. These subcommands only work when running in a
+secure execution guest. Only the \fBroot\fP user is allowed to perform these
+subcommands.
+.
+.SS "List available protected virtualization secrets"
+.
+.B zkey pvsecrets
+.BR list | li
+.RB [ \-\-all | \-A ]
+.RB [ \-\-hex | \-H ]
+.RB [ \-\-pvsecret\-type | \-T
+.IR pvsecret\-type ]
+.RB [ \-\-pvsecret\-id | \-I
+.IR pvsecret\-id ]
+.RB [ \-\-pvsecret\-name | \-e
+.IR pvsecret\-name ]
+.RB [ \-\-verbose | \-V ]
+.
+.PP
+Use the
+.B pvsecrets list
+command to display a list of protected virtualization (PV) secrets. It displays
+the pvsecret ID as hex string of 32 bytes or as printable name enclosed in
+single quotes (\fB'\fP), if the pvsecret ID consists of only printable
+characters. Specify the \fB\-\-hex\fP option to list all pvsecret IDs as hex
+string. The
+.B pvsecrets list
+command also shows the pvsecret type of each secret.
+.PP
+You can filter the list of pvsecrets by pvsecret ID, pvsecret name and pvsecret
+type. Either the \fB\-\-pvsecret\-id\fP option or the
+\fB\-\-pvsecret\-name\fP option can be specified. By default the
+\fBpvsecrets list\fP command displays only those pvsecrets with types that
+are supported by the \fBzkey\fP tool. To list all pvsecret types, specify the
+\fB\-\-all\fP option.
+.PP
+This command is only available when running in a secure execution guest.
+Only the \fBroot\fP user is allowed to perform this command.
+.
+.
+.
.
.SH OPTIONS
.SS "Options for the generate command"
@@ -2030,6 +2078,45 @@ repository. This option only has an effect when specified together with option
.
.
.
+.SS "Options for the pvsecrets list command"
+.TP
+.BR \-A ", " \-\-all
+List all protected virtualization (PV) secret types, not only those that can be
+used with zkey.
+.TP
+.BR \-H ", " \-\-hex
+Show all protected virtualization (PV) secret IDs in hex, even if the ID
+contains only printable characters.
+.TP
+.BR \-T ", " \-\-pvsecret\-type\~\fIpvsecret\-type\fP
+Type of the protected virtualization (PV) secret to list. If omitted, all
+secret types are listed. Possible values are: \fBPLAIN\-TEXT\fP, \fBAES\-128\fP,
+\fBAES\-192\fP, \fBAES\-256\fP, \fBAES\-XTS\-128\fP, \fBAES\-XTS\-256\fP,
+\fBHMAC\-SHA\-256\fP, \fBHMAC\-SHA\-512\fP, \fBECDSA\-P256\fP,
+\fBECDSA\-P384\fP, \fBECDSA\-P521\fP, \fBEDDSA\-ED25519\fP, and
+\fBEDDSA\-ED448\fP.
+.TP
+.BR \-I ", " \-\-pvsecret\-id\~\fIpvsecret\-id\fP
+ID of the protected virtualization (PV) secret to list. The pvsecret ID is a 32
+byte hex string, optionally prefixed by \fB0x\fP. You can use the YAML file that
+was created when using the \fBpvsecret create\fP command for adding the
+protected virtualization secret:
+\fB\-\-pvsecret\-id "$(yq .id \fP\fIYAML\-FILE\fP\fB)"\fP.
+You might have to install the \fByq\fP package first.
+Either the \fB\-\-pvsecret\-id\fP option or the \fB\-\-pvsecret\-name\fP option
+can be specified, but not both.
+.TP
+.BR \-e ", " \-\-pvsecret\-name\~\fIpvsecret\-name\fP
+Name of the protected virtualization (PV) secret to list. You can use the YAML
+file that was created when using the \fBpvsecret create\fP command for adding
+the protected virtualization secret:
+\fB\-\-pvsecret\-name "$(yq .name \fP\fIYAML\-FILE\fP\fB)"\fP.
+You might have to install the \fByq\fP package first.
+Either the \fB\-\-pvsecret\-id\fP option or the \fB\-\-pvsecret\-name\fP option
+can be specified, but not both.
+.
+.
+.
.SS "General options"
.TP
.BR \-V ", " \-\-verbose
diff --git a/zkey/zkey.c b/zkey/zkey.c
index 7c909ff0..adc48d60 100644
--- a/zkey/zkey.c
+++ b/zkey/zkey.c
@@ -1,7 +1,7 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
- * Copyright IBM Corp. 2017, 2020
+ * Copyright IBM Corp. 2017, 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -34,6 +34,7 @@
#include "pkey.h"
#include "utils.h"
#include "kms.h"
+#include "pvsecrets.h"
/*
* Program configuration
@@ -46,7 +47,7 @@ static const struct util_prg prg = {
{
.owner = "IBM Corp.",
.pub_first = 2017,
- .pub_last = 2020,
+ .pub_last = 2024,
},
UTIL_PRG_COPYRIGHT_END
}
@@ -93,10 +94,16 @@ static struct zkey_globals {
bool open;
bool format;
bool refresh_properties;
+ bool all;
+ bool hex;
+ char *secret_type;
+ char *secret_id;
+ char *secret_name;
struct ext_lib lib;
struct cca_lib cca;
struct ep11_lib ep11;
int pkey_fd;
+ int uv_fd;
struct keystore *keystore;
struct kms_info kms_info;
int first_kms_option;
@@ -104,6 +111,7 @@ static struct zkey_globals {
size_t num_kms_options;
} g = {
.pkey_fd = -1,
+ .uv_fd = -1,
.sector_size = -1,
.lib.cca = &g.cca,
.lib.ep11 = &g.ep11,
@@ -135,6 +143,8 @@ static struct zkey_globals {
#define COMMAND_KMS_LIST "list"
#define COMMAND_KMS_IMPORT "import"
#define COMMAND_KMS_REFRESH "refresh"
+#define COMMAND_PVSECRETS "pvsecrets"
+#define COMMAND_PVSECRETS_LIST "list"
#define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER"
@@ -1182,6 +1192,48 @@ static struct util_opt opt_vec[] = {
.flags = UTIL_OPT_FLAG_NOSHORT,
},
/***********************************************************/
+ {
+ .flags = UTIL_OPT_FLAG_SECTION,
+ .desc = "OPTIONS",
+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
+ },
+ {
+ .option = {"all", 0, NULL, 'A'},
+ .desc = "List all protected virtualization (PV) secret types, "
+ "not only those that can be used with zkey.",
+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
+ },
+ {
+ .option = {"hex", 0, NULL, 'H'},
+ .desc = "Show all protected virtualization (PV) secret IDs in "
+ "hex, even if the ID contains only printable "
+ "characters.",
+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
+ },
+ {
+ .option = { "pvsecret-type", required_argument, NULL, 'T'},
+ .argument = "PVSECRET-TYPE",
+ .desc = "Type of the protected virtualization (PV) secret to "
+ "list. If omitted, all pvsecret types are listed.",
+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
+ },
+ {
+ .option = { "pvsecret-id", required_argument, NULL, 'I'},
+ .argument = "PVSECRET-ID",
+ .desc = "ID of the protected virtualization (PV) secret to "
+ "list. Either '--pvsecret-id/-I' or "
+ "'--pvsecret-name/-e' can be specified, but not both.",
+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
+ },
+ {
+ .option = { "pvsecret-name", required_argument, NULL, 'e'},
+ .argument = "PVSECRET-NAME",
+ .desc = "Name of the protected virtualization (PV) secret to "
+ "list. Either '--pvsecret-name/-e' or "
+ "'--pvsecret-id/-I' can be specified, but not both.",
+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
+ },
+ /***********************************************************/
OPT_PLACEHOLDER,
OPT_PLACEHOLDER,
OPT_PLACEHOLDER,
@@ -1249,6 +1301,7 @@ struct zkey_command {
int need_cca_library;
int need_ep11_library;
int need_pkey_device;
+ int need_uv_device;
char *short_desc;
char *long_desc;
int has_options;
@@ -1285,6 +1338,7 @@ static int command_kms_reencipher(void);
static int command_kms_list(void);
static int command_kms_import(void);
static int command_kms_refresh(void);
+static int command_pvsecrets_list(void);
static struct zkey_command zkey_kms_commands[] = {
{
@@ -1402,6 +1456,22 @@ static struct zkey_command zkey_kms_commands[] = {
{ .command = NULL }
};
+static struct zkey_command zkey_pvsecrets_commands[] = {
+ {
+ .command = COMMAND_PVSECRETS_LIST,
+ .abbrev_len = 2,
+ .function = command_pvsecrets_list,
+ .short_desc = "Lists protected virtualization (PV) secrets",
+ .long_desc = "Lists available protected virtualization (PV) "
+ "secrets. This command is only available when "
+ "running in a secure execution guest. Only the "
+ "'root' user is allowed to perform this command",
+ .has_options = 1,
+ .need_uv_device = 1,
+ },
+ { .command = NULL }
+};
+
static struct zkey_command zkey_commands[] = {
{
.command = COMMAND_GENERATE,
@@ -1565,6 +1635,21 @@ static struct zkey_command zkey_commands[] = {
.has_options = 1,
.sub_commands = zkey_kms_commands,
},
+ {
+ .command = COMMAND_PVSECRETS,
+ .abbrev_len = 2,
+ .short_desc = "Protected virtualization (PV) support",
+ .long_desc = "Provides subcommands for working with protected "
+ "virtualization (PV) secrets. Protected "
+ "virtualization secrets can be made available to "
+ "a secure execution guest and can be used only "
+ "within that guest. Thus, these subcommands are "
+ "only available when running in a secure "
+ "execution guest. Only the 'root' user is allowed "
+ "to perform these subcommands.",
+ .has_options = 1,
+ .sub_commands = zkey_pvsecrets_commands,
+ },
{ .command = NULL }
};
@@ -2899,6 +2984,28 @@ static int command_kms_refresh(void)
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
+/*
+ * Command handler for 'pvsecrets list'.
+ *
+ * Lists available protected virtualization secrets
+ */
+static int command_pvsecrets_list(void)
+{
+ int rc;
+
+ if (g.secret_id != NULL && g.secret_name != NULL) {
+ warnx("Either '--pvsecret-id/-I' or '--pvsecret-name/-e' can "
+ "be specified, but not both");
+ util_prg_print_parse_error();
+ return EXIT_FAILURE;
+ }
+
+ rc = pvsecrets_list(g.uv_fd, g.all, g.hex, g.secret_type, g.secret_id,
+ g.secret_name, g.verbose);
+
+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
/**
* Opens the keystore. The keystore directory is either the
* default directory or as specified in an environment variable
@@ -3234,6 +3341,21 @@ int main(int argc, char *argv[])
case OPT_REMOVE_DUMMY_PASSPHRASE:
g.remove_passphrase = 1;
break;
+ case 'A':
+ g.all = 1;
+ break;
+ case 'H':
+ g.hex = 1;
+ break;
+ case 'T':
+ g.secret_type = optarg;
+ break;
+ case 'I':
+ g.secret_id = optarg;
+ break;
+ case 'e':
+ g.secret_name = optarg;
+ break;
case 'h':
print_help(command, sub_command);
return EXIT_SUCCESS;
@@ -3294,6 +3416,13 @@ int main(int argc, char *argv[])
goto out;
}
}
+ if (cmd->need_uv_device) {
+ g.uv_fd = uv_open_device(g.verbose);
+ if (g.uv_fd == -1) {
+ rc = EXIT_FAILURE;
+ goto out;
+ }
+ }
if (g.kms_info.plugin_lib != NULL) {
rc = init_kms_plugin(&g.kms_info, g.verbose);
@@ -3323,6 +3452,8 @@ int main(int argc, char *argv[])
dlclose(g.ep11.lib_ep11);
if (g.pkey_fd >= 0)
close(g.pkey_fd);
+ if (g.uv_fd >= 0)
+ close(g.uv_fd);
if (g.keystore)
keystore_free(g.keystore);
if (g.kms_options != NULL)