mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
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>
This commit is contained in:
committed by
Steffen Eiden
parent
8c4b2872b8
commit
5ce79ea667
@@ -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 @@ out:
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user