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>
This commit is contained in:
Ingo Franzki
2024-02-15 09:08:43 +01:00
committed by Steffen Eiden
parent 7be364aa84
commit 8c4b2872b8
3 changed files with 253 additions and 1 deletions
+3 -1
View File
@@ -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
+161
View File
@@ -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;
}
+89
View File
@@ -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