s390-tools/s390-tools-01-zkey-Add-support-for-retrieving-a-list-of-ultravisor-secrets.patch
Nikolay Gueorguiev 27cc4620be - Applied more additional patches (jsc#PED-11870, jec#PED-11958)
* 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

OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=247
2025-02-03 08:20:55 +00:00

300 lines
8.4 KiB
Diff

From 8c4b2872b8e24c1a27d8201beb5979c66ac05268 Mon Sep 17 00:00:00 2001
From: Ingo Franzki <ifranzki@linux.ibm.com>
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 <ifranzki@linux.ibm.com>
Reviewed-by: Jorg Schmidbauer <jschmidb@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
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 <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "lib/util_base.h"
+#include "lib/util_file.h"
+#include "lib/util_libc.h"
+#include "lib/util_panic.h"
+#include "lib/util_path.h"
+
+#include "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