diff --git a/s390-tools-01-zipl_helper.device-mapper-add-missed-step-in-logical.patch b/s390-tools-01-zipl_helper.device-mapper-add-missed-step-in-logical.patch deleted file mode 100644 index 0c1282b..0000000 --- a/s390-tools-01-zipl_helper.device-mapper-add-missed-step-in-logical.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 2d26a63806d2847f549c06276070a636a61bcb80 Mon Sep 17 00:00:00 2001 -From: Eduard Shishkin -Date: Wed, 4 Dec 2024 13:37:46 +0100 -Subject: [PATCH s390-tools] zipl_helper.device-mapper: add missed step in - logical device resolution - -This fixes 670bf3e - -Preparing a loop device for IPL by zipl tool, using its partition as -zipl target, leads to inconsistent installation setup. The problem is in -a missed step in the procedure of logical device resolution performed -by the script zipl_helper.device-mapper: - -\# lsblk - -NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT -loop0 7:0 0 5G 0 loop -|-loop0p1 253:15 0 128M 0 part -`-loop0p2 253:16 0 4.9G 0 part /mnt - -\# ./zipl_helper.device-mapper 253:16 - -Expected result: - -targetbase=7:0 -targettype=SCSI -targetblocksize=4096 -targetoffset=32784 - -Actual result: - -targetbase=253:16 -targettype=SCSI -targetblocksize=4096 -targetoffset=32784 - -The fixup adds a missed resolution step. - -Reference-ID: LTC210771 -Signed-off-by: Eduard Shishkin ---- - zipl/src/zipl_helper.device-mapper.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/zipl/src/zipl_helper.device-mapper.c b/zipl/src/zipl_helper.device-mapper.c -index aca52be1..918c5aba 100644 ---- a/zipl/src/zipl_helper.device-mapper.c -+++ b/zipl/src/zipl_helper.device-mapper.c -@@ -1306,13 +1306,13 @@ static int complete_physical_device(struct physical_device *pd, dev_t *base_dev) - *base_dev = base_entry->dev.dev; - } else { - /* -- * In this case base device is the uppermost logical -+ * In this case base device is the uppermost - * device which provides access to boot sectors - */ - base_entry = find_base_entry(pd->dmpath, dc->bootsectors); - if (!base_entry) - return -1; -- *base_dev = base_entry->dev.dev; -+ *base_dev = first_device_by_target_data(base_entry->target); - } - /* Check for valid offset of filesystem */ - if ((pd->offset % (dc->blocksize / SECTOR_SIZE)) != 0) { --- -2.39.0 - diff --git a/s390-tools-01-zkey-Add-support-for-retrieving-a-list-of-ultravisor-secrets.patch b/s390-tools-01-zkey-Add-support-for-retrieving-a-list-of-ultravisor-secrets.patch deleted file mode 100644 index c409126..0000000 --- a/s390-tools-01-zkey-Add-support-for-retrieving-a-list-of-ultravisor-secrets.patch +++ /dev/null @@ -1,299 +0,0 @@ -From 8c4b2872b8e24c1a27d8201beb5979c66ac05268 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Thu, 15 Feb 2024 09:08:43 +0100 -Subject: [PATCH] zkey: Add support for retrieving a list of ultravisor secrets - -Add functions to interface with the ultravisor device (/dev/uv) when -running in a secure execution guest to retrieve a list of available -secrets. - -Signed-off-by: Ingo Franzki -Reviewed-by: Jorg Schmidbauer -Signed-off-by: Steffen Eiden ---- - zkey/Makefile | 4 +- - zkey/pvsecrets.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++ - zkey/pvsecrets.h | 89 ++++++++++++++++++++++++++ - 3 files changed, 253 insertions(+), 1 deletion(-) - create mode 100644 zkey/pvsecrets.c - create mode 100644 zkey/pvsecrets.h - -diff --git a/zkey/Makefile b/zkey/Makefile -index 501c5ebf..cbecf125 100644 ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -92,9 +92,11 @@ keystore.o: keystore.c keystore.h properties.h pkey.h cca.h ep11.h utils.h - zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h cca.h \ - ep11.h misc.h utils.h - kms.o: kms.c kms.h kms-plugin.h utils.h pkey.h -+pvsecrets.o: pvsecrets.h - - zkey: LDLIBS = -ldl -lcrypto --zkey: zkey.o pkey.o cca.o ep11.o properties.o keystore.o utils.o kms.o $(libs) -+zkey: zkey.o pkey.o cca.o ep11.o properties.o keystore.o utils.o kms.o \ -+ pvsecrets.o $(libs) - $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ - - zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c -lcrypto -diff --git a/zkey/pvsecrets.c b/zkey/pvsecrets.c -new file mode 100644 -index 00000000..2874fdf1 ---- /dev/null -+++ b/zkey/pvsecrets.c -@@ -0,0 +1,161 @@ -+/* -+ * zkey - Generate, re-encipher, and validate secure keys -+ * -+ * Copyright IBM Corp. 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 "pvsecrets.h" -+ -+#define pr_verbose(verbose, fmt...) do { \ -+ if (verbose) \ -+ warnx(fmt); \ -+ } while (0) -+ -+/** -+ * Opens the ultravisor device and returns its file descriptor. -+ * This only succeeds when running in a secure execution guest. -+ * A failure of this function indicates that it is not running in a secure -+ * execution guest. -+ * -+ * @param verbose if true, verbose messages are printed -+ * -+ * @returns the file descriptor or -1 to indicate an error -+ */ -+int uv_open_device(bool verbose) -+{ -+ unsigned int pvguest = 0, max_retr_secrets = 0; -+ char *path = NULL; -+ int uv_fd, err; -+ -+ uv_fd = open(UVDEVICE, O_RDWR); -+ if (uv_fd < 0) { -+ err = errno; -+ warnx("File '%s:' %s\n", UVDEVICE, strerror(errno)); -+ if (err == EACCES) -+ warnx("Only the 'root' user is allowed to perform " -+ "this command"); -+ else -+ warnx("Ensure that you are running in a secure " -+ "execution guest, and that the 'uvdevice' " -+ "kernel module is loaded."); -+ return -1; -+ } -+ -+ path = util_path_sysfs(SYSFS_UV); -+ if (util_file_read_ui(&pvguest, 10, SYSFS_UV_PV_GUEST, path) != 0 || -+ pvguest != 1) { -+ warnx("You are not running in a secure execution guest."); -+ goto error; -+ } -+ -+ if (util_file_read_ui(&max_retr_secrets, 10, SYSFS_UV_MAX_SECRETS, -+ path) != 0 || -+ max_retr_secrets == 0) { -+ warnx("The ultravisor device is at a too old version, or " -+ "the ultravisor does not support retrievable secrets."); -+ goto error; -+ } -+ free(path); -+ -+ pr_verbose(verbose, "Device '%s' has been opened successfully", -+ UVDEVICE); -+ return uv_fd; -+ -+error: -+ free(path); -+ close(uv_fd); -+ -+ return -1; -+} -+ -+/** -+ * Retrieves a list of secrets from the ultravisor. Calls the supplied callback -+ * function for each secret found. -+ * -+ * @param uv_fd the file descriptor of the ultravisor device -+ * @param cb the callback function -+ * @param cb_private private data to pass to the callback function -+ * @param verbose if true, verbose messages are printed -+ * -+ * @returns 0 on success, a negative errno in case of an error -+ */ -+static int uv_list_secrets(int uv_fd, int (*cb)(u16 idx, u16 type, u32 len, -+ const u8 id[UV_SECRET_ID_LEN], -+ void *cb_private), -+ void *cb_private, bool verbose) -+{ -+ struct uvio_list_secrets *list; -+ struct uvio_ioctl_cb io; -+ unsigned int i; -+ int rc; -+ -+ util_assert(uv_fd != -1, "Internal error: uv_fd is -1"); -+ util_assert(cb != NULL, "Internal error: cb is NULL"); -+ -+ list = util_zalloc(UVIO_LIST_SECRETS_MAX_LEN); -+ -+ memset(&io, 0, sizeof(io)); -+ io.argument_addr = list; -+ io.argument_len = UVIO_LIST_SECRETS_MAX_LEN; -+ -+ rc = ioctl(uv_fd, UVIO_IOCTL_LIST_SECRETS, &io); -+ if (rc != 0) { -+ rc = -errno; -+ -+ pr_verbose(verbose, "ioctl UVIO_IOCTL_LIST_SECRETS: %s", -+ strerror(-rc)); -+ -+ if (rc == -ENOTTY || rc == -EINVAL) -+ warnx("The ultravisor device is at a too old version"); -+ -+ goto out; -+ } -+ -+ if (io.uv_rc != UVIO_RC_SUCCESS) { -+ pr_verbose(verbose, "ioctl UVIO_IOCTL_LIST_SECRETS' uv_rc: %u", -+ io.uv_rc); -+ rc = -EIO; -+ goto out; -+ } -+ -+ pr_verbose(verbose, "Number of secrets: %u", list->num_secrets_stored); -+ -+ for (i = 0; i < list->num_secrets_stored && -+ i < ARRAY_SIZE(list->secret_entries); i++) { -+ if (list->secret_entries[i].secret_type <= -+ UV_SECRET_TYPE_AP_ASSOCIATION) -+ continue; -+ -+ rc = cb(list->secret_entries[i].secret_idx, -+ list->secret_entries[i].secret_type, -+ list->secret_entries[i].secret_len, -+ list->secret_entries[i].secret_id, -+ cb_private); -+ if (rc != 0) -+ break; -+ } -+ -+out: -+ free(list); -+ -+ return rc; -+} -diff --git a/zkey/pvsecrets.h b/zkey/pvsecrets.h -new file mode 100644 -index 00000000..2667e859 ---- /dev/null -+++ b/zkey/pvsecrets.h -@@ -0,0 +1,89 @@ -+/* -+ * zkey - Generate, re-encipher, and validate secure keys -+ * -+ * This header file defines functions for the PV secrets support as well -+ * as the interface to the uv kernel module. -+ * -+ * Copyright IBM Corp. 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. -+ */ -+ -+#ifndef PVSECRETS_H -+#define PVSECRETS_H -+ -+#include "lib/zt_common.h" -+ -+/* -+ * Definitions for the /dev/uv kernel module interface -+ */ -+#define UVDEVICE "/dev/uv" -+#define SYSFS_UV "firmware/uv" -+#define SYSFS_UV_PV_GUEST "%s/prot_virt_guest" -+#define SYSFS_UV_MAX_SECRETS "%s/query/max_retr_secrets" -+ -+struct uvio_ioctl_cb { -+ u32 flags; -+ u16 uv_rc; /* UV header rc value */ -+ u16 uv_rrc; /* UV header rrc value */ -+ void *argument_addr; /* Userspace address of uvio argument */ -+ u32 argument_len; -+ u8 reserved14[0x40 - 0x14]; /* must be zero */ -+}; -+ -+#define UVIO_IOCTL_LIST_SECRETS_NR 3 -+ -+#define UVIO_TYPE_UVC 'u' -+#define UVIO_IOCTL(nr) _IOWR(UVIO_TYPE_UVC, \ -+ nr, struct uvio_ioctl_cb) -+#define UVIO_IOCTL_LIST_SECRETS UVIO_IOCTL( \ -+ UVIO_IOCTL_LIST_SECRETS_NR) -+ -+#define UVIO_RC_SUCCESS 0x0001 -+#define UVIO_RC_MORE_DATA 0x0100 -+ -+#define UV_SECRET_TYPE_INVALID 0x00 -+#define UV_SECRET_TYPE_NULL 0x01 -+#define UV_SECRET_TYPE_AP_ASSOCIATION 0x02 -+#define UV_SECRET_TYPE_PLAIN_TEXT 0x03 -+#define UV_SECRET_TYPE_AES_128 0x04 -+#define UV_SECRET_TYPE_AES_192 0x05 -+#define UV_SECRET_TYPE_AES_256 0x06 -+#define UV_SECRET_TYPE_AES_XTS_128 0x07 -+#define UV_SECRET_TYPE_AES_XTS_256 0x08 -+#define UV_SECRET_TYPE_HMAC_SHA_256 0x09 -+#define UV_SECRET_TYPE_HMAC_SHA_512 0x0a -+#define UV_SECRET_TYPE_ECDSA_P256 0x11 -+#define UV_SECRET_TYPE_ECDSA_P384 0x12 -+#define UV_SECRET_TYPE_ECDSA_P521 0x13 -+#define UV_SECRET_TYPE_EDDSA_ED25519 0x14 -+#define UV_SECRET_TYPE_EDDSA_ED448 0x15 -+ -+#define UV_SECRET_ID_LEN 32 -+ -+#define UVIO_LIST_SECRETS_MAX_LEN 0x8000 -+ -+struct uvio_list_secret_entry { -+ u16 secret_idx; -+ u16 secret_type; -+ u32 secret_len; -+ u64 reserved; -+ u8 secret_id[UV_SECRET_ID_LEN]; -+} __packed; -+ -+#define UVIO_MAX_SECRET_ENTRIES ((UVIO_LIST_SECRETS_MAX_LEN - 16) / \ -+ sizeof(struct uvio_list_secret_entry)) -+ -+struct uvio_list_secrets { -+ u16 num_secrets_stored; -+ u16 num_secrets_total; -+ u16 next_secret_idx; -+ u16 reserved1; -+ u64 reserved2; -+ struct uvio_list_secret_entry secret_entries[UVIO_MAX_SECRET_ENTRIES]; -+} __packed; -+ -+int uv_open_device(bool verbose); -+ -+#endif diff --git a/s390-tools-02-zipl-src-fix-imprecise-check-that-file-is-on-specifi.patch b/s390-tools-02-zipl-src-fix-imprecise-check-that-file-is-on-specifi.patch deleted file mode 100644 index bf9ce66..0000000 --- a/s390-tools-02-zipl-src-fix-imprecise-check-that-file-is-on-specifi.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 592a016a1095fa9813f0bae8256433ba5af4ab9b Mon Sep 17 00:00:00 2001 -From: Eduard Shishkin -Date: Sat, 7 Dec 2024 12:48:12 +0100 -Subject: [PATCH s390-tools 2/2] zipl/src: fix imprecise check that file is on - specified device - -This fixes c0f02d2 - -The check that file is on specified disk is imprecise: In case when -target parameters are specified by user, the check compares a logical -device with a base disk, which is incorrect. - -The fixup makes the check compare base disks (a specified one with -the base disk determined by disk_get_info() procedure). - -Signed-off-by: Eduard Shishkin ---- - zipl/src/bootmap.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/zipl/src/bootmap.c b/zipl/src/bootmap.c -index 7d340156..880b93ce 100644 ---- a/zipl/src/bootmap.c -+++ b/zipl/src/bootmap.c -@@ -299,14 +299,15 @@ create_component_header(void* buffer, component_header_type type) - } - - /* -- * Not precise check that the file FILENAME locates on specified physical DISK. -+ * Not precise check that the file FILENAME locates on the physical -+ * disk specified by WHERE. - * - * Try to auto-detect parameters of the disk which the file locates on - * and compare found device-ID with DISK. - * Return 0, if auto-detection succeeded, and it is proven that the - * file does NOT locate on DISK. Otherwise, return 1. - */ --static int file_is_on_disk(const char *filename, dev_t disk) -+static int file_is_on_disk(const char *filename, struct disk_info *where) - { - /* - * Retrieve info of the underlying disk without any user hints -@@ -331,7 +332,7 @@ static int file_is_on_disk(const char *filename, dev_t disk) - "Warning: Preparing a logical device for boot might fail\n"); - return 1; - } -- if (info->device != disk) { -+ if (info->basedisks[0] != where->basedisks[0]) { - disk_free_info(info); - return 0; - } -@@ -378,7 +379,7 @@ static int add_component_file_range(struct install_set *bis, - return -1; - } - } else { -- if (!file_is_on_disk(filename, bis->info->device)) { -+ if (!file_is_on_disk(filename, bis->info)) { - error_reason("File is not on target device"); - return -1; - } --- -2.39.0 - diff --git a/s390-tools-02-zkey-Add-the--pvsecrets-list-command.patch b/s390-tools-02-zkey-Add-the--pvsecrets-list-command.patch deleted file mode 100644 index 5055ce4..0000000 --- a/s390-tools-02-zkey-Add-the--pvsecrets-list-command.patch +++ /dev/null @@ -1,823 +0,0 @@ -From 5ce79ea667ea946e6591fe898db13becad018667 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -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 -Reviewed-by: Jorg Schmidbauer -Signed-off-by: Steffen Eiden ---- - 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 - #include - #include - #include -@@ -17,14 +18,60 @@ - #include - #include - -+#include -+ - #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) diff --git a/s390-tools-03-zkey-Add-PVSECRETS-AES-key-type.patch b/s390-tools-03-zkey-Add-PVSECRETS-AES-key-type.patch deleted file mode 100644 index f17e3a7..0000000 --- a/s390-tools-03-zkey-Add-PVSECRETS-AES-key-type.patch +++ /dev/null @@ -1,340 +0,0 @@ -From fdf66dc148c09f1d3300cd3378e3f75a83c6214e Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Thu, 15 Feb 2024 16:56:04 +0100 -Subject: [PATCH] zkey: Add PVSECRETS-AES key type - -Add the definitions and utility functions for the PVSECRETS-AES key type. -A PVSECRETS-AES key token contains the secret id of a protected -virtualization secret. It does not contain the key material, just a -reference to the key in the ultravisor. - -When such a key token is used to perform crypto operations later on, the -PAES kernel cipher will obtain the protected key belonging to this secret -id with the help of the pkey kernel module. - -Signed-off-by: Ingo Franzki -Reviewed-by: Jorg Schmidbauer -Signed-off-by: Steffen Eiden ---- - zkey/keystore.c | 4 +- - zkey/pkey.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++- - zkey/pkey.h | 38 ++++++++++++---- - zkey/pvsecrets.h | 4 +- - 4 files changed, 143 insertions(+), 13 deletions(-) - -diff --git a/zkey/keystore.c b/zkey/keystore.c -index 9589d82d..771bc08d 100644 ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -3,7 +3,7 @@ - * - * Keystore handling functions - * -- * Copyright IBM Corp. 2018, 2020 -+ * Copyright IBM Corp. 2018, 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. -@@ -360,6 +360,8 @@ static int _keystore_valid_key_type(const char *key_type) - return 1; - if (strcasecmp(key_type, KEY_TYPE_EP11_AES) == 0) - return 1; -+ if (strcasecmp(key_type, KEY_TYPE_PVSECRET_AES) == 0) -+ return 1; - - return 0; - } -diff --git a/zkey/pkey.c b/zkey/pkey.c -index 821978bd..53c0a550 100644 ---- a/zkey/pkey.c -+++ b/zkey/pkey.c -@@ -1,7 +1,7 @@ - /* - * zkey - Generate, re-encipher, and validate secure keys - * -- * Copyright IBM Corp. 2018 -+ * Copyright IBM Corp. 2018, 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. -@@ -26,6 +26,7 @@ - #include "lib/util_panic.h" - - #include "pkey.h" -+#include "pvsecrets.h" - #include "utils.h" - - #ifndef AF_ALG -@@ -1719,6 +1720,38 @@ bool is_ep11_key_session_bound(const u8 *key, size_t key_size) - } - } - -+/** -+ * Check if the specified key is a PVSECRET-AES key token. -+ * -+ * @param[in] key the secure key token -+ * @param[in] key_size the size of the secure key -+ * -+ * @returns true if the key is a PVSECRET token type -+ */ -+bool is_pvsecret_aes_key(const u8 *key, size_t key_size) -+{ -+ struct pvsecrettoken *pvsecret = (struct pvsecrettoken *)key; -+ -+ if (key == NULL || key_size < PVSECRET_KEY_SIZE) -+ return false; -+ -+ if (pvsecret->hdr.type != TOKEN_TYPE_NON_CCA) -+ return false; -+ if (pvsecret->hdr.version != TOKEN_VERSION_PVSECRET) -+ return false; -+ -+ switch (pvsecret->secret_type) { -+ case UV_SECRET_TYPE_AES_128: -+ case UV_SECRET_TYPE_AES_192: -+ case UV_SECRET_TYPE_AES_256: -+ case UV_SECRET_TYPE_AES_XTS_128: -+ case UV_SECRET_TYPE_AES_XTS_256: -+ return true; -+ default: -+ return false; -+ } -+} -+ - /** - * Check if the specified key is an XTS type key - * -@@ -1729,6 +1762,8 @@ bool is_ep11_key_session_bound(const u8 *key, size_t key_size) - */ - bool is_xts_key(const u8 *key, size_t key_size) - { -+ struct pvsecrettoken *pvsecret = (struct pvsecrettoken *)key; -+ - if (is_cca_aes_data_key(key, key_size)) { - if (key_size == 2 * AESDATA_KEY_SIZE && - is_cca_aes_data_key(key + AESDATA_KEY_SIZE, -@@ -1749,11 +1784,41 @@ bool is_xts_key(const u8 *key, size_t key_size) - is_ep11_aes_key_with_header(key + EP11_AES_KEY_SIZE, - key_size - EP11_AES_KEY_SIZE)) - return true; -+ } else if (is_pvsecret_aes_key(key, key_size)) { -+ switch (pvsecret->secret_type) { -+ case UV_SECRET_TYPE_AES_XTS_128: -+ case UV_SECRET_TYPE_AES_XTS_256: -+ return true; -+ default: -+ return false; -+ } - } - - return false; - } - -+/** -+ * Check if the specified key is a secure key type (i.e. requires a crypto card) -+ * -+ * @param[in] key the secure key token -+ * @param[in] key_size the size of the secure key -+ * -+ * @returns true if the key is a secure key type -+ */ -+bool is_secure_key(const u8 *key, size_t key_size) -+{ -+ if (is_cca_aes_data_key(key, key_size)) -+ return true; -+ if (is_cca_aes_cipher_key(key, key_size)) -+ return true; -+ if (is_ep11_aes_key(key, key_size)) -+ return true; -+ if (is_ep11_aes_key_with_header(key, key_size)) -+ return true; -+ -+ return false; -+} -+ - /** - * Gets the size in bits of the effective key of the specified secure key - * -@@ -1771,6 +1836,7 @@ int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize) - struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key; - struct ep11keytoken *ep11key = (struct ep11keytoken *)key; - struct ep11kblob_header *hdr = (struct ep11kblob_header *)key; -+ struct pvsecrettoken *pvsecret = (struct pvsecrettoken *)key; - - util_assert(bitsize != NULL, "Internal error: bitsize is NULL"); - -@@ -1805,6 +1871,26 @@ int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize) - (key + EP11_AES_KEY_SIZE); - *bitsize += hdr->bitlen; - } -+ } else if (is_pvsecret_aes_key(key, key_size)) { -+ switch (pvsecret->secret_type) { -+ case UV_SECRET_TYPE_AES_128: -+ *bitsize = 128; -+ break; -+ case UV_SECRET_TYPE_AES_192: -+ *bitsize = 192; -+ break; -+ case UV_SECRET_TYPE_AES_256: -+ *bitsize = 256; -+ break; -+ case UV_SECRET_TYPE_AES_XTS_128: -+ *bitsize = 128 * 2; -+ break; -+ case UV_SECRET_TYPE_AES_XTS_256: -+ *bitsize = 256 * 2; -+ break; -+ default: -+ return -EINVAL; -+ } - } else { - return -EINVAL; - } -@@ -1830,9 +1916,31 @@ const char *get_key_type(const u8 *key, size_t key_size) - return KEY_TYPE_EP11_AES; - if (is_ep11_aes_key_with_header(key, key_size)) - return KEY_TYPE_EP11_AES; -+ if (is_pvsecret_aes_key(key, key_size)) -+ return KEY_TYPE_PVSECRET_AES; -+ - return NULL; - } - -+/** -+ * Returns true if the key type is a secure key type -+ * -+ * @param[in] key_type the type of the key -+ * -+ * @returns true if the key type is a secure key type, false otherwise -+ */ -+bool is_secure_key_type(const char *key_type) -+{ -+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESCIPHER) == 0) -+ return true; -+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0) -+ return true; -+ if (strcasecmp(key_type, KEY_TYPE_EP11_AES) == 0) -+ return true; -+ -+ return false; -+} -+ - /** - * Returns the minimum card level for a specific key type - * -diff --git a/zkey/pkey.h b/zkey/pkey.h -index 3b57c5f0..ce3bd8bd 100644 ---- a/zkey/pkey.h -+++ b/zkey/pkey.h -@@ -4,7 +4,7 @@ - * This header file defines the interface to the pkey kernel module. - * It defines a set of IOCTL commands with its associated structures. - * -- * Copyright IBM Corp. 2017, 2018 -+ * 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. -@@ -41,6 +41,8 @@ struct tokenheader { - #define TOKEN_VERSION_EP11_AES 0x03 - #define TOKEN_VERSION_EP11_AES_WITH_HEADER 0x06 - #define TOKEN_VERSION_EP11_ECC_WITH_HEADER 0x07 -+/* 0x08 is reserved for internal use */ -+#define TOKEN_VERSION_PVSECRET 0x09 - - struct aesdatakeytoken { - u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */ -@@ -116,6 +118,15 @@ struct ep11keytoken { - u8 padding[64]; - } __packed; - -+#define UV_SECRET_ID_LEN 32 -+ -+struct pvsecrettoken { -+ struct tokenheader hdr; -+ u16 secret_type; /* the secret type as the UV told us */ -+ u16 secret_len; /* length in bytes of the secret */ -+ u8 secretid[UV_SECRET_ID_LEN]; /* the secret id for this secret */ -+} __packed; -+ - #define ZERO_SESSION \ - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - -@@ -124,21 +135,26 @@ struct ep11keytoken { - #define EP11_KEY_SIZE sizeof(struct ep11keytoken) - #define EP11_AES_KEY_SIZE (sizeof(struct ep11kblob_header) + \ - sizeof(struct ep11keytoken)) -+#define PVSECRET_KEY_SIZE sizeof(struct pvsecrettoken) - - /* MAX/MIN from zt_common.h produces warnings for variable length arrays */ - #define _MIN(a, b) ((a) < (b) ? (a) : (b)) - #define _MAX(a, b) ((a) > (b) ? (a) : (b)) - - #define MAX_SECURE_KEY_SIZE _MAX( \ -- _MAX(EP11_KEY_SIZE, \ -- EP11_AES_KEY_SIZE), \ -- _MAX(AESDATA_KEY_SIZE, \ -- AESCIPHER_KEY_SIZE)) -+ _MAX( \ -+ _MAX(EP11_KEY_SIZE, \ -+ EP11_AES_KEY_SIZE), \ -+ _MAX(AESDATA_KEY_SIZE, \ -+ AESCIPHER_KEY_SIZE)), \ -+ PVSECRET_KEY_SIZE) - #define MIN_SECURE_KEY_SIZE _MIN( \ -- _MIN(EP11_KEY_SIZE, \ -- EP11_AES_KEY_SIZE), \ -- _MIN(AESDATA_KEY_SIZE, \ -- AESCIPHER_KEY_SIZE)) -+ _MIN( \ -+ _MIN(EP11_KEY_SIZE, \ -+ EP11_AES_KEY_SIZE), \ -+ _MIN(AESDATA_KEY_SIZE, \ -+ AESCIPHER_KEY_SIZE)), \ -+ PVSECRET_KEY_SIZE) - - struct pkey_seckey { - u8 seckey[AESDATA_KEY_SIZE]; /* the secure key blob */ -@@ -285,6 +301,7 @@ struct pkey_apqns4keytype { - #define KEY_TYPE_CCA_AESDATA "CCA-AESDATA" - #define KEY_TYPE_CCA_AESCIPHER "CCA-AESCIPHER" - #define KEY_TYPE_EP11_AES "EP11-AES" -+#define KEY_TYPE_PVSECRET_AES "PVSECRET-AES" - - #define DEFAULT_KEYBITS 256 - #define PAES_BLOCK_SIZE 16 -@@ -342,9 +359,12 @@ bool is_cca_aes_cipher_key(const u8 *key, size_t key_size); - bool is_ep11_aes_key(const u8 *key, size_t key_size); - bool is_ep11_aes_key_with_header(const u8 *key, size_t key_size); - bool is_ep11_key_session_bound(const u8 *key, size_t key_size); -+bool is_pvsecret_aes_key(const u8 *key, size_t key_size); - bool is_xts_key(const u8 *key, size_t key_size); -+bool is_secure_key(const u8 *key, size_t key_size); - int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize); - const char *get_key_type(const u8 *key, size_t key_size); -+bool is_secure_key_type(const char *key_type); - int get_min_card_level_for_keytype(const char *key_type); - const struct fw_version *get_min_fw_version_for_keytype(const char *key_type); - enum card_type get_card_type_for_keytype(const char *key_type); -diff --git a/zkey/pvsecrets.h b/zkey/pvsecrets.h -index 6acebfdd..ad844035 100644 ---- a/zkey/pvsecrets.h -+++ b/zkey/pvsecrets.h -@@ -15,6 +15,8 @@ - - #include "lib/zt_common.h" - -+#include "pkey.h" -+ - /* - * Definitions for the /dev/uv kernel module interface - */ -@@ -60,8 +62,6 @@ struct uvio_ioctl_cb { - #define UV_SECRET_TYPE_EDDSA_ED25519 0x14 - #define UV_SECRET_TYPE_EDDSA_ED448 0x15 - --#define UV_SECRET_ID_LEN 32 -- - #define UVIO_LIST_SECRETS_MAX_LEN 0x8000 - - struct uvio_list_secret_entry { diff --git a/s390-tools-04-zkey-Add-the-pvsecrets-import-command.patch b/s390-tools-04-zkey-Add-the-pvsecrets-import-command.patch deleted file mode 100644 index 4b5186c..0000000 --- a/s390-tools-04-zkey-Add-the-pvsecrets-import-command.patch +++ /dev/null @@ -1,784 +0,0 @@ -From 95bf7eb285f39a8f827cc013393cc69b1265cd68 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Thu, 15 Feb 2024 15:14:04 +0100 -Subject: [PATCH] zkey: Add the 'pvsecrets import' command - -The 'pvsecrets import' command imports a protected virtualization secret -into the zkey key repository. Like other key import or key generation -commands, additional information can be associated with the imported key, -such as a textual description, the volume to encrypt with together with -the volume type, the sector size, and a dummy passphrase. You can not -associate a set of APQNs, since a protected virtualization secret does -not need or use a crypto card. - -This command only works when running in a secure execution guest. - -Signed-off-by: Ingo Franzki -Reviewed-by: Jorg Schmidbauer -Signed-off-by: Steffen Eiden ---- - zkey/keystore.c | 112 +++++++++++++++++++++++---------- - zkey/keystore.h | 9 ++- - zkey/pvsecrets.c | 126 +++++++++++++++++++++++++++++++++++++ - zkey/pvsecrets.h | 7 +++ - zkey/zkey.1 | 134 ++++++++++++++++++++++++++++++++++++++++ - zkey/zkey.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 513 insertions(+), 32 deletions(-) - -diff --git a/zkey/keystore.c b/zkey/keystore.c -index 771bc08df..cde0caf58 100644 ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -2259,9 +2259,11 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name, - } - - /** -- * Imports a secure key from a file and adds it to the key store -+ * Imports a secure key from a buffer and adds it to the key store - * - * @param[in] keystore the key store -+ * @param[in] secure_key the buffer containing the key -+ * @param[in] secure_key_size the size of the key - * @param[in] name the name of the key - * @param[in] description textual description of the key (optional, can be NULL) - * @param[in] volumes a comma separated list of volumes associated with this -@@ -2274,7 +2276,6 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name, - * of two and in range 512 - 4096 bytes. 0 means that - * the sector size is not specified and the system - * default is used. -- * @param[in] import_file The name of a secure key containing the key to import - * @param[in] volume_type the type of volume - * @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2 - * @param[in] passphrase_file the file name of a file containing a passphrase -@@ -2283,25 +2284,23 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name, - * - * @returns 0 for success or a negative errno in case of an error - */ --int keystore_import_key(struct keystore *keystore, const char *name, -- const char *description, const char *volumes, -- const char *apqns, bool noapqncheck, size_t sector_size, -- const char *import_file, const char *volume_type, -- bool gen_passphrase, const char *passphrase_file, -- struct ext_lib *lib) -+int keystore_import(struct keystore *keystore, unsigned char *secure_key, -+ size_t secure_key_size, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, bool noapqncheck, size_t sector_size, -+ const char *volume_type, bool gen_passphrase, -+ const char *passphrase_file, struct ext_lib *lib) - { - struct key_filenames file_names = { 0 }; - struct properties *key_props = NULL; -- size_t secure_key_size; - const char *key_type; - u8 mkvp[MKVP_LENGTH]; - int selected = 1; -- u8 *secure_key; - int rc; - - util_assert(keystore != NULL, "Internal error: keystore is NULL"); - util_assert(name != NULL, "Internal error: name is NULL"); -- util_assert(import_file != NULL, "Internal error: import_file is NULL"); -+ util_assert(secure_key != NULL, "Internal error: secure_key is NULL"); - - rc = _keystore_get_key_filenames(keystore, name, &file_names); - if (rc != 0) -@@ -2311,27 +2310,29 @@ int keystore_import_key(struct keystore *keystore, const char *name, - if (rc != 0) - goto out_free_key_filenames; - -- secure_key = read_secure_key(import_file, &secure_key_size, -- keystore->verbose); -- if (secure_key == NULL) { -- rc = -ENOENT; -- goto out_free_key_filenames; -- } -- - key_type = get_key_type(secure_key, secure_key_size); - if (key_type == NULL) { - warnx("Key '%s' is not a valid secure key", name); -- free(secure_key); - rc = -EINVAL; - goto out_free_key_filenames; - } - -+ if (!is_secure_key(secure_key, secure_key_size)) { -+ if (apqns != NULL) { -+ warnx("No APQNs can be associated with keys of type %s", -+ key_type); -+ rc = -EINVAL; -+ goto out_free_props; -+ } -+ goto write_key; -+ } -+ - rc = get_master_key_verification_pattern(secure_key, secure_key_size, - mkvp, keystore->verbose); - if (rc != 0) { - warnx("Failed to get the master key verification pattern: %s", - strerror(-rc)); -- goto out_free_key; -+ goto out_free_props; - } - - rc = cross_check_apqns(apqns, mkvp, -@@ -2340,17 +2341,17 @@ int keystore_import_key(struct keystore *keystore, const char *name, - get_card_type_for_keytype(key_type), - true, keystore->verbose); - if (rc == -EINVAL) -- goto out_free_key; -+ goto out_free_props; - if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) { - warnx("Your master key setup is improper"); -- goto out_free_key; -+ goto out_free_props; - } - - if (is_cca_aes_cipher_key(secure_key, secure_key_size)) { - if (lib->cca->lib_csulcca == NULL) { - rc = load_cca_library(lib->cca, keystore->verbose); - if (rc != 0) -- goto out_free_key; -+ goto out_free_props; - } - - rc = select_cca_adapter_by_mkvp(lib->cca, mkvp, apqns, -@@ -2365,7 +2366,7 @@ int keystore_import_key(struct keystore *keystore, const char *name, - warnx("No APQN found that is suitable for " - "working with the secure AES key '%s'", name); - rc = 0; -- goto out_free_key; -+ goto out_free_props; - } - - rc = restrict_key_export(lib->cca, secure_key, secure_key_size, -@@ -2375,7 +2376,7 @@ int keystore_import_key(struct keystore *keystore, const char *name, - "key: %s", strerror(-rc)); - if (!selected) - print_msg_for_cca_envvars("secure AES key"); -- goto out_free_key; -+ goto out_free_props; - } - - rc = check_aes_cipher_key(secure_key, secure_key_size); -@@ -2386,15 +2387,14 @@ int keystore_import_key(struct keystore *keystore, const char *name, - if (!prompt_for_yes(keystore->verbose)) { - warnx("Operation aborted"); - rc = -ECANCELED; -- goto out_free_key; -+ goto out_free_props; - } - } - } - -+write_key: - rc = write_secure_key(file_names.skey_filename, secure_key, - secure_key_size, keystore->verbose); -- free(secure_key); -- secure_key = NULL; - if (rc != 0) - goto out_free_props; - -@@ -2414,9 +2414,6 @@ int keystore_import_key(struct keystore *keystore, const char *name, - "Successfully imported a secure key in '%s' and key info in '%s'", - file_names.skey_filename, file_names.info_filename); - --out_free_key: -- if (secure_key != NULL) -- free(secure_key); - out_free_props: - if (key_props != NULL) - properties_free(key_props); -@@ -2431,6 +2428,59 @@ int keystore_import_key(struct keystore *keystore, const char *name, - return rc; - } - -+/** -+ * Imports a secure key from a file and adds it to the key store -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] description textual description of the key (optional, can be NULL) -+ * @param[in] volumes a comma separated list of volumes associated with this -+ * key (optional, can be NULL) -+ * @param[in] apqns a comma separated list of APQNs associated with this -+ * key (optional, can be NULL) -+ * @param[in] noapqncheck if true, the specified APQN(s) are not checked for -+ * existence and type. -+ * @param[in] sector_size the sector size to use with dm-crypt. It must be a -+ * power of two and in range 512 - 4096 bytes. 0 means -+ * that the sector size is not specified and the system -+ * default is used. -+ * @param[in] import_file The name of a secure key containing the key to import -+ * @param[in] volume_type the type of volume -+ * @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2 -+ * @param[in] passphrase_file the file name of a file containing a passphrase -+ * for LUKS2 (optional, can be NULL) -+ * @param[in] lib the external library struct -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_import_key(struct keystore *keystore, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, bool noapqncheck, size_t sector_size, -+ const char *import_file, const char *volume_type, -+ bool gen_passphrase, const char *passphrase_file, -+ struct ext_lib *lib) -+{ -+ size_t secure_key_size; -+ u8 *secure_key; -+ int rc; -+ -+ util_assert(import_file != NULL, "Internal error: import_file is NULL"); -+ -+ secure_key = read_secure_key(import_file, &secure_key_size, -+ keystore->verbose); -+ if (secure_key == NULL) -+ return -ENOENT; -+ -+ rc = keystore_import(keystore, secure_key, secure_key_size, name, -+ description, volumes, apqns, noapqncheck, -+ sector_size, volume_type, gen_passphrase, -+ passphrase_file, lib); -+ -+ if (secure_key != NULL) -+ free(secure_key); -+ -+ return rc; -+} - - /** - * Changes properties of a key in the keystore. -diff --git a/zkey/keystore.h b/zkey/keystore.h -index 1443b5df4..b4cae9aae 100644 ---- a/zkey/keystore.h -+++ b/zkey/keystore.h -@@ -3,7 +3,7 @@ - * - * Keystore handling functions - * -- * Copyright IBM Corp. 2018, 2020 -+ * Copyright IBM Corp. 2018, 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. -@@ -65,6 +65,13 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name, - struct kms_option *kms_options, - size_t num_kms_options); - -+int keystore_import(struct keystore *keystore, unsigned char *secure_key, -+ size_t secure_key_size, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, bool noapqncheck, size_t sector_size, -+ const char *volume_type, bool gen_passphrase, -+ const char *passphrase_file, struct ext_lib *lib); -+ - int keystore_import_key(struct keystore *keystore, const char *name, - const char *description, const char *volumes, - const char *apqns, bool noapqncheck, size_t sector_size, -diff --git a/zkey/pvsecrets.c b/zkey/pvsecrets.c -index 7f28febad..a4b3a5a83 100644 ---- a/zkey/pvsecrets.c -+++ b/zkey/pvsecrets.c -@@ -552,3 +552,129 @@ int pvsecrets_list(int uv_fd, bool all, bool hex, const char *type_filter, - - return rc; - } -+ -+struct build_secret_key_blob_data { -+ unsigned char id[UV_SECRET_ID_LEN]; -+ char name[UV_SECRET_ID_LEN]; -+ struct pvsecrettoken token; -+ bool found; -+}; -+ -+/** -+ * Callback used to generate a pvsecrets key blob for a specific secret ID. -+ * 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_build_key_blob_cb(u16 UNUSED(idx), u16 type, u32 len, -+ const u8 id[UV_SECRET_ID_LEN], -+ void *cb_private) -+{ -+ struct build_secret_key_blob_data *build_blob_data = cb_private; -+ -+ if (build_blob_data->found) -+ return 0; -+ -+ if (memcmp(id, build_blob_data->name, UV_SECRET_ID_LEN) != 0 && -+ memcmp(id, build_blob_data->id, UV_SECRET_ID_LEN) != 0) -+ return 0; -+ -+ memset(&build_blob_data->token, 0, sizeof(build_blob_data->token)); -+ build_blob_data->token.hdr.type = TOKEN_TYPE_NON_CCA; -+ build_blob_data->token.hdr.version = TOKEN_VERSION_PVSECRET; -+ build_blob_data->token.secret_type = type; -+ build_blob_data->token.secret_len = len; -+ memcpy(build_blob_data->token.secretid, id, UV_SECRET_ID_LEN); -+ -+ build_blob_data->found = true; -+ -+ return 0; -+} -+ -+/** -+ * Imports a protected virtualization secure key from the UV and adds it to the -+ * key store -+ * -+ * @param keystore the key store -+ * @param uv_fd the file descriptor of the ultravisor device -+ * @param secret_id the secret id as 32 byte hex string. Can be NULL if -+ * secret_name is non-NULL. -+ * @param secret_name the secret name. Can be NULL if secret_id is non-NULL. -+ * @param name the name of the key in the repository -+ * @param description textual description of the key (optional, can be NULL) -+ * @param volumes a comma separated list of volumes associated with this -+ * key (optional, can be NULL) -+ * @param volume_type the type of volume -+ * @param sector_size the sector size to use with dm-crypt. It must be a -+ * power of two and in range 512 - 4096 bytes. 0 means -+ * that the sector size is not specified and the system -+ * default is used. -+ * @param gen_passphrase if true, generate a (dummy) passphrase for LUKS2 -+ * @param passphrase_file the file name of a file containing a passphrase -+ * for LUKS2 (optional, can be NULL) -+ * @param verbose if true, verbose messages are printed -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int pvsecrets_import(struct keystore *keystore, int uv_fd, -+ const char *secret_id, const char *secret_name, -+ const char *name, const char *description, -+ const char *volumes, const char *volume_type, -+ long sector_size, bool gen_passphrase, -+ const char *passphrase_file, bool verbose) -+{ -+ struct build_secret_key_blob_data build_blob_data = { 0 }; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ util_assert(uv_fd != -1, "Internal error: uv_fd is -1"); -+ util_assert(secret_id != NULL || secret_name != NULL, -+ "Internal error: secret_id and secrest_name is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ -+ rc = get_secret_id_from_hex_or_name(secret_id, secret_name, -+ build_blob_data.id, -+ build_blob_data.name); -+ if (rc < 0) -+ return rc; -+ if (rc > 0) -+ return -EINVAL; -+ -+ rc = uv_list_secrets(uv_fd, pvsecrets_build_key_blob_cb, -+ &build_blob_data, verbose); -+ if (rc != 0) { -+ warnx("Failed to import the pvsecret with %s '%s': %s", -+ secret_id != NULL ? "id" : "name", -+ secret_id != NULL ? secret_id : secret_name, -+ strerror(-rc)); -+ return rc; -+ } -+ -+ if (!build_blob_data.found) { -+ warnx("The pvsecret with %s '%s' does not exist", -+ secret_id != NULL ? "id" : "name", -+ secret_id != NULL ? secret_id : secret_name); -+ return -ENOENT; -+ } -+ -+ if (!is_pvsecret_type_supported(build_blob_data.token.secret_type)) { -+ warnx("The type of the pvsecret with %s '%s' is not supported " -+ "by zkey: %s", secret_id != NULL ? "id" : "name", -+ secret_id != NULL ? secret_id : secret_name, -+ get_pvsecret_type_name( -+ build_blob_data.token.secret_type)); -+ return -EINVAL; -+ } -+ -+ rc = keystore_import(keystore, (unsigned char *)&build_blob_data.token, -+ sizeof(build_blob_data.token), name, description, -+ volumes, NULL, false, sector_size, volume_type, -+ gen_passphrase, passphrase_file, NULL); -+ -+ return rc; -+} -diff --git a/zkey/pvsecrets.h b/zkey/pvsecrets.h -index ad8440350..9503c5155 100644 ---- a/zkey/pvsecrets.h -+++ b/zkey/pvsecrets.h -@@ -16,6 +16,7 @@ - #include "lib/zt_common.h" - - #include "pkey.h" -+#include "keystore.h" - - /* - * Definitions for the /dev/uv kernel module interface -@@ -89,5 +90,11 @@ 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); -+int pvsecrets_import(struct keystore *keystore, int uv_fd, -+ const char *secret_id, const char *secret_name, -+ const char *name, const char *description, -+ const char *volumes, const char *volume_type, -+ long sector_size, bool gen_passphrase, -+ const char *passphrase_file, bool verbose); - - #endif -diff --git a/zkey/zkey.1 b/zkey/zkey.1 -index 4386629f9..ba71a839b 100644 ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -1208,6 +1208,64 @@ are supported by the \fBzkey\fP tool. To list all pvsecret types, specify the - This command is only available when running in a secure execution guest. - Only the \fBroot\fP user is allowed to perform this command. - . -+.SS "Import protected virtualization secrets into the repository" -+. -+.B zkey pvsecrets -+.BR import | im -+.RB [ \-\-pvsecret\-id | \-I -+.IR pvsecret\-id ] -+.RB [ \-\-pvsecret\-name | \-e -+.IR pvsecret\-name ] -+.B \-\-name | \-N -+.IR key\-name -+.RB [ \-\-description | \-d -+.IR description ] -+.RB [ \-\-volumes | \-l -+.IR volume1:dmname1[,volume2:dmname2[,...]] ] -+.RB [ \-\-sector\-size | \-S -+.IR bytes ] -+.RB [ \-\-volume\-type | \-t -+.IR type ] -+.RB [ \-\-gen\-dummy\-passphrase ] -+.RB [ \-\-set\-dummy\-passphrase -+.IR passphrase\-file ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B pvsecrets import -+command to import a protected virtualization (PV) secret into the repository. -+Either the \fB\-\-pvsecret\-id\fP option or the \fB\-\-pvsecret\-name\fP -+option can be specified. If the pvsecret name is specified, then the -+\fB\-\-name\fP option can be omitted. The name of the protected virtualization -+secret key object in the repository will then be the same as the pvsecret name. -+.PP -+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 or -+\fB\-\-pvsecret\-name "$(yq .name \fP\fIYAML\-FILE\fP\fB)"\fP. -+You might have to install the \fByq\fP package first. -+.PP -+A protected virtualization secret key object does not contain the key material, -+but only a reference (i.e. the secret ID) to the key in the ultravisor. -+When such a protected virtualization secret key object is used with -+\fBdm\-crypt\fP and the \fBPAES\fP kernel cipher, the key material (i.e. a -+protected key) is retrieved from the ultravisor and the crypto operation is -+performed with it. -+.PP -+When importing a protected virtualization secret in a key repository, -+additional information can be associated with it using the -+.B \-\-description -+, -+.B \-\-volumes -+, or the -+.B \-\-sector\-size -+options. APQNs can not be associated, because protected virtualization secrets -+do not require a crypto card. -+.PP -+This command is only available when running in a secure execution guest. -+Only the \fBroot\fP user is allowed to perform this command. -+. - . - . - . -@@ -2117,6 +2175,82 @@ can be specified, but not both. - . - . - . -+.SS "Options for the pvsecrets import command" -+.TP -+.BR \-I ", " \-\-pvsecret\-id\~\fIpvsecret\-id\fP -+ID of the protected virtualization (PV) secret to import. 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 import. 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. If the \fB\-\-pvsecret\-name\fP option is -+specified, then the \fB\-\-name\fP option can be omitted. The name of the -+protected virtualization secret key object in the repository will then be the -+same as the pvsecret name. -+.TP -+.BR \-N ", " \-\-name\~\fIkey\-name\fP -+Specifies the name of the protected virtualization secret key object in the key -+repository. If the \fB\-\-pvsecret\-name\fP option is specified, then the -+\fB\-\-name\fP option can be omitted. The name of the protected virtualization -+secret in the repository will then be the same as the pvsecret name. -+.TP -+.BR \-d ", " \-\-description\~\fIdescription\fP -+Specifies a textual description for the protected virtualization secret in the -+key repository. -+.TP -+.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1[,volume2:dmname2[,...]]\fP -+Specifies a comma-separated list of volumes (block devices) which are -+associated with the protected virtualization secret in the repository. These -+volumes are to be encrypted using \fBdm\-crypt\fP with the protected -+virtualization secret. The volume association also contains the device-mapper -+name, separated by a colon, used with \fBdm\-crypt\fP. A specific volume can -+only be associated with a single key. -+.TP -+.BR \-S ", " \-\-sector\-size\~\fIbytes\fP -+Specifies the sector size in bytes used with \fBdm\-crypt\fP. It must be a power -+of two and in the range of 512 to 4096 bytes. If omitted, the system default -+sector size is used. -+.TP -+.BR \-t ", " \-\-volume\-type\~\fItype\fP -+Specifies the volume type of the associated volumes used with \fBdm\-crypt\fP. -+Possible values are \fBplain\fP and \fBluks2\fP. If omitted, \fBluks2\fP is -+used. This option is only available if -+.B zkey -+has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled, -+the default volume type is \fBplain\fP. -+.TP -+.BR \-\-gen\-dummy\-passphrase -+Generate a dummy passphrase randomly and associate it with the protected -+virtualization secret used to encrypt LUKS2 volume(s). The LUKS2 passphrase is -+of less or no relevance for the security of the volume(s), when a protected -+virtualization secret is used to encrypt the volume(s), and can therefore be -+stored insecurely inside the key repository. If for a certain usage the -+passphrase is of relevance for security, then do not use this option. This -+option can only be specified for keys with a volume type of \fBluks2\fP. -+.TP -+.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP -+Set a dummy passphrase that is read from the specified file and associate it -+with the protected virtualization secret used to encrypt LUKS2 volume(s). -+The LUKS2 passphrase is of less or no relevance for the security of the -+volume(s), when an protected virtualization secret is used to encrypt the -+volume(s), and can therefore be stored insecurely inside the key repository. -+If for a certain usage the passphrase is of relevance for security, then do -+not use this option. This option can only be specified for keys with a volume -+type of \fBluks2\fP. -+. -+. -+. - .SS "General options" - .TP - .BR \-V ", " \-\-verbose -diff --git a/zkey/zkey.c b/zkey/zkey.c -index adc48d60b..6e9b32af5 100644 ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -145,6 +145,7 @@ static struct zkey_globals { - #define COMMAND_KMS_REFRESH "refresh" - #define COMMAND_PVSECRETS "pvsecrets" - #define COMMAND_PVSECRETS_LIST "list" -+#define COMMAND_PVSECRETS_IMPORT "import" - - #define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER" - -@@ -1234,6 +1235,103 @@ static struct util_opt opt_vec[] = { - .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST, - }, - /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ { -+ .option = { "pvsecret-id", required_argument, NULL, 'I'}, -+ .argument = "PVSECRET-ID", -+ .desc = "ID of the protected virtualization (PV) secret to " -+ "import. Either '--pvsecret-id/-I' or " -+ "'--pvsecret-name/-e' can be specified, but not both.", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ { -+ .option = { "pvsecret-name", required_argument, NULL, 'e'}, -+ .argument = "PVSECRET-NAME", -+ .desc = "Name of the protected virtualization (PV) secret to " -+ "import. Either '--pvsecret-name/-e' or " -+ "'--pvsecret-id/-I' can be specified, but not both. " -+ "If the '--pvsecret-name/-e' option is specified, but " -+ "the '--name/-N' option is omitted, then the imported " -+ "protected virtualisation secret will be named the " -+ "same as the pvsecret name.", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the imported protected virtualisation secret " -+ "in the repository. If the '--name/-N' option is " -+ "omitted, but the '--pvsecret-name/-e' is specified, " -+ "then the imported protected virtualisation secret " -+ "will be named the same as the pvsecret name.", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ { -+ .option = { "description", required_argument, NULL, 'd'}, -+ .argument = "DESCRIPTION", -+ .desc = "Textual description of the protected virtualisation " -+ "secret in the repository", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "VOLUME:DMNAME[,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the protected " -+ "virtualisation secret in the repository", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ { -+ .option = { "sector-size", required_argument, NULL, 'S'}, -+ .argument = "512|4096", -+ .desc = "The sector size used with dm-crypt. It must be a power " -+ "of two and in range 512 - 4096 bytes. If this option " -+ "is omitted, the system default sector size (512) is " -+ "used", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+#ifdef HAVE_LUKS2_SUPPORT -+ { -+ .option = { "volume-type", required_argument, NULL, 't'}, -+ .argument = "type", -+ .desc = "The type of the associated volume(s). Possible values " -+ "are 'plain' and 'luks2'. When this option is omitted, " -+ "the default is 'luks2'", -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+#endif -+ { -+ .option = { "gen-dummy-passphrase", 0, NULL, -+ OPT_GEN_DUMMY_PASSPHRASE}, -+ .desc = "Generate a dummy passphrase and associate it with the " -+ "protected virtualisation secret used to encrypt LUKS2 " -+ "volume(s). The LUKS2 passphrase is of less or no " -+ "relevance for the security of the volume(s), when an " -+ "protected virtualisation secret is used to encrypt " -+ "the volume(s), and can therefore be stored insecurely " -+ "inside the secure key repository.", -+ .flags = UTIL_OPT_FLAG_NOSHORT, -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ { -+ .option = { "set-dummy-passphrase", required_argument, NULL, -+ OPT_SET_DUMMY_PASSPHRASE}, -+ .argument = "passphrase-file", -+ .desc = "Set a dummy passphrase to be associated with the " -+ "protected virtualisation secret used to encrypt LUKS2 " -+ "volume(s). The LUKS2 passphrase is of less or no " -+ "relevance for the security of the volume(s), when a " -+ "protected virtualisation secret is used to encrypt " -+ "the volume(s), and can therefore be stored insecurely " -+ "inside the secure key repository.", -+ .flags = UTIL_OPT_FLAG_NOSHORT, -+ .command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT, -+ }, -+ /***********************************************************/ - OPT_PLACEHOLDER, - OPT_PLACEHOLDER, - OPT_PLACEHOLDER, -@@ -1339,6 +1437,7 @@ 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 int command_pvsecrets_import(void); - - static struct zkey_command zkey_kms_commands[] = { - { -@@ -1469,6 +1568,19 @@ static struct zkey_command zkey_pvsecrets_commands[] = { - .has_options = 1, - .need_uv_device = 1, - }, -+ { -+ .command = COMMAND_PVSECRETS_IMPORT, -+ .abbrev_len = 2, -+ .function = command_pvsecrets_import, -+ .short_desc = "Imports a protected virtualization (PV) secret", -+ .long_desc = "Imports a protected virtualization (PV) secret " -+ "into the repository. This command is only " -+ "available when running in a secure execution " -+ "guest.", -+ .has_options = 1, -+ .need_keystore = 1, -+ .need_uv_device = 1, -+ }, - { .command = NULL } - }; - -@@ -3006,6 +3118,51 @@ static int command_pvsecrets_list(void) - return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } - -+/* -+ * Command handler for 'pvsecrets import'. -+ * -+ * Import a protected virtualization secret into the repository -+ */ -+static int command_pvsecrets_import(void) -+{ -+ int rc; -+ -+ if (g.secret_id == NULL && g.secret_name == NULL) { -+ misc_print_required_parm("--pvsecret-id/-I or " -+ "--pvsecret-name/-e"); -+ return EXIT_FAILURE; -+ } -+ 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; -+ } -+ if (g.secret_name == NULL && g.name == NULL) { -+ misc_print_required_parm("--name/-N"); -+ return EXIT_FAILURE; -+ } -+ -+ if (g.sector_size < 0) -+ g.sector_size = 0; -+ -+ if (g.gen_passphrase && g.passphrase_file != NULL) { -+ warnx("Either '--gen-dummy-passphrase' or " -+ "'--set-dummy-passphrase' can be specified, but not " -+ "both"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ -+ rc = pvsecrets_import(g.keystore, g.uv_fd, g.secret_id, g.secret_name, -+ g.name != NULL ? g.name : g.secret_name, -+ g.description, g.volumes, g.volume_type, -+ g.sector_size, g.gen_passphrase, -+ g.passphrase_file, 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 diff --git a/s390-tools-05-zkey-Reject-key-generation-and-APQN-association-for-PVSECRET-AES-keys.patch b/s390-tools-05-zkey-Reject-key-generation-and-APQN-association-for-PVSECRET-AES-keys.patch deleted file mode 100644 index 42da0b9..0000000 --- a/s390-tools-05-zkey-Reject-key-generation-and-APQN-association-for-PVSECRET-AES-keys.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 5276d408fd10669b3d8e623455778a675e8dc149 Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Mon, 19 Feb 2024 10:21:06 +0100 -Subject: [PATCH] zkey: Reject key generation and APQN association for - PVSECRET-AES keys - -Keys of type PVSECRET-AES can not be generated using 'zkey generate'. -Furthermore, APQNs can not be associated with keys of type PVSECRET-AES -via 'zkey change'. Reject that with a proper error message. - -Signed-off-by: Ingo Franzki -Reviewed-by: Jorg Schmidbauer -Signed-off-by: Steffen Eiden ---- - zkey/keystore.c | 32 +++++++++++++++++++++++--------- - zkey/zkey.1 | 7 +++++++ - zkey/zkey.c | 5 +++++ - 3 files changed, 35 insertions(+), 9 deletions(-) - -diff --git a/zkey/keystore.c b/zkey/keystore.c -index cde0caf5..db62e0a6 100644 ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -2009,6 +2009,12 @@ int keystore_generate_key(struct keystore *keystore, const char *name, - return -EINVAL; - } - -+ if (!is_secure_key_type(key_type)) { -+ warnx("Keys of type %s can not be generated. Use 'zkey " -+ "pvsecret import' instead", key_type); -+ return -EINVAL; -+ } -+ - rc = _keystore_get_key_filenames(keystore, name, &file_names); - if (rc != 0) - goto out_free_key_filenames; -@@ -2535,9 +2541,9 @@ int keystore_change_key(struct keystore *keystore, const char *name, - const char *null_ptr = NULL; - char *upd_volumes = NULL; - size_t secure_key_size; -+ u8 *secure_key = NULL; - u8 mkvp[MKVP_LENGTH]; - char sect_size[30]; -- u8 *secure_key; - bool kms_bound; - int rc; - -@@ -2589,13 +2595,6 @@ int keystore_change_key(struct keystore *keystore, const char *name, - goto out; - } - -- rc = _keystore_change_association(key_props, PROP_NAME_APQNS, -- apqns, "APQN", -- _keystore_apqn_check, -- &apqn_check); -- if (rc != 0) -- goto out; -- - secure_key = read_secure_key(file_names.skey_filename, - &secure_key_size, - keystore->verbose); -@@ -2604,11 +2603,24 @@ int keystore_change_key(struct keystore *keystore, const char *name, - goto out; - } - -+ if (!is_secure_key(secure_key, secure_key_size)) { -+ warnx("No APQNs can be associated with keys of type %s", -+ get_key_type(secure_key, secure_key_size)); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ rc = _keystore_change_association(key_props, PROP_NAME_APQNS, -+ apqns, "APQN", -+ _keystore_apqn_check, -+ &apqn_check); -+ if (rc != 0) -+ goto out; -+ - rc = get_master_key_verification_pattern(secure_key, - secure_key_size, - mkvp, - keystore->verbose); -- free(secure_key); - if (rc) - goto out; - -@@ -2742,6 +2754,8 @@ int keystore_change_key(struct keystore *keystore, const char *name, - free(upd_volumes); - if (upd_volume_type != NULL) - free(upd_volume_type); -+ if (secure_key != NULL) -+ free(secure_key); - - if (rc != 0) - pr_verbose(keystore, "Failed to change key '%s': %s", -diff --git a/zkey/zkey.1 b/zkey/zkey.1 -index ba71a839..baaf8478 100644 ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -402,6 +402,9 @@ additional information can be associated with a secure key using the - .B \-\-sector\-size - options. - .PP -+Keys of type \fBPVSECRET\-AES\fP do not use a cryptographic adapter, thus APQNs -+can not be associated with them. -+.PP - .B Note: - The \fBimport\fP command requires the CCA host library (libcsulcca.so) - to be installed when secure keys of type \fBCCA\-AESCIPHER\fP are imported. -@@ -564,6 +567,10 @@ APQNs that are associated with the key management system plugin. - Other associated information is also changed in the key management system when - changed using the change command. - .PP -+For keys of type \fBPVSECRET\-AES\fP you can not change or set the APQN -+association. These keys do not use a cryptographic adapter, thus APQNs can not -+be associated with them. -+.PP - .B Note: - The secure key itself cannot be changed, only information about the secure - key is changed. To rename a secure key, use the \fBrename\fP command. -diff --git a/zkey/zkey.c b/zkey/zkey.c -index 6e9b32af..36bdbcc0 100644 ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -2001,6 +2001,11 @@ static int command_generate(void) - return command_generate_repository(); - if (g.key_type == NULL) - g.key_type = KEY_TYPE_CCA_AESDATA; -+ if (!is_secure_key_type(g.key_type)) { -+ warnx("Keys of type '%s' can not be generated. Use 'zkey " -+ "pvsecret import' instead", g.key_type); -+ return -EXIT_FAILURE; -+ } - if (g.pos_arg != NULL) { - if (g.volumes != NULL) { - warnx("Option '--volumes|-l' is not valid for " diff --git a/s390-tools-06-zkey-Reject-re-enciphering-of-PVSECRET-AES-keys.patch b/s390-tools-06-zkey-Reject-re-enciphering-of-PVSECRET-AES-keys.patch deleted file mode 100644 index 116e03a..0000000 --- a/s390-tools-06-zkey-Reject-re-enciphering-of-PVSECRET-AES-keys.patch +++ /dev/null @@ -1,145 +0,0 @@ -From a8eb2bd4e7e74445c953906b33d450c2ace5223f Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Mon, 19 Feb 2024 11:26:41 +0100 -Subject: [PATCH] zkey: Reject re-enciphering of PVSECRET-AES keys - -Keys of type PVSECRET-AES can not be reenciphered using 'zkey reencipher' -or 'zkey-cryptsetup reencipher'. Reject that with a proper error message. - -Signed-off-by: Ingo Franzki -Reviewed-by: Jorg Schmidbauer -Signed-off-by: Steffen Eiden ---- - zkey/keystore.c | 9 +++++++++ - zkey/zkey-cryptsetup.1 | 8 ++++++-- - zkey/zkey-cryptsetup.c | 16 ++++++++++++---- - zkey/zkey.1 | 4 ++++ - zkey/zkey.c | 7 +++++++ - 5 files changed, 38 insertions(+), 6 deletions(-) - -diff --git a/zkey/keystore.c b/zkey/keystore.c -index db62e0a6..4f795a28 100644 ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -3567,6 +3567,15 @@ static int _keystore_process_reencipher(struct keystore *keystore, - goto out; - } - -+ if (!is_secure_key(secure_key, secure_key_size)) { -+ warnx("Key '%s' is of type %s and can not be re-enciphered, " -+ "skipping", name, get_key_type(secure_key, -+ secure_key_size)); -+ info->num_skipped++; -+ rc = 0; -+ goto out; -+ } -+ - apqns = properties_get(properties, PROP_NAME_APQNS); - if (apqns != NULL) - apqn_list = str_list_split(apqns); -diff --git a/zkey/zkey-cryptsetup.1 b/zkey/zkey-cryptsetup.1 -index c455f845..185edab9 100644 ---- a/zkey/zkey-cryptsetup.1 -+++ b/zkey/zkey-cryptsetup.1 -@@ -1,8 +1,8 @@ --.\" Copyright IBM Corp. 2018 -+.\" Copyright IBM Corp. 2018, 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\-CRYPTSETUP 1 "May 2018" "s390-tools" -+.TH ZKEY\-CRYPTSETUP 1 "February 2024" "s390-tools" - .SH NAME - zkey\-cryptsetup \- Manage secure AES volume keys of volumes encrypted with - \fBLUKS2\fP and the \fBpaes\fP cipher -@@ -115,6 +115,10 @@ command to re-encipher a secure AES volume key of a volume encrypted with - re-enciphered when the master key of the cryptographic adapter in CCA or EP11 - coprocessor mode changes. - .PP -+Volume keys of type \fBPVSECRET\-AES\fP can not be re-enciphered. These keys do -+not use a cryptographic adapter, thus they do not need to be re-enciphered when -+the master key of a cryptographic adapter changes. -+.PP - The cryptographic adapter in CCA coprocessor mode has three different registers - to store master keys: - .RS 2 -diff --git a/zkey/zkey-cryptsetup.c b/zkey/zkey-cryptsetup.c -index 8b55f7d1..2b018a2a 100644 ---- a/zkey/zkey-cryptsetup.c -+++ b/zkey/zkey-cryptsetup.c -@@ -2,7 +2,7 @@ - * zkey-cryptsetup - Re-encipher or validate volume keys of volumes - * encrypted with LUKS2 and the paes cipher. - * -- * Copyright IBM Corp. 2018 -+ * Copyright IBM Corp. 2018, 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. -@@ -82,7 +82,7 @@ static const struct util_prg prg = { - { - .owner = "IBM Corp.", - .pub_first = 2018, -- .pub_last = 2018, -+ .pub_last = 2024, - }, - UTIL_PRG_COPYRIGHT_END - } -@@ -1609,14 +1609,22 @@ static int reencipher_prepare(int token) - if (rc < 0) - goto out; - -+ securekeysize = keysize - integrity_keysize; -+ -+ if (!is_secure_key((u8 *)key, securekeysize)) { -+ warnx("The volume key of device '%s' is of type %s and can " -+ "not be re-enciphered", g.pos_arg, -+ get_key_type((u8 *)key, securekeysize)); -+ rc = -EINVAL; -+ goto out; -+ } -+ - reenc_tok.original_keyslot = rc; - - rc = ensure_is_active_keylot(reenc_tok.original_keyslot); - if (rc != 0) - goto out; - -- securekeysize = keysize - integrity_keysize; -- - rc = generate_key_verification_pattern((u8 *)key, securekeysize, - reenc_tok.verification_pattern, - sizeof(reenc_tok.verification_pattern), -diff --git a/zkey/zkey.1 b/zkey/zkey.1 -index baaf8478..316db5f0 100644 ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -266,6 +266,10 @@ command to re-encipher an existing secure key with a new master key. - A secure key must be re-enciphered when the master key of the CCA or EP11 - cryptographic adapter changes. - .PP -+Keys of type \fBPVSECRET\-AES\fP can not be re-enciphered. These keys do not -+use a cryptographic adapter, thus they do not need to be re-enciphered when the -+master of a cryptographic adapter changes. -+.PP - The CCA cryptographic adapter has three different registers to store - master keys: - .RS 2 -diff --git a/zkey/zkey.c b/zkey/zkey.c -index 36bdbcc0..90b46106 100644 ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -2118,6 +2118,13 @@ static int command_reencipher_file(void) - if (secure_key == NULL) - return EXIT_FAILURE; - -+ if (!is_secure_key(secure_key, secure_key_size)) { -+ warnx("A key of type %s can not be re-enciphered", -+ get_key_type(secure_key, secure_key_size)); -+ rc = EXIT_FAILURE; -+ goto out; -+ } -+ - rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL, - &is_old_mk, NULL, g.verbose); - if (rc != 0) { diff --git a/s390-tools-07-zkey-Support-validation-of-key-of-type-PVSECRET-AES.patch b/s390-tools-07-zkey-Support-validation-of-key-of-type-PVSECRET-AES.patch deleted file mode 100644 index 46bfd6b..0000000 --- a/s390-tools-07-zkey-Support-validation-of-key-of-type-PVSECRET-AES.patch +++ /dev/null @@ -1,407 +0,0 @@ -From 833a8e7309ebf0ce70f2ee989ced5f87d6c3550b Mon Sep 17 00:00:00 2001 -From: Ingo Franzki -Date: Mon, 19 Feb 2024 10:25:54 +0100 -Subject: [PATCH] zkey: Support validation of key of type PVSECRET-AES - -Keys of type PVSECRET-AES can also be verified via the pkey IOCTL -PKEY_VERIFYKEY2, but the card and domain fields must be zero, because such -a key does not use a crypto card. Also XTS keys of type PVSRCRET-AES are -not represented by 2 concatenated keys but by just one key of type -PVSECRET-AES. Thus, special handling is required for XTS keys. - -Signed-off-by: Ingo Franzki -Reviewed-by: Jorg Schmidbauer -Signed-off-by: Steffen Eiden ---- - zkey/keystore.c | 50 ++++++++++++++++++++++-------------- - zkey/pkey.c | 46 +++++++++++++++++++++------------- - zkey/zkey-cryptsetup.1 | 4 ++- - zkey/zkey-cryptsetup.c | 45 +++++++++++++++++++-------------- - zkey/zkey.1 | 8 +++--- - zkey/zkey.c | 57 ++++++++++++++++++++++++------------------ - 6 files changed, 126 insertions(+), 84 deletions(-) - -diff --git a/zkey/keystore.c b/zkey/keystore.c -index 4f795a28..58f27df2 100644 ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -3055,19 +3055,25 @@ static void _keystore_print_record(struct util_rec *rec, - util_rec_set(rec, REC_XTS, is_xts ? "Yes" : "No"); - util_rec_set(rec, REC_KEY_TYPE, key_type); - if (validation) { -- if (valid) -- util_rec_set(rec, REC_MASTERKEY, -- "%s master key (MKVP: %s)", -- is_old_mk ? "OLD" : "CURRENT", -- printable_mkvp( -- get_card_type_for_keytype(key_type), -- mkvp)); -- else -- util_rec_set(rec, REC_MASTERKEY, -- "(unknown, MKVP: %s)", -- printable_mkvp( -- get_card_type_for_keytype(key_type), -- mkvp)); -+ if (mkvp != NULL) { -+ if (valid) -+ util_rec_set(rec, REC_MASTERKEY, -+ "%s master key (MKVP: %s)", -+ is_old_mk ? "OLD" : "CURRENT", -+ printable_mkvp( -+ get_card_type_for_keytype( -+ key_type), -+ mkvp)); -+ else -+ util_rec_set(rec, REC_MASTERKEY, -+ "(unknown, MKVP: %s)", -+ printable_mkvp( -+ get_card_type_for_keytype( -+ key_type), -+ mkvp)); -+ } else { -+ util_rec_set(rec, REC_MASTERKEY, "(none)"); -+ } - } - if (volumes_argz != NULL) - util_rec_set_argz(rec, REC_VOLUMES, volumes_argz, -@@ -3294,17 +3300,22 @@ static int _keystore_process_validate(struct keystore *keystore, - valid = 1; - } - -- rc = get_master_key_verification_pattern(secure_key, secure_key_size, -- mkvp, keystore->verbose); -- if (rc != 0) -- goto out; -+ if (is_secure_key(secure_key, secure_key_size)) { -+ rc = get_master_key_verification_pattern(secure_key, -+ secure_key_size, -+ mkvp, -+ keystore->verbose); -+ if (rc != 0) -+ goto out; -+ } - - _keystore_print_record(info->rec, name, properties, 1, - file_names->skey_filename, secure_key_size, - is_xts_key(secure_key, secure_key_size), - clear_key_bitsize, valid, is_old_mk, - _keystore_reencipher_key_exists(file_names), -- mkvp, -+ is_secure_key(secure_key, secure_key_size) ? -+ mkvp : NULL, - _keystore_passphrase_file_exists(file_names) ? - file_names->pass_filename : NULL); - -@@ -3316,7 +3327,8 @@ static int _keystore_process_validate(struct keystore *keystore, - "master key\n", 0); - info->num_warnings++; - } -- if (info->noapqncheck == 0) -+ if (info->noapqncheck == 0 && -+ is_secure_key(secure_key, secure_key_size)) - if (_keystore_display_apqn_status(keystore, properties, - mkvp) != 0) - info->num_warnings++; -diff --git a/zkey/pkey.c b/zkey/pkey.c -index 53c0a550..25deb05a 100644 ---- a/zkey/pkey.c -+++ b/zkey/pkey.c -@@ -1287,33 +1287,43 @@ int validate_secure_key(int pkey_fd, - { - struct pkey_verifykey2 verifykey2; - struct pkey_apqn *list = NULL; -+ bool xts, valid, securekey; - u32 i, list_entries = 0; -- bool xts, valid; -- u32 flags; -+ u32 flags = 0; - int rc; - - util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); - util_assert(secure_key != NULL, "Internal error: secure_key is NULL"); - -- xts = is_xts_key(secure_key, secure_key_size); -+ securekey = is_secure_key(secure_key, secure_key_size); -+ xts = securekey ? is_xts_key(secure_key, secure_key_size) : false; - -- flags = PKEY_FLAGS_MATCH_CUR_MKVP; -- if (is_cca_aes_data_key(secure_key, secure_key_size) || -- is_cca_aes_cipher_key(secure_key, secure_key_size)) -- flags |= PKEY_FLAGS_MATCH_ALT_MKVP; -+ if (securekey) { -+ flags = PKEY_FLAGS_MATCH_CUR_MKVP; -+ if (is_cca_aes_data_key(secure_key, secure_key_size) || -+ is_cca_aes_cipher_key(secure_key, secure_key_size)) -+ flags |= PKEY_FLAGS_MATCH_ALT_MKVP; - -- rc = build_apqn_list_for_key(pkey_fd, secure_key, -- HALF_KEYSIZE_FOR_XTS(secure_key_size, xts), -- flags, apqns, &list, &list_entries, -- verbose); -- if (rc != 0) { -- pr_verbose(verbose, "Failed to build a list of APQNs that can " -- "validate this secure key: %s", strerror(-rc)); -- return rc; -+ rc = build_apqn_list_for_key(pkey_fd, secure_key, -+ HALF_KEYSIZE_FOR_XTS( -+ secure_key_size, xts), -+ flags, apqns, &list, &list_entries, -+ verbose); -+ if (rc != 0) { -+ pr_verbose(verbose, "Failed to build a list of APQNs " -+ "that can validate this secure " -+ "key: %s", strerror(-rc)); -+ return rc; -+ } -+ } else { -+ list = util_malloc(sizeof(struct pkey_apqn)); -+ list[0].card = 0; -+ list[0].domain = 0; -+ list_entries = 1; - } - - if (is_old_mk != NULL) -- *is_old_mk = true; -+ *is_old_mk = securekey ? true : false; - if (clear_key_bitsize != NULL) - *clear_key_bitsize = 0; - -@@ -1333,7 +1343,7 @@ int validate_secure_key(int pkey_fd, - continue; - } - -- if (is_xts_key(secure_key, secure_key_size)) { -+ if (xts) { - rc = validate_secure_xts_key(pkey_fd, &list[i], - secure_key, - secure_key_size, -@@ -1358,7 +1368,7 @@ int validate_secure_key(int pkey_fd, - * If at least one of the APQNs have a matching current MK, - * then don't report OLD, even if some match the old MK. - */ -- if (is_old_mk && -+ if (securekey && is_old_mk && - (verifykey2.flags & PKEY_FLAGS_MATCH_CUR_MKVP)) - *is_old_mk = false; - } -diff --git a/zkey/zkey-cryptsetup.1 b/zkey/zkey-cryptsetup.1 -index 185edab9..ffd600d4 100644 ---- a/zkey/zkey-cryptsetup.1 -+++ b/zkey/zkey-cryptsetup.1 -@@ -68,7 +68,9 @@ It also displays the attributes of the secure key, such as key size, whether - it is a secure key that can be used for the XTS cipher mode, and the master key - register (CURRENT or OLD) with which the secure key is enciphered. - For further information about master key registers, see the --\fBreencipher\fP command. -+\fBreencipher\fP command. Keys of type \fBPVSECRET\-AES\fP do not use a -+cryptographic adapter, thus no master key information is displayed for such -+keys. - .PP - To open a key slot contained in the LUKS2 header of the volume, a passphrase is - required. You are prompted for the passphrase, unless option -diff --git a/zkey/zkey-cryptsetup.c b/zkey/zkey-cryptsetup.c -index 2b018a2a..65716f3b 100644 ---- a/zkey/zkey-cryptsetup.c -+++ b/zkey/zkey-cryptsetup.c -@@ -1346,8 +1346,7 @@ static int check_keysize_and_cipher_mode(const u8 *key, size_t keysize) - } - - if (strncmp(crypt_get_cipher_mode(g.cd), "xts", 3) == 0) { -- if (keysize < 2 * MIN_SECURE_KEY_SIZE || -- (key != NULL && !is_xts_key(key, keysize))) { -+ if (key != NULL && !is_xts_key(key, keysize)) { - warnx("The volume key size %lu is not valid for the " - "cipher mode '%s'", keysize, - crypt_get_cipher_mode(g.cd)); -@@ -1539,8 +1538,9 @@ static int validate_keyslot(int keyslot, char **key, size_t *keysize, - rc = -EINVAL; - goto out; - } -- pr_verbose("Volume key is currently enciphered with %s master key", -- is_old ? "OLD" : "CURRENT"); -+ if (is_secure_key((u8 *)vkey, vkeysize - ikeysize)) -+ pr_verbose("Volume key is currently enciphered with %s " -+ "master key", is_old ? "OLD" : "CURRENT"); - - if (key != NULL) - *key = vkey; -@@ -2023,12 +2023,14 @@ static int command_validate(void) - vp_tok_avail = 1; - } - -- rc = get_master_key_verification_pattern((u8 *)key, seckeysize, -- mkvp, g.verbose); -- if (rc != 0) { -- warnx("Failed to get the master key verification pattern: %s", -- strerror(-rc)); -- goto out; -+ if (is_secure_key((u8 *)key, seckeysize)) { -+ rc = get_master_key_verification_pattern((u8 *)key, seckeysize, -+ mkvp, g.verbose); -+ if (rc != 0) { -+ warnx("Failed to get the master key verification " -+ "pattern: %s", strerror(-rc)); -+ goto out; -+ } - } - - key_type = get_key_type((u8 *)key, seckeysize); -@@ -2041,15 +2043,19 @@ static int command_validate(void) - printf(" Key type: %s\n", key_type); - if (is_valid) { - printf(" Clear key size: %lu bits\n", clear_keysize); -- printf(" Enciphered with: %s master key (MKVP: " -- "%s)\n", is_old_mk ? "OLD" : "CURRENT", -- printable_mkvp(get_card_type_for_keytype(key_type), -- mkvp)); -+ if (is_secure_key((u8 *)key, seckeysize)) { -+ printf(" Enciphered with: %s master key (MKVP: " -+ "%s)\n", is_old_mk ? "OLD" : "CURRENT", -+ printable_mkvp(get_card_type_for_keytype( -+ key_type), mkvp)); -+ } - } else { - printf(" Clear key size: (unknown)\n"); -- printf(" Enciphered with: (unknown, MKVP: %s)\n", -- printable_mkvp(get_card_type_for_keytype(key_type), -- mkvp)); -+ if (is_secure_key((u8 *)key, seckeysize)) { -+ printf(" Enciphered with: (unknown, MKVP: %s)\n", -+ printable_mkvp(get_card_type_for_keytype( -+ key_type), mkvp)); -+ } - } - if (vp_tok_avail) - print_verification_pattern(vp_tok.verification_pattern); -@@ -2065,7 +2071,7 @@ static int command_validate(void) - if (!is_valid) - printf("\nATTENTION: The secure volume key is not valid.\n"); - -- if (is_old_mk) -+ if (is_secure_key((u8 *)key, seckeysize) && is_old_mk) - util_print_indented("\nWARNING: The secure volume key is " - "currently enciphered with the OLD " - "master key. To mitigate the danger of " -@@ -2195,7 +2201,8 @@ static int command_setkey(void) - goto out; - } - -- if (is_old_mk) { -+ if (is_secure_key(newkey, newkey_size - integrity_keysize) && -+ is_old_mk) { - util_asprintf(&msg, "The secure key in file '%s' is " - "enciphered with the master key in the OLD " - "master key register. Do you want to set this " -diff --git a/zkey/zkey.1 b/zkey/zkey.1 -index 316db5f0..b44eadf1 100644 ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -209,7 +209,9 @@ It also displays the attributes of the secure key, such as key sizes, whether - it is a secure key that can be used for the XTS cipher mode, the master key - register (CURRENT or OLD) with which the secure key is enciphered, and other key - attributes. For further information about master key registers, see the --\fBreencipher\fP command. -+\fBreencipher\fP command. Keys of type \fBPVSECRET\-AES\fP do not use a -+cryptographic adapter, thus no master key information is displayed for such -+keys. - .PP - The secure key can either be contained in a file in the file system, or in a - secure key repository. To validate a secure key contained in a file, specify -@@ -1599,8 +1601,8 @@ This option is only used for secure keys contained in the secure key repository. - .TP - .BR \-K ", " \-\-key\-type\~\fItype\fP - Specifies the key type of the secure key. Possible values are --\fBCCA\-AESDATA\fP, \fBCCA\-AESCIPHER\fP, and \fBEP11\-AES\fP. Only keys with --the specified key type are listed. -+\fBCCA\-AESDATA\fP, \fBCCA\-AESCIPHER\fP, \fBEP11\-AES\fP, and -+\fBPVSECRET\-AES\fP. Only keys with the specified key type are listed. - This option is only used for secure keys contained in the secure key repository. - .TP - .BR \-L ", " \-\-local\fP -diff --git a/zkey/zkey.c b/zkey/zkey.c -index 90b46106..39a527c4 100644 ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -558,9 +558,10 @@ static struct util_opt opt_vec[] = { - .option = { "key-type", required_argument, NULL, 'K'}, - .argument = "type", - .desc = "The type of the key. Possible values are '" -- KEY_TYPE_CCA_AESDATA"', '"KEY_TYPE_CCA_AESCIPHER"' " -- "and '"KEY_TYPE_EP11_AES"'. Use this option to list " -- "all keys with the specified key type.", -+ KEY_TYPE_CCA_AESDATA "', '" KEY_TYPE_CCA_AESCIPHER -+ "', '" KEY_TYPE_EP11_AES "', and '" -+ KEY_TYPE_PVSECRET_AES "'. Use this option to list all " -+ "keys with the specified key type.", - .command = COMMAND_LIST, - }, - { -@@ -2345,13 +2346,16 @@ static int command_validate_file(void) - goto out; - } - -- rc = get_master_key_verification_pattern(secure_key, secure_key_size, -- mkvp, g.verbose); -- if (rc != 0) { -- warnx("Failed to get the master key verification pattern: %s", -- strerror(-rc)); -- rc = EXIT_FAILURE; -- goto out; -+ if (is_secure_key(secure_key, secure_key_size)) { -+ rc = get_master_key_verification_pattern(secure_key, -+ secure_key_size, -+ mkvp, g.verbose); -+ if (rc != 0) { -+ warnx("Failed to get the master key verification " -+ "pattern: %s", strerror(-rc)); -+ rc = EXIT_FAILURE; -+ goto out; -+ } - } - - key_type = get_key_type(secure_key, secure_key_size); -@@ -2363,25 +2367,30 @@ static int command_validate_file(void) - printf(" Clear key size: %lu bits\n", clear_key_size); - printf(" XTS type key: %s\n", - is_xts_key(secure_key, secure_key_size) ? "Yes" : "No"); -- printf(" Enciphered with: %s master key (MKVP: %s)\n", -- is_old_mk ? "OLD" : "CURRENT", -- printable_mkvp(get_card_type_for_keytype(key_type), mkvp)); -+ if (is_secure_key(secure_key, secure_key_size)) { -+ printf(" Enciphered with: %s master key (MKVP: %s)\n", -+ is_old_mk ? "OLD" : "CURRENT", -+ printable_mkvp(get_card_type_for_keytype(key_type), -+ mkvp)); -+ } - printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2, - vp); - printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2, - &vp[VERIFICATION_PATTERN_LEN / 2]); - -- rc = cross_check_apqns(NULL, mkvp, -- get_min_card_level_for_keytype(key_type), -- get_min_fw_version_for_keytype(key_type), -- get_card_type_for_keytype(key_type), -- true, g.verbose); -- if (rc == -EINVAL) -- return EXIT_FAILURE; -- if (rc != 0 && rc != -ENOTSUP) { -- warnx("Your master key setup is improper"); -- rc = EXIT_FAILURE; -- goto out; -+ if (is_secure_key(secure_key, secure_key_size)) { -+ rc = cross_check_apqns(NULL, mkvp, -+ get_min_card_level_for_keytype(key_type), -+ get_min_fw_version_for_keytype(key_type), -+ get_card_type_for_keytype(key_type), -+ true, g.verbose); -+ if (rc == -EINVAL) -+ return EXIT_FAILURE; -+ if (rc != 0 && rc != -ENOTSUP) { -+ warnx("Your master key setup is improper"); -+ rc = EXIT_FAILURE; -+ goto out; -+ } - } - - out: diff --git a/s390-tools-08-rust-pvimg-Fix-flag-parsing-for-allowing-dump.patch b/s390-tools-08-rust-pvimg-Fix-flag-parsing-for-allowing-dump.patch deleted file mode 100644 index 9941241..0000000 --- a/s390-tools-08-rust-pvimg-Fix-flag-parsing-for-allowing-dump.patch +++ /dev/null @@ -1,31 +0,0 @@ -From caaf2b2116235d282c2561f0bf6f62b0033c78c4 Mon Sep 17 00:00:00 2001 -From: Jakob Naucke -Date: Wed, 15 Jan 2025 17:36:01 +0100 -Subject: [PATCH] rust/pvimg: Fix flag parsing for allowing dump -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Parsing of pvimg flags did not pick up allowing dumping correctly. - -Fixes: f4cf4ae6ebb1 (rust: Add a new tool called 'pvimg') -Reviewed-by: Marc Hartmayer -Signed-off-by: Jakob Naucke -Signed-off-by: Jan Höppner ---- - rust/pvimg/src/cmd/create.rs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/rust/pvimg/src/cmd/create.rs b/rust/pvimg/src/cmd/create.rs -index 3e2ca655..c9d39745 100644 ---- a/rust/pvimg/src/cmd/create.rs -+++ b/rust/pvimg/src/cmd/create.rs -@@ -55,7 +55,7 @@ fn parse_flags( - .and(Some(PcfV1::all_disabled([PcfV1::AllowDumping]))), - lf.enable_dump - .filter(|x| *x) -- .and(Some(PcfV1::all_disabled([PcfV1::AllowDumping]))), -+ .and(Some(PcfV1::all_enabled([PcfV1::AllowDumping]))), - lf.disable_pckmo - .filter(|x| *x) - .and(Some(PcfV1::all_disabled([ diff --git a/s390-tools-09-rust-pvimg-Document-the-change-from--comm-key-to--cck.patch b/s390-tools-09-rust-pvimg-Document-the-change-from--comm-key-to--cck.patch deleted file mode 100644 index b1edf9f..0000000 --- a/s390-tools-09-rust-pvimg-Document-the-change-from--comm-key-to--cck.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 7bc12d0202d5819442dd4c32755feb5eb19af70b Mon Sep 17 00:00:00 2001 -From: Marc Hartmayer -Date: Wed, 8 Jan 2025 12:33:05 +0100 -Subject: [PATCH] rust/pvimg: Document the change from '--comm-key' to '--cck' - in the help message - -This fixes problems when users search for '--comm-key' in the help -message. - -Fixes: 5b6d7a467dc3 ("rust/pvimg: Add '--cck ' command line option and make '--comm-key' an alias") -Reviewed-by: Steffen Eiden -Reviewed-by: Nico Boehr -Signed-off-by: Marc Hartmayer -Signed-off-by: Steffen Eiden ---- - rust/pvimg/src/cli.rs | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/rust/pvimg/src/cli.rs b/rust/pvimg/src/cli.rs -index 446e9b74..f5a8c308 100644 ---- a/rust/pvimg/src/cli.rs -+++ b/rust/pvimg/src/cli.rs -@@ -330,7 +330,8 @@ pub struct CreateBootImageArgs { - - /// Use the content of FILE as the customer-communication key (CCK). - /// -- /// The file must contain exactly 32 bytes of data. -+ /// The file must contain exactly 32 bytes of data. This option used to be -+ /// called '--comm-key' in previous versions. - #[arg(long, value_name = "FILE", visible_alias = "comm-key")] - pub cck: Option, - diff --git a/s390-tools-2.36.0.tar.gz b/s390-tools-2.36.0.tar.gz deleted file mode 100644 index 261eabe..0000000 --- a/s390-tools-2.36.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:53d5ee7adce0fe3f22a5e869f953cff3a655e8b13aff64b0998bce3e0e3c2a43 -size 2184500 diff --git a/s390-tools-2.37.0.tar.gz b/s390-tools-2.37.0.tar.gz new file mode 100644 index 0000000..6a25a34 --- /dev/null +++ b/s390-tools-2.37.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d701413fe80a1185c1c96a0678c2441c22447420722c7f44286c9faf5eeb5d5a +size 2214011 diff --git a/s390-tools-Additional-update-01.patch b/s390-tools-Additional-update-01.patch deleted file mode 100644 index 1433eb5..0000000 --- a/s390-tools-Additional-update-01.patch +++ /dev/null @@ -1,64 +0,0 @@ -From dff965465ca9d9c4edaf0f90eadd9a6de335b354 Mon Sep 17 00:00:00 2001 -From: Niklas Schnelle -Date: Fri, 6 Dec 2024 15:28:08 +0100 -Subject: [PATCH] opticsmon: Fix runaway loop in on_link_change() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When on_link_change() gets called with a netdev that would be monitored -but hasn't entered zpci_list yet, reloads is 1 after the loops and -a reload occurs. Then the netdev is found in the list and reloads -becomes -1 which incorrectly triggers more reloads until underflow. -Fix this by returning once the device is found. Also just check for -reloads being larger than zero. - -Fixes: c34adb9cabee ("opticsmon: Introduce opticsmon tool") -Reviewed-by: Halil Pasic -Signed-off-by: Niklas Schnelle -Signed-off-by: Jan Höppner ---- - opticsmon/opticsmon.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/opticsmon/opticsmon.c b/opticsmon/opticsmon.c -index c2f355e2..50dd8d7f 100644 ---- a/opticsmon/opticsmon.c -+++ b/opticsmon/opticsmon.c -@@ -280,16 +280,15 @@ void on_link_change(struct zpci_netdev *netdev, void *arg) - if (!ctx->zpci_list || util_list_is_empty(ctx->zpci_list)) - zpci_list_reload(&ctx->zpci_list); - --reload: -+find: - util_list_iterate(ctx->zpci_list, zdev) { - for (i = 0; i < zdev->num_netdevs; i++) { - if (!strcmp(zdev->netdevs[i].name, netdev->name)) { -- reloads--; - /* Skip data collection if operational state is - * unchanged - */ - if (zdev->netdevs[i].operstate == netdev->operstate) -- continue; -+ return; - /* Update operation state for VFs even though - * they are skipped just for a consistent view - */ -@@ -297,14 +296,15 @@ void on_link_change(struct zpci_netdev *netdev, void *arg) - /* Only collect optics data for PFs */ - if (!zpci_is_vf(zdev)) - dump_adapter_data(ctx, zdev); -+ return; - } - } - } - /* Might be a new device, reload list of devices and retry */ -- if (reloads) { -+ if (reloads > 0) { - zpci_list_reload(&ctx->zpci_list); - reloads--; -- goto reload; -+ goto find; - } - } - diff --git a/s390-tools-Additional-update-02.patch b/s390-tools-Additional-update-02.patch deleted file mode 100644 index 7c711cc..0000000 --- a/s390-tools-Additional-update-02.patch +++ /dev/null @@ -1,129 +0,0 @@ -From cf5560a100b5552e2eeeaac9c60a88ae77233530 Mon Sep 17 00:00:00 2001 -From: Niklas Schnelle -Date: Mon, 9 Dec 2024 15:08:03 +0100 -Subject: [PATCH] libzpci: opticsmon: Refactor on_link_change() using new - zpci_find_by_netdev() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Finding a PCI device given the name of a netdev seems generally useful -so pull this out into a new zpci_find_by_netdev() function in libzpci -and use this to simplify on_link_change() removing the need for -backwards goto. - -Reviewed-by: Halil Pasic -Reviewed-by: Jan Höppner -Signed-off-by: Niklas Schnelle -Signed-off-by: Jan Höppner ---- - include/lib/pci_list.h | 3 +++ - libzpci/pci_list.c | 31 +++++++++++++++++++++++++++++++ - opticsmon/opticsmon.c | 27 +++++++++++---------------- - 3 files changed, 45 insertions(+), 16 deletions(-) - -diff --git a/include/lib/pci_list.h b/include/lib/pci_list.h -index 829ec244..5b2918bc 100644 ---- a/include/lib/pci_list.h -+++ b/include/lib/pci_list.h -@@ -93,4 +93,7 @@ const char *zpci_pft_str(struct zpci_dev *zdev); - const char *zpci_operstate_str(operstate_t state); - operstate_t zpci_operstate_from_str(const char *oper_str); - -+struct zpci_dev *zpci_find_by_netdev(struct util_list *zpci_list, char *netdev_name, -+ struct zpci_netdev **netdev); -+ - #endif /* LIB_ZPCI_PCI_LIST_H */ -diff --git a/libzpci/pci_list.c b/libzpci/pci_list.c -index 10f64e89..e0d56e44 100644 ---- a/libzpci/pci_list.c -+++ b/libzpci/pci_list.c -@@ -356,3 +356,34 @@ void zpci_free_dev_list(struct util_list *zpci_list) - } - util_list_free(zpci_list); - } -+ -+/** -+ * Find a PCI device given the name of a netdev -+ * -+ * This function allows finding a PCI device when only the name of one -+ * of its netdevs is known. -+ * -+ * @param[in] zpci_list The device list to search -+ * @param[in] netdev_name The name of the netdev -+ * @param[out] netdev Pointer to store the netdev or NULL if -+ * only the PCI device is needed -+ * -+ * @return The PCI device if one is found NULL otherwise -+ */ -+struct zpci_dev *zpci_find_by_netdev(struct util_list *zpci_list, char *netdev_name, -+ struct zpci_netdev **netdev) -+{ -+ struct zpci_dev *zdev = NULL; -+ int i; -+ -+ util_list_iterate(zpci_list, zdev) { -+ for (i = 0; i < zdev->num_netdevs; i++) { -+ if (!strcmp(zdev->netdevs[i].name, netdev_name)) { -+ if (netdev) -+ *netdev = &zdev->netdevs[i]; -+ return zdev; -+ } -+ } -+ } -+ return NULL; -+} -diff --git a/opticsmon/opticsmon.c b/opticsmon/opticsmon.c -index 50dd8d7f..7ecaa125 100644 ---- a/opticsmon/opticsmon.c -+++ b/opticsmon/opticsmon.c -@@ -274,38 +274,33 @@ static int oneshot_mode(struct opticsmon_ctx *ctx) - void on_link_change(struct zpci_netdev *netdev, void *arg) - { - struct opticsmon_ctx *ctx = arg; -- struct zpci_dev *zdev; -- int i, reloads = 1; -- -- if (!ctx->zpci_list || util_list_is_empty(ctx->zpci_list)) -- zpci_list_reload(&ctx->zpci_list); -+ struct zpci_netdev *found_netdev; -+ struct zpci_dev *zdev = NULL; -+ int reloads = 1; - --find: -- util_list_iterate(ctx->zpci_list, zdev) { -- for (i = 0; i < zdev->num_netdevs; i++) { -- if (!strcmp(zdev->netdevs[i].name, netdev->name)) { -+ do { -+ if (ctx->zpci_list) { -+ zdev = zpci_find_by_netdev(ctx->zpci_list, netdev->name, &found_netdev); -+ if (zdev) { - /* Skip data collection if operational state is - * unchanged - */ -- if (zdev->netdevs[i].operstate == netdev->operstate) -+ if (found_netdev->operstate == netdev->operstate) - return; - /* Update operation state for VFs even though - * they are skipped just for a consistent view - */ -- zdev->netdevs[i].operstate = netdev->operstate; -+ found_netdev->operstate = netdev->operstate; - /* Only collect optics data for PFs */ - if (!zpci_is_vf(zdev)) - dump_adapter_data(ctx, zdev); - return; - } - } -- } -- /* Might be a new device, reload list of devices and retry */ -- if (reloads > 0) { -+ /* Could be uninitalized list or a new device, retry after reload */ - zpci_list_reload(&ctx->zpci_list); - reloads--; -- goto find; -- } -+ } while (reloads > 0); - } - - #define MAX_EVENTS 8 diff --git a/s390-tools-General-update-01.patch b/s390-tools-General-update-01.patch deleted file mode 100644 index fadf386..0000000 --- a/s390-tools-General-update-01.patch +++ /dev/null @@ -1,147 +0,0 @@ -From 1e44ace41de3cbd744b22a8f9835473b091186e0 Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Thu, 18 Jul 2024 10:55:45 +0200 -Subject: [PATCH] rust/pvsecret: Refactor writing secret -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Refactor the writing of secret-type dependent output files to ease -extensions. - -Reviewed-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv/src/uvsecret/guest_secret.rs | 2 +- - rust/pvsecret/src/cmd/create.rs | 89 +++++++++++++++------------- - 2 files changed, 48 insertions(+), 43 deletions(-) - -diff --git a/rust/pv/src/uvsecret/guest_secret.rs b/rust/pv/src/uvsecret/guest_secret.rs -index 509691fa..4f1db31c 100644 ---- a/rust/pv/src/uvsecret/guest_secret.rs -+++ b/rust/pv/src/uvsecret/guest_secret.rs -@@ -68,7 +68,7 @@ impl GuestSecret { - } - - /// Reference to the confidential data -- pub(crate) fn confidential(&self) -> &[u8] { -+ pub fn confidential(&self) -> &[u8] { - match &self { - Self::Null => &[], - Self::Association { secret, .. } => secret.value().as_slice(), -diff --git a/rust/pvsecret/src/cmd/create.rs b/rust/pvsecret/src/cmd/create.rs -index 808b29e1..9251c38c 100644 ---- a/rust/pvsecret/src/cmd/create.rs -+++ b/rust/pvsecret/src/cmd/create.rs -@@ -62,7 +62,7 @@ pub fn create(opt: &CreateSecretOpt) -> Result<()> { - write_out(&opt.output, ser_asrbc, "add-secret request")?; - info!("Successfully wrote the request to '{}'", &opt.output); - -- write_secret(&opt.secret, &asrcb, &opt.output) -+ write_secret(&opt.secret, asrcb.guest_secret(), &opt.output) - } - - /// Read+parse the first key from the buffer. -@@ -206,54 +206,59 @@ fn read_cuid(asrcb: &mut AddSecretRequest, opt: &CreateSecretOpt) -> Result<()> - Ok(()) - } - -+// Write non confidential data (=name+id) to a yaml stdout -+fn write_yaml>( -+ name: &str, -+ guest_secret: &GuestSecret, -+ stdout: &bool, -+ outp_path: P, -+) -> Result<()> { -+ debug!("Non-confidential secret information: {guest_secret:x?}"); -+ -+ let secret_info = serde_yaml::to_string(guest_secret)?; -+ if stdout.to_owned() { -+ println!("{secret_info}"); -+ return Ok(()); -+ } -+ -+ let gen_name: String = name -+ .chars() -+ .map(|c| if c.is_whitespace() { '_' } else { c }) -+ .collect(); -+ let mut yaml_path = outp_path -+ .as_ref() -+ .parent() -+ .with_context(|| format!("Cannot open directory of {:?}", outp_path.as_ref()))? -+ .to_owned(); -+ yaml_path.push(gen_name); -+ yaml_path.set_extension("yaml"); -+ write_out(&yaml_path, secret_info, "secret information")?; -+ warn!( -+ "Successfully wrote secret info to '{}'", -+ yaml_path.display().to_string() -+ ); -+ Ok(()) -+} -+ - /// Write the generated secret (if any) to the specified output stream - fn write_secret>( - secret: &AddSecretType, -- asrcb: &AddSecretRequest, -+ guest_secret: &GuestSecret, - outp_path: P, - ) -> Result<()> { -- if let AddSecretType::Association { -- name, -- stdout, -- output_secret: secret_out, -- .. -- } = secret -- { -- let gen_name: String = name -- .chars() -- .map(|c| if c.is_whitespace() { '_' } else { c }) -- .collect(); -- let mut gen_path = outp_path -- .as_ref() -- .parent() -- .with_context(|| format!("Cannot open directory of {:?}", outp_path.as_ref()))? -- .to_owned(); -- gen_path.push(format!("{gen_name}.yaml")); -- -- // write non confidential data (=name+id) to a yaml -- let secret_info = serde_yaml::to_string(asrcb.guest_secret())?; -- if stdout.to_owned() { -- println!("{secret_info}"); -- } else { -- write_out(&gen_path, secret_info, "association secret info")?; -- debug!( -- "Non-confidential secret information: {:x?}", -- asrcb.guest_secret() -- ); -- warn!( -- "Successfully wrote association info to '{}'", -- gen_path.display() -- ); -- } -- -- if let Some(path) = secret_out { -- if let GuestSecret::Association { secret, .. } = asrcb.guest_secret() { -- write_out(path, secret.value(), "Association secret")? -- } else { -- unreachable!("The secret type has to be `association` at this point (bug)!") -+ match secret { -+ AddSecretType::Association { -+ name, -+ stdout, -+ output_secret, -+ .. -+ } => { -+ write_yaml(name, guest_secret, stdout, outp_path)?; -+ if let Some(path) = output_secret { -+ write_out(path, guest_secret.confidential(), "Association secret")? - } -- info!("Successfully wrote generated association secret to '{path}'"); - } -+ _ => (), - }; - Ok(()) - } diff --git a/s390-tools-General-update-02.patch b/s390-tools-General-update-02.patch deleted file mode 100644 index a1a1ac1..0000000 --- a/s390-tools-General-update-02.patch +++ /dev/null @@ -1,467 +0,0 @@ -From d1636168b26cc842bc0766235c8a4f2da9663f20 Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Tue, 5 Mar 2024 10:46:29 +0100 -Subject: [PATCH] rust/pv: Support for writing data in PEM format -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use existing OpenSSL functionalities to create PEM files containing -arbitrary data. - -Acked-by: Marc Hartmayer -Acked-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv/src/error.rs | 3 + - rust/pv/src/lib.rs | 6 + - rust/pv/src/openssl_extensions/bio.rs | 85 +++++++ - rust/pv/src/openssl_extensions/mod.rs | 2 + - .../src/openssl_extensions/stackable_crl.rs | 41 +--- - rust/pv/src/pem_utils.rs | 222 ++++++++++++++++++ - 6 files changed, 321 insertions(+), 38 deletions(-) - create mode 100644 rust/pv/src/openssl_extensions/bio.rs - create mode 100644 rust/pv/src/pem_utils.rs - -diff --git a/rust/pv/src/error.rs b/rust/pv/src/error.rs -index af85e93e..3ba808f2 100644 ---- a/rust/pv/src/error.rs -+++ b/rust/pv/src/error.rs -@@ -106,6 +106,9 @@ pub enum Error { - )] - AddDataMissing(&'static str), - -+ #[error("An ASCII string was expected, but non-ASCII characters were received.")] -+ NonAscii, -+ - // errors from other crates - #[error(transparent)] - PvCore(#[from] pv_core::Error), -diff --git a/rust/pv/src/lib.rs b/rust/pv/src/lib.rs -index 7a33210c..ec31b9a4 100644 ---- a/rust/pv/src/lib.rs -+++ b/rust/pv/src/lib.rs -@@ -37,6 +37,7 @@ mod brcb; - mod crypto; - mod error; - mod openssl_extensions; -+mod pem_utils; - mod req; - mod utils; - mod uvattest; -@@ -71,6 +72,11 @@ pub mod attest { - }; - } - -+/// Definitions and functions to write objects in PEM format -+pub mod pem { -+ pub use crate::pem_utils::Pem; -+} -+ - /// Miscellaneous functions and definitions - pub mod misc { - pub use pv_core::misc::*; -diff --git a/rust/pv/src/openssl_extensions/bio.rs b/rust/pv/src/openssl_extensions/bio.rs -new file mode 100644 -index 00000000..73528eed ---- /dev/null -+++ b/rust/pv/src/openssl_extensions/bio.rs -@@ -0,0 +1,85 @@ -+// SPDX-License-Identifier: MIT -+// -+// Copyright IBM Corp. 2024 -+ -+use core::slice; -+use openssl::error::ErrorStack; -+use openssl_sys::BIO_new_mem_buf; -+use std::ffi::c_int; -+use std::{marker::PhantomData, ptr}; -+ -+pub struct BioMem(*mut openssl_sys::BIO); -+ -+impl Drop for BioMem { -+ fn drop(&mut self) { -+ // SAFETY: Pointer is valid. The pointer value is dropped after the free. -+ unsafe { -+ openssl_sys::BIO_free_all(self.0); -+ } -+ } -+} -+ -+impl BioMem { -+ pub fn new() -> Result { -+ openssl_sys::init(); -+ -+ // SAFETY: Returns a valid pointer or null. null-case is tested right after this. -+ let bio = unsafe { openssl_sys::BIO_new(openssl_sys::BIO_s_mem()) }; -+ match bio.is_null() { -+ true => Err(ErrorStack::get()), -+ false => Ok(Self(bio)), -+ } -+ } -+ -+ pub fn as_ptr(&self) -> *mut openssl_sys::BIO { -+ self.0 -+ } -+ -+ /// Copies the content of this slice into a Vec -+ pub fn to_vec(&self) -> Vec { -+ let buf; -+ // SAFTEY: BIO provides a continuous memory that can be used to build a slice. -+ unsafe { -+ let mut ptr = ptr::null_mut(); -+ let len = openssl_sys::BIO_get_mem_data(self.0, &mut ptr); -+ buf = slice::from_raw_parts(ptr as *const _ as *const _, len as usize) -+ } -+ buf.to_vec() -+ } -+} -+ -+pub struct BioMemSlice<'a>(*mut openssl_sys::BIO, PhantomData<&'a [u8]>); -+impl Drop for BioMemSlice<'_> { -+ fn drop(&mut self) { -+ // SAFETY: Pointer is valid. The pointer value is dropped after the free. -+ unsafe { -+ openssl_sys::BIO_free_all(self.0); -+ } -+ } -+} -+ -+impl<'a> BioMemSlice<'a> { -+ pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { -+ openssl_sys::init(); -+ -+ // SAFETY: `buf` is a slice (i.e. pointer+size) pointing to a valid memory region. -+ // So the resulting bio is valid. Lifetime of the slice is connected by this Rust -+ // structure. -+ assert!(buf.len() <= c_int::MAX as usize); -+ let bio = unsafe { -+ { -+ let r = BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int); -+ match r.is_null() { -+ true => Err(ErrorStack::get()), -+ false => Ok(r), -+ } -+ }? -+ }; -+ -+ Ok(BioMemSlice(bio, PhantomData)) -+ } -+ -+ pub fn as_ptr(&self) -> *mut openssl_sys::BIO { -+ self.0 -+ } -+} -diff --git a/rust/pv/src/openssl_extensions/mod.rs b/rust/pv/src/openssl_extensions/mod.rs -index fab26638..f6234e5d 100644 ---- a/rust/pv/src/openssl_extensions/mod.rs -+++ b/rust/pv/src/openssl_extensions/mod.rs -@@ -6,8 +6,10 @@ - - /// Extensions to the rust-openssl crate - mod akid; -+mod bio; - mod crl; - mod stackable_crl; - - pub use akid::*; -+pub use bio::*; - pub use crl::*; -diff --git a/rust/pv/src/openssl_extensions/stackable_crl.rs b/rust/pv/src/openssl_extensions/stackable_crl.rs -index aef7cf86..12a9f9de 100644 ---- a/rust/pv/src/openssl_extensions/stackable_crl.rs -+++ b/rust/pv/src/openssl_extensions/stackable_crl.rs -@@ -2,16 +2,14 @@ - // - // Copyright IBM Corp. 2023 - --use std::{marker::PhantomData, ptr}; -- -+use crate::openssl_extensions::bio::BioMemSlice; - use foreign_types::{ForeignType, ForeignTypeRef}; - use openssl::{ - error::ErrorStack, - stack::Stackable, - x509::{X509Crl, X509CrlRef}, - }; --use openssl_sys::BIO_new_mem_buf; --use std::ffi::c_int; -+use std::ptr; - - #[derive(Debug)] - pub struct StackableX509Crl(*mut openssl_sys::X509_CRL); -@@ -62,44 +60,11 @@ impl Stackable for StackableX509Crl { - type StackType = openssl_sys::stack_st_X509_CRL; - } - --pub struct MemBioSlice<'a>(*mut openssl_sys::BIO, PhantomData<&'a [u8]>); --impl Drop for MemBioSlice<'_> { -- fn drop(&mut self) { -- unsafe { -- openssl_sys::BIO_free_all(self.0); -- } -- } --} -- --impl<'a> MemBioSlice<'a> { -- pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { -- openssl_sys::init(); -- -- assert!(buf.len() <= c_int::MAX as usize); -- let bio = unsafe { -- { -- let r = BIO_new_mem_buf(buf.as_ptr() as *const _, buf.len() as c_int); -- if r.is_null() { -- Err(ErrorStack::get()) -- } else { -- Ok(r) -- } -- }? -- }; -- -- Ok(MemBioSlice(bio, PhantomData)) -- } -- -- pub fn as_ptr(&self) -> *mut openssl_sys::BIO { -- self.0 -- } --} -- - impl StackableX509Crl { - pub fn stack_from_pem(pem: &[u8]) -> Result, ErrorStack> { - unsafe { - openssl_sys::init(); -- let bio = MemBioSlice::new(pem)?; -+ let bio = BioMemSlice::new(pem)?; - - let mut crls = vec![]; - loop { -diff --git a/rust/pv/src/pem_utils.rs b/rust/pv/src/pem_utils.rs -new file mode 100644 -index 00000000..e6462519 ---- /dev/null -+++ b/rust/pv/src/pem_utils.rs -@@ -0,0 +1,222 @@ -+// SPDX-License-Identifier: MIT -+// -+// Copyright IBM Corp. 2024 -+ -+use crate::Result; -+use crate::{openssl_extensions::BioMem, Error}; -+use openssl::error::ErrorStack; -+use pv_core::request::Confidential; -+use std::{ -+ ffi::{c_char, CString}, -+ fmt::Display, -+}; -+ -+mod ffi { -+ use openssl_sys::BIO; -+ use std::ffi::{c_char, c_int, c_long, c_uchar}; -+ extern "C" { -+ pub fn PEM_write_bio( -+ bio: *mut BIO, -+ name: *const c_char, -+ header: *const c_char, -+ data: *const c_uchar, -+ len: c_long, -+ ) -> c_int; -+ } -+} -+ -+/// Thin wrapper around [`CString`] only containing ASCII chars. -+#[derive(Debug)] -+struct AsciiCString(CString); -+ -+impl AsciiCString { -+ /// Convert from string -+ /// -+ /// # Returns -+ /// Error if string is not ASCII or contains null chars -+ pub(crate) fn from_str(s: &str) -> Result { -+ match s.is_ascii() { -+ true => Ok(Self(CString::new(s).map_err(|_| Error::NonAscii)?)), -+ false => Err(Error::NonAscii), -+ } -+ } -+ -+ fn as_ptr(&self) -> *const c_char { -+ self.0.as_ptr() -+ } -+} -+ -+/// Helper struct to construct the PEM format -+#[derive(Debug)] -+struct InnerPem<'d> { -+ name: AsciiCString, -+ header: Option, -+ data: &'d [u8], -+} -+ -+impl<'d> InnerPem<'d> { -+ fn new(name: &str, header: Option, data: &'d [u8]) -> Result { -+ Ok(Self { -+ name: AsciiCString::from_str(name)?, -+ header: match header { -+ Some(h) => Some(AsciiCString::from_str(&h)?), -+ None => None, -+ }, -+ data, -+ }) -+ } -+ -+ /// Generate PEM representation of the data -+ fn to_pem(&self) -> Result> { -+ let bio = BioMem::new()?; -+ let hdr_ptr = match self.header { -+ // avoid moving variable -> use reference -+ Some(ref h) => h.as_ptr(), -+ None => std::ptr::null(), -+ }; -+ -+ // SAFETY: -+ // All pointers point to valid C strings or memory regions -+ let rc = unsafe { -+ ffi::PEM_write_bio( -+ bio.as_ptr(), -+ self.name.as_ptr(), -+ hdr_ptr, -+ self.data.as_ptr(), -+ self.data.len() as std::ffi::c_long, -+ ) -+ }; -+ -+ match rc { -+ 1 => Err(Error::InternalSsl("Could not write PEM", ErrorStack::get())), -+ _ => Ok(bio.to_vec()), -+ } -+ } -+} -+ -+/// Data in PEM format -+/// -+/// Displays into a printable PEM structure. -+/// Must be constructed from another structure in this library. -+/// -+/// ```rust,ignore -+/// let pem: Pem = ...; -+/// println!("PEM {pem}"); -+/// ``` -+/// ```PEM -+///-----BEGIN ----- -+///
-+/// -+/// -+///-----END ----- -+ -+#[derive(Debug)] -+pub struct Pem { -+ pem: Confidential, -+} -+ -+#[allow(unused)] -+impl Pem { -+ /// Create a new PEM structure. -+ /// -+ /// # Errors -+ /// -+ /// This function will return an error if name or header contain non-ASCII chars, or OpenSSL -+ /// could not generate the PEM (very likely due to OOM). -+ pub(crate) fn new(name: &str, header: H, data: D) -> Result -+ where -+ D: AsRef<[u8]>, -+ H: Into>, -+ { -+ let mut header = header.into(); -+ let header = match header { -+ Some(h) if h.ends_with('\n') => Some(h), -+ Some(h) if h.is_empty() => None, -+ Some(mut h) => { -+ h.push('\n'); -+ Some(h) -+ } -+ None => None, -+ }; -+ -+ let inner_pem = InnerPem::new(name, header, data.as_ref())?; -+ -+ // Create the PEM format eagerly so that to_string/display cannot fail because of ASCII or OpenSSL Errors -+ // Both error should be very unlikely -+ // OpenSSL should be able to create PEM if there is enough memory and produce a non-null -+ // terminated ASCII-string -+ // Unwrap succeeds it's all ASCII -+ // Std lib implements all the conversations without a copy -+ let pem = CString::new(inner_pem.to_pem()?) -+ .map_err(|_| Error::NonAscii)? -+ .into_string() -+ .unwrap() -+ .into(); -+ -+ Ok(Self { pem }) -+ } -+ -+ /// Converts the PEM-data into a byte vector. -+ /// -+ /// This consumes the `PEM`. -+ #[inline] -+ #[must_use = "`self` will be dropped if the result is not used"] -+ pub fn into_bytes(self) -> Confidential> { -+ self.pem.into_inner().into_bytes().into() -+ } -+} -+ -+impl Display for Pem { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ self.pem.value().fmt(f) -+ } -+} -+ -+#[cfg(test)] -+mod test { -+ use super::*; -+ -+ #[test] -+ fn no_data() { -+ const EXP: &str = -+ "-----BEGIN PEM test-----\ntest hdr value: 17\n\n-----END PEM test-----\n"; -+ let test_pem = Pem::new("PEM test", "test hdr value: 17".to_string(), []).unwrap(); -+ let pem_str = test_pem.to_string(); -+ assert_eq!(pem_str, EXP); -+ } -+ -+ #[test] -+ fn no_hdr() { -+ const EXP: &str = -+ "-----BEGIN PEM test-----\ndmVyeSBzZWNyZXQga2V5\n-----END PEM test-----\n"; -+ let test_pem = Pem::new("PEM test", None, "very secret key").unwrap(); -+ let pem_str = test_pem.to_string(); -+ assert_eq!(pem_str, EXP); -+ } -+ -+ #[test] -+ fn some_data() { -+ const EXP: &str= "-----BEGIN PEM test-----\ntest hdr value: 17\n\ndmVyeSBzZWNyZXQga2V5\n-----END PEM test-----\n"; -+ let test_pem = Pem::new( -+ "PEM test", -+ "test hdr value: 17".to_string(), -+ "very secret key", -+ ) -+ .unwrap(); -+ let pem_str = test_pem.to_string(); -+ assert_eq!(pem_str, EXP); -+ } -+ -+ #[test] -+ fn data_linebreak() { -+ const EXP: &str= "-----BEGIN PEM test-----\ntest hdr value: 17\n\ndmVyeSBzZWNyZXQga2V5\n-----END PEM test-----\n"; -+ let test_pem = Pem::new( -+ "PEM test", -+ "test hdr value: 17\n".to_string(), -+ "very secret key", -+ ) -+ .unwrap(); -+ let pem_str = test_pem.to_string(); -+ assert_eq!(pem_str, EXP); -+ } -+} diff --git a/s390-tools-General-update-03.patch b/s390-tools-General-update-03.patch deleted file mode 100644 index 70364cc..0000000 --- a/s390-tools-General-update-03.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 69eb06f39e5134565babfe96c66a3786c0a571cf Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Tue, 20 Feb 2024 14:50:47 +0100 -Subject: [PATCH] rust/pv_core: Update ffi.rs to linux/uvdevice.h v6.13 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -While at it, add a file global #[allow(dead_code)]. -The file is a rustified copy of linux/arch/s390/include/uapi/asm/uvdevice.h -and there might be things that are not needed here but are defined in that header. - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv_core/src/uvdevice/ffi.rs | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/rust/pv_core/src/uvdevice/ffi.rs b/rust/pv_core/src/uvdevice/ffi.rs -index bbcc5867..3d9998db 100644 ---- a/rust/pv_core/src/uvdevice/ffi.rs -+++ b/rust/pv_core/src/uvdevice/ffi.rs -@@ -2,6 +2,13 @@ - // - // Copyright IBM Corp. 2023 - -+// This file is a rustified copy of linux/arch/s390/include/uapi/asm/uvdevice.h -+// There might be things that are not needed here but nontheless defined in that header. -+// Those two files should be in sync -> there might be unused/dead code. -+// -+// The `UVIO_IOCTL_*` and `UVIO_SUPP_*` macros -+#![allow(dead_code)] -+ - use std::mem::size_of; - - use crate::{assert_size, static_assert}; -@@ -11,9 +18,8 @@ pub const UVIO_ATT_ARCB_MAX_LEN: usize = 0x100000; - pub const UVIO_ATT_MEASUREMENT_MAX_LEN: usize = 0x8000; - pub const UVIO_ATT_ADDITIONAL_MAX_LEN: usize = 0x8000; - pub const UVIO_ADD_SECRET_MAX_LEN: usize = 0x100000; --#[allow(unused)] --// here for completeness - pub const UVIO_LIST_SECRETS_LEN: usize = 0x1000; -+pub const UVIO_RETR_SECRET_MAX_LEN: usize = 0x2000; - - // equal to ascii 'u' - pub const UVIO_TYPE_UVC: u8 = 117u8; -@@ -23,6 +29,7 @@ pub const UVIO_IOCTL_ATT_NR: u8 = 1; - pub const UVIO_IOCTL_ADD_SECRET_NR: u8 = 2; - pub const UVIO_IOCTL_LIST_SECRETS_NR: u8 = 3; - pub const UVIO_IOCTL_LOCK_SECRETS_NR: u8 = 4; -+pub const UVIO_IOCTL_RETR_SECRET_NR: u8 = 5; - - /// Uvdevice IOCTL control block - /// Programs can use this struct to communicate with the uvdevice via IOCTLs diff --git a/s390-tools-General-update-04.patch b/s390-tools-General-update-04.patch deleted file mode 100644 index 88e1007..0000000 --- a/s390-tools-General-update-04.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 01cd81ecf5d1a7e1e504ae1b67692cf63cd4b51d Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Tue, 5 Mar 2024 11:56:57 +0100 -Subject: [PATCH] rust/pv_core: Retrieve Secret UVC -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Create the uvdevice-IOCTL functionality for the new Retrieve Secret UVC. - -Reviewed-by: Christoph Schlameuss -Acked-by: Marc Hartmayer -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv_core/src/error.rs | 7 ++ - rust/pv_core/src/lib.rs | 2 +- - rust/pv_core/src/uvdevice/secret.rs | 97 +++++++++++++++++++++++- - rust/pv_core/src/uvdevice/secret_list.rs | 15 ++++ - 4 files changed, 118 insertions(+), 3 deletions(-) - -diff --git a/rust/pv_core/src/error.rs b/rust/pv_core/src/error.rs -index 20fca24d..ba7b7e26 100644 ---- a/rust/pv_core/src/error.rs -+++ b/rust/pv_core/src/error.rs -@@ -4,6 +4,8 @@ - - use std::path::PathBuf; - -+use crate::uv::SecretId; -+ - /// Result type for this crate - pub type Result = std::result::Result; - -@@ -70,6 +72,11 @@ pub enum Error { - #[error("The attestation request does not specify a measurement size or measurement data.")] - BinArcbNoMeasurement, - -+ #[error( -+ "The secret with the ID {id} cannot be retrieved. The requested size is too large ({size})" -+ )] -+ InvalidRetrievableSecretType { id: SecretId, size: usize }, -+ - // errors from other crates - #[error(transparent)] - Io(#[from] std::io::Error), -diff --git a/rust/pv_core/src/lib.rs b/rust/pv_core/src/lib.rs -index 349c0b28..5922211f 100644 ---- a/rust/pv_core/src/lib.rs -+++ b/rust/pv_core/src/lib.rs -@@ -32,7 +32,7 @@ pub mod misc { - /// [`crate::uv::UvCmd`] - pub mod uv { - pub use crate::uvdevice::attest::AttestationCmd; -- pub use crate::uvdevice::secret::{AddCmd, ListCmd, LockCmd}; -+ pub use crate::uvdevice::secret::{AddCmd, ListCmd, LockCmd, RetrieveCmd}; - pub use crate::uvdevice::secret_list::{ListableSecretType, SecretEntry, SecretId, SecretList}; - pub use crate::uvdevice::{ConfigUid, UvCmd, UvDevice, UvDeviceInfo, UvFlags, UvcSuccess}; - } -diff --git a/rust/pv_core/src/uvdevice/secret.rs b/rust/pv_core/src/uvdevice/secret.rs -index 6c22b6ed..263f17d5 100644 ---- a/rust/pv_core/src/uvdevice/secret.rs -+++ b/rust/pv_core/src/uvdevice/secret.rs -@@ -3,8 +3,15 @@ - // Copyright IBM Corp. 2023 - - use super::ffi; --use crate::{request::MagicValue, uv::UvCmd, uvsecret::AddSecretMagic, Error, Result, PAGESIZE}; --use std::io::Read; -+use crate::{ -+ request::{Confidential, MagicValue}, -+ uv::{SecretEntry, UvCmd}, -+ uvsecret::AddSecretMagic, -+ Error, Result, PAGESIZE, -+}; -+use log::debug; -+use std::{io::Read, mem::size_of_val}; -+use zerocopy::AsBytes; - - /// _List Secrets_ Ultravisor command. - /// -@@ -116,3 +123,89 @@ impl UvCmd for LockCmd { - } - } - } -+ -+/// Retrieve a secret value from UV store -+#[derive(Debug)] -+pub struct RetrieveCmd { -+ entry: SecretEntry, -+ key: Confidential>, -+} -+ -+impl RetrieveCmd { -+ /// Maximum size of a retrieved key (=2 pages) -+ pub const MAX_SIZE: usize = ffi::UVIO_RETR_SECRET_MAX_LEN; -+ -+ /// Create a retrieve-secret UVC from a [`SecretEntry`]. -+ /// -+ /// This uses the index of the secret entry for the UVC. -+ pub fn from_entry(entry: SecretEntry) -> Result { -+ entry.try_into() -+ } -+ -+ /// Transform a [`RetrieveCmd`] into a key-vector. -+ /// -+ /// Only makes sense to call after a successful UVC execution. -+ pub fn into_key(self) -> Confidential> { -+ self.key -+ } -+ -+ /// Get the secret entry -+ /// -+ /// Get the secret entry that is used as metadata to retrieve the secret -+ pub fn meta_data(&self) -> &SecretEntry { -+ &self.entry -+ } -+} -+ -+impl TryFrom for RetrieveCmd { -+ type Error = Error; -+ -+ fn try_from(entry: SecretEntry) -> Result { -+ let len = entry.secret_size() as usize; -+ -+ // Next to impossible if the secret entry is a valid response from UV -+ if len > Self::MAX_SIZE { -+ return Err(Error::InvalidRetrievableSecretType { -+ id: entry.secret_id().to_owned(), -+ size: len, -+ }); -+ } -+ -+ // Ensure that an u16 fits into the buffer. -+ let size = std::cmp::max(size_of_val(&entry.index()), len); -+ debug!("Create a buf with {} elements", size); -+ let mut buf = vec![0; size]; -+ // The IOCTL expects the secret index in the first two bytes of the buffer. They will be -+ // overwritten in the response -+ entry.index_be().write_to_prefix(&mut buf).unwrap(); -+ Ok(Self { -+ entry, -+ key: buf.into(), -+ }) -+ } -+} -+ -+impl UvCmd for RetrieveCmd { -+ const UV_IOCTL_NR: u8 = ffi::UVIO_IOCTL_RETR_SECRET_NR; -+ -+ fn rc_fmt(&self, rc: u16, _: u16) -> Option<&'static str> { -+ match rc { -+ // should not appear (TM), software creates request from a list item -+ 0x0009 => Some("the allocated buffer is to small to store the secret"), -+ // should not appear (TM), kernel allocates the memory -+ 0x0102 => { -+ Some("access exception recognized when accessing retrieved secret storage area") -+ } -+ // should not appear (TM), software creates request from a list item -+ 0x010f => Some("the Secret Store is empty"), -+ // should not appear (TM), software creates request from a list item -+ 0x0110 => Some("the Secret Store does not contain a secret with the specified index"), -+ 0x0111 => Some("the secret is not retrievable"), -+ _ => None, -+ } -+ } -+ -+ fn data(&mut self) -> Option<&mut [u8]> { -+ Some(self.key.value_mut()) -+ } -+} -diff --git a/rust/pv_core/src/uvdevice/secret_list.rs b/rust/pv_core/src/uvdevice/secret_list.rs -index d20928b5..0a8af504 100644 ---- a/rust/pv_core/src/uvdevice/secret_list.rs -+++ b/rust/pv_core/src/uvdevice/secret_list.rs -@@ -110,6 +110,11 @@ impl SecretEntry { - self.index.get() - } - -+ /// Returns the index of this [`SecretEntry`] in BE. -+ pub(crate) fn index_be(&self) -> &U16 { -+ &self.index -+ } -+ - /// Returns the secret type of this [`SecretEntry`]. - pub fn stype(&self) -> ListableSecretType { - self.stype.into() -@@ -127,6 +132,16 @@ impl SecretEntry { - pub fn id(&self) -> &[u8] { - self.id.as_ref() - } -+ -+ /// Get the id as [`SecretId`] reference -+ pub(crate) fn secret_id(&self) -> &SecretId { -+ &self.id -+ } -+ -+ /// Returns the secret size of this [`SecretEntry`]. -+ pub fn secret_size(&self) -> u32 { -+ self.len.get() -+ } - } - - impl Display for SecretEntry { diff --git a/s390-tools-General-update-05.patch b/s390-tools-General-update-05.patch deleted file mode 100644 index 4750656..0000000 --- a/s390-tools-General-update-05.patch +++ /dev/null @@ -1,710 +0,0 @@ -From 4af137f4fad8638169ccf0ddcb6dc4b0fe8fb1c1 Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Tue, 5 Mar 2024 12:16:44 +0100 -Subject: [PATCH] rust/pv_core: Support for listing Retrievable Secrets -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add support for listing retrievable secrets in the List Secrets UVC. - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv_core/src/lib.rs | 2 + - rust/pv_core/src/uvdevice.rs | 1 + - rust/pv_core/src/uvdevice/retr_secret.rs | 399 +++++++++++++++++++++++ - rust/pv_core/src/uvdevice/secret_list.rs | 157 +++++++-- - 4 files changed, 536 insertions(+), 23 deletions(-) - create mode 100644 rust/pv_core/src/uvdevice/retr_secret.rs - -diff --git a/rust/pv_core/src/lib.rs b/rust/pv_core/src/lib.rs -index 5922211f..caebfcea 100644 ---- a/rust/pv_core/src/lib.rs -+++ b/rust/pv_core/src/lib.rs -@@ -32,6 +32,8 @@ pub mod misc { - /// [`crate::uv::UvCmd`] - pub mod uv { - pub use crate::uvdevice::attest::AttestationCmd; -+ pub use crate::uvdevice::retr_secret::RetrievableSecret; -+ pub use crate::uvdevice::retr_secret::{AesSizes, AesXtsSizes, EcCurves, HmacShaSizes}; - pub use crate::uvdevice::secret::{AddCmd, ListCmd, LockCmd, RetrieveCmd}; - pub use crate::uvdevice::secret_list::{ListableSecretType, SecretEntry, SecretId, SecretList}; - pub use crate::uvdevice::{ConfigUid, UvCmd, UvDevice, UvDeviceInfo, UvFlags, UvcSuccess}; -diff --git a/rust/pv_core/src/uvdevice.rs b/rust/pv_core/src/uvdevice.rs -index d4176815..e9848243 100644 ---- a/rust/pv_core/src/uvdevice.rs -+++ b/rust/pv_core/src/uvdevice.rs -@@ -25,6 +25,7 @@ mod info; - mod test; - pub(crate) use ffi::uv_ioctl; - pub mod attest; -+pub mod retr_secret; - pub mod secret; - pub mod secret_list; - -diff --git a/rust/pv_core/src/uvdevice/retr_secret.rs b/rust/pv_core/src/uvdevice/retr_secret.rs -new file mode 100644 -index 00000000..490152b4 ---- /dev/null -+++ b/rust/pv_core/src/uvdevice/retr_secret.rs -@@ -0,0 +1,399 @@ -+// SPDX-License-Identifier: MIT -+// -+// Copyright IBM Corp. 2024 -+ -+use crate::uv::{ListableSecretType, RetrieveCmd}; -+use serde::{Deserialize, Serialize, Serializer}; -+use std::fmt::Display; -+ -+/// Allowed sizes for AES keys -+#[non_exhaustive] -+#[derive(PartialEq, Eq, Debug)] -+pub enum AesSizes { -+ /// 128 bit key -+ Bits128, -+ /// 192 bit key -+ Bits192, -+ /// 256 bit key -+ Bits256, -+} -+ -+impl AesSizes { -+ /// Construct the key-size from the bit-size. -+ /// -+ /// Returns [`None`] if the bit-size is not supported. -+ pub fn from_bits(bits: u32) -> Option { -+ match bits { -+ 128 => Some(Self::Bits128), -+ 192 => Some(Self::Bits192), -+ 256 => Some(Self::Bits256), -+ _ => None, -+ } -+ } -+ -+ /// Returns the bit-size for the key-type -+ const fn bit_size(&self) -> u32 { -+ match self { -+ Self::Bits128 => 128, -+ Self::Bits192 => 192, -+ Self::Bits256 => 256, -+ } -+ } -+} -+ -+impl Display for AesSizes { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ write!(f, "{}", self.bit_size()) -+ } -+} -+ -+/// Allowed sizes for AES-XTS keys -+#[non_exhaustive] -+#[derive(PartialEq, Eq, Debug)] -+pub enum AesXtsSizes { -+ /// Two AES 128 bit keys -+ Bits128, -+ /// Two AES 256 bit keys -+ Bits256, -+} -+ -+impl AesXtsSizes { -+ /// Construct the key-size from the bit-size. -+ /// -+ /// It's a key containing two keys; bit-size is half the number of bits it has -+ /// Returns [`None`] if the bit-size is not supported. -+ pub fn from_bits(bits: u32) -> Option { -+ match bits { -+ 128 => Some(Self::Bits128), -+ 256 => Some(Self::Bits256), -+ _ => None, -+ } -+ } -+ -+ /// Returns the bit-size for the key-type -+ /// -+ /// It's a key containing two keys: bit-size is half the number of bits it has -+ const fn bit_size(&self) -> u32 { -+ match self { -+ Self::Bits128 => 128, -+ Self::Bits256 => 256, -+ } -+ } -+} -+ -+impl Display for AesXtsSizes { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ write!(f, "{}", self.bit_size()) -+ } -+} -+ -+/// Allowed sizes for HMAC-SHA keys -+#[non_exhaustive] -+#[derive(PartialEq, Eq, Debug)] -+pub enum HmacShaSizes { -+ /// SHA 256 bit -+ Sha256, -+ /// SHA 512 bit -+ Sha512, -+} -+ -+impl HmacShaSizes { -+ /// Construct the key-size from the sha-size. -+ /// -+ /// FW expects maximum resistance keys (double the SHA size). -+ /// The `sha_size` is half of the number of bits in the key -+ /// Returns [`None`] if the `sha_size` is not supported. -+ pub fn from_sha_size(sha_size: u32) -> Option { -+ match sha_size { -+ 256 => Some(Self::Sha256), -+ 512 => Some(Self::Sha512), -+ _ => None, -+ } -+ } -+ -+ /// Returns the sha-size for the key-type -+ /// -+ /// FW expects maximum resistance keys (double the SHA size). -+ /// The `sha_size` is half of the number of bits in the key -+ const fn sha_size(&self) -> u32 { -+ match self { -+ Self::Sha256 => 256, -+ Self::Sha512 => 512, -+ } -+ } -+} -+ -+impl Display for HmacShaSizes { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ write!(f, "{}", self.sha_size()) -+ } -+} -+ -+/// Allowed curves for EC private keys -+#[non_exhaustive] -+#[derive(PartialEq, Eq, Debug)] -+pub enum EcCurves { -+ /// secp256r1 or prime256v1 curve -+ Secp256R1, -+ /// secp384p1 curve -+ Secp384R1, -+ /// secp521r1 curve -+ Secp521R1, -+ /// ed25519 curve -+ Ed25519, -+ /// ed448 curve -+ Ed448, -+} -+ -+impl EcCurves { -+ const fn exp_size(&self) -> usize { -+ match self { -+ Self::Secp256R1 => 32, -+ Self::Secp384R1 => 48, -+ Self::Secp521R1 => 80, -+ Self::Ed25519 => 32, -+ Self::Ed448 => 64, -+ } -+ } -+ -+ /// Resizes the raw key to the expected size. -+ /// -+ /// See [`Vec::resize`] -+ pub fn resize_raw_key(&self, mut raw: Vec) -> Vec { -+ raw.resize(self.exp_size(), 0); -+ raw -+ } -+} -+ -+// The names have to stay constant, otherwise the PEM contains invalid types -+impl Display for EcCurves { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ match self { -+ Self::Secp256R1 => write!(f, "SECP256R1"), -+ Self::Secp384R1 => write!(f, "SECP384R1"), -+ Self::Secp521R1 => write!(f, "SECP521R1"), -+ Self::Ed25519 => write!(f, "ED25519"), -+ Self::Ed448 => write!(f, "ED448"), -+ } -+ } -+} -+ -+/// Retrievable Secret types -+#[non_exhaustive] -+#[derive(PartialEq, Eq, Debug)] -+pub enum RetrievableSecret { -+ /// Plain-text secret -+ PlainText, -+ /// Protected AES key -+ Aes(AesSizes), -+ /// Protected AES-XTS key -+ AesXts(AesXtsSizes), -+ /// Protected HMAC-SHA key -+ HmacSha(HmacShaSizes), -+ /// Protected EC-private key -+ Ec(EcCurves), -+} -+ -+// The names have to stay constant, otherwise the PEM contains invalid/unknown types -+impl Display for RetrievableSecret { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ // Alternate representation: Omit sizes/curves -+ if f.alternate() { -+ match self { -+ Self::PlainText => write!(f, "PLAINTEXT"), -+ Self::Aes(_) => write!(f, "AES-KEY"), -+ Self::AesXts(_) => write!(f, "AES-XTS-KEY"), -+ Self::HmacSha(_) => write!(f, "HMAC-SHA-KEY"), -+ Self::Ec(_) => write!(f, "EC-PRIVATE-KEY"), -+ } -+ } else { -+ match self { -+ Self::PlainText => write!(f, "PLAINTEXT"), -+ Self::Aes(s) => write!(f, "AES-{s}-KEY"), -+ Self::AesXts(s) => write!(f, "AES-XTS-{s}-KEY"), -+ Self::HmacSha(s) => write!(f, "HMAC-SHA-{s}-KEY"), -+ Self::Ec(c) => write!(f, "EC-{c}-PRIVATE-KEY"), -+ } -+ } -+ } -+} -+ -+impl RetrievableSecret { -+ /// Report expected input types -+ pub fn expected(&self) -> String { -+ match self { -+ Self::PlainText => format!("less than {}", RetrieveCmd::MAX_SIZE), -+ Self::Aes(_) => "128, 192, or 256".to_string(), -+ Self::AesXts(_) => "128 or 256".to_string(), -+ Self::HmacSha(_) => "256 or 512".to_string(), -+ Self::Ec(_) => "secp256r1, secp384r1, secp521r1, ed25519, or ed448".to_string(), -+ } -+ } -+} -+ -+impl From<&RetrievableSecret> for u16 { -+ fn from(value: &RetrievableSecret) -> Self { -+ match value { -+ RetrievableSecret::PlainText => ListableSecretType::PLAINTEXT, -+ RetrievableSecret::Aes(AesSizes::Bits128) => ListableSecretType::AES_128_KEY, -+ RetrievableSecret::Aes(AesSizes::Bits192) => ListableSecretType::AES_192_KEY, -+ RetrievableSecret::Aes(AesSizes::Bits256) => ListableSecretType::AES_256_KEY, -+ RetrievableSecret::AesXts(AesXtsSizes::Bits128) => ListableSecretType::AES_128_XTS_KEY, -+ RetrievableSecret::AesXts(AesXtsSizes::Bits256) => ListableSecretType::AES_256_XTS_KEY, -+ RetrievableSecret::HmacSha(HmacShaSizes::Sha256) => { -+ ListableSecretType::HMAC_SHA_256_KEY -+ } -+ RetrievableSecret::HmacSha(HmacShaSizes::Sha512) => { -+ ListableSecretType::HMAC_SHA_512_KEY -+ } -+ RetrievableSecret::Ec(EcCurves::Secp256R1) => ListableSecretType::ECDSA_P256_KEY, -+ RetrievableSecret::Ec(EcCurves::Secp384R1) => ListableSecretType::ECDSA_P384_KEY, -+ RetrievableSecret::Ec(EcCurves::Secp521R1) => ListableSecretType::ECDSA_P521_KEY, -+ RetrievableSecret::Ec(EcCurves::Ed25519) => ListableSecretType::ECDSA_ED25519_KEY, -+ RetrievableSecret::Ec(EcCurves::Ed448) => ListableSecretType::ECDSA_ED448_KEY, -+ } -+ } -+} -+ -+// serializes to: (String name) -+impl Serialize for RetrievableSecret { -+ fn serialize(&self, serializer: S) -> Result -+ where -+ S: Serializer, -+ { -+ let id: u16 = self.into(); -+ serializer.serialize_str(&format!("{id} ({self})")) -+ } -+} -+ -+/// deserializes from the secret type nb only -+impl<'de> Deserialize<'de> for RetrievableSecret { -+ fn deserialize(de: D) -> Result -+ where -+ D: serde::Deserializer<'de>, -+ { -+ struct RetrSecretVisitor; -+ impl<'de> serde::de::Visitor<'de> for RetrSecretVisitor { -+ type Value = RetrievableSecret; -+ -+ fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { -+ fmt.write_str( -+ "a retrievable secret type: ` (String name)` number in [3,10]|[17,21]", -+ ) -+ } -+ fn visit_str(self, s: &str) -> Result -+ where -+ E: serde::de::Error, -+ { -+ let (n, _) = s.split_once(' ').ok_or(serde::de::Error::invalid_value( -+ serde::de::Unexpected::Str(s), -+ &self, -+ ))?; -+ let id: u16 = n.parse().map_err(|_| { -+ serde::de::Error::invalid_value(serde::de::Unexpected::Str(n), &self) -+ })?; -+ let listable: ListableSecretType = id.into(); -+ match listable { -+ ListableSecretType::Retrievable(r) => Ok(r), -+ _ => Err(serde::de::Error::invalid_value( -+ serde::de::Unexpected::Unsigned(id.into()), -+ &self, -+ )), -+ } -+ } -+ } -+ de.deserialize_str(RetrSecretVisitor) -+ } -+} -+ -+#[cfg(test)] -+mod test { -+ use serde_test::{assert_tokens, Token}; -+ -+ use super::*; -+ -+ #[test] -+ fn retr_serde_plain() { -+ let retr = RetrievableSecret::PlainText; -+ assert_tokens(&retr, &[Token::Str("3 (PLAINTEXT)")]); -+ } -+ -+ #[test] -+ fn retr_serde_aes() { -+ let retr = RetrievableSecret::Aes(AesSizes::Bits192); -+ assert_tokens(&retr, &[Token::Str("5 (AES-192-KEY)")]); -+ } -+ -+ #[test] -+ fn retr_serde_aes_xts() { -+ let retr = RetrievableSecret::AesXts(AesXtsSizes::Bits128); -+ assert_tokens(&retr, &[Token::Str("7 (AES-XTS-128-KEY)")]); -+ } -+ -+ #[test] -+ fn retr_serde_hmac() { -+ let retr = RetrievableSecret::HmacSha(HmacShaSizes::Sha256); -+ assert_tokens(&retr, &[Token::Str("9 (HMAC-SHA-256-KEY)")]); -+ } -+ -+ #[test] -+ fn retr_serde_es() { -+ let retr = RetrievableSecret::Ec(EcCurves::Secp521R1); -+ assert_tokens(&retr, &[Token::Str("19 (EC-SECP521R1-PRIVATE-KEY)")]); -+ } -+ -+ // Ensure that the string representation of the retrievable types stay constant, or PEM will have -+ // different, incompatible types -+ #[test] -+ fn stable_type_names() { -+ assert_eq!("PLAINTEXT", RetrievableSecret::PlainText.to_string()); -+ assert_eq!( -+ "AES-128-KEY", -+ RetrievableSecret::Aes(AesSizes::Bits128).to_string() -+ ); -+ assert_eq!( -+ "AES-192-KEY", -+ RetrievableSecret::Aes(AesSizes::Bits192).to_string() -+ ); -+ assert_eq!( -+ "AES-256-KEY", -+ RetrievableSecret::Aes(AesSizes::Bits256).to_string() -+ ); -+ assert_eq!( -+ "AES-XTS-128-KEY", -+ RetrievableSecret::AesXts(AesXtsSizes::Bits128).to_string() -+ ); -+ assert_eq!( -+ "AES-XTS-256-KEY", -+ RetrievableSecret::AesXts(AesXtsSizes::Bits256).to_string() -+ ); -+ assert_eq!( -+ "HMAC-SHA-256-KEY", -+ RetrievableSecret::HmacSha(HmacShaSizes::Sha256).to_string() -+ ); -+ assert_eq!( -+ "HMAC-SHA-512-KEY", -+ RetrievableSecret::HmacSha(HmacShaSizes::Sha512).to_string() -+ ); -+ assert_eq!( -+ "EC-SECP256R1-PRIVATE-KEY", -+ RetrievableSecret::Ec(EcCurves::Secp256R1).to_string() -+ ); -+ assert_eq!( -+ "EC-SECP384R1-PRIVATE-KEY", -+ RetrievableSecret::Ec(EcCurves::Secp384R1).to_string() -+ ); -+ assert_eq!( -+ "EC-SECP521R1-PRIVATE-KEY", -+ RetrievableSecret::Ec(EcCurves::Secp521R1).to_string() -+ ); -+ assert_eq!( -+ "EC-ED25519-PRIVATE-KEY", -+ RetrievableSecret::Ec(EcCurves::Ed25519).to_string() -+ ); -+ assert_eq!( -+ "EC-ED448-PRIVATE-KEY", -+ RetrievableSecret::Ec(EcCurves::Ed448).to_string() -+ ); -+ } -+} -diff --git a/rust/pv_core/src/uvdevice/secret_list.rs b/rust/pv_core/src/uvdevice/secret_list.rs -index 0a8af504..4e955010 100644 ---- a/rust/pv_core/src/uvdevice/secret_list.rs -+++ b/rust/pv_core/src/uvdevice/secret_list.rs -@@ -2,9 +2,14 @@ - // - // Copyright IBM Corp. 2024 - --use crate::assert_size; --use crate::{misc::to_u16, uv::ListCmd, uvdevice::UvCmd, Error, Result}; --use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -+use crate::{ -+ assert_size, -+ misc::to_u16, -+ uv::{AesSizes, AesXtsSizes, EcCurves, HmacShaSizes, ListCmd, RetrievableSecret}, -+ uvdevice::UvCmd, -+ Error, Result, -+}; -+use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; - use serde::{Deserialize, Serialize, Serializer}; - use std::{ - fmt::Display, -@@ -18,7 +23,7 @@ use zerocopy::{AsBytes, FromBytes, FromZeroes, U16, U32}; - /// - /// (de)serializes itself in/from a hex-string - #[repr(C)] --#[derive(PartialEq, Eq, AsBytes, FromZeroes, FromBytes, Debug, Clone)] -+#[derive(PartialEq, Eq, AsBytes, FromZeroes, FromBytes, Debug, Clone, Default)] - pub struct SecretId([u8; Self::ID_SIZE]); - assert_size!(SecretId, SecretId::ID_SIZE); - -@@ -94,11 +99,11 @@ impl SecretEntry { - /// Create a new entry for a [`SecretList`]. - /// - /// The content of this entry will very likely not represent the status of the guest in the -- /// Ultravisor. Use of [`SecretList::decode`] in any non-test environments is encuraged. -+ /// Ultravisor. Use of [`SecretList::decode`] in any non-test environments is encouraged. - pub fn new(index: u16, stype: ListableSecretType, id: SecretId, secret_len: u32) -> Self { - Self { - index: index.into(), -- stype: stype.into(), -+ stype: U16::new(stype.into()), - len: secret_len.into(), - res_8: 0, - id, -@@ -117,7 +122,7 @@ impl SecretEntry { - - /// Returns the secret type of this [`SecretEntry`]. - pub fn stype(&self) -> ListableSecretType { -- self.stype.into() -+ self.stype.get().into() - } - - /// Returns a reference to the id of this [`SecretEntry`]. -@@ -146,7 +151,7 @@ impl SecretEntry { - - impl Display for SecretEntry { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -- let stype: ListableSecretType = self.stype.into(); -+ let stype: ListableSecretType = self.stype.get().into(); - writeln!(f, "{} {}:", self.index, stype)?; - write!(f, " ")?; - for b in self.id.as_ref() { -@@ -298,51 +303,115 @@ fn ser_u16(v: &U16, ser: S) -> Result - pub enum ListableSecretType { - /// Association Secret - Association, -+ /// Retrievable key -+ Retrievable(RetrievableSecret), -+ - /// Invalid secret type, that should never appear in a list - /// - /// 0 is reserved -- /// 1 is Null secret, with no id and not listable -+ /// 1 is Null secret, with no id and not list-able - Invalid(u16), - /// Unknown secret type - Unknown(u16), - } - - impl ListableSecretType { -- /// UV type id for an association secret -- pub const ASSOCIATION: u16 = 0x0002; -- /// UV type id for a null secret -- pub const NULL: u16 = 0x0001; - const RESERVED_0: u16 = 0x0000; -+ /// UV secret-type id for a null secret -+ pub const NULL: u16 = 0x0001; -+ /// UV secret-type id for an association secret -+ pub const ASSOCIATION: u16 = 0x0002; -+ /// UV secret-type id for a plain text secret -+ pub const PLAINTEXT: u16 = 0x0003; -+ /// UV secret-type id for an aes-128-key secret -+ pub const AES_128_KEY: u16 = 0x0004; -+ /// UV secret-type id for an aes-192-key secret -+ pub const AES_192_KEY: u16 = 0x0005; -+ /// UV secret-type id for an aes-256-key secret -+ pub const AES_256_KEY: u16 = 0x0006; -+ /// UV secret-type id for an aes-xts-128-key secret -+ pub const AES_128_XTS_KEY: u16 = 0x0007; -+ /// UV secret-type id for an aes-xts-256-key secret -+ pub const AES_256_XTS_KEY: u16 = 0x0008; -+ /// UV secret-type id for an hmac-sha-256-key secret -+ pub const HMAC_SHA_256_KEY: u16 = 0x0009; -+ /// UV secret-type id for an hmac-sha-512-key secret -+ pub const HMAC_SHA_512_KEY: u16 = 0x000a; -+ // 0x000b - 0x0010 reserved -+ /// UV secret-type id for an ecdsa-p256-private-key secret -+ pub const ECDSA_P256_KEY: u16 = 0x0011; -+ /// UV secret-type id for an ecdsa-p384-private-key secret -+ pub const ECDSA_P384_KEY: u16 = 0x0012; -+ /// UV secret-type id for an ecdsa-p521-private-key secret -+ pub const ECDSA_P521_KEY: u16 = 0x0013; -+ /// UV secret-type id for an ed25519-private-key secret -+ pub const ECDSA_ED25519_KEY: u16 = 0x0014; -+ /// UV secret-type id for an ed448-private-key secret -+ pub const ECDSA_ED448_KEY: u16 = 0x0015; - } - - impl Display for ListableSecretType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Association => write!(f, "Association"), -- Self::Invalid(n) => write!(f, "Invalid({n})"), -- Self::Unknown(n) => write!(f, "Unknown({n})"), -+ Self::Invalid(n) => write!(f, "Invalid(0x{n:04x})"), -+ Self::Unknown(n) => write!(f, "Unknown(0x{n:04x})"), -+ Self::Retrievable(r) => write!(f, "{r}"), - } - } - } - --impl From> for ListableSecretType { -- fn from(value: U16) -> Self { -- match value.get() { -+impl From> for ListableSecretType { -+ fn from(value: U16) -> Self { -+ value.get().into() -+ } -+} -+ -+impl From for ListableSecretType { -+ fn from(value: u16) -> Self { -+ match value { - Self::RESERVED_0 => Self::Invalid(Self::RESERVED_0), - Self::NULL => Self::Invalid(Self::NULL), - Self::ASSOCIATION => Self::Association, -+ Self::PLAINTEXT => Self::Retrievable(RetrievableSecret::PlainText), -+ Self::AES_128_KEY => Self::Retrievable(RetrievableSecret::Aes(AesSizes::Bits128)), -+ Self::AES_192_KEY => Self::Retrievable(RetrievableSecret::Aes(AesSizes::Bits192)), -+ Self::AES_256_KEY => Self::Retrievable(RetrievableSecret::Aes(AesSizes::Bits256)), -+ Self::AES_128_XTS_KEY => { -+ Self::Retrievable(RetrievableSecret::AesXts(AesXtsSizes::Bits128)) -+ } -+ Self::AES_256_XTS_KEY => { -+ Self::Retrievable(RetrievableSecret::AesXts(AesXtsSizes::Bits256)) -+ } -+ Self::HMAC_SHA_256_KEY => { -+ Self::Retrievable(RetrievableSecret::HmacSha(HmacShaSizes::Sha256)) -+ } -+ Self::HMAC_SHA_512_KEY => { -+ Self::Retrievable(RetrievableSecret::HmacSha(HmacShaSizes::Sha512)) -+ } -+ Self::ECDSA_P256_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Secp256R1)), -+ Self::ECDSA_P384_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Secp384R1)), -+ Self::ECDSA_P521_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Secp521R1)), -+ Self::ECDSA_ED25519_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Ed25519)), -+ Self::ECDSA_ED448_KEY => Self::Retrievable(RetrievableSecret::Ec(EcCurves::Ed448)), - n => Self::Unknown(n), - } - } - } - --impl From for U16 { -+impl From for U16 { -+ fn from(value: ListableSecretType) -> Self { -+ Self::new(value.into()) -+ } -+} -+ -+impl From for u16 { - fn from(value: ListableSecretType) -> Self { - match value { - ListableSecretType::Association => ListableSecretType::ASSOCIATION, - ListableSecretType::Invalid(n) | ListableSecretType::Unknown(n) => n, -+ ListableSecretType::Retrievable(r) => (&r).into(), - } -- .into() - } - } - -@@ -363,8 +432,8 @@ where - where - E: serde::de::Error, - { -- if s.len() != SecretId::ID_SIZE * 2 + 2 { -- return Err(serde::de::Error::invalid_length(s.len(), &self)); -+ if s.len() != SecretId::ID_SIZE * 2 + "0x".len() { -+ return Err(serde::de::Error::invalid_length(s.len() - 2, &self)); - } - let nb = s.strip_prefix("0x").ok_or_else(|| { - serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self) -@@ -385,7 +454,6 @@ mod test { - - use super::*; - use std::io::{BufReader, BufWriter, Cursor}; -- - #[test] - fn dump_secret_entry() { - const EXP: &[u8] = &[ -@@ -516,4 +584,47 @@ mod test { - )], - ) - } -+ -+ #[test] -+ fn secret_list_ser() { -+ let list = SecretList { -+ total_num_secrets: 0x112, -+ secrets: vec![SecretEntry { -+ index: 1.into(), -+ stype: 2.into(), -+ len: 32.into(), -+ res_8: 0, -+ id: SecretId::from([0; 32]), -+ }], -+ }; -+ -+ assert_ser_tokens( -+ &list, -+ &[ -+ Token::Struct { -+ name: "SecretList", -+ len: 2, -+ }, -+ Token::String("total_num_secrets"), -+ Token::U64(0x112), -+ Token::String("secrets"), -+ Token::Seq { len: Some(1) }, -+ Token::Struct { -+ name: "SecretEntry", -+ len: (4), -+ }, -+ Token::String("index"), -+ Token::U16(1), -+ Token::String("stype"), -+ Token::U16(2), -+ Token::String("len"), -+ Token::U32(32), -+ Token::String("id"), -+ Token::String("0x0000000000000000000000000000000000000000000000000000000000000000"), -+ Token::StructEnd, -+ Token::SeqEnd, -+ Token::StructEnd, -+ ], -+ ) -+ } - } diff --git a/s390-tools-General-update-06.patch b/s390-tools-General-update-06.patch deleted file mode 100644 index a6a9708..0000000 --- a/s390-tools-General-update-06.patch +++ /dev/null @@ -1,877 +0,0 @@ -From fd024387d710887bd2016658c44d4762a08c791c Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Tue, 5 Mar 2024 12:19:22 +0100 -Subject: [PATCH] rust/pv: Retrievable secrets support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Support retrievable secret for Add-Secret requests. - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv/src/crypto.rs | 3 +- - rust/pv/src/error.rs | 8 + - rust/pv/src/lib.rs | 8 +- - rust/pv/src/uvsecret.rs | 1 + - rust/pv/src/uvsecret/guest_secret.rs | 399 +++++++++++++++++++++++++-- - rust/pv/src/uvsecret/retr_secret.rs | 234 ++++++++++++++++ - 6 files changed, 631 insertions(+), 22 deletions(-) - create mode 100644 rust/pv/src/uvsecret/retr_secret.rs - -diff --git a/rust/pv/src/crypto.rs b/rust/pv/src/crypto.rs -index 8f11d2b4..ebc85f72 100644 ---- a/rust/pv/src/crypto.rs -+++ b/rust/pv/src/crypto.rs -@@ -29,7 +29,6 @@ pub type Aes256XtsKey = Confidential<[u8; SymKeyType::AES_256_XTS_KEY_LEN]>; - - /// SHA-512 digest length (in bytes) - pub const SHA_512_HASH_LEN: usize = 64; -- - #[allow(dead_code)] - pub(crate) const SHA_256_HASH_LEN: u32 = 32; - #[allow(dead_code)] -@@ -60,6 +59,8 @@ impl SymKeyType { - pub const AES_256_XTS_KEY_LEN: usize = 64; - /// AES256-XTS tweak length (in bytes) - pub const AES_256_XTS_TWEAK_LEN: usize = 16; -+ /// AES256 GCM Block length -+ pub const AES_256_GCM_BLOCK_LEN: usize = 16; - - /// Returns the tag length of the [`SymKeyType`] if it is an AEAD key - pub const fn tag_len(&self) -> Option { -diff --git a/rust/pv/src/error.rs b/rust/pv/src/error.rs -index 3ba808f2..601b40f0 100644 ---- a/rust/pv/src/error.rs -+++ b/rust/pv/src/error.rs -@@ -109,6 +109,14 @@ pub enum Error { - #[error("An ASCII string was expected, but non-ASCII characters were received.")] - NonAscii, - -+ #[error("Incorrect {what} for a {kind}. Is: {value}; expected: {exp}")] -+ RetrInvKey { -+ what: &'static str, -+ kind: String, -+ value: String, -+ exp: String, -+ }, -+ - // errors from other crates - #[error(transparent)] - PvCore(#[from] pv_core::Error), -diff --git a/rust/pv/src/lib.rs b/rust/pv/src/lib.rs -index ec31b9a4..43375669 100644 ---- a/rust/pv/src/lib.rs -+++ b/rust/pv/src/lib.rs -@@ -104,7 +104,12 @@ pub mod request { - - /// Reexports some useful OpenSSL symbols - pub mod openssl { -- pub use openssl::{error::ErrorStack, hash::DigestBytes, pkey, x509}; -+ pub use openssl::{error::ErrorStack, hash::DigestBytes, nid::Nid, pkey, x509}; -+ // rust-OpenSSL does not define these NIDs -+ #[allow(missing_docs)] -+ pub const NID_ED25519: Nid = Nid::from_raw(openssl_sys::NID_ED25519); -+ #[allow(missing_docs)] -+ pub const NID_ED448: Nid = Nid::from_raw(openssl_sys::NID_ED448); - } - - pub use pv_core::request::*; -@@ -118,6 +123,7 @@ pub mod secret { - asrcb::{AddSecretFlags, AddSecretRequest, AddSecretVersion}, - ext_secret::ExtSecret, - guest_secret::GuestSecret, -+ retr_secret::{IbmProtectedKey, RetrievedSecret}, - user_data::verify_asrcb_and_get_user_data, - }; - } -diff --git a/rust/pv/src/uvsecret.rs b/rust/pv/src/uvsecret.rs -index 343e4b05..c3b43bba 100644 ---- a/rust/pv/src/uvsecret.rs -+++ b/rust/pv/src/uvsecret.rs -@@ -10,4 +10,5 @@ - pub mod asrcb; - pub mod ext_secret; - pub mod guest_secret; -+pub mod retr_secret; - pub mod user_data; -diff --git a/rust/pv/src/uvsecret/guest_secret.rs b/rust/pv/src/uvsecret/guest_secret.rs -index 4f1db31c..3bad6d3c 100644 ---- a/rust/pv/src/uvsecret/guest_secret.rs -+++ b/rust/pv/src/uvsecret/guest_secret.rs -@@ -4,20 +4,34 @@ - - #[allow(unused_imports)] // used for more convenient docstring - use super::asrcb::AddSecretRequest; --use crate::assert_size; - use crate::{ -- crypto::{hash, random_array}, -- request::Confidential, -- Result, -+ assert_size, -+ crypto::{hash, random_array, SymKeyType}, -+ request::{ -+ openssl::{NID_ED25519, NID_ED448}, -+ Confidential, -+ }, -+ uv::{ -+ AesSizes, AesXtsSizes, EcCurves, HmacShaSizes, ListableSecretType, RetrievableSecret, -+ RetrieveCmd, SecretId, -+ }, -+ Error, Result, - }; - use byteorder::BigEndian; --use openssl::hash::MessageDigest; --use pv_core::uv::{ListableSecretType, SecretId}; -+use openssl::{ -+ hash::MessageDigest, -+ nid::Nid, -+ pkey::{Id, PKey, Private}, -+}; -+use pv_core::static_assert; - use serde::{Deserialize, Serialize}; --use std::{convert::TryInto, fmt::Display}; -+use std::fmt::Display; - use zerocopy::{AsBytes, U16, U32}; - - const ASSOC_SECRET_SIZE: usize = 32; -+/// Maximum size of a plain-text secret payload (8190) -+pub(crate) const MAX_SIZE_PLAIN_PAYLOAD: usize = RetrieveCmd::MAX_SIZE - 2; -+static_assert!(MAX_SIZE_PLAIN_PAYLOAD == 8190); - - /// A Secret to be added in [`AddSecretRequest`] - #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -@@ -36,13 +50,60 @@ pub enum GuestSecret { - #[serde(skip)] - secret: Confidential<[u8; ASSOC_SECRET_SIZE]>, - }, -+ /// Retrievable key -+ /// -+ /// Create Retrievables using [`GuestSecret::retrievable`] -+ /// Secret size is always valid for the type/kind -+ Retrievable { -+ /// Retrievable secret type -+ kind: RetrievableSecret, -+ /// Name of the secret -+ name: String, -+ /// SHA256 hash of [`GuestSecret::RetrievableKey::name`] -+ id: SecretId, -+ /// Confidential actual retrievable secret (32 bytes) -+ #[serde(skip)] -+ secret: Confidential>, -+ }, -+} -+ -+macro_rules! retr_constructor { -+ ($(#[$err:meta])* | $(#[$kind:meta])* => $type: ty, $func: ident) => { -+ /// Create a new -+ $(#[$kind])* -+ /// [`GuestSecret::Retrievable`] secret. -+ /// -+ /// * `name` - Name of the secret. Will be hashed into a 32 byte id -+ /// * `secret` - the secret value -+ /// -+ /// # Errors -+ /// -+ $(#[$err])* -+ pub fn $func(name: &str, secret: $type) -> Result { -+ let (kind, secret) = $func(secret)?; -+ Ok(Self::Retrievable { -+ kind, -+ name: name.to_string(), -+ id: Self::name_to_id(name)?, -+ secret, -+ }) -+ } -+ }; - } - - impl GuestSecret { -+ fn name_to_id(name: &str) -> Result { -+ let id: [u8; SecretId::ID_SIZE] = hash(MessageDigest::sha256(), name.as_bytes())? -+ .to_vec() -+ .try_into() -+ .unwrap(); -+ Ok(id.into()) -+ } -+ - /// Create a new [`GuestSecret::Association`]. - /// - /// * `name` - Name of the secret. Will be hashed into a 32 byte id -- /// * `secret` - Value of the secret. Ranom if [`Option::None`] -+ /// * `secret` - Value of the secret. Random if [`Option::None`] - /// - /// # Errors - /// -@@ -51,10 +112,6 @@ impl GuestSecret { - where - O: Into>, - { -- let id: [u8; SecretId::ID_SIZE] = hash(MessageDigest::sha256(), name.as_bytes())? -- .to_vec() -- .try_into() -- .unwrap(); - let secret = match secret.into() { - Some(s) => s, - None => random_array()?, -@@ -62,16 +119,28 @@ impl GuestSecret { - - Ok(Self::Association { - name: name.to_string(), -- id: id.into(), -+ id: Self::name_to_id(name)?, - secret: secret.into(), - }) - } - -+ retr_constructor!(#[doc = r"This function will return an error if the secret is larger than 8 pages"] -+ | #[doc = r"plaintext"] => Confidential>, plaintext); -+ retr_constructor!(#[doc = r"This function will return an error if OpenSSL cannot create a hash or the secret size is invalid"] -+ | #[doc = r"AES Key"] => Confidential>, aes); -+ retr_constructor!(#[doc = r"This function will return an error if OpenSSL cannot create a hash or the secret size is invalid"] -+ | #[doc = r"AES-XTS Key"] => Confidential>, aes_xts); -+ retr_constructor!(#[doc = r"This function will return an error if OpenSSL cannot create a hash or the secret size is invalid"] -+ | #[doc = r"HMAC-SHA Key"] => Confidential>, hmac_sha); -+ retr_constructor!(#[doc = r"This function will return an error if OpenSSL cannot create a hash or the curve is invalid"] -+ | #[doc = r"EC PRIVATE Key"] => PKey, ec); -+ - /// Reference to the confidential data - pub fn confidential(&self) -> &[u8] { - match &self { - Self::Null => &[], - Self::Association { secret, .. } => secret.value().as_slice(), -+ Self::Retrievable { secret, .. } => secret.value(), - } - } - -@@ -79,7 +148,7 @@ impl GuestSecret { - pub(crate) fn auth(&self) -> SecretAuth { - match &self { - Self::Null => SecretAuth::Null, -- // Panic: every non null secret type is listable -> no panic -+ // Panic: every non null secret type is list-able -> no panic - listable => { - SecretAuth::Listable(ListableSecretHdr::from_guest_secret(listable).unwrap()) - } -@@ -92,6 +161,7 @@ impl GuestSecret { - // Null is not listable, but the ListableSecretType provides the type constant (1) - Self::Null => ListableSecretType::NULL, - Self::Association { .. } => ListableSecretType::ASSOCIATION, -+ Self::Retrievable { kind, .. } => kind.into(), - } - } - -@@ -100,6 +170,7 @@ impl GuestSecret { - match self { - Self::Null => 0, - Self::Association { secret, .. } => secret.value().len() as u32, -+ Self::Retrievable { secret, .. } => secret.value().len() as u32, - } - } - -@@ -107,18 +178,157 @@ impl GuestSecret { - fn id(&self) -> Option { - match self { - Self::Null => None, -- Self::Association { id, .. } => Some(id.to_owned()), -+ Self::Association { id, .. } | Self::Retrievable { id, .. } => Some(id.to_owned()), - } - } - } - -+type RetrKeyInfo = (RetrievableSecret, Confidential>); -+ -+fn extend_to_multiple(mut key: Vec, multiple: usize) -> Confidential> { -+ match key.len().checked_rem(multiple) { -+ Some(0) | None => key, -+ Some(m) => { -+ key.resize(key.len() + multiple - m, 0); -+ key -+ } -+ } -+ .into() -+} -+ -+/// Get a plain-text key -+/// -+/// ```none -+/// size U16 | payload (0-8190) bytes -+/// ``` -+fn plaintext(inp: Confidential>) -> Result { -+ let key_len = inp.value().len(); -+ if key_len > RetrieveCmd::MAX_SIZE { -+ return Err(Error::RetrInvKey { -+ what: "key size", -+ value: key_len.to_string(), -+ kind: RetrievableSecret::PlainText.to_string(), -+ exp: RetrievableSecret::PlainText.expected(), -+ }); -+ } -+ let mut key = Vec::with_capacity(2 + inp.value().len()); -+ let key_len: U16 = (key_len as u16).into(); -+ key.extend_from_slice(key_len.as_bytes()); -+ key.extend_from_slice(inp.value()); -+ let key = extend_to_multiple(key, SymKeyType::AES_256_GCM_BLOCK_LEN); -+ -+ Ok((RetrievableSecret::PlainText, key)) -+} -+ -+/// Get an AES-key -+fn aes(key: Confidential>) -> Result { -+ let key_len = key.value().len() as u32; -+ let bit_size = bitsize(key_len); -+ match AesSizes::from_bits(bit_size) { -+ Some(size) => Ok((RetrievableSecret::Aes(size), key)), -+ None => { -+ // Use some AES type to get exp sizes and name -+ let kind = RetrievableSecret::Aes(AesSizes::Bits128); -+ Err(Error::RetrInvKey { -+ what: "key size", -+ value: bit_size.to_string(), -+ kind: format!("{kind:#}"), -+ exp: kind.expected(), -+ }) -+ } -+ } -+} -+ -+/// Get an AES-XTS-key -+fn aes_xts(key: Confidential>) -> Result { -+ let key_len = key.value().len() as u32; -+ let bit_size = bitsize(key_len / 2); -+ match AesXtsSizes::from_bits(bit_size) { -+ Some(size) => Ok((RetrievableSecret::AesXts(size), key)), -+ None => { -+ // Use some AES-XTS type to get exp sizes and name -+ let kind = RetrievableSecret::AesXts(AesXtsSizes::Bits128); -+ Err(Error::RetrInvKey { -+ what: "key size", -+ value: bit_size.to_string(), -+ kind: format!("{kind:#}"), -+ exp: kind.expected(), -+ }) -+ } -+ } -+} -+ -+/// Get an HMAC-SHA-key -+fn hmac_sha(key: Confidential>) -> Result { -+ let key_len = key.value().len() as u32; -+ let size = bitsize(key_len / 2); -+ match HmacShaSizes::from_sha_size(size) { -+ Some(size) => Ok((RetrievableSecret::HmacSha(size), key)), -+ None => { -+ // Use some HMAC type to get exp sizes and name -+ let kind = RetrievableSecret::HmacSha(HmacShaSizes::Sha256); -+ Err(Error::RetrInvKey { -+ what: "key size", -+ value: size.to_string(), -+ kind: format!("{kind:#}"), -+ exp: kind.expected(), -+ }) -+ } -+ } -+} -+ -+/// Get an EC-private-key -+fn ec(key: PKey) -> Result { -+ let (key, nid) = match key.id() { -+ Id::EC => { -+ let ec_key = key.ec_key()?; -+ let key = ec_key.private_key().to_vec(); -+ let nid = ec_key.group().curve_name().unwrap_or(Nid::UNDEF); -+ (key, nid) -+ } -+ // ED keys are not handled via the EC struct in OpenSSL. -+ id @ (Id::ED25519 | Id::ED448) => { -+ let key = key.raw_private_key()?; -+ let nid = Nid::from_raw(id.as_raw()); -+ (key, nid) -+ } -+ _ => (vec![], Nid::UNDEF), -+ }; -+ -+ let kind = match nid { -+ Nid::X9_62_PRIME256V1 => EcCurves::Secp256R1, -+ Nid::SECP384R1 => EcCurves::Secp384R1, -+ Nid::SECP521R1 => EcCurves::Secp521R1, -+ NID_ED25519 => EcCurves::Ed25519, -+ NID_ED448 => EcCurves::Ed448, -+ nid => { -+ // Use some EC type to get exp sizes and name -+ let ec = RetrievableSecret::Ec(EcCurves::Secp521R1); -+ return Err(Error::RetrInvKey { -+ what: "curve or format", -+ kind: format!("{ec:#}"), -+ value: nid.long_name()?.to_string(), -+ exp: ec.expected(), -+ }); -+ } -+ }; -+ -+ let key = kind.resize_raw_key(key); -+ Ok((RetrievableSecret::Ec(kind), key.into())) -+} -+ -+#[inline(always)] -+const fn bitsize(bytesize: u32) -> u32 { -+ bytesize * 8 -+} -+ - impl Display for GuestSecret { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Null => write!(f, "Meta"), - gs => { - let kind: U16 = gs.kind().into(); -- let st: ListableSecretType = kind.into(); -+ let st: ListableSecretType = kind.get().into(); - write!(f, "{st}") - } - } -@@ -153,20 +363,24 @@ assert_size!(ListableSecretHdr, 0x30); - - impl ListableSecretHdr { - fn from_guest_secret(gs: &GuestSecret) -> Option { -- let id = gs.id()?; - Some(Self { - res0: 0, - kind: gs.kind().into(), - secret_len: gs.secret_len().into(), - res8: 0, -- id, -+ id: gs.id()?, - }) - } - } - - #[cfg(test)] - mod test { -+ -+ use super::HmacShaSizes as HmacSizes; -+ use super::RetrievableSecret::*; - use super::*; -+ use openssl::ec::{EcGroup, EcKey}; -+ use pv_core::uv::AesSizes; - use serde_test::{assert_tokens, Token}; - - #[test] -@@ -187,8 +401,103 @@ mod test { - assert_eq!(secret, exp); - } - -+ macro_rules! retr_test { -+ ($name: ident, $func: ident, $size: expr, $exp_kind: expr) => { -+ #[test] -+ fn $name() { -+ let secret_value = vec![0x11; $size]; -+ let name = "test retr secret".to_string(); -+ let secret = GuestSecret::$func(&name, secret_value.clone().into()).unwrap(); -+ let exp_id = [ -+ 0x61, 0x2c, 0xd6, 0x3e, 0xa8, 0xf2, 0xc1, 0x15, 0xc1, 0xe, 0x15, 0xb8, 0x8a, -+ 0x90, 0x16, 0xc1, 0x55, 0xef, 0x9c, 0x7c, 0x2c, 0x8e, 0x56, 0xd0, 0x78, 0x4c, -+ 0x8a, 0x1d, 0xc9, 0x3a, 0x80, 0xba, -+ ]; -+ let exp = GuestSecret::Retrievable { -+ kind: $exp_kind, -+ name, -+ id: exp_id.into(), -+ secret: secret_value.into(), -+ }; -+ assert_eq!(exp, secret); -+ } -+ }; -+ } -+ -+ retr_test!(retr_aes_128, aes, 16, Aes(AesSizes::Bits128)); -+ retr_test!(retr_aes_192, aes, 24, Aes(AesSizes::Bits192)); -+ retr_test!(retr_aes_256, aes, 32, Aes(AesSizes::Bits256)); -+ retr_test!(retr_aes_xts_128, aes_xts, 32, AesXts(AesXtsSizes::Bits128)); -+ retr_test!(retr_aes_xts_256, aes_xts, 64, AesXts(AesXtsSizes::Bits256)); -+ retr_test!(retr_aes_hmac_256, hmac_sha, 64, HmacSha(HmacSizes::Sha256)); -+ retr_test!(retr_aes_hmac_512, hmac_sha, 128, HmacSha(HmacSizes::Sha512)); -+ -+ #[test] -+ fn plaintext_no_pad() { -+ let key = vec![0, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]; -+ let name = "PLAINTEXT_PAD".to_string(); -+ let secret = GuestSecret::plaintext(&name, key[2..].to_vec().into()).unwrap(); -+ let exp_id = [ -+ 15, 123, 176, 210, 135, 231, 220, 232, 148, 93, 198, 195, 165, 212, 214, 129, 45, 1, -+ 94, 11, 167, 18, 151, 15, 120, 254, 13, 109, 173, 186, 37, 74, -+ ]; -+ let exp = GuestSecret::Retrievable { -+ kind: PlainText, -+ name, -+ id: exp_id.into(), -+ secret: key.into(), -+ }; -+ -+ assert_eq!(secret, exp); -+ } -+ - #[test] -- fn ap_asc_parse() { -+ fn plaintext_pad() { -+ let key = vec![0, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0]; -+ let name = "PLAINTEXT_PAD".to_string(); -+ let secret = GuestSecret::plaintext(&name, key[2..12].to_vec().into()).unwrap(); -+ let exp_id = [ -+ 15, 123, 176, 210, 135, 231, 220, 232, 148, 93, 198, 195, 165, 212, 214, 129, 45, 1, -+ 94, 11, 167, 18, 151, 15, 120, 254, 13, 109, 173, 186, 37, 74, -+ ]; -+ let exp = GuestSecret::Retrievable { -+ kind: PlainText, -+ name, -+ id: exp_id.into(), -+ secret: key.into(), -+ }; -+ -+ assert_eq!(secret, exp); -+ } -+ -+ #[track_caller] -+ fn test_ec(grp: Nid, exp_kind: EcCurves, exp_len: usize) { -+ let key = match grp { -+ NID_ED25519 => PKey::generate_ed25519().unwrap(), -+ NID_ED448 => PKey::generate_ed448().unwrap(), -+ nid => { -+ let group = EcGroup::from_curve_name(nid).unwrap(); -+ let key = EcKey::generate(&group).unwrap(); -+ PKey::from_ec_key(key).unwrap() -+ } -+ }; -+ let (kind, key) = ec(key).unwrap(); -+ -+ assert_eq!(kind, Ec(exp_kind)); -+ assert_eq!(key.value().len(), exp_len); -+ } -+ -+ #[test] -+ fn retr_ec() { -+ test_ec(Nid::X9_62_PRIME256V1, EcCurves::Secp256R1, 32); -+ test_ec(Nid::SECP384R1, EcCurves::Secp384R1, 48); -+ test_ec(Nid::SECP521R1, EcCurves::Secp521R1, 80); -+ test_ec(NID_ED25519, EcCurves::Ed25519, 32); -+ test_ec(NID_ED448, EcCurves::Ed448, 64); -+ } -+ -+ #[test] -+ fn asc_parse() { - let id = [ - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, - 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, -@@ -217,6 +526,39 @@ mod test { - ); - } - -+ #[test] -+ fn retrievable_parse() { -+ let id = [ -+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, -+ 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, -+ 0x89, 0xab, 0xcd, 0xef, -+ ]; -+ let asc = GuestSecret::Retrievable { -+ kind: PlainText, -+ name: "test123".to_string(), -+ id: id.into(), -+ secret: vec![].into(), -+ }; -+ -+ assert_tokens( -+ &asc, -+ &[ -+ Token::StructVariant { -+ name: "GuestSecret", -+ variant: "Retrievable", -+ len: 3, -+ }, -+ Token::String("kind"), -+ Token::String("3 (PLAINTEXT)"), -+ Token::String("name"), -+ Token::String("test123"), -+ Token::String("id"), -+ Token::String("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), -+ Token::StructVariantEnd, -+ ], -+ ); -+ } -+ - #[test] - fn guest_secret_bin_null() { - let gs = GuestSecret::Null; -@@ -228,7 +570,7 @@ mod test { - } - - #[test] -- fn guest_secret_bin_ap() { -+ fn guest_secret_bin_asoc() { - let gs = GuestSecret::Association { - name: "test".to_string(), - id: [1; 32].into(), -@@ -241,4 +583,21 @@ mod test { - assert_eq!(exp, gs_bytes_auth.get()); - assert_eq!(&[2; 32], gs.confidential()); - } -+ -+ #[test] -+ fn guest_secret_bin_retr() { -+ let gs = GuestSecret::Retrievable { -+ kind: PlainText, -+ name: "test".to_string(), -+ id: [1; 32].into(), -+ secret: vec![2; 32].into(), -+ }; -+ let auth = gs.auth(); -+ let gs_bytes_auth = auth.get(); -+ let mut exp = vec![0u8, 0, 0, 3, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0]; -+ exp.extend([1; 32]); -+ -+ assert_eq!(exp, gs_bytes_auth); -+ assert_eq!(&[2; 32], gs.confidential()); -+ } - } -diff --git a/rust/pv/src/uvsecret/retr_secret.rs b/rust/pv/src/uvsecret/retr_secret.rs -new file mode 100644 -index 00000000..5fad016f ---- /dev/null -+++ b/rust/pv/src/uvsecret/retr_secret.rs -@@ -0,0 +1,234 @@ -+// SPDX-License-Identifier: MIT -+// -+// Copyright IBM Corp. 2024 -+ -+use crate::{pem::Pem, uvsecret::guest_secret::MAX_SIZE_PLAIN_PAYLOAD, Result}; -+ -+use byteorder::BigEndian; -+use log::warn; -+use pv_core::{ -+ request::Confidential, -+ uv::{ListableSecretType, RetrievableSecret, RetrieveCmd}, -+}; -+use zerocopy::{FromBytes, U16}; -+ -+/// An IBM Protected Key -+/// -+/// A protected key, writeable as pem. -+/// -+/// Will convert into PEM as: -+/// ```PEM -+///-----BEGIN IBM PROTECTED KEY----- -+///kind: -+/// -+/// -+///-----END IBM PROTECTED KEY----- -+/// ``` -+#[derive(Debug, PartialEq, Eq)] -+pub struct IbmProtectedKey { -+ kind: ListableSecretType, -+ key: Confidential>, -+} -+ -+impl IbmProtectedKey { -+ /// Get the binary representation of the key. -+ pub fn data(&self) -> &[u8] { -+ self.key.value() -+ } -+ -+ /// Converts a [`IbmProtectedKey`] into a vector. -+ pub fn into_bytes(self) -> Confidential> { -+ self.key -+ } -+ -+ /// Get the data in PEM format. -+ /// -+ /// # Errors -+ /// -+ /// This function will return an error if the PEM conversion failed (very unlikely). -+ pub fn to_pem(&self) -> Result { -+ Pem::new( -+ "IBM PROTECTED KEY", -+ format!("kind: {}", self.kind), -+ self.key.value(), -+ ) -+ } -+ -+ fn new(kind: ListableSecretType, key: K) -> Self -+ where -+ K: Into>>, -+ { -+ Self { -+ kind, -+ key: key.into(), -+ } -+ } -+} -+ -+impl From for RetrievedSecret { -+ fn from(value: RetrieveCmd) -> Self { -+ let kind = value.meta_data().stype(); -+ let key = value.into_key(); -+ -+ match kind { -+ ListableSecretType::Retrievable(RetrievableSecret::PlainText) => { -+ // Will not run into default, retrieve has a granularity of 16 bytes and 16 bytes is the -+ // minimum size -+ let len = U16::::read_from_prefix(key.value()) -+ .unwrap_or_default() -+ .get() as usize; -+ -+ // Test if the plain text secret has a size: -+ // 1. len <= 8190 -+ // 2. first two bytes are max 15 less than buffer-size+2 -+ // 3. bytes after len + 2 are zero -+ match len <= MAX_SIZE_PLAIN_PAYLOAD -+ && key.value().len() - (len + 2) < 15 -+ && key.value()[len + 2..].iter().all(|c| *c == 0) -+ { -+ false => Self::Plaintext(key), -+ true => Self::Plaintext(key.value()[2..len + 2].to_vec().into()), -+ } -+ } -+ kind => { -+ match kind { -+ ListableSecretType::Retrievable(_) => (), -+ _ => warn!("Retrieved an unretrievable Secret! Will continue; interpreting it as a protected key."), -+ } -+ Self::ProtectedKey(IbmProtectedKey::new(kind, key)) -+ } -+ } -+ } -+} -+ -+/// A retrieved Secret. -+#[derive(Debug, PartialEq, Eq)] -+pub enum RetrievedSecret { -+ /// A plaintext secret -+ Plaintext(Confidential>), -+ /// An [`IbmProtectedKey`] -+ ProtectedKey(IbmProtectedKey), -+} -+ -+impl RetrievedSecret { -+ /// Create a new IBM PROTECTED KEY object -+ pub fn from_cmd(cmd: RetrieveCmd) -> Self { -+ cmd.into() -+ } -+ -+ /// Get the binary representation of the key. -+ pub fn data(&self) -> &[u8] { -+ match self { -+ RetrievedSecret::Plaintext(p) => p.value(), -+ RetrievedSecret::ProtectedKey(p) => p.data(), -+ } -+ } -+ -+ /// Converts a [`IbmProtectedKey`] into a vector. -+ pub fn into_bytes(self) -> Confidential> { -+ match self { -+ RetrievedSecret::Plaintext(p) => p, -+ RetrievedSecret::ProtectedKey(p) => p.into_bytes(), -+ } -+ } -+ /// Get the data in PEM format. -+ /// -+ /// # Errors -+ /// -+ /// This function will return an error if the PEM conversion failed (very unlikely). -+ pub fn to_pem(&self) -> Result { -+ match self { -+ RetrievedSecret::Plaintext(p) => Pem::new("PLAINTEXT SECRET", None, p.value()), -+ RetrievedSecret::ProtectedKey(p) => p.to_pem(), -+ } -+ } -+} -+ -+#[cfg(test)] -+mod test { -+ use super::*; -+ use pv_core::uv::*; -+ -+ fn mk_retr(secret: &[u8]) -> RetrievedSecret { -+ let entry = SecretEntry::new( -+ 0, -+ ListableSecretType::Retrievable(RetrievableSecret::PlainText), -+ SecretId::default(), -+ secret.len() as u32, -+ ); -+ let mut cmd = RetrieveCmd::from_entry(entry).unwrap(); -+ cmd.data().unwrap().copy_from_slice(secret); -+ RetrievedSecret::from_cmd(cmd) -+ } -+ -+ #[test] -+ fn from_retr_cmd() { -+ let secret = vec![0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0, 0, 0, 0]; -+ let prot_key = mk_retr(&secret); -+ let exp = RetrievedSecret::Plaintext(secret[2..12].to_vec().into()); -+ assert_eq!(prot_key, exp); -+ } -+ -+ #[test] -+ fn from_retr_inv_size() { -+ let secret = vec![0x20; 32]; -+ let prot_key = mk_retr(&secret); -+ let exp = RetrievedSecret::Plaintext(secret.into()); -+ assert_eq!(prot_key, exp); -+ } -+ -+ #[test] -+ fn from_retr_inv_no_zero_after_end() { -+ let secret = vec![0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 1, 0, 0, 0]; -+ let prot_key = mk_retr(&secret); -+ let exp = RetrievedSecret::Plaintext(secret.into()); -+ assert_eq!(prot_key, exp); -+ } -+ -+ #[test] -+ fn from_retr_inv_to_much_padding() { -+ let secret = vec![ -+ 0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ ]; -+ let prot_key = mk_retr(&secret); -+ let exp = RetrievedSecret::Plaintext(secret.into()); -+ assert_eq!(prot_key, exp); -+ } -+ -+ #[test] -+ fn from_retr_0_size() { -+ let secret = vec![0x00; 32]; -+ let prot_key = mk_retr(&secret); -+ let exp = RetrievedSecret::Plaintext(secret.into()); -+ assert_eq!(prot_key, exp); -+ } -+ -+ #[test] -+ fn plain_text_pem() { -+ let exp = "\ -+ -----BEGIN PLAINTEXT SECRET-----\n\ -+ ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER\n\ -+ -----END PLAINTEXT SECRET-----\n"; -+ let prot = RetrievedSecret::Plaintext(vec![17; 48].into()); -+ let pem = prot.to_pem().unwrap(); -+ let pem_str = pem.to_string(); -+ assert_eq!(pem_str, exp); -+ } -+ -+ #[test] -+ fn prot_key_pem() { -+ let exp = "\ -+ -----BEGIN IBM PROTECTED KEY-----\n\ -+ kind: AES-128-KEY\n\n\ -+ ERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERER\n\ -+ -----END IBM PROTECTED KEY-----\n"; -+ let prot = IbmProtectedKey::new( -+ ListableSecretType::Retrievable(RetrievableSecret::Aes(AesSizes::Bits128)), -+ vec![17; 48], -+ ); -+ let pem = prot.to_pem().unwrap(); -+ let pem_str = pem.to_string(); -+ assert_eq!(pem_str, exp); -+ } -+} diff --git a/s390-tools-General-update-07.patch b/s390-tools-General-update-07.patch deleted file mode 100644 index d468f05..0000000 --- a/s390-tools-General-update-07.patch +++ /dev/null @@ -1,95 +0,0 @@ -From a14f9d4edcc5db0d54e4fbe3ec3d98c7c270bf8e Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Fri, 13 Dec 2024 15:04:02 +0100 -Subject: [PATCH] rust/pvsecret: Improve CLI -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Improve the wording of the help/man text/ - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pvsecret/src/cli.rs | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - -diff --git a/rust/pvsecret/src/cli.rs b/rust/pvsecret/src/cli.rs -index 6deaaebd..c4b9f2b3 100644 ---- a/rust/pvsecret/src/cli.rs -+++ b/rust/pvsecret/src/cli.rs -@@ -37,8 +37,8 @@ pub struct CreateSecretOpt { - - /// Specifies the header of the guest image. - /// -- /// Can be an IBM Secure Execution image created by genprotimg or an extracted IBM Secure -- /// Execution header. The header must start at a page boundary. -+ /// Can be an IBM Secure Execution image created by 'pvimg/genprotimg' or an -+ /// extracted IBM Secure Execution header. - #[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath)] - pub hdr: String, - -@@ -150,12 +150,12 @@ pub enum AddSecretType { - - /// Create an association secret. - /// -- /// Use an association secret to connect a trusted I/O device to a guest. The `pvapconfig` tool -+ /// Use an association secret to connect a trusted I/O device to a guest. The 'pvapconfig' tool - /// provides more information about association secrets. - Association { -- /// String to identify the new secret. -+ /// String that identifies the new secret. - /// -- /// The actual secret is set with --input-secret. The name is saved in `NAME.yaml` with -+ /// The actual secret is set with '--input-secret'. The name is saved in `NAME.yaml` with - /// white-spaces mapped to `_`. - name: String, - -@@ -166,15 +166,15 @@ pub enum AddSecretType { - stdout: bool, - - /// Path from which to read the plaintext secret. Uses a random secret if not specified. -- #[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath, conflicts_with("output_secret"))] -+ #[arg(long, value_name = "SECRET-FILE", value_hint = ValueHint::FilePath, conflicts_with("output_secret"))] - input_secret: Option, - -- /// Save the generated secret as plaintext in FILE. -+ /// Save the generated secret as plaintext in SECRET-FILE. - /// - /// The generated secret can be used to generate add-secret requests for a different guest -- /// with the same secret using --input-secret. Destroy the secret when it is not used -+ /// with the same secret using '--input-secret'. Destroy the secret when it is not used - /// anymore. -- #[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)] -+ #[arg(long, value_name = "SECRET-FILE", value_hint = ValueHint::FilePath,)] - output_secret: Option, - }, - } -@@ -243,13 +243,13 @@ pub enum Command { - /// Create a new add-secret request. - /// - /// Create add-secret requests for IBM Secure Execution guests. Only create these requests in a -- /// trusted environment, such as your workstation. The `pvattest create` command creates a -+ /// trusted environment, such as your workstation. The 'pvattest create' command creates a - /// randomly generated key to protect the request. The generated requests can then be added on -- /// an IBM Secure Execution guest using `pvsecret add`. The guest can then use the secrets with -+ /// an IBM Secure Execution guest using 'pvsecret add'. The guest can then use the secrets with - /// the use case depending on the secret type. - Create(Box), - -- /// Perform an add-secret request (s390x only). -+ /// Submit an add-secret request to the Ultravisor (s390x only). - /// - /// Perform an add-secret request using a previously generated add-secret request. Only - /// available on s390x. -@@ -258,7 +258,7 @@ pub enum Command { - /// Lock the secret-store (s390x only). - /// - /// Lock the secret store (s390x only). After this command executed successfully, all -- /// add-secret requests will fail. Only available on s390x. -+ /// subsequent add-secret requests will fail. Only available on s390x. - Lock, - - /// List all ultravisor secrets (s390x only). diff --git a/s390-tools-General-update-08.patch b/s390-tools-General-update-08.patch deleted file mode 100644 index 6fdd2d3..0000000 --- a/s390-tools-General-update-08.patch +++ /dev/null @@ -1,423 +0,0 @@ -From 93da795520ca2f0a73cfbfc951a9b16437a1b95b Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Mon, 19 Feb 2024 15:15:16 +0100 -Subject: [PATCH] rust/pvsecret: Add support for retrievable secrets -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Support for creating and retrieving retrievable secrets. - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pvsecret/src/cli.rs | 129 +++++++++++++++++++++++++++++++- - rust/pvsecret/src/cmd.rs | 6 +- - rust/pvsecret/src/cmd/create.rs | 30 +++++++- - rust/pvsecret/src/cmd/list.rs | 12 ++- - rust/pvsecret/src/cmd/retr.rs | 62 +++++++++++++++ - rust/pvsecret/src/main.rs | 1 + - 6 files changed, 230 insertions(+), 10 deletions(-) - create mode 100644 rust/pvsecret/src/cmd/retr.rs - -diff --git a/rust/pvsecret/src/cli.rs b/rust/pvsecret/src/cli.rs -index c4b9f2b3..4e747682 100644 ---- a/rust/pvsecret/src/cli.rs -+++ b/rust/pvsecret/src/cli.rs -@@ -1,7 +1,10 @@ - // SPDX-License-Identifier: MIT - // --// Copyright IBM Corp. 2023 -+// Copyright IBM Corp. 2023, 2024 - -+use std::fmt::Display; -+ -+use clap::error::ErrorKind::ValueValidation; - use clap::{ArgGroup, Args, CommandFactory, Parser, Subcommand, ValueEnum, ValueHint}; - use utils::{CertificateOptions, DeprecatedVerbosityOptions, STDOUT}; - -@@ -177,6 +180,72 @@ pub enum AddSecretType { - #[arg(long, value_name = "SECRET-FILE", value_hint = ValueHint::FilePath,)] - output_secret: Option, - }, -+ -+ /// Create a retrievable secret. -+ /// -+ /// A retrievable secret is stored in the per-guest storage of the Ultravisor. A SE-guest can -+ /// retrieve the secret at runtime and use it. All retrievable secrets, but the plaintext -+ /// secret, are retrieved as wrapped/protected key objects and only usable inside the current, -+ /// running SE-guest instance. -+ #[command(visible_alias = "retr")] -+ Retrievable { -+ /// String that identifies the new secret. -+ /// -+ /// The actual secret is set with '--secret'. The name is saved in `NAME.yaml` with -+ /// white-spaces mapped to `_`. -+ name: String, -+ -+ /// Print the hashed name to stdout. -+ /// -+ /// The hashed name is not written to `NAME.yaml` -+ #[arg(long)] -+ stdout: bool, -+ -+ /// Use SECRET-FILE as retrievable secret -+ #[arg(long, value_name = "SECRET-FILE", value_hint = ValueHint::FilePath)] -+ secret: String, -+ -+ /// Specify the secret type. -+ /// -+ /// Limitations to the input data apply depending on the secret type. -+ #[arg(long = "type", value_name = "TYPE")] -+ kind: RetrieveableSecretInpKind, -+ }, -+} -+ -+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)] -+pub enum RetrieveableSecretInpKind { -+ /// A plaintext secret. -+ /// Can be any file up to 8190 bytes long -+ Plain, -+ /// An AES key. -+ /// Must be a plain byte file 128, 192, or 256 bit long. -+ Aes, -+ /// An AES-XTS key. -+ /// Must be a plain byte file 512, or 1024 bit long. -+ AesXts, -+ /// A HMAC-SHA key. -+ /// Must be a plain byte file 512, or 1024 bit long. -+ HmacSha, -+ /// An elliptic curve private key. -+ /// Must be a PEM or DER file. -+ Ec, -+} -+ -+impl Display for RetrieveableSecretInpKind { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ write!( -+ f, -+ "{}", -+ match self { -+ Self::Plain => "PLAINTEXT", -+ Self::Aes => "AES KEY", -+ Self::AesXts => "AES-XTS KEY", -+ Self::HmacSha => "HMAC-SHA KEY", -+ Self::Ec => "EC PRIVATE KEY", -+ } -+ ) -+ } - } - - // all members s390x only -@@ -238,6 +307,56 @@ pub struct VerifyOpt { - pub output: String, - } - -+// all members s390x only -+#[derive(Args, Debug)] -+pub struct RetrSecretOptions { -+ /// Specify the secret ID to be retrieved. -+ /// -+ /// Input type depends on '--inform'. If `yaml` (default) is specified, it must be a yaml -+ /// created by the create subcommand of this tool. If `hex` is specified, it must be a hex -+ /// 32-byte unsigned big endian number string. Leading zeros are required. -+ #[cfg(target_arch = "s390x")] -+ #[arg(value_name = "ID", value_hint = ValueHint::FilePath)] -+ pub input: String, -+ -+ /// Specify the output path to place the secret value -+ #[cfg(target_arch = "s390x")] -+ #[arg(short, long, value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath)] -+ pub output: String, -+ -+ /// Define input type for the Secret ID -+ #[cfg(target_arch = "s390x")] -+ #[arg(long, value_enum, default_value_t)] -+ pub inform: RetrInpFmt, -+ -+ /// Define the output format for the retrieved secret -+ #[cfg(target_arch = "s390x")] -+ #[arg(long, value_enum, default_value_t)] -+ pub outform: RetrOutFmt, -+} -+ -+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)] -+pub enum RetrInpFmt { -+ /// Use a yaml file -+ #[default] -+ Yaml, -+ /// Use a hex string. -+ Hex, -+} -+ -+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)] -+pub enum RetrOutFmt { -+ /// Write the secret as PEM. -+ /// -+ /// File starts with `-----BEGIN IBM PROTECTED KEY----` and `-----BEGIN -+ /// PLAINTEXT SECRET-----` for plaintext secrets it contains one header -+ /// line with the type information and the base64 protected key -+ #[default] -+ Pem, -+ /// Write the secret in binary. -+ Bin, -+} -+ - #[derive(Subcommand, Debug)] - pub enum Command { - /// Create a new add-secret request. -@@ -274,6 +393,10 @@ pub enum Command { - /// provided key. Outputs the arbitrary user-data. - Verify(VerifyOpt), - -+ /// Retrieve a secret from the UV secret store (s390x only). -+ #[command(visible_alias = "retr")] -+ Retrieve(RetrSecretOptions), -+ - /// Print version information and exit. - #[command(aliases(["--version"]), hide(true))] - Version, -@@ -294,13 +417,13 @@ pub fn validate_cli(cli: &CliOptions) -> Result<(), clap::Error> { - } - if secret_out == &Some(format!("{name}.yaml")) { - return Err(CliOptions::command().error( -- clap::error::ErrorKind::ValueValidation, -+ ValueValidation, - format!("Secret output file and the secret name '{name}.yaml' are the same."), - )); - } - if format!("{name}.yaml") == opt.output { - return Err(CliOptions::command().error( -- clap::error::ErrorKind::ValueValidation, -+ ValueValidation, - format!( - "output file and the secret name '{}' are the same.", - &opt.output -diff --git a/rust/pvsecret/src/cmd.rs b/rust/pvsecret/src/cmd.rs -index a826fb31..10d99a5b 100644 ---- a/rust/pvsecret/src/cmd.rs -+++ b/rust/pvsecret/src/cmd.rs -@@ -16,6 +16,8 @@ mod add; - mod list; - #[cfg(target_arch = "s390x")] - mod lock; -+#[cfg(target_arch = "s390x")] -+mod retr; - - // Commands (directly) related to UVCs are only available on s389x - #[cfg(target_arch = "s390x")] -@@ -24,12 +26,13 @@ mod uv_cmd { - pub use add::add; - pub use list::list; - pub use lock::lock; -+ pub use retr::retr; - pub const UV_CMD_FN: &[&str] = &["+add", "+lock", "+list"]; - } - - #[cfg(not(target_arch = "s390x"))] - mod uv_cmd { -- use crate::cli::{AddSecretOpt, ListSecretOpt}; -+ use crate::cli::{AddSecretOpt, ListSecretOpt, RetrSecretOptions}; - use anyhow::{bail, Result}; - macro_rules! not_supp { - ($name: ident $( ,$opt: ty )?) => { -@@ -40,6 +43,7 @@ mod uv_cmd { - } - not_supp!(add, AddSecretOpt); - not_supp!(list, ListSecretOpt); -+ not_supp!(retr, RetrSecretOptions); - not_supp!(lock); - pub const UV_CMD_FN: &[&str] = &[]; - } -diff --git a/rust/pvsecret/src/cmd/create.rs b/rust/pvsecret/src/cmd/create.rs -index 9251c38c..73089a12 100644 ---- a/rust/pvsecret/src/cmd/create.rs -+++ b/rust/pvsecret/src/cmd/create.rs -@@ -4,7 +4,6 @@ - - use std::path::Path; - --use crate::cli::{AddSecretType, CreateSecretFlags, CreateSecretOpt}; - use anyhow::{anyhow, bail, Context, Error, Result}; - use log::{debug, info, trace, warn}; - use pv::{ -@@ -22,6 +21,8 @@ use pv::{ - use serde_yaml::Value; - use utils::get_writer_from_cli_file_arg; - -+use crate::cli::{AddSecretType, CreateSecretFlags, CreateSecretOpt, RetrieveableSecretInpKind}; -+ - fn write_out(path: &P, data: D, ctx: &str) -> pv::Result<()> - where - P: AsRef, -@@ -32,6 +33,23 @@ where - Ok(()) - } - -+fn retrievable(name: &str, secret: &str, kind: &RetrieveableSecretInpKind) -> Result { -+ let secret_data = read_file(secret, &format!("retrievable {kind}"))?.into(); -+ -+ match kind { -+ RetrieveableSecretInpKind::Plain => GuestSecret::plaintext(name, secret_data), -+ RetrieveableSecretInpKind::Aes => GuestSecret::aes(name, secret_data), -+ RetrieveableSecretInpKind::AesXts => GuestSecret::aes_xts(name, secret_data), -+ RetrieveableSecretInpKind::HmacSha => GuestSecret::hmac_sha(name, secret_data), -+ RetrieveableSecretInpKind::Ec => GuestSecret::ec( -+ name, -+ read_private_key(secret_data.value()) -+ .with_context(|| format!("Cannot read {secret} as {kind} from PEM or DER"))?, -+ ), -+ } -+ .map_err(Error::from) -+} -+ - /// Prepare an add-secret request - pub fn create(opt: &CreateSecretOpt) -> Result<()> { - if pv_guest_bit_set() { -@@ -88,6 +106,9 @@ fn build_asrcb(opt: &CreateSecretOpt) -> Result { - input_secret: None, - .. - } => GuestSecret::association(name, None)?, -+ AddSecretType::Retrievable { -+ name, secret, kind, .. -+ } => retrievable(name, secret, kind)?, - }; - trace!("AddSecret: {secret:x?}"); - -@@ -136,7 +157,9 @@ fn build_asrcb(opt: &CreateSecretOpt) -> Result { - .as_ref() - .map(|p| read_file(p, "User-signing key")) - .transpose()? -- .map(|buf| read_private_key(&buf)) -+ .map(|buf| { -+ read_private_key(&buf).context("Cannot read {secret} as private key from PEM or DER") -+ }) - .transpose()?; - - if user_data.is_some() || user_key.is_some() { -@@ -258,6 +281,9 @@ fn write_secret>( - write_out(path, guest_secret.confidential(), "Association secret")? - } - } -+ AddSecretType::Retrievable { name, stdout, .. } => { -+ write_yaml(name, guest_secret, stdout, outp_path)? -+ } - _ => (), - }; - Ok(()) -diff --git a/rust/pvsecret/src/cmd/list.rs b/rust/pvsecret/src/cmd/list.rs -index f7e3a72b..0bd9eca4 100644 ---- a/rust/pvsecret/src/cmd/list.rs -+++ b/rust/pvsecret/src/cmd/list.rs -@@ -3,21 +3,25 @@ - // Copyright IBM Corp. 2023 - - use crate::cli::{ListSecretOpt, ListSecretOutputType}; --use anyhow::{Context, Result}; -+use anyhow::{Context, Error, Result}; - use log::warn; - use pv::uv::{ListCmd, SecretList, UvDevice, UvcSuccess}; - use utils::{get_writer_from_cli_file_arg, STDOUT}; - - /// Do a List Secrets UVC --pub fn list(opt: &ListSecretOpt) -> Result<()> { -- let uv = UvDevice::open()?; -+pub fn list_uvc(uv: &UvDevice) -> Result { - let mut cmd = ListCmd::default(); - match uv.send_cmd(&mut cmd)? { - UvcSuccess::RC_SUCCESS => (), - UvcSuccess::RC_MORE_DATA => warn!("There is more data available than expected"), - }; -+ cmd.try_into().map_err(Error::new) -+} - -- let secret_list: SecretList = cmd.try_into()?; -+/// Do a List Secrets UVC and output the list in the requested format -+pub fn list(opt: &ListSecretOpt) -> Result<()> { -+ let uv = UvDevice::open()?; -+ let secret_list = list_uvc(&uv)?; - let mut wr_out = get_writer_from_cli_file_arg(&opt.output)?; - - match &opt.format { -diff --git a/rust/pvsecret/src/cmd/retr.rs b/rust/pvsecret/src/cmd/retr.rs -new file mode 100644 -index 00000000..7f7704cc ---- /dev/null -+++ b/rust/pvsecret/src/cmd/retr.rs -@@ -0,0 +1,62 @@ -+// SPDX-License-Identifier: MIT -+// -+// Copyright IBM Corp. 2024 -+ -+use super::list::list_uvc; -+use crate::cli::{RetrInpFmt, RetrOutFmt, RetrSecretOptions}; -+use anyhow::{anyhow, bail, Context, Result}; -+use log::{debug, info}; -+use pv::{ -+ misc::open_file, -+ misc::write, -+ secret::{GuestSecret, RetrievedSecret}, -+ uv::{RetrieveCmd, SecretId, UvDevice}, -+}; -+use utils::get_writer_from_cli_file_arg; -+ -+fn retrieve(id: &SecretId) -> Result { -+ let uv = UvDevice::open()?; -+ let secrets = list_uvc(&uv)?; -+ let secret = secrets -+ .into_iter() -+ .find(|s| s.id() == id.as_ref()) -+ .ok_or(anyhow!( -+ "The UV secret-store has no secret with the ID {id}" -+ ))?; -+ -+ info!("Try to retrieve secret at index: {}", secret.index()); -+ debug!("Try to retrieve: {secret:?}"); -+ -+ let mut uv_cmd = RetrieveCmd::from_entry(secret)?; -+ uv.send_cmd(&mut uv_cmd)?; -+ -+ Ok(RetrievedSecret::from_cmd(uv_cmd)) -+} -+ -+pub fn retr(opt: &RetrSecretOptions) -> Result<()> { -+ let mut output = get_writer_from_cli_file_arg(&opt.output)?; -+ let id = match &opt.inform { -+ RetrInpFmt::Yaml => match serde_yaml::from_reader(&mut open_file(&opt.input)?)? { -+ GuestSecret::Retrievable { id, .. } => id, -+ gs => bail!("The file contains a {gs}-secret, which is not retrievable."), -+ }, -+ RetrInpFmt::Hex => { -+ serde_yaml::from_str(&opt.input).context("Cannot parse SecretId information")? -+ } -+ }; -+ -+ let retr_secret = -+ retrieve(&id).context("Could not retrieve the secret from the UV secret store.")?; -+ -+ let out_data = match opt.outform { -+ RetrOutFmt::Bin => retr_secret.into_bytes(), -+ RetrOutFmt::Pem => retr_secret.to_pem()?.into_bytes(), -+ }; -+ write( -+ &mut output, -+ out_data.value(), -+ &opt.output, -+ "IBM Protected Key", -+ )?; -+ Ok(()) -+} -diff --git a/rust/pvsecret/src/main.rs b/rust/pvsecret/src/main.rs -index 502a6ea0..883a3ee2 100644 ---- a/rust/pvsecret/src/main.rs -+++ b/rust/pvsecret/src/main.rs -@@ -45,6 +45,7 @@ fn main() -> ExitCode { - Command::Create(opt) => cmd::create(opt), - Command::Version => Ok(print_version!("2024", log_level; FEATURES.concat())), - Command::Verify(opt) => cmd::verify(opt), -+ Command::Retrieve(opt) => cmd::retr(opt), - }; - - match res { diff --git a/s390-tools-General-update-09.patch b/s390-tools-General-update-09.patch deleted file mode 100644 index ee9844f..0000000 --- a/s390-tools-General-update-09.patch +++ /dev/null @@ -1,313 +0,0 @@ -From 256289a30aa5d3f6a4d2631dea69d1dc47205150 Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Wed, 12 Jun 2024 16:23:31 +0200 -Subject: [PATCH] rust/pv_core: Refactor secret list -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Improve the secret list implementation. Use structs+{As,From}Bytes -instead of arbitrary seeks and reads/writes to parse the secret list. - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv_core/src/uvdevice.rs | 10 ++ - rust/pv_core/src/uvdevice/secret_list.rs | 124 ++++++++++++++--------- - 2 files changed, 86 insertions(+), 48 deletions(-) - -diff --git a/rust/pv_core/src/uvdevice.rs b/rust/pv_core/src/uvdevice.rs -index e9848243..e701366d 100644 ---- a/rust/pv_core/src/uvdevice.rs -+++ b/rust/pv_core/src/uvdevice.rs -@@ -163,6 +163,16 @@ pub enum UvcSuccess { - RC_MORE_DATA = UvDevice::RC_MORE_DATA, - } - -+impl UvcSuccess { -+ /// Returns true if there is more data available -+ pub fn more_data(&self) -> bool { -+ match self { -+ Self::RC_SUCCESS => false, -+ Self::RC_MORE_DATA => true, -+ } -+ } -+} -+ - /// The `UvDevice` is a (virtual) device on s390 machines to send Ultravisor commands(UVCs) from - /// userspace. - /// -diff --git a/rust/pv_core/src/uvdevice/secret_list.rs b/rust/pv_core/src/uvdevice/secret_list.rs -index 4e955010..d7c268c9 100644 ---- a/rust/pv_core/src/uvdevice/secret_list.rs -+++ b/rust/pv_core/src/uvdevice/secret_list.rs -@@ -4,16 +4,16 @@ - - use crate::{ - assert_size, -- misc::to_u16, - uv::{AesSizes, AesXtsSizes, EcCurves, HmacShaSizes, ListCmd, RetrievableSecret}, - uvdevice::UvCmd, - Error, Result, - }; --use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; -+use byteorder::{BigEndian, ByteOrder}; - use serde::{Deserialize, Serialize, Serializer}; - use std::{ - fmt::Display, - io::{Cursor, Read, Seek, Write}, -+ mem::size_of, - slice::Iter, - vec::IntoIter, - }; -@@ -31,7 +31,7 @@ impl SecretId { - /// Size in bytes of the [`SecretId`] - pub const ID_SIZE: usize = 32; - -- /// Create a [`SecretId`] forom a buffer. -+ /// Create a [`SecretId`] from a buffer. - pub fn from(buf: [u8; Self::ID_SIZE]) -> Self { - buf.into() - } -@@ -120,7 +120,7 @@ impl SecretEntry { - &self.index - } - -- /// Returns the secret type of this [`SecretEntry`]. -+ /// Returns the secret type of this [`SecretEntry`] - pub fn stype(&self) -> ListableSecretType { - self.stype.get().into() - } -@@ -161,12 +161,45 @@ impl Display for SecretEntry { - } - } - -+#[repr(C)] -+#[derive(Debug, FromBytes, AsBytes, FromZeroes, Clone, PartialEq, Eq, Default, Serialize)] -+struct SecretListHdr { -+ #[serde(skip)] -+ num_secrets_stored: U16, -+ #[serde(serialize_with = "ser_u16")] -+ total_num_secrets: U16, -+ #[serde(skip)] -+ next_secret_idx: U16, -+ #[serde(skip)] -+ reserved_06: u16, -+ #[serde(skip)] -+ reserved_08: u64, -+} -+ -+impl SecretListHdr { -+ fn new(num_secrets_stored: u16, total_num_secrets: u16, next_secret_idx: u16) -> Self { -+ Self { -+ num_secrets_stored: num_secrets_stored.into(), -+ total_num_secrets: total_num_secrets.into(), -+ next_secret_idx: next_secret_idx.into(), -+ reserved_06: 0, -+ reserved_08: 0, -+ } -+ } -+} -+assert_size!(SecretListHdr, 16); -+ - /// List of secrets used to parse the [`crate::uv::ListCmd`] result. - /// --/// The list should not hold more than 0xffffffff elements --#[derive(Debug, PartialEq, Eq, Serialize)] -+/// The list should ONLY be created from an UV-Call result using either: -+/// - [`TryInto::try_into`] from [`ListCmd`] -+/// - [`SecretList::decode`] -+/// Any other ways can create invalid lists that do not represent the UV secret store. -+/// The list must not hold more than [`u32::MAX`] elements -+#[derive(Debug, PartialEq, Eq, Serialize, Default)] - pub struct SecretList { -- total_num_secrets: usize, -+ #[serde(flatten)] -+ hdr: SecretListHdr, - secrets: Vec, - } - -@@ -202,10 +235,14 @@ impl SecretList { - /// The content of this list will very likely not represent the status of the guest in the - /// Ultravisor. Use of [`SecretList::decode`] in any non-test environments is encuraged. - pub fn new(total_num_secrets: u16, secrets: Vec) -> Self { -- Self { -- total_num_secrets: total_num_secrets as usize, -+ Self::new_with_hdr( -+ SecretListHdr::new(total_num_secrets, total_num_secrets, 0), - secrets, -- } -+ ) -+ } -+ -+ fn new_with_hdr(hdr: SecretListHdr, secrets: Vec) -> Self { -+ Self { hdr, secrets } - } - - /// Returns an iterator over the slice. -@@ -229,19 +266,12 @@ impl SecretList { - /// - /// This number may be not equal to the provided number of [`SecretEntry`] - pub fn total_num_secrets(&self) -> usize { -- self.total_num_secrets -+ self.hdr.total_num_secrets.get() as usize - } - - /// Encodes the list in the same binary format the UV would do - pub fn encode(&self, w: &mut T) -> Result<()> { -- let num_s = to_u16(self.secrets.len()).ok_or(Error::ManySecrets)?; -- w.write_u16::(num_s)?; -- w.write_u16::( -- self.total_num_secrets -- .try_into() -- .map_err(|_| Error::ManySecrets)?, -- )?; -- w.write_all(&[0u8; 12])?; -+ w.write_all(self.hdr.as_bytes())?; - for secret in &self.secrets { - w.write_all(secret.as_bytes())?; - } -@@ -250,19 +280,20 @@ impl SecretList { - - /// Decodes the list from the binary format of the UV into this internal representation - pub fn decode(r: &mut R) -> std::io::Result { -- let num_s = r.read_u16::()?; -- let total_num_secrets = r.read_u16::()? as usize; -- let mut v: Vec = Vec::with_capacity(num_s as usize); -- r.seek(std::io::SeekFrom::Current(12))?; // skip reserved bytes -+ let mut buf = [0u8; size_of::()]; -+ r.read_exact(&mut buf)?; -+ let hdr = SecretListHdr::ref_from(&buf).unwrap(); -+ - let mut buf = [0u8; SecretEntry::STRUCT_SIZE]; -- for _ in 0..num_s { -+ let mut v = Vec::with_capacity(hdr.num_secrets_stored.get() as usize); -+ for _ in 0..hdr.num_secrets_stored.get() { - r.read_exact(&mut buf)?; - // cannot fail. buffer has the same size as the secret entry - let secr = SecretEntry::read_from(buf.as_slice()).unwrap(); - v.push(secr); - } - Ok(Self { -- total_num_secrets, -+ hdr: hdr.clone(), - secrets: v, - }) - } -@@ -278,7 +309,7 @@ impl TryFrom for SecretList { - - impl Display for SecretList { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -- writeln!(f, "Total number of secrets: {}", self.total_num_secrets)?; -+ writeln!(f, "Total number of secrets: {}", self.total_num_secrets())?; - if !self.secrets.is_empty() { - writeln!(f)?; - } -@@ -481,8 +512,8 @@ mod test { - let buf = [ - 0x00u8, 0x01, // num secr stored - 0x01, 0x12, // total num secrets -- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -- 0x00, // reserved -+ 0x01, 0x01, // next valid idx -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved - // secret - 0x00, 0x01, 0x00, 0x02, // idx + type - 0x00, 0x00, 0x00, 0x20, // len -@@ -493,16 +524,16 @@ mod test { - 0x00, 0x00, 0x00, 0x00, - ]; - -- let exp = SecretList { -- total_num_secrets: 0x112, -- secrets: vec![SecretEntry { -+ let exp = SecretList::new_with_hdr( -+ SecretListHdr::new(0x001, 0x112, 0x101), -+ vec![SecretEntry { - index: 1.into(), - stype: 2.into(), - len: 32.into(), - res_8: 0, - id: SecretId::from([0; 32]), - }], -- }; -+ ); - - let mut br = BufReader::new(Cursor::new(buf)); - let sl = SecretList::decode(&mut br).unwrap(); -@@ -514,8 +545,8 @@ mod test { - const EXP: &[u8] = &[ - 0x00, 0x01, // num secr stored - 0x01, 0x12, // total num secrets -- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -- 0x00, // reserved -+ 0x01, 0x01, // next valid idx -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved - // secret - 0x00, 0x01, 0x00, 0x02, // idx + type - 0x00, 0x00, 0x00, 0x20, // len -@@ -526,16 +557,16 @@ mod test { - 0x00, 0x00, 0x00, 0x00, - ]; - -- let sl = SecretList { -- total_num_secrets: 0x112, -- secrets: vec![SecretEntry { -+ let sl = SecretList::new_with_hdr( -+ SecretListHdr::new(0x001, 0x112, 0x101), -+ vec![SecretEntry { - index: 1.into(), - stype: 2.into(), - len: 32.into(), - res_8: 0, - id: SecretId::from([0; 32]), - }], -- }; -+ ); - - let mut buf = [0u8; 0x40]; - { -@@ -587,26 +618,23 @@ mod test { - - #[test] - fn secret_list_ser() { -- let list = SecretList { -- total_num_secrets: 0x112, -- secrets: vec![SecretEntry { -+ let list = SecretList::new_with_hdr( -+ SecretListHdr::new(0x001, 0x112, 0x101), -+ vec![SecretEntry { - index: 1.into(), - stype: 2.into(), - len: 32.into(), - res_8: 0, - id: SecretId::from([0; 32]), - }], -- }; -+ ); - - assert_ser_tokens( - &list, - &[ -- Token::Struct { -- name: "SecretList", -- len: 2, -- }, -+ Token::Map { len: None }, - Token::String("total_num_secrets"), -- Token::U64(0x112), -+ Token::U16(0x112), - Token::String("secrets"), - Token::Seq { len: Some(1) }, - Token::Struct { -@@ -623,7 +651,7 @@ mod test { - Token::String("0x0000000000000000000000000000000000000000000000000000000000000000"), - Token::StructEnd, - Token::SeqEnd, -- Token::StructEnd, -+ Token::MapEnd, - ], - ) - } diff --git a/s390-tools-General-update-10.patch b/s390-tools-General-update-10.patch deleted file mode 100644 index 01b0dbc..0000000 --- a/s390-tools-General-update-10.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 93216d916c479ee1292aa1d598ac9c0e7f585bd8 Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Wed, 12 Jun 2024 16:35:15 +0200 -Subject: [PATCH] rust/pv*: Support longer secret lists -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Make use of the enhanced list secrets UAPI for the uvdevice in the latest kernel -version. This allows fetching secret lists with more than 85 entries via -reserving more userspace memory in the IOCTL argument. - -While at it, move the errno readout next to the ioctl-syscall. - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv_core/src/uvdevice.rs | 6 ++++-- - rust/pv_core/src/uvdevice/secret.rs | 11 +++++++++++ - rust/pvsecret/src/cmd/list.rs | 28 +++++++++++++++++++++------- - 3 files changed, 36 insertions(+), 9 deletions(-) - -diff --git a/rust/pv_core/src/uvdevice.rs b/rust/pv_core/src/uvdevice.rs -index e701366d..689748a1 100644 ---- a/rust/pv_core/src/uvdevice.rs -+++ b/rust/pv_core/src/uvdevice.rs -@@ -59,11 +59,13 @@ fn ioctl_raw(raw_fd: RawFd, cmd: c_ulong, cb: &mut IoctlCb) -> Result<()> { - rc = ioctl(raw_fd, cmd, cb.as_ptr_mut()); - } - -+ // NOTE io::Error handles all errnos ioctl uses -+ let errno = std::io::Error::last_os_error(); -+ - debug!("ioctl resulted with {cb:?}"); - match rc { - 0 => Ok(()), -- // NOTE io::Error handles all errnos ioctl uses -- _ => Err(std::io::Error::last_os_error().into()), -+ _ => Err(errno.into()), - } - } - -diff --git a/rust/pv_core/src/uvdevice/secret.rs b/rust/pv_core/src/uvdevice/secret.rs -index 263f17d5..cb5b7233 100644 ---- a/rust/pv_core/src/uvdevice/secret.rs -+++ b/rust/pv_core/src/uvdevice/secret.rs -@@ -24,6 +24,17 @@ impl ListCmd { - Self(vec![0; size]) - } - -+ /// Create a new list secrets command with `pages` capacity. -+ /// -+ /// * `pages` - number pf pages to allocate for this IOCTL -+ /// -+ /// # Panic -+ /// This function will trigger a panic if the allocation size is larger than [`usize::MAX`]. -+ /// Very likely an OOM situation occurs way before this! -+ pub fn with_pages(pages: usize) -> Self { -+ Self::with_size(pages * PAGESIZE) -+ } -+ - /// Create a new list secrets command with a one page capacity - pub fn new() -> Self { - Self::with_size(PAGESIZE) -diff --git a/rust/pvsecret/src/cmd/list.rs b/rust/pvsecret/src/cmd/list.rs -index 0bd9eca4..56294cac 100644 ---- a/rust/pvsecret/src/cmd/list.rs -+++ b/rust/pvsecret/src/cmd/list.rs -@@ -2,19 +2,33 @@ - // - // Copyright IBM Corp. 2023 - -+use std::io::ErrorKind; -+ - use crate::cli::{ListSecretOpt, ListSecretOutputType}; - use anyhow::{Context, Error, Result}; --use log::warn; --use pv::uv::{ListCmd, SecretList, UvDevice, UvcSuccess}; -+use log::{info, warn}; -+use pv::uv::{ListCmd, SecretList, UvDevice}; - use utils::{get_writer_from_cli_file_arg, STDOUT}; - -+const SECRET_LIST_BUF_SIZE: usize = 4; -+ - /// Do a List Secrets UVC - pub fn list_uvc(uv: &UvDevice) -> Result { -- let mut cmd = ListCmd::default(); -- match uv.send_cmd(&mut cmd)? { -- UvcSuccess::RC_SUCCESS => (), -- UvcSuccess::RC_MORE_DATA => warn!("There is more data available than expected"), -- }; -+ let mut cmd = ListCmd::with_pages(SECRET_LIST_BUF_SIZE); -+ let more_data = match uv.send_cmd(&mut cmd) { -+ Ok(v) => Ok(v), -+ Err(pv::PvCoreError::Io(e)) if e.kind() == ErrorKind::InvalidInput => { -+ info!("Uvdevice does not suport longer list. Fallback to one page list."); -+ cmd = ListCmd::default(); -+ uv.send_cmd(&mut cmd) -+ } -+ Err(e) => Err(e), -+ }? -+ .more_data(); -+ if more_data { -+ warn!("The secret list contains more data but the uvdevice cannot show all."); -+ } -+ - cmd.try_into().map_err(Error::new) - } - diff --git a/s390-tools-General-update-11.patch b/s390-tools-General-update-11.patch deleted file mode 100644 index 8bb5da9..0000000 --- a/s390-tools-General-update-11.patch +++ /dev/null @@ -1,387 +0,0 @@ -From ff04f76257791593c8f92374f295a0c478e3b0f7 Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Mon, 5 Aug 2024 09:34:47 +0200 -Subject: [PATCH] rust/pv*: Allow the use of non-hashes secret IDs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Secret IDs identify a secret in the store. Tooling (pvsecret) calculates -them by hashing a user-defined string. With this patch it is now -possible to skip the hash step and directly use the input string as the -ID. Up to the first 31 bytes of the input ASCII-string are used. The last byte -is the NUL char. During list pvsecret tries to interpret the secret -as ASCII string and if possible displays the ASCII characters alongside -the hex number. - -Also, use the Upper/Lower Hex formatters for the hexstring formatting of -SecretId. Display will, additionally show the ASCII representation if -applicable. - -While at it, use Self wherever possible. - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pv/src/uvsecret/guest_secret.rs | 16 ++- - rust/pv_core/src/uvdevice/secret_list.rs | 163 ++++++++++++++++++++--- - rust/pvsecret/src/cli.rs | 8 ++ - rust/pvsecret/src/cmd/create.rs | 4 +- - rust/pvsecret/src/cmd/retr.rs | 14 +- - 5 files changed, 184 insertions(+), 21 deletions(-) - -diff --git a/rust/pv/src/uvsecret/guest_secret.rs b/rust/pv/src/uvsecret/guest_secret.rs -index 3bad6d3c..87b58bb8 100644 ---- a/rust/pv/src/uvsecret/guest_secret.rs -+++ b/rust/pv/src/uvsecret/guest_secret.rs -@@ -92,7 +92,8 @@ macro_rules! retr_constructor { - } - - impl GuestSecret { -- fn name_to_id(name: &str) -> Result { -+ /// Hashes the name with sha256 -+ pub fn name_to_id(name: &str) -> Result { - let id: [u8; SecretId::ID_SIZE] = hash(MessageDigest::sha256(), name.as_bytes())? - .to_vec() - .try_into() -@@ -135,6 +136,19 @@ impl GuestSecret { - retr_constructor!(#[doc = r"This function will return an error if OpenSSL cannot create a hash or the curve is invalid"] - | #[doc = r"EC PRIVATE Key"] => PKey, ec); - -+ /// Use the name as ID, do not hash it -+ pub fn no_hash_name(&mut self) { -+ match self { -+ Self::Null => (), -+ Self::Association { -+ name, ref mut id, .. -+ } -+ | Self::Retrievable { -+ name, ref mut id, .. -+ } => id.clone_from(&SecretId::from_string(name)), -+ } -+ } -+ - /// Reference to the confidential data - pub fn confidential(&self) -> &[u8] { - match &self { -diff --git a/rust/pv_core/src/uvdevice/secret_list.rs b/rust/pv_core/src/uvdevice/secret_list.rs -index d7c268c9..7c7e63b5 100644 ---- a/rust/pv_core/src/uvdevice/secret_list.rs -+++ b/rust/pv_core/src/uvdevice/secret_list.rs -@@ -11,7 +11,9 @@ use crate::{ - use byteorder::{BigEndian, ByteOrder}; - use serde::{Deserialize, Serialize, Serializer}; - use std::{ -- fmt::Display, -+ cmp::min, -+ ffi::CStr, -+ fmt::{Debug, Display, LowerHex, UpperHex}, - io::{Cursor, Read, Seek, Write}, - mem::size_of, - slice::Iter, -@@ -35,6 +37,33 @@ impl SecretId { - pub fn from(buf: [u8; Self::ID_SIZE]) -> Self { - buf.into() - } -+ -+ /// Create a Id from a string -+ /// -+ /// Uses the first 31 bytes from `name` as id -+ /// Does not hash anything. Byte 32 is the NUL char -+ pub fn from_string(name: &str) -> Self { -+ let len = min(name.len(), Self::ID_SIZE - 1); -+ let mut res = Self::default(); -+ res.0[0..len].copy_from_slice(&name.as_bytes()[0..len]); -+ res -+ } -+ -+ /// Tries to represent the Id as printable-ASCII string -+ pub fn as_ascii(&self) -> Option<&str> { -+ if let Ok(t) = CStr::from_bytes_until_nul(&self.0) { -+ if let Ok(t) = t.to_str() { -+ if !t.is_empty() -+ && t.chars() -+ .all(|c| c.is_ascii_whitespace() | c.is_ascii_graphic()) -+ && self.0[t.len()..].iter().all(|b| *b == 0) -+ { -+ return Some(t); -+ } -+ } -+ }; -+ None -+ } - } - - impl Serialize for SecretId { -@@ -42,8 +71,8 @@ impl Serialize for SecretId { - where - S: Serializer, - { -- // calls Display at one point -- ser.serialize_str(&self.to_string()) -+ // calls LowerHex at one point -+ ser.serialize_str(&format!("{self:#x}")) - } - } - -@@ -56,12 +85,36 @@ impl<'de> Deserialize<'de> for SecretId { - } - } - -+impl UpperHex for SecretId { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ if f.alternate() { -+ write!(f, "0x")?; -+ } -+ for b in self.0 { -+ write!(f, "{b:02X}")?; -+ } -+ Ok(()) -+ } -+} -+ -+impl LowerHex for SecretId { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ if f.alternate() { -+ write!(f, "0x")?; -+ } -+ for b in self.0 { -+ write!(f, "{b:02x}")?; -+ } -+ Ok(()) -+ } -+} -+ - impl Display for SecretId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -- let mut s = String::with_capacity(32 * 2 + 2); -- s.push_str("0x"); -- let s = self.0.iter().fold(s, |acc, e| acc + &format!("{e:02x}")); -- write!(f, "{s}") -+ if let Some(s) = self.as_ascii() { -+ write!(f, "{s} | ")?; -+ } -+ write!(f, "{self:#x}") - } - } - -@@ -79,7 +132,7 @@ impl AsRef<[u8]> for SecretId { - - /// A secret in a [`SecretList`] - #[repr(C)] --#[derive(Debug, PartialEq, Eq, AsBytes, FromZeroes, FromBytes, Serialize)] -+#[derive(Debug, Clone, PartialEq, Eq, AsBytes, FromZeroes, FromBytes, Serialize)] - pub struct SecretEntry { - #[serde(serialize_with = "ser_u16")] - index: U16, -@@ -153,11 +206,7 @@ impl Display for SecretEntry { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let stype: ListableSecretType = self.stype.get().into(); - writeln!(f, "{} {}:", self.index, stype)?; -- write!(f, " ")?; -- for b in self.id.as_ref() { -- write!(f, "{b:02x}")?; -- } -- Ok(()) -+ write!(f, " {}", self.id) - } - } - -@@ -269,6 +318,11 @@ impl SecretList { - self.hdr.total_num_secrets.get() as usize - } - -+ /// Find the first [`SecretEntry`] that has the provided [`SecretId`] -+ pub fn find(&self, id: &SecretId) -> Option { -+ self.iter().find(|e| e.id() == id.as_ref()).cloned() -+ } -+ - /// Encodes the list in the same binary format the UV would do - pub fn encode(&self, w: &mut T) -> Result<()> { - w.write_all(self.hdr.as_bytes())?; -@@ -456,7 +510,7 @@ where - type Value = [u8; SecretId::ID_SIZE]; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { -- formatter.write_str("a `32 bytes long hexstring` prepended with 0x") -+ formatter.write_str("a `32 bytes (=64 character) long hexstring` prepended with 0x") - } - - fn visit_str(self, s: &str) -> Result -@@ -464,7 +518,10 @@ where - E: serde::de::Error, - { - if s.len() != SecretId::ID_SIZE * 2 + "0x".len() { -- return Err(serde::de::Error::invalid_length(s.len() - 2, &self)); -+ return Err(serde::de::Error::invalid_length( -+ s.len().saturating_sub("0x".len()), -+ &self, -+ )); - } - let nb = s.strip_prefix("0x").ok_or_else(|| { - serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self) -@@ -655,4 +712,80 @@ mod test { - ], - ) - } -+ -+ #[test] -+ fn secret_id_display() { -+ let text = "Fancy secret ID"; -+ let id = SecretId::from_string(text); -+ -+ let exp = -+ "Fancy secret ID | 0x46616e6379207365637265742049440000000000000000000000000000000000"; -+ assert_eq!(id.to_string(), exp); -+ } -+ -+ #[test] -+ fn secret_id_long_name() { -+ let text = "the most fanciest secret ID you ever seen in the time the universe exists"; -+ let id = SecretId::from_string(text); -+ let exp = -+ "the most fanciest secret ID you | 0x746865206d6f73742066616e63696573742073656372657420494420796f7500"; -+ assert_eq!(id.to_string(), exp); -+ } -+ -+ #[test] -+ fn secret_id_no_ascii_name() { -+ let text = [0; 32]; -+ let id = SecretId::from(text); -+ -+ let exp = "0x0000000000000000000000000000000000000000000000000000000000000000"; -+ assert_eq!(id.to_string(), exp); -+ } -+ -+ #[test] -+ fn secret_id_no_ascii_name2() { -+ let text = [ -+ 0x25, 0x55, 3, 4, 50, 0, 6, 0, 8, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0xa, 0, 0, 0, 0, 0xf, 0, -+ 0, 0, 0, 0, 0, 0, 0, -+ ]; -+ let id = SecretId::from(text); -+ assert_eq!(id.as_ascii(), None); -+ } -+ -+ #[test] -+ fn secret_id_no_ascii_name3() { -+ let text = [ -+ 0x25, 0x55, 0, 4, 50, 0, 6, 0, 8, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0xa, 0, 0, 0, 0, 0xf, 0, -+ 0, 0, 0, 0, 0, 0, 0, -+ ]; -+ let id = SecretId::from(text); -+ assert_eq!(id.as_ascii(), None); -+ } -+ -+ #[test] -+ fn secret_id_hex() { -+ let id_str = "Nice Test 123"; -+ let id = SecretId::from_string(id_str); -+ -+ let s = format!("{id:#x}"); -+ assert_eq!( -+ s, -+ "0x4e69636520546573742031323300000000000000000000000000000000000000" -+ ); -+ let s = format!("{id:x}"); -+ assert_eq!( -+ s, -+ "4e69636520546573742031323300000000000000000000000000000000000000" -+ ); -+ let s = format!("{id:#X}"); -+ assert_eq!( -+ s, -+ "0x4E69636520546573742031323300000000000000000000000000000000000000" -+ ); -+ -+ let s = format!("{id:X}"); -+ assert_eq!( -+ s, -+ "4E69636520546573742031323300000000000000000000000000000000000000" -+ ); -+ } - } -diff --git a/rust/pvsecret/src/cli.rs b/rust/pvsecret/src/cli.rs -index 4e747682..d858fc29 100644 ---- a/rust/pvsecret/src/cli.rs -+++ b/rust/pvsecret/src/cli.rs -@@ -141,6 +141,12 @@ pub struct CreateSecretOpt { - /// by default. - #[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)] - pub user_sign_key: Option, -+ -+ /// Do not hash the name, use it directly as secret ID. -+ /// -+ /// Ignored for meta-secrets. -+ #[arg(long)] -+ pub use_name: bool, - } - - #[derive(Subcommand, Debug)] -@@ -342,6 +348,8 @@ pub enum RetrInpFmt { - Yaml, - /// Use a hex string. - Hex, -+ /// Use a name-string. Will hash it if no secret with the name found. -+ Name, - } - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)] -diff --git a/rust/pvsecret/src/cmd/create.rs b/rust/pvsecret/src/cmd/create.rs -index 73089a12..fab37e67 100644 ---- a/rust/pvsecret/src/cmd/create.rs -+++ b/rust/pvsecret/src/cmd/create.rs -@@ -94,7 +94,7 @@ fn read_private_key(buf: &[u8]) -> Result> { - fn build_asrcb(opt: &CreateSecretOpt) -> Result { - debug!("Build add-secret request"); - -- let secret = match &opt.secret { -+ let mut secret = match &opt.secret { - AddSecretType::Meta => GuestSecret::Null, - AddSecretType::Association { - name, -@@ -112,6 +112,8 @@ fn build_asrcb(opt: &CreateSecretOpt) -> Result { - }; - trace!("AddSecret: {secret:x?}"); - -+ opt.use_name.then(|| secret.no_hash_name()); -+ - let mut flags = match &opt.pcf { - Some(v) => (&try_parse_u64(v, "pcf")?).into(), - None => AddSecretFlags::default(), -diff --git a/rust/pvsecret/src/cmd/retr.rs b/rust/pvsecret/src/cmd/retr.rs -index 7f7704cc..ad3e91c3 100644 ---- a/rust/pvsecret/src/cmd/retr.rs -+++ b/rust/pvsecret/src/cmd/retr.rs -@@ -17,12 +17,17 @@ use utils::get_writer_from_cli_file_arg; - fn retrieve(id: &SecretId) -> Result { - let uv = UvDevice::open()?; - let secrets = list_uvc(&uv)?; -- let secret = secrets -- .into_iter() -- .find(|s| s.id() == id.as_ref()) -+ let secret = match secrets.find(id) { -+ Some(s) => s, -+ // hash it + try again if it is ASCII-representable -+ None => match id.as_ascii() { -+ Some(s) => secrets.find(&GuestSecret::name_to_id(s)?), -+ None => None, -+ } - .ok_or(anyhow!( - "The UV secret-store has no secret with the ID {id}" -- ))?; -+ ))?, -+ }; - - info!("Try to retrieve secret at index: {}", secret.index()); - debug!("Try to retrieve: {secret:?}"); -@@ -43,6 +48,7 @@ pub fn retr(opt: &RetrSecretOptions) -> Result<()> { - RetrInpFmt::Hex => { - serde_yaml::from_str(&opt.input).context("Cannot parse SecretId information")? - } -+ RetrInpFmt::Name => SecretId::from_string(&opt.input), - }; - - let retr_secret = diff --git a/s390-tools-General-update-12.patch b/s390-tools-General-update-12.patch deleted file mode 100644 index 6e679a9..0000000 --- a/s390-tools-General-update-12.patch +++ /dev/null @@ -1,1207 +0,0 @@ -From a8a3e7d49cb0d3a069dacbe54c91a31b76876846 Mon Sep 17 00:00:00 2001 -From: Steffen Eiden -Date: Tue, 22 Oct 2024 17:53:17 +0200 -Subject: [PATCH] rust/pvsecret: Update manuals and README -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Acked-by: Marc Hartmayer -Reviewed-by: Christoph Schlameuss -Signed-off-by: Steffen Eiden -Signed-off-by: Jan Höppner ---- - rust/pvsecret/README.md | 222 ++++++++++++++---- - rust/pvsecret/man/pvsecret-add.1 | 9 +- - .../man/pvsecret-create-association.1 | 26 +- - rust/pvsecret/man/pvsecret-create-meta.1 | 7 +- - .../man/pvsecret-create-retrievable.1 | 74 ++++++ - rust/pvsecret/man/pvsecret-create.1 | 111 +++++---- - rust/pvsecret/man/pvsecret-list.1 | 17 +- - rust/pvsecret/man/pvsecret-lock.1 | 7 +- - rust/pvsecret/man/pvsecret-retrieve.1 | 77 ++++++ - rust/pvsecret/man/pvsecret-verify.1 | 17 +- - rust/pvsecret/man/pvsecret.1 | 34 ++- - 11 files changed, 449 insertions(+), 152 deletions(-) - create mode 100644 rust/pvsecret/man/pvsecret-create-retrievable.1 - create mode 100644 rust/pvsecret/man/pvsecret-retrieve.1 - -diff --git a/rust/pvsecret/README.md b/rust/pvsecret/README.md -index b31d3deb..711f81d7 100644 ---- a/rust/pvsecret/README.md -+++ b/rust/pvsecret/README.md -@@ -32,7 +32,7 @@ Create a new add-secret request - - - **add** -
    --Perform an add-secret request (s390x only) -+Submit an add-secret request to the Ultravisor (s390x only) -
- - - **lock** -@@ -50,23 +50,34 @@ List all ultravisor secrets (s390x only) - Verify that an add-secret request is sane - - -+- **retrieve** -+
    -+Retrieve a secret from the UV secret store (s390x only) -+
-+ - ## Options - - `-v`, `--verbose` -
    --Provide more detailed output -+Provide more detailed output. -+
-+ -+ -+`-q`, `--quiet` -+
    -+Provide less output. -
- - - `--version` -
    --Print version information and exit -+Print version information and exit. -
- - - `-h`, `--help` -
    --Print help -+Print help (see a summary with '-h'). -
- - -@@ -95,12 +106,17 @@ Create a meta secret - Create an association secret - - -+- **retrievable** -+
    -+Create a retrievable secret -+
-+ - ### Options - - `-k`, `--host-key-document ` -
    - Use FILE as a host-key document. Can be specified multiple times and must be --used at least once. -+specified at least once. -
- - -@@ -114,7 +130,7 @@ the host-key document beforehand. - - `-C`, `--cert ` -
    --Use FILE as a certificate to verify the host key or keys. The certificates are -+Use FILE as a certificate to verify the host-key or keys. The certificates are - used to establish a chain of trust for the verification of the host-key - documents. Specify this option twice to specify the IBM Z signing key and the - intermediate CA certificate (signed by the root CA). -@@ -123,15 +139,15 @@ intermediate CA certificate (signed by the root CA). - - `--crl ` -
      --Use FILE as a certificate revocation list. The list is used to check whether a --certificate of the chain of trust is revoked. Specify this option multiple times --to use multiple CRLs. -+Use FILE as a certificate revocation list (CRL). The list is used to check -+whether a certificate of the chain of trust is revoked. Specify this option -+multiple times to use multiple CRLs. -
    - - - `--offline` -
      --Make no attempt to download CRLs -+Make no attempt to download CRLs. -
    - - -@@ -146,8 +162,7 @@ specified certificate. - `--hdr ` -
      - Specifies the header of the guest image. Can be an IBM Secure Execution image --created by genprotimg or an extracted IBM Secure Execution header. The header --must start at a page boundary. -+created by 'pvimg/genprotimg' or an extracted IBM Secure Execution header. -
    - - -@@ -162,7 +177,7 @@ behavior. - - `-o`, `--output ` -
      --Write the generated request to FILE -+Write the generated request to FILE. -
    - - -@@ -209,15 +224,15 @@ the request. - - `--flags ` -
      --Flags for the add-secret request -+Flags for the add-secret request. - Possible values: -- - **disable-dump**: Disables host-initiated dumping for the target guest instance -+ - **disable-dump**: Disables host-initiated dumping for the target guest instance. -
    - - - `--user-data ` -
      --Use the content of FILE as user-data. Passes user data defined in through -+Use the content of FILE as user-data. Passes user data defined in FILE through - the add-secret request to the ultravisor. The user data can be up to 512 bytes - of arbitrary data, and the maximum size depends on the size of the user-signing - key: -@@ -236,19 +251,25 @@ Optional. No user-data by default. - `--user-sign-key ` -
        - Use the content of FILE as user signing key. Adds a signature calculated from --the key in to the add-secret request. The file must be in DER or PEM --format containing a private key. Supported are RSA 2048 & 3072-bit and --EC(secp521r1) keys. The firmware ignores the content, but the request tag --protects the signature. The user-signing key signs the request. The location of --the signature is filled with zeros during the signature calculation. The request --tag also secures the signature. See man pvsecret verify for more details. --Optional. No signature by default. -+the key in FILE to the add-secret request. The file must be in DER or PEM format -+containing a private key. Supported are RSA 2048 & 3072-bit and EC(secp521r1) -+keys. The firmware ignores the content, but the request tag protects the -+signature. The user-signing key signs the request. The location of the signature -+is filled with zeros during the signature calculation. The request tag also -+secures the signature. See man pvsecret verify for more details. Optional. No -+signature by default. -+
      -+ -+ -+`--use-name` -+
        -+Do not hash the name, use it directly as secret ID. Ignored for meta-secrets. -
      - - - `-h`, `--help` -
        --Print help -+Print help (see a summary with '-h'). -
      - - -@@ -265,14 +286,15 @@ of secrets. - `pvsecret create association [OPTIONS] ` - #### Description - Create an association secret. Use an association secret to connect a trusted I/O --device to a guest. The `pvapconfig` tool provides more information about -+device to a guest. The 'pvapconfig' tool provides more information about - association secrets. - #### Arguments - - `` -
        --String to identify the new secret. The actual secret is set with --input-secret. --The name is saved in `NAME.yaml` with white-spaces mapped to `_`. -+String that identifies the new secret. The actual secret is set with -+'--input-secret'. The name is saved in `NAME.yaml` with white-spaces mapped to -+`_`. -
      - - -@@ -284,24 +306,76 @@ Print the hashed name to stdout. The hashed name is not written to `NAME.yaml` -
    - - --`--input-secret ` -+`--input-secret ` -
      - Path from which to read the plaintext secret. Uses a random secret if not --specified -+specified. -+
    -+ -+ -+`--output-secret ` -+
      -+Save the generated secret as plaintext in SECRET-FILE. The generated secret can -+be used to generate add-secret requests for a different guest with the same -+secret using '--input-secret'. Destroy the secret when it is not used anymore. -+
    -+ -+ -+`-h`, `--help` -+
      -+Print help (see a summary with '-h'). -+
    -+ -+ -+### pvsecret create retrievable -+#### Synopsis -+`pvsecret create retrievable [OPTIONS] --secret --type ` -+`pvsecret create retr [OPTIONS] --secret --type ` -+#### Description -+Create a retrievable secret. A retrievable secret is stored in the per-guest -+storage of the Ultravisor. A SE-guest can retrieve the secret at runtime and use -+it. All retrievable secrets, but the plaintext secret, are retrieved as -+wrapped/protected key objects and only usable inside the current, running -+SE-guest instance. -+#### Arguments -+ -+`` -+
      -+String that identifies the new secret. The actual secret is set with '--secret'. -+The name is saved in `NAME.yaml` with white-spaces mapped to `_`. -+
    -+ -+ -+#### Options -+ -+`--stdout` -+
      -+Print the hashed name to stdout. The hashed name is not written to `NAME.yaml` -+
    -+ -+ -+`--secret ` -+
      -+Use SECRET-FILE as retrievable secret. -
    - - --`--output-secret ` -+`--type ` -
      --Save the generated secret as plaintext in FILE. The generated secret can be used --to generate add-secret requests for a different guest with the same secret using ----input-secret. Destroy the secret when it is not used anymore. -+Specify the secret type. Limitations to the input data apply depending on the -+secret type. -+ Possible values: -+ - **plain**: A plaintext secret. Can be any file up to 8190 bytes long. -+ - **aes**: An AES key. Must be a plain byte file 128, 192, or 256 bit long. -+ - **aes-xts**: An AES-XTS key. Must be a plain byte file 512, or 1024 bit long. -+ - **hmac-sha**: A HMAC-SHA key. Must be a plain byte file 512, or 1024 bit long. -+ - **ec**: An elliptic curve private key. Must be a PEM or DER file. -
    - - - `-h`, `--help` -
      --Print help -+Print help (see a summary with '-h'). -
    - - -@@ -309,13 +383,14 @@ Print help - ### Synopsis - `pvsecret add ` - ### Description --Perform an add-secret request (s390x only). Perform an add-secret request using --a previously generated add-secret request. Only available on s390x. -+Submit an add-secret request to the Ultravisor (s390x only). Perform an -+add-secret request using a previously generated add-secret request. Only -+available on s390x. - ### Arguments - - `` -
      --Specify the request to be sent -+Specify the request to be sent. -
    - - -@@ -325,8 +400,8 @@ Specify the request to be sent - `pvsecret lock` - ### Description - Lock the secret-store (s390x only). Lock the secret store (s390x only). After --this command executed successfully, all add-secret requests will fail. Only --available on s390x. -+this command executed successfully, all subsequent add-secret requests will -+fail. Only available on s390x. - - ## pvsecret list - ### Synopsis -@@ -339,7 +414,7 @@ Execution guest. Only available on s390x. - - `` -
      --Store the result in FILE -+Store the result in FILE. - Default value: '-' -
    - -@@ -348,18 +423,18 @@ Store the result in FILE - - `--format ` -
      --Define the output format of the list -+Define the output format of the list. - Default value: 'human' - Possible values: -- - **human**: Human-focused, non-parsable output format -- - **yaml**: Use yaml format -- - **bin**: Use the format the ultravisor uses to pass the list -+ - **human**: Human-focused, non-parsable output format. -+ - **yaml**: Use yaml format. -+ - **bin**: Use the format the ultravisor uses to pass the list. -
    - - - `-h`, `--help` -
      --Print help -+Print help (see a summary with '-h'). -
    - - -@@ -407,7 +482,7 @@ The verification process works as follows: - - `` -
      --Specify the request to be checked -+Specify the request to be checked. -
    - - -@@ -435,5 +510,58 @@ contains this user-data with padded zeros if available. - - `-h`, `--help` -
      --Print help -+Print help (see a summary with '-h'). -+
    -+ -+ -+## pvsecret retrieve -+### Synopsis -+`pvsecret retrieve [OPTIONS] ` -+`pvsecret retr [OPTIONS] ` -+### Description -+Retrieve a secret from the UV secret store (s390x only) -+### Arguments -+ -+`` -+
      -+Specify the secret ID to be retrieved. Input type depends on '--inform'. If -+`yaml` (default) is specified, it must be a yaml created by the create -+subcommand of this tool. If `hex` is specified, it must be a hex 32-byte -+unsigned big endian number string. Leading zeros are required. -+
    -+ -+ -+### Options -+ -+`-o`, `--output ` -+
      -+Specify the output path to place the secret value. -+ Default value: '-' -+
    -+ -+ -+`--inform ` -+
      -+Define input type for the Secret ID. -+ Default value: 'yaml' -+ Possible values: -+ - **yaml**: Use a yaml file. -+ - **hex**: Use a hex string. -+ - **name**: Use a name-string. Will hash it if no secret with the name found. -+
    -+ -+ -+`--outform ` -+
      -+Define the output format for the retrieved secret. -+ Default value: 'pem' -+ Possible values: -+ - **pem**: Write the secret as PEM. -+ - **bin**: Write the secret in binary. -+
    -+ -+ -+`-h`, `--help` -+
      -+Print help (see a summary with '-h'). -
    -diff --git a/rust/pvsecret/man/pvsecret-add.1 b/rust/pvsecret/man/pvsecret-add.1 -index a84702f5..5ac54a91 100644 ---- a/rust/pvsecret/man/pvsecret-add.1 -+++ b/rust/pvsecret/man/pvsecret-add.1 -@@ -3,12 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvsecret-add 1 "2024-05-21" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET-ADD" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret add\fP - Perform an add-secret request (s390x only) --\fB -+pvsecret-add \- Submit an add-secret request to the Ultravisor (s390x only) - .SH SYNOPSIS - .nf - .fam C -@@ -16,7 +15,7 @@ pvsecret add - .fam C - .fi - .SH DESCRIPTION --Perform an add-secret request using a previously generated add-secret request. -+Perform an add\-secret request using a previously generated add\-secret request. - Only available on s390x. - .SH OPTIONS - .PP -@@ -29,7 +28,7 @@ Specify the request to be sent. - .PP - \-h, \-\-help - .RS 4 --Print help. -+Print help (see a summary with \fB\-h\fR). - .RE - .RE - -diff --git a/rust/pvsecret/man/pvsecret-create-association.1 b/rust/pvsecret/man/pvsecret-create-association.1 -index 5704d30c..87a411e5 100644 ---- a/rust/pvsecret/man/pvsecret-create-association.1 -+++ b/rust/pvsecret/man/pvsecret-create-association.1 -@@ -3,12 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvsecret-create-association 1 "2024-05-21" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET-CREATE-ASSOCIATION" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret create association\fP - Create an association secret --\fB -+pvsecret-create-association \- Create an association secret - .SH SYNOPSIS - .nf - .fam C -@@ -17,14 +16,14 @@ pvsecret create association [OPTIONS] - .fi - .SH DESCRIPTION - Use an association secret to connect a trusted I/O device to a guest. The --`pvapconfig` tool provides more information about association secrets. -+\fBpvapconfig\fR tool provides more information about association secrets. - .SH OPTIONS - .PP - - .RS 4 --String to identify the new secret. The actual secret is set with --\fB--input-secret\fR. The name is saved in `NAME.yaml` with white-spaces mapped --to `_`. -+String that identifies the new secret. The actual secret is set with -+\fB\-\-input\-secret\fR. The name is saved in `NAME.yaml` with white\-spaces -+mapped to `_`. - .RE - .RE - -@@ -35,24 +34,25 @@ Print the hashed name to stdout. The hashed name is not written to `NAME.yaml` - .RE - .RE - .PP --\-\-input-secret -+\-\-input\-secret - .RS 4 - Path from which to read the plaintext secret. Uses a random secret if not - specified. - .RE - .RE - .PP --\-\-output-secret -+\-\-output\-secret - .RS 4 --Save the generated secret as plaintext in FILE. The generated secret can be used --to generate add-secret requests for a different guest with the same secret using --\fB--input-secret\fR. Destroy the secret when it is not used anymore. -+Save the generated secret as plaintext in SECRET\-FILE. The generated secret can -+be used to generate add\-secret requests for a different guest with the same -+secret using \fB\-\-input\-secret\fR. Destroy the secret when it is not used -+anymore. - .RE - .RE - .PP - \-h, \-\-help - .RS 4 --Print help. -+Print help (see a summary with \fB\-h\fR). - .RE - .RE - -diff --git a/rust/pvsecret/man/pvsecret-create-meta.1 b/rust/pvsecret/man/pvsecret-create-meta.1 -index c89cee77..78a57a22 100644 ---- a/rust/pvsecret/man/pvsecret-create-meta.1 -+++ b/rust/pvsecret/man/pvsecret-create-meta.1 -@@ -1,14 +1,13 @@ --.\" Copyright 2023 IBM Corp. -+.\" Copyright 2023, 2024 IBM Corp. - .\" 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 pvsecret-create-meta 1 "2024-01-30" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET-CREATE-META" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret create meta\fP - Create a meta secret --\fB -+pvsecret-create-meta \- Create a meta secret - .SH SYNOPSIS - .nf - .fam C -diff --git a/rust/pvsecret/man/pvsecret-create-retrievable.1 b/rust/pvsecret/man/pvsecret-create-retrievable.1 -new file mode 100644 -index 00000000..0d7575eb ---- /dev/null -+++ b/rust/pvsecret/man/pvsecret-create-retrievable.1 -@@ -0,0 +1,74 @@ -+.\" Copyright 2024 IBM Corp. -+.\" 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 "PVSECRET-CREATE-RETRIEVABLE" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" -+.nh -+.ad l -+.SH NAME -+pvsecret-create-retrievable \- Create a retrievable secret -+.SH SYNOPSIS -+.nf -+.fam C -+pvsecret create retrievable [OPTIONS] --secret --type -+pvsecret create retr [OPTIONS] --secret --type -+.fam C -+.fi -+.SH DESCRIPTION -+A retrievable secret is stored in the per\-guest storage of the Ultravisor. A -+SE\-guest can retrieve the secret at runtime and use it. All retrievable -+secrets, but the plaintext secret, are retrieved as wrapped/protected key -+objects and only usable inside the current, running SE\-guest instance. -+.SH OPTIONS -+.PP -+ -+.RS 4 -+String that identifies the new secret. The actual secret is set with -+\fB\-\-secret\fR. The name is saved in `NAME.yaml` with white\-spaces mapped to -+`_`. -+.RE -+.RE -+ -+.PP -+\-\-stdout -+.RS 4 -+Print the hashed name to stdout. The hashed name is not written to `NAME.yaml` -+.RE -+.RE -+.PP -+\-\-secret -+.RS 4 -+Use SECRET\-FILE as retrievable secret. -+.RE -+.RE -+.PP -+\-\-type -+.RS 4 -+Specify the secret type. Limitations to the input data apply depending on the -+secret type. -+ -+Possible values: -+.RS 4 -+\- \fBplain\fP: A plaintext secret. Can be any file up to 8190 bytes long. -+ -+\- \fBaes\fP: An AES key. Must be a plain byte file 128, 192, or 256 bit long. -+ -+\- \fBaes-xts\fP: An AES-XTS key. Must be a plain byte file 512, or 1024 bit long. -+ -+\- \fBhmac-sha\fP: A HMAC-SHA key. Must be a plain byte file 512, or 1024 bit long. -+ -+\- \fBec\fP: An elliptic curve private key. Must be a PEM or DER file. -+ -+.RE -+.RE -+.PP -+\-h, \-\-help -+.RS 4 -+Print help (see a summary with \fB\-h\fR). -+.RE -+.RE -+ -+.SH "SEE ALSO" -+.sp -+\fBpvsecret\fR(1) \fBpvsecret-create\fR(1) -diff --git a/rust/pvsecret/man/pvsecret-create.1 b/rust/pvsecret/man/pvsecret-create.1 -index 8237c06c..87c8d8bd 100644 ---- a/rust/pvsecret/man/pvsecret-create.1 -+++ b/rust/pvsecret/man/pvsecret-create.1 -@@ -3,12 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvsecret-create 1 "2024-05-21" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET-CREATE" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret create\fP - Create a new add-secret request --\fB -+pvsecret-create \- Create a new add-secret request - .SH SYNOPSIS - .nf - .fam C -@@ -29,39 +28,46 @@ bound to the Configuration Unique ID from \fBpvattest\fR using \fB--cuid\fR - .SH "PVSECRET CREATE COMMANDS" - .PP - --\fBmeta\fR -+\fBpvsecret create-meta(1)\fR - .RS 4 - Create a meta secret - .RE - - .PP - --\fBassociation\fR -+\fBpvsecret create-association(1)\fR - .RS 4 - Create an association secret - .RE - -+.PP -+ -+\fBpvsecret create-retrievable(1)\fR -+.RS 4 -+Create a retrievable secret -+.RE -+ - .SH OPTIONS - .PP --\-k, \-\-host-key-document -+\-k, \-\-host\-key\-document - .RS 4 --Use FILE as a host-key document. Can be specified multiple times and must be --used at least once. -+Use FILE as a host\-key document. Can be specified multiple times and must be -+specified at least once. - .RE - .RE - .PP --\-\-no-verify -+\-\-no\-verify - .RS 4 --Disable the host-key document verification. Does not require the host-key -+Disable the host\-key document verification. Does not require the host\-key - documents to be valid. Do not use for a production request unless you verified --the host-key document beforehand. -+the host\-key document beforehand. - .RE - .RE - .PP - \-C, \-\-cert - .RS 4 --Use FILE as a certificate to verify the host key or keys. The certificates are --used to establish a chain of trust for the verification of the host-key -+Use FILE as a certificate to verify the host\-key or keys. The certificates are -+used to establish a chain of trust for the verification of the host\-key - documents. Specify this option twice to specify the IBM Z signing key and the - intermediate CA certificate (signed by the root CA). - .RE -@@ -69,9 +75,9 @@ intermediate CA certificate (signed by the root CA). - .PP - \-\-crl - .RS 4 --Use FILE as a certificate revocation list. The list is used to check whether a --certificate of the chain of trust is revoked. Specify this option multiple times --to use multiple CRLs. -+Use FILE as a certificate revocation list (CRL). The list is used to check -+whether a certificate of the chain of trust is revoked. Specify this option -+multiple times to use multiple CRLs. - .RE - .RE - .PP -@@ -81,27 +87,26 @@ Make no attempt to download CRLs. - .RE - .RE - .PP --\-\-root-ca -+\-\-root\-ca - .RS 4 --Use FILE as the root-CA certificate for the verification. If omitted, the system --wide-root CAs installed on the system are used. Use this only if you trust the --specified certificate. -+Use FILE as the root\-CA certificate for the verification. If omitted, the -+system wide\-root CAs installed on the system are used. Use this only if you -+trust the specified certificate. - .RE - .RE - .PP - \-\-hdr - .RS 4 - Specifies the header of the guest image. Can be an IBM Secure Execution image --created by genprotimg or an extracted IBM Secure Execution header. The header --must start at a page boundary. -+created by \fBpvimg/genprotimg\fR or an extracted IBM Secure Execution header. - .RE - .RE - .PP - \-f, \-\-force - .RS 4 --Force the generation of add-secret requests on IBM Secure Execution guests. If -+Force the generation of add\-secret requests on IBM Secure Execution guests. If - the program detects that it is running on an IBM Secure Execution guest, it --denies the generation of add-secret requests. The force flag overwrites this -+denies the generation of add\-secret requests. The force flag overwrites this - behavior. - .RE - .RE -@@ -112,7 +117,7 @@ Write the generated request to FILE. - .RE - .RE - .PP --\-\-extension-secret -+\-\-extension\-secret - .RS 4 - Use the content of FILE as an extension secret. The file must be exactly 32 - bytes long. If this request is the first, all subsequent requests must have the -@@ -124,7 +129,7 @@ request. - .PP - \-\-cck - .RS 4 --Use the content of FILE as the customer-communication key (CCK) to derive the -+Use the content of FILE as the customer\-communication key (CCK) to derive the - extension secret. The file must contain exactly 32 bytes of data. If the target - guest was started with bit 1 of the secret control flag set, the ultravisor also - derives the secret from the CCK. Otherwise, the ultravisor interprets the -@@ -133,13 +138,13 @@ all requests. - .RE - .RE - .PP --\-\-cuid-hex -+\-\-cuid\-hex - .RS 4 --Use HEXSTRING as the Configuration Unique ID. Must be a hex 128-bit unsigned big --endian number string. Leading zeros must be provided. If specified, the value --must match with the Config-UID from the attestation result of that guest. If not --specified, the CUID will be ignored by the ultravisor during the verification of --the request. -+Use HEXSTRING as the Configuration Unique ID. Must be a hex 128\-bit unsigned -+big endian number string. Leading zeros must be provided. If specified, the -+value must match with the Config\-UID from the attestation result of that guest. -+If not specified, the CUID will be ignored by the ultravisor during the -+verification of the request. - .RE - .RE - .PP -@@ -147,7 +152,7 @@ the request. - .RS 4 - Use the content of FILE as the Configuration Unique ID. The file must contain - exactly 128 bit of data or a yaml with a `cuid` entry. If specified, the value --must match the Config-UID from the attestation result of that guest. If not -+must match the Config\-UID from the attestation result of that guest. If not - specified, the CUID will be ignored by the Ultravisor during the verification of - the request. - .RE -@@ -155,52 +160,58 @@ the request. - .PP - \-\-flags - .RS 4 --Flags for the add-secret request. -+Flags for the add\-secret request. - - Possible values: - .RS 4 --- \fBdisable-dump\fP: Disables host-initiated dumping for the target guest instance. -+\- \fBdisable-dump\fP: Disables host-initiated dumping for the target guest instance. - - .RE - .RE - .PP --\-\-user-data -+\-\-user\-data - .RS 4 --Use the content of FILE as user-data. Passes user data defined in through --the add-secret request to the ultravisor. The user data can be up to 512 bytes --of arbitrary data, and the maximum size depends on the size of the user-signing -+Use the content of FILE as user\-data. Passes user data defined in FILE through -+the add\-secret request to the ultravisor. The user data can be up to 512 bytes -+of arbitrary data, and the maximum size depends on the size of the user\-signing - key: - -- - No key: user data can be 512 bytes. -+ \- No key: user data can be 512 bytes. - -- - EC(secp521r1) or RSA 2048 keys: user data can be 256 bytes. -+ \- EC(secp521r1) or RSA 2048 keys: user data can be 256 bytes. - -- - RSA 3072 key: user data can be 128 bytes. -+ \- RSA 3072 key: user data can be 128 bytes. - --The firmware ignores this data, but the request tag protects the user-data. --Optional. No user-data by default. -+The firmware ignores this data, but the request tag protects the user\-data. -+Optional. No user\-data by default. - .RE - .RE - .PP --\-\-user-sign-key -+\-\-user\-sign\-key - .RS 4 - Use the content of FILE as user signing key. Adds a signature calculated from --the key in to the add-secret request. The file must be in DER or PEM --format containing a private key. Supported are RSA 2048 & 3072-bit and -+the key in FILE to the add\-secret request. The file must be in DER or PEM -+format containing a private key. Supported are RSA 2048 & 3072\-bit and - EC(secp521r1) keys. The firmware ignores the content, but the request tag --protects the signature. The user-signing key signs the request. The location of -+protects the signature. The user\-signing key signs the request. The location of - the signature is filled with zeros during the signature calculation. The request - tag also secures the signature. See man pvsecret verify for more details. - Optional. No signature by default. - .RE - .RE - .PP -+\-\-use\-name -+.RS 4 -+Do not hash the name, use it directly as secret ID. Ignored for meta\-secrets. -+.RE -+.RE -+.PP - \-h, \-\-help - .RS 4 --Print help. -+Print help (see a summary with \fB\-h\fR). - .RE - .RE - - .SH "SEE ALSO" - .sp --\fBpvsecret\fR(1) \fBpvsecret-create-meta\fR(1) \fBpvsecret-create-association\fR(1) -+\fBpvsecret\fR(1) \fBpvsecret-create-meta\fR(1) \fBpvsecret-create-association\fR(1) \fBpvsecret-create-retrievable\fR(1) -diff --git a/rust/pvsecret/man/pvsecret-list.1 b/rust/pvsecret/man/pvsecret-list.1 -index 2828179a..4dfc3033 100644 ---- a/rust/pvsecret/man/pvsecret-list.1 -+++ b/rust/pvsecret/man/pvsecret-list.1 -@@ -3,12 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvsecret-list 1 "2024-05-21" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET-LIST" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret list\fP - List all ultravisor secrets (s390x only) --\fB -+pvsecret-list \- List all ultravisor secrets (s390x only) - .SH SYNOPSIS - .nf - .fam C -@@ -16,8 +15,8 @@ pvsecret list [OPTIONS] [FILE] - .fam C - .fi - .SH DESCRIPTION --Lists the IDs of all non-null secrets currently stored in the ultravisor for the --currently running IBM Secure Execution guest. Only available on s390x. -+Lists the IDs of all non\-null secrets currently stored in the ultravisor for -+the currently running IBM Secure Execution guest. Only available on s390x. - .SH OPTIONS - .PP - -@@ -35,18 +34,18 @@ Define the output format of the list. - - Possible values: - .RS 4 --- \fBhuman\fP: Human-focused, non-parsable output format. -+\- \fBhuman\fP: Human-focused, non-parsable output format. - --- \fByaml\fP: Use yaml format. -+\- \fByaml\fP: Use yaml format. - --- \fBbin\fP: Use the format the ultravisor uses to pass the list. -+\- \fBbin\fP: Use the format the ultravisor uses to pass the list. - - .RE - .RE - .PP - \-h, \-\-help - .RS 4 --Print help. -+Print help (see a summary with \fB\-h\fR). - .RE - .RE - -diff --git a/rust/pvsecret/man/pvsecret-lock.1 b/rust/pvsecret/man/pvsecret-lock.1 -index c59c34d8..d5b1ab25 100644 ---- a/rust/pvsecret/man/pvsecret-lock.1 -+++ b/rust/pvsecret/man/pvsecret-lock.1 -@@ -3,12 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvsecret-lock 1 "2024-05-15" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET-LOCK" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret lock\fP - Lock the secret-store (s390x only) --\fB -+pvsecret-lock \- Lock the secret-store (s390x only) - .SH SYNOPSIS - .nf - .fam C -@@ -17,7 +16,7 @@ pvsecret lock - .fi - .SH DESCRIPTION - Lock the secret store (s390x only). After this command executed successfully, --all add-secret requests will fail. Only available on s390x. -+all subsequent add\-secret requests will fail. Only available on s390x. - .SH "SEE ALSO" - .sp - \fBpvsecret\fR(1) -diff --git a/rust/pvsecret/man/pvsecret-retrieve.1 b/rust/pvsecret/man/pvsecret-retrieve.1 -new file mode 100644 -index 00000000..369037fa ---- /dev/null -+++ b/rust/pvsecret/man/pvsecret-retrieve.1 -@@ -0,0 +1,77 @@ -+.\" Copyright 2024 IBM Corp. -+.\" 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 "PVSECRET-RETRIEVE" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" -+.nh -+.ad l -+.SH NAME -+pvsecret-retrieve \- Retrieve a secret from the UV secret store (s390x only) -+.SH SYNOPSIS -+.nf -+.fam C -+pvsecret retrieve [OPTIONS] -+pvsecret retr [OPTIONS] -+.fam C -+.fi -+.SH DESCRIPTION -+Retrieve a secret from the UV secret store (s390x only) -+.SH OPTIONS -+.PP -+ -+.RS 4 -+Specify the secret ID to be retrieved. Input type depends on \fB\-\-inform\fR. -+If `yaml` (default) is specified, it must be a yaml created by the create -+subcommand of this tool. If `hex` is specified, it must be a hex 32\-byte -+unsigned big endian number string. Leading zeros are required. -+.RE -+.RE -+ -+.PP -+\-o, \-\-output -+.RS 4 -+Specify the output path to place the secret value. -+[default: '-'] -+.RE -+.RE -+.PP -+\-\-inform -+.RS 4 -+Define input type for the Secret ID. -+[default: 'yaml'] -+ -+Possible values: -+.RS 4 -+\- \fByaml\fP: Use a yaml file. -+ -+\- \fBhex\fP: Use a hex string. -+ -+\- \fBname\fP: Use a name-string. Will hash it if no secret with the name found. -+ -+.RE -+.RE -+.PP -+\-\-outform -+.RS 4 -+Define the output format for the retrieved secret. -+[default: 'pem'] -+ -+Possible values: -+.RS 4 -+\- \fBpem\fP: Write the secret as PEM. -+ -+\- \fBbin\fP: Write the secret in binary. -+ -+.RE -+.RE -+.PP -+\-h, \-\-help -+.RS 4 -+Print help (see a summary with \fB\-h\fR). -+.RE -+.RE -+ -+.SH "SEE ALSO" -+.sp -+\fBpvsecret\fR(1) -diff --git a/rust/pvsecret/man/pvsecret-verify.1 b/rust/pvsecret/man/pvsecret-verify.1 -index a9d636fc..136ecadc 100644 ---- a/rust/pvsecret/man/pvsecret-verify.1 -+++ b/rust/pvsecret/man/pvsecret-verify.1 -@@ -3,12 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvsecret-verify 1 "2024-05-21" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET-VERIFY" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret verify\fP - Verify that an add-secret request is sane --\fB -+pvsecret-verify \- Verify that an add-secret request is sane - .SH SYNOPSIS - .nf - .fam C -@@ -89,12 +88,12 @@ Specify the request to be checked. - .RE - - .PP --\-\-user-cert -+\-\-user\-cert - .RS 4 - Certificate containing a public key used to verify the user data signature. --Specifies a public key used to verify the user-data signature. The file must be -+Specifies a public key used to verify the user\-data signature. The file must be - a X509 certificate in DSA or PEM format. The certificate must hold the public --EC, RSA 2048, or RSA 3072 key corresponding to the private user-key used during -+EC, RSA 2048, or RSA 3072 key corresponding to the private user\-key used during - `create`. No chain of trust is established. Ensuring that the certificate can be - trusted is the responsibility of the user. The EC key must use the NIST/SECG - curve over a 521 bit prime field (secp521r1). -@@ -103,15 +102,15 @@ curve over a 521 bit prime field (secp521r1). - .PP - \-o, \-\-output - .RS 4 --Store the result in FILE If the request contained abirtary user-data the output --contains this user-data with padded zeros if available. -+Store the result in FILE If the request contained abirtary user\-data the output -+contains this user\-data with padded zeros if available. - [default: '-'] - .RE - .RE - .PP - \-h, \-\-help - .RS 4 --Print help. -+Print help (see a summary with \fB\-h\fR). - .RE - .RE - -diff --git a/rust/pvsecret/man/pvsecret.1 b/rust/pvsecret/man/pvsecret.1 -index b2a1d0f6..e8cb1327 100644 ---- a/rust/pvsecret/man/pvsecret.1 -+++ b/rust/pvsecret/man/pvsecret.1 -@@ -3,12 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvsecret 1 "2024-05-21" "s390-tools" "UV-Secret Manual" -+.TH "PVSECRET" "1" "2024-12-19" "s390-tools" "UV-Secret Manual" - .nh - .ad l - .SH NAME --\fBpvsecret\fP - Manage secrets for IBM Secure Execution guests --\fB -+pvsecret \- Manage secrets for IBM Secure Execution guests - .SH SYNOPSIS - .nf - .fam C -@@ -36,39 +35,46 @@ both the PEM and DER input formats are supported. - .SH "PVSECRET COMMANDS" - .PP - --\fBcreate\fR -+\fBpvsecret-create(1)\fR - .RS 4 - Create a new add-secret request - .RE - - .PP - --\fBadd\fR -+\fBpvsecret-add(1)\fR - .RS 4 --Perform an add-secret request (s390x only) -+Submit an add-secret request to the Ultravisor (s390x only) - .RE - - .PP - --\fBlock\fR -+\fBpvsecret-lock(1)\fR - .RS 4 - Lock the secret-store (s390x only) - .RE - - .PP - --\fBlist\fR -+\fBpvsecret-list(1)\fR - .RS 4 - List all ultravisor secrets (s390x only) - .RE - - .PP - --\fBverify\fR -+\fBpvsecret-verify(1)\fR - .RS 4 - Verify that an add-secret request is sane - .RE - -+.PP -+ -+\fBpvsecret-retrieve(1)\fR -+.RS 4 -+Retrieve a secret from the UV secret store (s390x only) -+.RE -+ - .SH OPTIONS - .PP - \-v, \-\-verbose -@@ -77,6 +83,12 @@ Provide more detailed output. - .RE - .RE - .PP -+\-q, \-\-quiet -+.RS 4 -+Provide less output. -+.RE -+.RE -+.PP - \-\-version - .RS 4 - Print version information and exit. -@@ -85,7 +97,7 @@ Print version information and exit. - .PP - \-h, \-\-help - .RS 4 --Print help. -+Print help (see a summary with \fB\-h\fR). - .RE - .RE - -@@ -138,4 +150,4 @@ On the SE-guest, \fIlock\fP the secret store. - .fi - .SH "SEE ALSO" - .sp --\fBpvsecret-create\fR(1) \fBpvsecret-add\fR(1) \fBpvsecret-lock\fR(1) \fBpvsecret-list\fR(1) \fBpvsecret-verify\fR(1) -+\fBpvsecret-create\fR(1) \fBpvsecret-add\fR(1) \fBpvsecret-lock\fR(1) \fBpvsecret-list\fR(1) \fBpvsecret-verify\fR(1) \fBpvsecret-retrieve\fR(1) diff --git a/s390-tools-Support-unencrypted-SE-images-01.patch b/s390-tools-Support-unencrypted-SE-images-01.patch deleted file mode 100644 index 446e3e7..0000000 --- a/s390-tools-Support-unencrypted-SE-images-01.patch +++ /dev/null @@ -1,334 +0,0 @@ -From cf51ac786095f2a1a17d04fea9ee73271438d247 Mon Sep 17 00:00:00 2001 -From: Marc Hartmayer -Date: Wed, 11 Dec 2024 19:25:59 +0100 -Subject: [PATCH] rust/pvimg: Add '--(enable|disable)-image-encryption' flags - to 'pvimg create' -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -With runtime attestation it might be useful to have non-encrypted Secure -Execution images. This patch adds the support for this to the 'pvimg -create' and 'genprotimg' commands. - -Reviewed-by: Steffen Eiden -Acked-by: Hendrik Brueckner -Signed-off-by: Marc Hartmayer -Signed-off-by: Jan Höppner ---- - rust/pvimg/man/genprotimg.1 | 26 +++++++++++++++++++++----- - rust/pvimg/man/pvimg-create.1 | 26 +++++++++++++++++++++----- - rust/pvimg/man/pvimg-info.1 | 10 +++++----- - rust/pvimg/man/pvimg-test.1 | 10 +++++----- - rust/pvimg/man/pvimg.1 | 10 +++++----- - rust/pvimg/src/cli.rs | 18 ++++++++++++++++++ - rust/pvimg/src/cmd/create.rs | 10 ++++++++++ - 7 files changed, 85 insertions(+), 25 deletions(-) - -diff --git a/rust/pvimg/man/genprotimg.1 b/rust/pvimg/man/genprotimg.1 -index 46a91aa4..3f4949e9 100644 ---- a/rust/pvimg/man/genprotimg.1 -+++ b/rust/pvimg/man/genprotimg.1 -@@ -3,11 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH genprotimg 1 "2024-12-05" "s390-tools" "Genprotimg Manual" -+.TH genprotimg 1 "2024-12-11" "s390-tools" "Genprotimg Manual" - .nh - .ad l - .SH NAME --\fBgenprotimg\fP - Create an IBM Secure Execution image -+\fBgenprotimg\fP \- Create an IBM Secure Execution image - \fB - .SH SYNOPSIS - .nf -@@ -196,6 +196,22 @@ Disable the support for backup target keys (default). - .RE - .RE - .PP -+\-\-enable\-image\-encryption -+.RS 4 -+Enable encryption of the image components (default). The image components are: -+the kernel, ramdisk, and kernel command line. -+.RE -+.RE -+.PP -+\-\-disable\-image\-encryption -+.RS 4 -+Disable encryption of the image components. The image components are: the -+kernel, ramdisk, and kernel command line. Use only if the components used do not -+contain any confidential content (for example, secrets like non\-public -+cryptographic keys). -+.RE -+.RE -+.PP - \-v, \-\-verbose - .RS 4 - Provide more detailed output. -@@ -222,16 +238,16 @@ Print help (see a summary with \fB\-h\fR). - - .SH EXIT STATUS - .TP 8 --.B 0 - Program finished successfully -+.B 0 \- Program finished successfully - The command was executed successfully. - .RE - .TP 8 --.B 1 - Generic error -+.B 1 \- Generic error - Something went wrong during the operation. Refer to the error - message. - .RE - .TP 8 --.B 2 - Usage error -+.B 2 \- Usage error - The command was used incorrectly, for example: unsupported command - line flag, or wrong number of arguments. - .RE -diff --git a/rust/pvimg/man/pvimg-create.1 b/rust/pvimg/man/pvimg-create.1 -index aba197fa..dae1cf18 100644 ---- a/rust/pvimg/man/pvimg-create.1 -+++ b/rust/pvimg/man/pvimg-create.1 -@@ -3,11 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvimg-create 1 "2024-12-05" "s390-tools" "Pvimg Manual" -+.TH pvimg-create 1 "2024-12-11" "s390-tools" "Pvimg Manual" - .nh - .ad l - .SH NAME --\fBpvimg create\fP - Create an IBM Secure Execution image -+\fBpvimg create\fP \- Create an IBM Secure Execution image - \fB - .SH SYNOPSIS - .nf -@@ -195,6 +195,22 @@ Disable the support for backup target keys (default). - .RE - .RE - .PP -+\-\-enable\-image\-encryption -+.RS 4 -+Enable encryption of the image components (default). The image components are: -+the kernel, ramdisk, and kernel command line. -+.RE -+.RE -+.PP -+\-\-disable\-image\-encryption -+.RS 4 -+Disable encryption of the image components. The image components are: the -+kernel, ramdisk, and kernel command line. Use only if the components used do not -+contain any confidential content (for example, secrets like non\-public -+cryptographic keys). -+.RE -+.RE -+.PP - \-h, \-\-help - .RS 4 - Print help (see a summary with \fB\-h\fR). -@@ -203,16 +219,16 @@ Print help (see a summary with \fB\-h\fR). - - .SH EXIT STATUS - .TP 8 --.B 0 - Program finished successfully -+.B 0 \- Program finished successfully - The command was executed successfully. - .RE - .TP 8 --.B 1 - Generic error -+.B 1 \- Generic error - Something went wrong during the operation. Refer to the error - message. - .RE - .TP 8 --.B 2 - Usage error -+.B 2 \- Usage error - The command was used incorrectly, for example: unsupported command - line flag, or wrong number of arguments. - .RE -diff --git a/rust/pvimg/man/pvimg-info.1 b/rust/pvimg/man/pvimg-info.1 -index e88cbe49..d2726c35 100644 ---- a/rust/pvimg/man/pvimg-info.1 -+++ b/rust/pvimg/man/pvimg-info.1 -@@ -3,11 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvimg-info 1 "2024-12-05" "s390-tools" "Pvimg Manual" -+.TH pvimg-info 1 "2024-12-11" "s390-tools" "Pvimg Manual" - .nh - .ad l - .SH NAME --\fBpvimg info\fP - Print information about the IBM Secure Execution image -+\fBpvimg info\fP \- Print information about the IBM Secure Execution image - \fB - .SH SYNOPSIS - .nf -@@ -51,16 +51,16 @@ Print help (see a summary with \fB\-h\fR). - - .SH EXIT STATUS - .TP 8 --.B 0 - Program finished successfully -+.B 0 \- Program finished successfully - The command was executed successfully. - .RE - .TP 8 --.B 1 - Generic error -+.B 1 \- Generic error - Something went wrong during the operation. Refer to the error - message. - .RE - .TP 8 --.B 2 - Usage error -+.B 2 \- Usage error - The command was used incorrectly, for example: unsupported command - line flag, or wrong number of arguments. - .RE -diff --git a/rust/pvimg/man/pvimg-test.1 b/rust/pvimg/man/pvimg-test.1 -index 901c7edb..4fb7d73f 100644 ---- a/rust/pvimg/man/pvimg-test.1 -+++ b/rust/pvimg/man/pvimg-test.1 -@@ -3,11 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvimg-test 1 "2024-12-05" "s390-tools" "Pvimg Manual" -+.TH pvimg-test 1 "2024-12-11" "s390-tools" "Pvimg Manual" - .nh - .ad l - .SH NAME --\fBpvimg test\fP - Test different aspects of an existing IBM Secure Execution image -+\fBpvimg test\fP \- Test different aspects of an existing IBM Secure Execution image - \fB - .SH SYNOPSIS - .nf -@@ -54,16 +54,16 @@ Print help (see a summary with \fB\-h\fR). - - .SH EXIT STATUS - .TP 8 --.B 0 - Program finished successfully -+.B 0 \- Program finished successfully - The command was executed successfully. - .RE - .TP 8 --.B 1 - Generic error -+.B 1 \- Generic error - Something went wrong during the operation. Refer to the error - message. - .RE - .TP 8 --.B 2 - Usage error -+.B 2 \- Usage error - The command was used incorrectly, for example: unsupported command - line flag, or wrong number of arguments. - .RE -diff --git a/rust/pvimg/man/pvimg.1 b/rust/pvimg/man/pvimg.1 -index 37c8e978..5676b61d 100644 ---- a/rust/pvimg/man/pvimg.1 -+++ b/rust/pvimg/man/pvimg.1 -@@ -3,11 +3,11 @@ - .\" it under the terms of the MIT license. See LICENSE for details. - .\" - --.TH pvimg 1 "2024-12-05" "s390-tools" "Pvimg Manual" -+.TH pvimg 1 "2024-12-11" "s390-tools" "Pvimg Manual" - .nh - .ad l - .SH NAME --\fBpvimg\fP - Create and inspect IBM Secure Execution images -+\fBpvimg\fP \- Create and inspect IBM Secure Execution images - \fB - .SH SYNOPSIS - .nf -@@ -69,16 +69,16 @@ Print help (see a summary with \fB\-h\fR). - - .SH EXIT STATUS - .TP 8 --.B 0 - Program finished successfully -+.B 0 \- Program finished successfully - The command was executed successfully. - .RE - .TP 8 --.B 1 - Generic error -+.B 1 \- Generic error - Something went wrong during the operation. Refer to the error - message. - .RE - .TP 8 --.B 2 - Usage error -+.B 2 \- Usage error - The command was used incorrectly, for example: unsupported command - line flag, or wrong number of arguments. - .RE -diff --git a/rust/pvimg/src/cli.rs b/rust/pvimg/src/cli.rs -index 2ca4e901..12f0b764 100644 ---- a/rust/pvimg/src/cli.rs -+++ b/rust/pvimg/src/cli.rs -@@ -140,6 +140,20 @@ pub struct CreateBootImageLegacyFlags { - /// Disable the support for backup target keys (default). - #[arg(long, action = clap::ArgAction::SetTrue, conflicts_with="enable_backup_keys", group="header-flags")] - pub disable_backup_keys: Option, -+ -+ /// Enable encryption of the image components (default). -+ /// -+ /// The image components are: the kernel, ramdisk, and kernel command line. -+ #[arg(long, action = clap::ArgAction::SetTrue, group="header-flags")] -+ pub enable_image_encryption: Option, -+ -+ /// Disable encryption of the image components. -+ /// -+ /// The image components are: the kernel, ramdisk, and kernel command line. -+ /// Use only if the components used do not contain any confidential content -+ /// (for example, secrets like non-public cryptographic keys). -+ #[arg(long, action = clap::ArgAction::SetTrue, conflicts_with="enable_image_encryption", group="header-flags")] -+ pub disable_image_encryption: Option, - } - - #[non_exhaustive] -@@ -476,6 +490,8 @@ mod test { - flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-pckmo", ["--enable-pckmo"])])), - flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-pckmo-hmac", ["--enable-pckmo-hmac"])])), - flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-backup-keys", ["--enable-backup-keys"])])), -+ flat_map_collect(insert(mvca.clone(), vec![CliOption::new("disable-image-encryption", ["--disable-image-encryption"])])), -+ flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-image-encryption", ["--enable-image-encryption"])])), - ]; - let invalid_create_args = [ - flat_map_collect(remove(mvcanv.clone(), "no-verify")), -@@ -501,6 +517,8 @@ mod test { - CliOption::new("x-pcf2", ["--x-pcf", "0x0"])])), - flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-pckmo", ["--enable-pckmo"]), - CliOption::new("disable-pckmo", ["--disable-pckmo"])])), -+ flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-image-encryption", ["--enable-image-encryption"]), -+ CliOption::new("disable-image-encryption", ["--disable-image-encryption"])])), - ]; - - let mut genprotimg_valid_args = vec![ -diff --git a/rust/pvimg/src/cmd/create.rs b/rust/pvimg/src/cmd/create.rs -index b696d790..475d3523 100644 ---- a/rust/pvimg/src/cmd/create.rs -+++ b/rust/pvimg/src/cmd/create.rs -@@ -80,6 +80,12 @@ fn parse_flags( - lf.enable_backup_keys - .filter(|x| *x) - .and(Some(PcfV1::all_enabled([PcfV1::BackupTargetKeys]))), -+ lf.disable_image_encryption -+ .filter(|x| *x) -+ .and(Some(PcfV1::all_enabled([PcfV1::NoComponentEncryption]))), -+ lf.enable_image_encryption -+ .filter(|x| *x) -+ .and(Some(PcfV1::all_disabled([PcfV1::NoComponentEncryption]))), - ] - .into_iter() - .flatten() -@@ -135,6 +141,10 @@ pub fn create(opt: &CreateBootImageArgs) -> Result { - read_user_provided_keys(opt.comm_key.as_deref(), &opt.experimental_args)?; - let (plaintext_flags, secret_flags) = parse_flags(opt)?; - -+ if plaintext_flags.is_set(PcfV1::NoComponentEncryption) { -+ warn!("The components encryption is disabled, make sure that the components do not contain any confidential content."); -+ } -+ - let mut components = components(&opt.component_paths)?; - if opt.no_component_check { - warn!("The component check is turned off!"); diff --git a/s390-tools-pvimg-additional-01.patch b/s390-tools-pvimg-additional-01.patch deleted file mode 100644 index cda88c4..0000000 --- a/s390-tools-pvimg-additional-01.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 5b6d7a467dc342c9c25a0af72b2d5546798cdc94 Mon Sep 17 00:00:00 2001 -From: Marc Hartmayer -Date: Thu, 12 Dec 2024 20:19:56 +0100 -Subject: [PATCH] rust/pvimg: Add '--cck ' command line option and make - '--comm-key' an alias -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add '--cck ' as an command line option and make '--comm-key' an -alias of it. This makes the command line more similar to the other -Secure Execution related PV-tools (e.g. pvattest and pvsecret). - -Suggested-by: Reinhard Bündgen -Reviewed-by: Steffen Eiden -Signed-off-by: Marc Hartmayer -Signed-off-by: Jan Höppner ---- - rust/pvimg/man/genprotimg.1 | 11 +++++------ - rust/pvimg/man/pvimg-create.1 | 11 +++++------ - rust/pvimg/src/cli.rs | 14 ++++++++------ - rust/pvimg/src/cmd/create.rs | 3 +-- - 4 files changed, 19 insertions(+), 20 deletions(-) - -Index: s390-tools-2.36.0/rust/pvimg/man/genprotimg.1 -=================================================================== ---- s390-tools-2.36.0.orig/rust/pvimg/man/genprotimg.1 -+++ s390-tools-2.36.0/rust/pvimg/man/genprotimg.1 -@@ -123,7 +123,7 @@ Overwrite an existing Secure Execution b - .RE - .RE - .PP --\-\-comm\-key -+\-\-cck, \-\-comm\-key - .RS 4 - Use the content of FILE as the customer\-communication key (CCK). The file must - contain exactly 32 bytes of data. -@@ -133,7 +133,7 @@ contain exactly 32 bytes of data. - \-\-enable\-dump - .RS 4 - Enable Secure Execution guest dump support. This option requires the --\fB\-\-comm\-key\fR option. -+\fB\-\-cck\fR option. - .RE - .RE - .PP -@@ -146,8 +146,7 @@ Disable Secure Execution guest dump supp - \-\-enable\-cck\-extension\-secret - .RS 4 - Add\-secret requests must provide an extension secret that matches the --CCK\-derived extension secret. This option requires the \fB\-\-comm\-key\fR --option. -+CCK\-derived extension secret. This option requires the \fB\-\-cck\fR option. - .RE - .RE - .PP -@@ -268,7 +267,7 @@ Generate an IBM Secure Execution image: - - Generate an IBM Secure Execution image with Secure Execution guest dump support: - .PP --.B genprotimg \-i \fI\,/boot/vmlinuz\/\fR \-r \fI\,/boot/initrd.img\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/secure-linux\/\fR \-\-enable\-dump \-\-comm\-key \fI\,comm-key\fR -+.B genprotimg \-i \fI\,/boot/vmlinuz\/\fR \-r \fI\,/boot/initrd.img\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/secure-linux\/\fR \-\-enable\-dump \-\-cck \fI\,comm-key\fR - .SH NOTES - .IP "1." 4 - The \fBgenprotimg\fR(1) command is a symbolic link to the \fBpvimg-create\fR(1) command. -Index: s390-tools-2.36.0/rust/pvimg/man/pvimg-create.1 -=================================================================== ---- s390-tools-2.36.0.orig/rust/pvimg/man/pvimg-create.1 -+++ s390-tools-2.36.0/rust/pvimg/man/pvimg-create.1 -@@ -122,7 +122,7 @@ Overwrite an existing Secure Execution b - .RE - .RE - .PP --\-\-comm\-key -+\-\-cck, \-\-comm\-key - .RS 4 - Use the content of FILE as the customer\-communication key (CCK). The file must - contain exactly 32 bytes of data. -@@ -132,7 +132,7 @@ contain exactly 32 bytes of data. - \-\-enable\-dump - .RS 4 - Enable Secure Execution guest dump support. This option requires the --\fB\-\-comm\-key\fR option. -+\fB\-\-cck\fR option. - .RE - .RE - .PP -@@ -145,8 +145,7 @@ Disable Secure Execution guest dump supp - \-\-enable\-cck\-extension\-secret - .RS 4 - Add\-secret requests must provide an extension secret that matches the --CCK\-derived extension secret. This option requires the \fB\-\-comm\-key\fR --option. -+CCK\-derived extension secret. This option requires the \fB\-\-cck\fR option. - .RE - .RE - .PP -@@ -249,7 +248,7 @@ Generate an IBM Secure Execution image: - - Generate an IBM Secure Execution image with Secure Execution guest dump support: - .PP --.B pvimg create \-i \fI\,/boot/vmlinuz\/\fR \-r \fI\,/boot/initrd.img\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/secure-linux\/\fR \-\-enable\-dump \-\-comm\-key \fI\,comm-key\fR -+.B pvimg create \-i \fI\,/boot/vmlinuz\/\fR \-r \fI\,/boot/initrd.img\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/secure-linux\/\fR \-\-enable\-dump \-\-cck \fI\,comm-key\fR - .SH NOTES - .IP "1." 4 - The \fBgenprotimg\fR(1) command is a symbolic link to the \fBpvimg-create\fR(1) command. -Index: s390-tools-2.36.0/rust/pvimg/src/cli.rs -=================================================================== ---- s390-tools-2.36.0.orig/rust/pvimg/src/cli.rs -+++ s390-tools-2.36.0/rust/pvimg/src/cli.rs -@@ -96,8 +96,8 @@ pub struct ComponentPaths { - #[command(group(ArgGroup::new("header-flags").multiple(true).conflicts_with_all(["x_pcf", "x_scf"])))] - pub struct CreateBootImageLegacyFlags { - /// Enable Secure Execution guest dump support. This option requires the -- /// '--comm-key' option. -- #[arg(long, action = clap::ArgAction::SetTrue, requires="comm_key", group="header-flags")] -+ /// '--cck' option. -+ #[arg(long, action = clap::ArgAction::SetTrue, requires="cck", group="header-flags")] - pub enable_dump: Option, - - /// Disable Secure Execution guest dump support (default). -@@ -105,9 +105,9 @@ pub struct CreateBootImageLegacyFlags { - pub disable_dump: Option, - - /// Add-secret requests must provide an extension secret that matches the -- /// CCK-derived extension secret. This option requires the '--comm-key' -+ /// CCK-derived extension secret. This option requires the '--cck' - /// option. -- #[arg(long, action = clap::ArgAction::SetTrue, requires="comm_key", group="header-flags")] -+ #[arg(long, action = clap::ArgAction::SetTrue, requires="cck", group="header-flags")] - pub enable_cck_extension_secret: Option, - - /// Add-secret requests don't have to provide the CCK-derived extension -@@ -328,8 +328,8 @@ pub struct CreateBootImageArgs { - /// Use the content of FILE as the customer-communication key (CCK). - /// - /// The file must contain exactly 32 bytes of data. -- #[arg(long, value_name = "FILE")] -- pub comm_key: Option, -+ #[arg(long, value_name = "FILE", visible_alias = "comm-key")] -+ pub cck: Option, - - #[clap(flatten)] - pub legacy_flags: CreateBootImageLegacyFlags, -@@ -482,6 +482,8 @@ mod test { - flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-dump", ["--enable-dump"]), - CliOption::new("comm-key", ["--comm-key", "/dev/null"])])), - flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-dump", ["--enable-dump"]), -+ CliOption::new("comm-key", ["--cck", "/dev/null"])])), -+ flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-dump", ["--enable-dump"]), - CliOption::new("comm-key", ["--comm-key", "/dev/null"])])), - flat_map_collect(insert(mvca.clone(), vec![CliOption::new("x-pcf", ["--x-pcf", "0x0"]), - CliOption::new("x-scf", ["--x-scf", "0x0"])])), -Index: s390-tools-2.36.0/rust/pvimg/src/cmd/create.rs -=================================================================== ---- s390-tools-2.36.0.orig/rust/pvimg/src/cmd/create.rs -+++ s390-tools-2.36.0/rust/pvimg/src/cmd/create.rs -@@ -137,8 +137,7 @@ pub fn create(opt: &CreateBootImageArgs) - let verified_host_keys = opt - .certificate_args - .get_verified_hkds("Secure Execution image")?; -- let user_provided_keys = -- read_user_provided_keys(opt.comm_key.as_deref(), &opt.experimental_args)?; -+ let user_provided_keys = read_user_provided_keys(opt.cck.as_deref(), &opt.experimental_args)?; - let (plaintext_flags, secret_flags) = parse_flags(opt)?; - - if plaintext_flags.is_set(PcfV1::NoComponentEncryption) { diff --git a/s390-tools-pvimg-info-command-01.patch b/s390-tools-pvimg-info-command-01.patch deleted file mode 100644 index 09c8b18..0000000 --- a/s390-tools-pvimg-info-command-01.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 560b276f7e9938475af921c8ebd4cd05910dbf31 Mon Sep 17 00:00:00 2001 -From: Marc Hartmayer -Date: Fri, 6 Dec 2024 20:45:36 +0100 -Subject: [PATCH] rust/pvimg: Fix possible 'range start index out of range for - slice' error -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix possible 'range start index 16 out of range for slice of length 0' -error by adding a check of the slice data length. - -Fixes: f4cf4ae6ebb1 ("rust: Add a new tool called 'pvimg'") -Reviewed-by: Steffen Eiden -Signed-off-by: Marc Hartmayer -Signed-off-by: Jan Höppner ---- - rust/pvimg/src/pv_utils/se_hdr/brb.rs | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/rust/pvimg/src/pv_utils/se_hdr/brb.rs b/rust/pvimg/src/pv_utils/se_hdr/brb.rs -index f7ae1bc9..ac3a2e6e 100644 ---- a/rust/pvimg/src/pv_utils/se_hdr/brb.rs -+++ b/rust/pvimg/src/pv_utils/se_hdr/brb.rs -@@ -259,6 +259,10 @@ impl SeHdr { - return Err(Error::InvalidSeHdr); - } - -+ if sehs <= common_size { -+ return Err(Error::InvalidSeHdr); -+ } -+ - data.resize(sehs, 0); - reader.read_exact(&mut data[common_size..])?; - Self::try_from_data(&data) -@@ -366,3 +370,22 @@ impl AeadCipherTrait for SeHdrPlain { - self.data.aead_tag_size() - } - } -+ -+#[cfg(test)] -+mod tests { -+ use std::io::Cursor; -+ -+ use super::SeHdr; -+ use crate::error::Error; -+ -+ #[test] -+ fn test_sehdr_try_from_io() { -+ // Invalid SeHdr as `sehs` is set to 0 -+ assert!(matches!( -+ SeHdr::try_from_io(Cursor::new([ -+ 73, 66, 77, 83, 101, 99, 69, 120, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 8 -+ ])), -+ Err(Error::InvalidSeHdr) -+ )); -+ } -+} diff --git a/s390-tools-pvimg-info-command-02.patch b/s390-tools-pvimg-info-command-02.patch deleted file mode 100644 index 6e0589b..0000000 --- a/s390-tools-pvimg-info-command-02.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 3f6572e901ddcc654021c4302cb2a99999acb87a Mon Sep 17 00:00:00 2001 -From: Marc Hartmayer -Date: Wed, 18 Dec 2024 13:41:13 +0100 -Subject: [PATCH] rust/utils: mkdtemp: fix memory leak -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fix memory leak of @template_raw. The documentation of CString::into_raw -reads: - -"Consumes the CString and transfers ownership of the string to a C -caller. -... -Failure to call CString::from_raw will lead to a memory leak." [1] - -Let's fix the memory leak by always calling `CString::from_raw` and -therefore reclaim the ownership. - -[1] https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_raw - -Fixes: e56acf4f14b0 ("pv_core: add `TemporaryDirectory`") -Reviewed-by: Steffen Eiden -Signed-off-by: Marc Hartmayer -Signed-off-by: Jan Höppner ---- - rust/utils/src/tmpfile.rs | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/rust/utils/src/tmpfile.rs b/rust/utils/src/tmpfile.rs -index 07acdba8..883d5586 100644 ---- a/rust/utils/src/tmpfile.rs -+++ b/rust/utils/src/tmpfile.rs -@@ -16,13 +16,14 @@ fn mkdtemp>(template: P) -> Result { - // SAFETY: template_raw is a valid CString because it was generated by - // the `CString::new`. - let ret = libc::mkdtemp(template_raw); -+ // SAFETY: `template_raw` is still a valid CString because it was -+ // generated by `CString::new` and modified by `libc::mkdtemp`. -+ let path_cstr = std::ffi::CString::from_raw(template_raw); - - if ret.is_null() { -+ drop(path_cstr); - Err(std::io::Error::last_os_error()) - } else { -- // SAFETY: `template_raw` is still a valid CString because it was -- // generated by `CString::new` and modified by `libc::mkdtemp`. -- let path_cstr = std::ffi::CString::from_raw(template_raw); - let path = OsStr::from_bytes(path_cstr.as_bytes()); - let path = std::path::PathBuf::from(path); - diff --git a/s390-tools-pvimg-info-command-03.patch b/s390-tools-pvimg-info-command-03.patch deleted file mode 100644 index 7f19275..0000000 --- a/s390-tools-pvimg-info-command-03.patch +++ /dev/null @@ -1,334 +0,0 @@ -From 944581eaefe4c6887790f2b8ed39c9ee76146c55 Mon Sep 17 00:00:00 2001 -From: Marc Hartmayer -Date: Tue, 17 Dec 2024 11:58:01 +0100 -Subject: [PATCH] rust/pvimg: Add upper estimates for the Secure Execution - header -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -A Secure Execution header V1 can be at maximum two pages large, optional -items are not supported, and the size of the encrypted part cannot be -larger than the total size of the Secure Execution header add this as -Deku assertions and additional conditions to the code. In addition, add -a check for the number of key slots. - -Fixes: f4cf4ae6ebb1 ("rust: Add a new tool called 'pvimg'") -Reviewed-by: Steffen Eiden -Signed-off-by: Marc Hartmayer -Signed-off-by: Jan Höppner ---- - rust/pvimg/src/pv_utils/error.rs | 3 + - rust/pvimg/src/pv_utils/se_hdr/brb.rs | 50 +++++++++++++--- - rust/pvimg/src/pv_utils/se_hdr/builder.rs | 10 +++- - rust/pvimg/src/pv_utils/se_hdr/hdr_v1.rs | 71 ++++++++++++++++++++--- - rust/pvimg/src/pv_utils/uvdata.rs | 18 ++++-- - 5 files changed, 130 insertions(+), 22 deletions(-) - -diff --git a/rust/pvimg/src/pv_utils/error.rs b/rust/pvimg/src/pv_utils/error.rs -index 2a176276..a12c4a22 100644 ---- a/rust/pvimg/src/pv_utils/error.rs -+++ b/rust/pvimg/src/pv_utils/error.rs -@@ -30,6 +30,9 @@ pub enum Error { - #[error("Invalid Secure Execution header")] - InvalidSeHdr, - -+ #[error("Secure Execution header size {given} is larger than the maximum of {maximum} bytes")] -+ InvalidSeHdrTooLarge { given: usize, maximum: usize }, -+ - #[error("Invalid component metadata.")] - InvalidComponentMetadata, - -diff --git a/rust/pvimg/src/pv_utils/se_hdr/brb.rs b/rust/pvimg/src/pv_utils/se_hdr/brb.rs -index ac3a2e6e..b8dadba1 100644 ---- a/rust/pvimg/src/pv_utils/se_hdr/brb.rs -+++ b/rust/pvimg/src/pv_utils/se_hdr/brb.rs -@@ -171,8 +171,8 @@ impl AeadCipherTrait for SeHdr { - } - - impl AeadDataTrait for SeHdr { -- fn aad(&self) -> Vec { -- [serialize_to_bytes(&self.common).unwrap(), self.data.aad()].concat() -+ fn aad(&self) -> Result> { -+ Ok([serialize_to_bytes(&self.common)?, self.data.aad()?].concat()) - } - - fn data(&self) -> Vec { -@@ -265,7 +265,7 @@ impl SeHdr { - - data.resize(sehs, 0); - reader.read_exact(&mut data[common_size..])?; -- Self::try_from_data(&data) -+ Self::try_from_data(&data).map_err(|_| Error::InvalidSeHdr) - } - } - -@@ -342,13 +342,13 @@ impl UvDataPlainTrait for SeHdrPlain { - } - - impl AeadPlainDataTrait for SeHdrPlain { -- fn aad(&self) -> Vec { -- let data_aad = self.data.aad(); -+ fn aad(&self) -> Result> { -+ let data_aad = self.data.aad()?; - -- [serialize_to_bytes(&self.common).unwrap(), data_aad].concat() -+ Ok([serialize_to_bytes(&self.common)?, data_aad].concat()) - } - -- fn data(&self) -> Confidential> { -+ fn data(&self) -> Result>> { - self.data.data() - } - -@@ -387,5 +387,41 @@ mod tests { - ])), - Err(Error::InvalidSeHdr) - )); -+ -+ // Invalid SeHdr as the `sehs` is too large. -+ assert!(matches!( -+ SeHdr::try_from_io(Cursor::new([ -+ 73, 66, 77, 83, 101, 99, 69, 120, 0, 0, 1, 0, 0, 0, 1, 255, 65, 65, 65, 65, 67, 0, -+ 65, 17, 65, 0, 65, 65, 65, 65, 65, 65, 91, 91, 180, 91, 91, 91, 91, 91, 91, 91, 91, -+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 241, 241, -+ 241, 241, 241, 91, 91, 91, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, -+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 80, -+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, -+ 112, 112, 112, 112, 91, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, -+ 112, 112, 112, 112, 112, 112, 112, 0, 0, 0, 0, 101, 99, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 65, 65, 65, 65, 67, 0, 65, 17, 65, 0, 65, 65, 65, 65, -+ 65, 65, 91, 91, 180, 91, 91, 91, 91, 91, 91, 91, 91, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 255, 255, 255, 255, 255, 241, 241, 241, 241, 241, 91, 91, 91, 112, -+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, -+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 80, 112, 112, 112, 112, 112, 112, -+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 91, 112, 112, -+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 73, 66, 77, 83, 101, 99, 69, 120, -+ 0, 112, 112, 0, 1, 0, 0, 0, 0, 101, 99, 255, 255, 255, 255, 255, 255, 255, 255, -+ 255, 255, 255, 65, 65, 65, 65, 67, 0, 65, 17, 65, 0, 65, 65, 65, 65, 65, 65, 91, -+ 91, 180, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, -+ 91, 91, 112, 112, 112, 112, 112, 73, 66, 77, 83, 101, 99, 69, 120, 0, 0, 1, 0, 0, -+ 0, 0, 48, 53, 53, 53, 53, 53, 53, 53, 91, 91, 91, 241, 241, 46, 49, 49, 0, 49, 49, -+ 0, 0, 112, 112, 112, 91, 0, 0, 0, 0, 9, 0, 49, 50, 22, 241, 241, 241, 241, 241, -+ 241, 241, 241, 241, 241, 241, 91, 91, 91, 91, 91, 255, 251, 0, 0, 91, 91, 91, 91, -+ 91, 91, 91, 91, 91, 91, 91, 0, 0, 91, 0, 0, 10, 91, 91, 91, 65, 65, 65, 65 -+ ])), -+ Err(Error::InvalidSeHdr) -+ )); - } - } -diff --git a/rust/pvimg/src/pv_utils/se_hdr/builder.rs b/rust/pvimg/src/pv_utils/se_hdr/builder.rs -index ba6de898..93bcc7af 100644 ---- a/rust/pvimg/src/pv_utils/se_hdr/builder.rs -+++ b/rust/pvimg/src/pv_utils/se_hdr/builder.rs -@@ -230,8 +230,14 @@ mod tests { - - let decrypted = bin.decrypt(&prot_key).expect("BUG"); - assert_eq!(bin.common, decrypted.common); -- assert_eq!(bin.aad(), decrypted.aad()); -- assert_ne!(&bin.data(), decrypted.data().value()); -+ assert_eq!( -+ bin.aad().expect("should not fail"), -+ decrypted.aad().expect("should not fail") -+ ); -+ assert_ne!( -+ &bin.data(), -+ decrypted.data().expect("should not fail").value() -+ ); - let _decrypted_hdrv1: SeHdrDataV1 = decrypted.data.try_into().expect("BUG"); - } - -diff --git a/rust/pvimg/src/pv_utils/se_hdr/hdr_v1.rs b/rust/pvimg/src/pv_utils/se_hdr/hdr_v1.rs -index a7f2f609..b179d50d 100644 ---- a/rust/pvimg/src/pv_utils/se_hdr/hdr_v1.rs -+++ b/rust/pvimg/src/pv_utils/se_hdr/hdr_v1.rs -@@ -19,6 +19,7 @@ use serde::{Serialize, Serializer}; - use super::keys::phkh_v1; - use crate::{ - error::Error, -+ misc::PAGESIZE, - pv_utils::{ - error::Result, - se_hdr::{ -@@ -51,11 +52,14 @@ struct HdrSizesV1 { - #[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)] - #[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")] - struct SeHdrAadV1 { -+ #[deku(assert = "*sehs <= SeHdrDataV1::MAX_SIZE.try_into().unwrap()")] - sehs: u32, - #[serde(serialize_with = "ser_hex")] - iv: [u8; SymKeyType::AES_256_GCM_IV_LEN], - res1: u32, -+ #[deku(assert = "*nks <= (*sehs).into()", update = "self.keyslots.len()")] - nks: u64, -+ #[deku(assert = "*sea <= (*sehs).into()")] - sea: u64, - nep: u64, - #[serde(serialize_with = "ser_lower_hex")] -@@ -118,6 +122,7 @@ pub struct SeHdrConfV1 { - psw: PSW, - #[serde(serialize_with = "ser_lower_hex")] - scf: u64, -+ #[deku(assert_eq = "0")] - noi: u32, - res2: u32, - #[deku(count = "noi")] -@@ -200,6 +205,7 @@ where - } - - impl SeHdrDataV1 { -+ const MAX_SIZE: usize = 2 * PAGESIZE; - const PCF_DEFAULT: u64 = 0x0; - const SCF_DEFAULT: u64 = 0x0; - -@@ -241,7 +247,14 @@ impl SeHdrDataV1 { - tag: SeHdrTagV1::default(), - }; - let hdr_size = ret.size()?; -- ret.aad.sehs = hdr_size.phs.try_into()?; -+ let phs = hdr_size.phs.try_into()?; -+ if phs > Self::MAX_SIZE { -+ return Err(Error::InvalidSeHdrTooLarge { -+ given: phs, -+ maximum: Self::MAX_SIZE, -+ }); -+ } -+ ret.aad.sehs = phs.try_into()?; - ret.aad.sea = hdr_size.sea; - Ok(ret) - } -@@ -494,8 +507,8 @@ impl KeyExchangeTrait for SeHdrBinV1 { - } - - impl AeadDataTrait for SeHdrBinV1 { -- fn aad(&self) -> Vec { -- serialize_to_bytes(&self.aad).unwrap() -+ fn aad(&self) -> Result> { -+ serialize_to_bytes(&self.aad) - } - - fn data(&self) -> Vec { -@@ -508,12 +521,12 @@ impl AeadDataTrait for SeHdrBinV1 { - } - - impl AeadPlainDataTrait for SeHdrDataV1 { -- fn aad(&self) -> Vec { -- serialize_to_bytes(&self.aad).unwrap() -+ fn aad(&self) -> Result> { -+ serialize_to_bytes(&self.aad) - } - -- fn data(&self) -> Confidential> { -- serialize_to_bytes(self.data.value()).unwrap().into() -+ fn data(&self) -> Result>> { -+ Ok(serialize_to_bytes(self.data.value())?.into()) - } - - fn tag(&self) -> Vec { -@@ -610,4 +623,48 @@ mod tests { - assert_eq!(psw, hdr_data_v1.data.value().psw); - assert_eq!(cck.value(), hdr_data_v1.data.value().cck.value()); - } -+ -+ #[test] -+ fn max_size_sehdr_test() { -+ const MAX_HOST_KEYS: usize = 95; -+ -+ let (_, host_key) = get_test_key_and_cert(); -+ let pub_key = host_key.public_key().unwrap(); -+ let host_keys_max: Vec<_> = (0..MAX_HOST_KEYS).map(|_| pub_key.clone()).collect(); -+ let too_many_host_keys: Vec<_> = (0..MAX_HOST_KEYS + 1).map(|_| pub_key.clone()).collect(); -+ let xts_key = Confidential::new([0x3; SymKeyType::AES_256_XTS_KEY_LEN]); -+ let meta = ComponentMetadataV1 { -+ ald: [0x1; SHA_512_HASH_LEN], -+ pld: [0x2; SHA_512_HASH_LEN], -+ tld: [0x3; SHA_512_HASH_LEN], -+ nep: 3, -+ key: xts_key, -+ }; -+ let psw = PSW { -+ addr: 1234, -+ mask: 5678, -+ }; -+ -+ let mut builder = SeHdrBuilder::new(SeHdrVersion::V1, psw.clone(), meta.clone()) -+ .expect("should not fail"); -+ builder -+ .add_hostkeys(&host_keys_max) -+ .expect("should not fail") -+ .with_components(meta.clone()) -+ .expect("should not fail"); -+ let bin = builder.build().expect("should not fail"); -+ assert_eq!(bin.common.version, SeHdrVersion::V1); -+ let hdr_v1: SeHdrBinV1 = bin.data.try_into().expect("should not fail"); -+ assert_eq!(hdr_v1.aad.sehs, 8160); -+ -+ let mut builder = SeHdrBuilder::new(SeHdrVersion::V1, psw.clone(), meta.clone()) -+ .expect("should not fail"); -+ -+ builder -+ .add_hostkeys(&too_many_host_keys) -+ .expect("should not fail") -+ .with_components(meta) -+ .expect("should not fail"); -+ assert!(matches!(builder.build(), Err(Error::InvalidSeHdr))); -+ } - } -diff --git a/rust/pvimg/src/pv_utils/uvdata.rs b/rust/pvimg/src/pv_utils/uvdata.rs -index b0ec355a..c6ed9567 100644 ---- a/rust/pvimg/src/pv_utils/uvdata.rs -+++ b/rust/pvimg/src/pv_utils/uvdata.rs -@@ -34,7 +34,7 @@ pub trait AeadCipherTrait { - #[enum_dispatch] - pub trait AeadDataTrait { - /// Returns the authenticated associated data. -- fn aad(&self) -> Vec; -+ fn aad(&self) -> Result>; - - /// Returns the encrypted data. - fn data(&self) -> Vec; -@@ -47,10 +47,10 @@ pub trait AeadDataTrait { - #[enum_dispatch] - pub trait AeadPlainDataTrait { - /// Returns the authenticated associated data. -- fn aad(&self) -> Vec; -+ fn aad(&self) -> Result>; - - /// Returns the unencrypted data. -- fn data(&self) -> Confidential>; -+ fn data(&self) -> Result>>; - - /// Returns the tag data. - fn tag(&self) -> Vec; -@@ -124,8 +124,14 @@ pub trait UvDataPlainTrait: - expected: self.aead_key_type().to_string(), - }); - } -- let aad = self.aad(); -- let unecrypted_data = self.data(); -+ let aad = self.aad().map_err(|err| match err { -+ Error::Deku(_) => Error::InvalidSeHdr, -+ err => err, -+ })?; -+ let unecrypted_data = self.data().map_err(|err| match err { -+ Error::Deku(_) => Error::InvalidSeHdr, -+ err => err, -+ })?; - let iv = self.iv(); - let result = encrypt_aead(key, iv, &aad, unecrypted_data.value())?; - Self::C::try_from_data(&result.into_buf()) -@@ -169,7 +175,7 @@ pub trait UvDataTrait: AeadDataTrait + AeadCipherTrait + KeyExchangeTrait + Clon - } - - let tag_size = self.aead_tag_size(); -- let aad = self.aad(); -+ let aad = self.aad()?; - let unecrypted_data = self.data(); - let iv = self.iv(); - let tag = self.tag(); diff --git a/s390-tools-pvimg-info-command-04.patch b/s390-tools-pvimg-info-command-04.patch deleted file mode 100644 index 6a05f76..0000000 --- a/s390-tools-pvimg-info-command-04.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 6e48c5ebaa26c6bd2a1bc33ccf36ed8bd6946358 Mon Sep 17 00:00:00 2001 -From: Marc Hartmayer -Date: Tue, 17 Dec 2024 18:13:31 +0100 -Subject: [PATCH] pvimg: info: Rename '--key' into '--hdr-key' and use '--key' - as an alias -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Rename '--key' into '--hdr-key' and use '--key' as an (non-visible) -alias for '--hdr-key' in order to keep the command line backwards -compatible. The chances of someone using '--key' are very low, as this -version has not yet been released by any OS distribution. - -This change makes the command line options for the different subcommands -more consistent and therefore easier to use. - -Suggested-by: Reinhard Bündgen -Acked-by: Hendrik Brueckner -Reviewed-by: Steffen Eiden -Signed-off-by: Marc Hartmayer -Signed-off-by: Jan Höppner ---- - rust/pvimg/man/pvimg-info.1 | 2 +- - rust/pvimg/src/cli.rs | 22 +++++++++++++++++++--- - rust/pvimg/src/cmd/info.rs | 2 +- - 3 files changed, 21 insertions(+), 5 deletions(-) - -Index: s390-tools-2.36.0/rust/pvimg/man/pvimg-info.1 -=================================================================== ---- s390-tools-2.36.0.orig/rust/pvimg/man/pvimg-info.1 -+++ s390-tools-2.36.0/rust/pvimg/man/pvimg-info.1 -@@ -37,7 +37,7 @@ Possible values: - .RE - .RE - .PP --\-\-key -+\-\-hdr\-key - .RS 4 - Use the key in FILE to decrypt the Secure Execution header. - .RE -Index: s390-tools-2.36.0/rust/pvimg/src/cli.rs -=================================================================== ---- s390-tools-2.36.0.orig/rust/pvimg/src/cli.rs -+++ s390-tools-2.36.0/rust/pvimg/src/cli.rs -@@ -192,8 +192,8 @@ pub struct InfoArgs { - pub format: OutputFormat, - - /// Use the key in FILE to decrypt the Secure Execution header. -- #[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)] -- pub key: Option, -+ #[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath, alias = "key")] -+ pub hdr_key: Option, - } - - #[derive(Args, Debug)] -@@ -710,6 +710,22 @@ mod test { - CliOption::new("image", ["/dev/null"]), - ], - )), -+ flat_map_collect(insert( -+ args.clone(), -+ vec![ -+ CliOption::new("hdr-key", ["--hdr-key", "/dev/null"]), -+ CliOption::new("format", ["--format=json"]), -+ CliOption::new("image", ["/dev/null"]), -+ ], -+ )), -+ flat_map_collect(insert( -+ args.clone(), -+ vec![ -+ CliOption::new("hdr-key", ["--key", "/dev/null"]), -+ CliOption::new("format", ["--format=json"]), -+ CliOption::new("image", ["/dev/null"]), -+ ], -+ )), - // separation between keyword and positional args works - flat_map_collect(insert( - args.clone(), -@@ -750,7 +766,7 @@ mod test { - - // Test for invalid combinations - // Input is missing -- let mut pvimg_invalid_args = vec![vec!["pvimg", "test"]]; -+ let mut pvimg_invalid_args = vec![vec!["pvimg", "info"]]; - - for create_args in &valid_test_args { - pvimg_valid_args.push( -Index: s390-tools-2.36.0/rust/pvimg/src/cmd/info.rs -=================================================================== ---- s390-tools-2.36.0.orig/rust/pvimg/src/cmd/info.rs -+++ s390-tools-2.36.0/rust/pvimg/src/cmd/info.rs -@@ -27,7 +27,7 @@ pub fn info(opt: &InfoArgs) -> Result + +- Upgrade s390-tools to 2.37 (jsc#PED-9591, jsc#PED-10303, jesc#PED-11870 (jsc#IBM-1062)) + * Changes of existing tools: + dbginfo.sh: Add details on CPU-measurement + dbginfo.sh: Add new crypto command + dbginfo.sh: Add overview commands and crypto update + dbginfo.sh: Adding kdump info + dbginfo.sh: Removing outdated email references + dbginfo.sh: Rework network section + dbginfo.sh: Update copyright 2nd year + pvimg: Add '--(enable|disable)-image-encryption' flags to 'pvimg create' + pvimg: Add '--cck ' command line option and make '--comm-key' an alias + pvimg: Add '--hdr-key' command line option to 'pvimg create' + pvimg: Rename '--key' into '--hdr-key' and use '--key' as an alias (for 'pvimg info') + pvsecret: Add support for retrievable secrets + ziorep_config: Add PCHID field to adapter report + ziorep_traffic: Add DEVBUSID column to traffic report + ziorep_utilization: Add --fcp-device parameter to print virtual adapter report + ziorep_utilization: Add PCHID column to physical adapter report + ziorep_utilization: Now prints only physical adapter report by default + ziorep_utilization: Swap Bus-ID and CHPID columns in virtual adapter report + zipl/boot: Increase section size for eckd_mv dumper + zkey: Add support for listing and importing protected virtualization secrets + * Bug Fixes: + chpstat: Fix invalid utilization data on older kernels + opticsmon: Fix runaway loop in on_link_change() + zipl: Update inline assembly for GCC 15 + zipl_helper.device-mapper: Add missed step in logical device resolution +- Revendored vendor.tar.gz +- Removed obsolete patches: + * s390-tools-01-zipl_helper.device-mapper-add-missed-step-in-logical.patch + * s390-tools-02-zipl-src-fix-imprecise-check-that-file-is-on-specifi.patch + * s390-tools-General-update-01.patch + * s390-tools-General-update-02.patch + * s390-tools-General-update-03.patch + * s390-tools-General-update-04.patch + * s390-tools-General-update-05.patch + * s390-tools-General-update-06.patch + * s390-tools-General-update-07.patch + * s390-tools-General-update-08.patch + * s390-tools-General-update-09.patch + * s390-tools-General-update-10.patch + * s390-tools-General-update-11.patch + * s390-tools-General-update-12.patch + * s390-tools-Additional-update-01.patch + * s390-tools-Additional-update-02.patch + * s390-tools-pvimg-info-command-01.patch + * s390-tools-pvimg-info-command-02.patch + * s390-tools-pvimg-info-command-03.patch + * s390-tools-Support-unencrypted-SE-images-01.patch + * s390-tools-pvimg-info-command-04.patch + * s390-tools-pvimg-additional-01.patch + * 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 + * s390-tools-08-rust-pvimg-Fix-flag-parsing-for-allowing-dump.patch + * s390-tools-09-rust-pvimg-Document-the-change-from--comm-key-to--cck.patch + ------------------------------------------------------------------- Mon Feb 3 07:51:27 UTC 2025 - Nikolay Gueorguiev diff --git a/s390-tools.spec b/s390-tools.spec index 3995bc5..c9a4d96 100644 --- a/s390-tools.spec +++ b/s390-tools.spec @@ -33,7 +33,7 @@ %endif Name: s390-tools -Version: 2.36.0 +Version: 2.37.0 Release: 0 Summary: S/390 tools like zipl and dasdfmt for s390x (plus selected tools for x86_64) License: MIT @@ -154,43 +154,6 @@ Patch911: s390-tools-sles15sp5-remove-no-pie-link-arguments.patch Patch912: s390-tools-ALP-zdev-live.patch Patch913: s390-tools-sles15sp6-kdump-initrd-59-zfcp-compat-rules.patch ### -Patch914: s390-tools-01-zipl_helper.device-mapper-add-missed-step-in-logical.patch -Patch915: s390-tools-02-zipl-src-fix-imprecise-check-that-file-is-on-specifi.patch -### -Patch920: s390-tools-General-update-01.patch -Patch921: s390-tools-General-update-02.patch -Patch922: s390-tools-General-update-03.patch -Patch923: s390-tools-General-update-04.patch -Patch924: s390-tools-General-update-05.patch -Patch925: s390-tools-General-update-06.patch -Patch926: s390-tools-General-update-07.patch -Patch927: s390-tools-General-update-08.patch -Patch928: s390-tools-General-update-09.patch -Patch929: s390-tools-General-update-10.patch -Patch930: s390-tools-General-update-11.patch -Patch931: s390-tools-General-update-12.patch -### -Patch935: s390-tools-Additional-update-01.patch -Patch936: s390-tools-Additional-update-02.patch -### -Patch950: s390-tools-pvimg-info-command-01.patch -Patch951: s390-tools-pvimg-info-command-02.patch -Patch952: s390-tools-pvimg-info-command-03.patch -### -Patch960: s390-tools-Support-unencrypted-SE-images-01.patch -Patch961: s390-tools-pvimg-info-command-04.patch -Patch962: s390-tools-pvimg-additional-01.patch -### -Patch970: s390-tools-01-zkey-Add-support-for-retrieving-a-list-of-ultravisor-secrets.patch -Patch971: s390-tools-02-zkey-Add-the--pvsecrets-list-command.patch -Patch972: s390-tools-03-zkey-Add-PVSECRETS-AES-key-type.patch -Patch973: s390-tools-04-zkey-Add-the-pvsecrets-import-command.patch -Patch974: s390-tools-05-zkey-Reject-key-generation-and-APQN-association-for-PVSECRET-AES-keys.patch -Patch975: s390-tools-06-zkey-Reject-re-enciphering-of-PVSECRET-AES-keys.patch -Patch976: s390-tools-07-zkey-Support-validation-of-key-of-type-PVSECRET-AES.patch -Patch977: s390-tools-08-rust-pvimg-Fix-flag-parsing-for-allowing-dump.patch -Patch978: s390-tools-09-rust-pvimg-Document-the-change-from--comm-key-to--cck.patch -### Patch990: s390-tools-slfo-01-parse-ipl-device-for-activation.patch ### diff --git a/vendor.tar.gz b/vendor.tar.gz index 3a97d7c..30178d7 100644 --- a/vendor.tar.gz +++ b/vendor.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a006e81236e6479a7141d04c11af6181b5baeee9bd1cd9140003ea79738a33bf -size 46331845 +oid sha256:dc557e5321b5dc1686b087e64e59613fb0da2e21826bf8d9f918050439450388 +size 23882832