From 268dcebe23d9813f2d5d7f75d62bd5794f1eeea6 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Fri, 21 May 2021 09:54:05 +0200 Subject: [PATCH] zkey-kmip: Add new zkey KMS plugin for KMIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support to integrate the external key management systems based on the KMIP protocol (KMIP: OASIS Key Management Interoperability Protocol) into zkey by providing a zkey KMS plugin for KMIP. The plugin communicates with KMIP servers using libkmipclient over a TLS or HTTPS connection. Signed-off-by: Ingo Franzki Signed-off-by: Jan Höppner --- .gitignore | 2 + zkey/Makefile | 3 + zkey/kmip/Makefile | 55 +++ zkey/kmip/zkey-kmip.c | 745 ++++++++++++++++++++++++++++++++++++++++ zkey/kmip/zkey-kmip.h | 26 ++ zkey/kmip/zkey-kmip.map | 5 + zkey/kms-plugins.conf | 3 +- 7 files changed, 838 insertions(+), 1 deletion(-) create mode 100644 zkey/kmip/Makefile create mode 100644 zkey/kmip/zkey-kmip.c create mode 100644 zkey/kmip/zkey-kmip.h create mode 100644 zkey/kmip/zkey-kmip.map diff --git a/.gitignore b/.gitignore index 9d5ca4ca..723d3120 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,8 @@ zkey/check-dep-zkey-cryptsetup zkey/detect-libcryptsetup.dep zkey/ekmfweb/libekmfweb.dep zkey/ekmfweb/zkey-ekmfweb.so +zkey/kmip/libkmipclient.dep +zkey/kmip/zkey-kmip.so zkey/zkey zkey/zkey-cryptsetup zpcictl/zpcictl diff --git a/zkey/Makefile b/zkey/Makefile index f74e2091..93b3ddbc 100644 --- a/zkey/Makefile +++ b/zkey/Makefile @@ -6,6 +6,9 @@ ifneq (${HAVE_OPENSSL},0) ifneq (${HAVE_JSONC},0) ifneq (${HAVE_LIBCURL},0) SUB_DIRS += ekmfweb + ifneq (${HAVE_LIBXML2},0) + SUB_DIRS += kmip + endif endif endif else diff --git a/zkey/kmip/Makefile b/zkey/kmip/Makefile new file mode 100644 index 00000000..ed718076 --- /dev/null +++ b/zkey/kmip/Makefile @@ -0,0 +1,55 @@ +include ../../common.mak + +VERSION = 1.0 +VERM = $(shell echo $(VERSION) | cut -d '.' -f 1) + +all: zkey-kmip.so + +libs = $(rootdir)/libutil/libutil.a + +zkey-kmip.o: zkey-kmip.c zkey-kmip.h ../kms-plugin.h ../plugin-utils.h \ + ../cca.h ../utils.h ../pkey.h ../properties.h \ + $(rootdir)include/kmipclient/kmipclient.h libkmipclient.dep + +plugin-utils.o: ../plugin-utils.c ../plugin-utils.h ../kms-plugin.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + +properties.o: ../properties.c ../properties.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + +pkey.o: ../pkey.c ../pkey.h ../cca.h ../ep11.h ../utils.h ../kms-plugin.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + +cca.o: ../cca.c ../cca.h ../pkey.h ../ep11.h ../utils.h ../properties.h ../kms-plugin.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + +ep11.o: ../ep11.c ../ep11.h ../pkey.h ../cca.h ../utils.h ../kms-plugin.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + +utils.o: ../utils.c ../utils.h ../pkey.h ../cca.h ../ep11.h ../kms-plugin.h + $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@ + +zkey-kmip.so: ALL_CFLAGS += -fPIC +zkey-kmip.so: LDLIBS = -L$(rootdir)/libkmipclient -lkmipclient -ldl -lcrypto +zkey-kmip.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-kmip.map \ + -Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-kmip.so.$(VERM) +zkey-kmip.so: zkey-kmip.o plugin-utils.o properties.o pkey.o cca.o ep11.o \ + utils.o $(libs) + $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + +install-libkmipclient.dep: + $(MAKE) -C $(rootdir)/libkmipclient/ TOPDIR=$(TOPDIR) ARCH=$(ARCH) install + touch install-libkmipclient.dep + +libkmipclient.dep: + $(MAKE) -C $(rootdir)/libkmipclient/ TOPDIR=$(TOPDIR) ARCH=$(ARCH) all + touch libkmipclient.dep + +install: all install-libkmipclient.dep zkey-kmip.so + $(INSTALL) -d -m 755 $(DESTDIR)$(ZKEYKMSPLUGINDIR) + $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T zkey-kmip.so $(DESTDIR)$(ZKEYKMSPLUGINDIR)/zkey-kmip.so + +clean: + rm -f *.o zkey-kmip.so install-libkmipclient.dep libkmipclient.dep + +.PHONY: all install clean \ No newline at end of file diff --git a/zkey/kmip/zkey-kmip.c b/zkey/kmip/zkey-kmip.c new file mode 100644 index 00000000..a6370506 --- /dev/null +++ b/zkey/kmip/zkey-kmip.c @@ -0,0 +1,745 @@ +/* + * zkey-kmip - KMIP zkey KMS plugin + * + * Copyright IBM Corp. 2021 + * + * 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 "lib/zt_common.h" +#include "lib/util_libc.h" +#include "lib/util_panic.h" + +#include "zkey-kmip.h" +#include "../kms-plugin.h" +#include "../cca.h" +#include "../utils.h" +#include "../pkey.h" +#include "../properties.h" + +#define _set_error(ph, fmt...) plugin_set_error(&(ph)->pd, fmt) + +/** + * Informs a KMS plugin that it is bound to a zkey repository. + * + * Note: This function is called before kms_initialize()! + * + * @param config_path name of a directory where the KMS plugin can store + * its configuration and other files it needs to store + * + * @returns 0 on success, or a negative errno in case of an error. + */ +int kms_bind(const char *UNUSED(config_path)) +{ + return 0; +} + +/** + * Initializes a KMS plugin for usage by zkey. When a repository is bound to a + * KMS plugin, zkey calls this function when opening the repository. + * + * @param config_path name of a directory where the KMS plugin can store + * its configuration and other files it needs to store + * @param verbose if true, the plugin should write verbose or debug + * messages to stderr during further processing. + * + * @returns a KMS plugin handle, or NULL in case of an error. + */ +kms_handle_t kms_initialize(const char *config_path, bool verbose) +{ + struct plugin_handle *ph; + int rc; + + util_assert(config_path != NULL, "Internal error: config_path is NULL"); + + ph = util_malloc(sizeof(struct plugin_handle)); + memset(ph, 0, sizeof(struct plugin_handle)); + + rc = plugin_init(&ph->pd, "zkey-kmip", config_path, + KMIP_CONFIG_FILE, verbose); + if (rc != 0) + goto error; + + return (kms_handle_t)ph; + +error: + if (strlen(ph->pd.error_msg) > 0) + warnx("%s", ph->pd.error_msg); + + kms_terminate(ph); + return NULL; +} + +/** + * Terminates the use of a KMS plugin. When a repository is bound to a KMS + * plugin, zkey calls this function when closing the repository. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_terminate(const kms_handle_t handle) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + + pr_verbose(&ph->pd, "Plugin terminating"); + + plugin_term(&ph->pd); + free(ph); + + return 0; +} + +/** + * Returns a textual message about the last occurred error that occurred in the + * last called KMS plugin function. If no error occurred (i.e. the last plugin + * function returned rc = 0), then NULL is returned. + * The returned string is static or contained within the handle. It is valid + * only until the next KMS plugin function is called. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * + * @returns an error message of NULL + */ +const char *kms_get_last_error(const kms_handle_t handle) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + + pr_verbose(&ph->pd, "Last error: '%s'", ph->pd.error_msg); + + if (strlen(ph->pd.error_msg) == 0) + return NULL; + + return ph->pd.error_msg; +} + +/** + * Returns true if the KMS plugin supports the specified key type. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param key_type the zkey key type, euch as 'CCA-AESDATA', + * 'CCA-AESCIPHER', 'EP11-AES'. + * + * @returns true if the KMS plugin supports the key type, false otherwise. + */ +bool kms_supports_key_type(const kms_handle_t handle, + const char *key_type) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(key_type != NULL, "Internal error: key_type is NULL"); + + plugin_clear_error(&ph->pd); + + return false; +} + +/** + * Displays information about the KMS Plugin and its current configuration on + * stdout. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_display_info(const kms_handle_t handle) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + + pr_verbose(&ph->pd, "Display Info"); + + plugin_clear_error(&ph->pd); + + return 0; +} + +/** + * Returns a list of KMS specific command line options that zkey should accept + * and pass to the appropriate KMS plugin function. The option list must be + * terminated by an UTIL_OPT_END entry (see util_opt.h). The options returned + * must not interfere with the already defined options of the zkey command. + * Field 'command' of the returned options should either be NULL or specify + * the command that it is for. + * + * If max_opts is not -1, then only up to max_opts options are allowed. If more + * options are returned, only up to max_opts options are used by zkey. + * + * @param command the command for which the KMS-specific options are + * to be returned, see KMS_COMMAND_xxx defines + * @param max_opts maximum number of options allowed. If -1 then there + * is no limit. + * + * @returns a list of options terminated by an UTIL_OPT_END entry, or NULL in + * case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +const struct util_opt *kms_get_command_options(const char *command, + int UNUSED(max_opts)) +{ + util_assert(command != NULL, "Internal error: command is NULL"); + + return NULL; +} + +/** + * Configures (or re-configures) a KMS plugin. This function can be called + * several times to configure a KMS plugin is several steps (if supported by the + * KMS plugin). In case a configuration is not fully complete, this function + * may return -EAGAIN to indicate that it has accepted the configuration so far, + * but the configuration needs to be completed. + * + * A KMS plugin must be associated with at least one APQN. Thus, in a multi-step + * configuration, a list f APQNs must be specified at least once. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param apqns a list of APQNs to associate with the KMS plugin, or + * NULL if no APQNs are specified. + * @param num_apqns number of APQNs in above array. 0 if no APQNs are + * specified. + * @param options a list of options as specified by the user. These + * options are a subset of the possible options as + * returned by kms_get_command_options() with command + * KMS_COMMAND_CONFIGURE. + * @param num_options number of options in above array. + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + * -EAGAIN to indicate that the specified configuration was accepted so far, but + * the configuration is still incomplete, and needs to be completed. + */ +int kms_configure(const kms_handle_t handle, + const struct kms_apqn *apqns, size_t num_apqns, + const struct kms_option *options, size_t num_options) +{ + struct plugin_handle *ph = handle; + size_t i; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(num_apqns == 0 || apqns != NULL, + "Internal error: apqns is NULL but num_apqns > 0"); + util_assert(num_options == 0 || options != NULL, + "Internal error: options is NULL but num_options > 0 "); + + pr_verbose(&ph->pd, "Configure"); + for (i = 0; i < num_apqns; i++) { + pr_verbose(&ph->pd, " APQN: %02x.%04x", apqns[i].card, + apqns[i].domain); + } + for (i = 0; i < num_options; i++) { + if (isalnum(options[i].option)) + pr_verbose(&ph->pd, " Option '%c': '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + else + pr_verbose(&ph->pd, " Option %d: '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + } + + plugin_clear_error(&ph->pd); + + return 0; +} + +/** + * De-configures a KMS plugin. This is called by zkey when a repository is + * unbound from a KMS plugin. It gives the KMS plugin the chance to gracefully + * remove any files that the plugin has stored in its config directory. zkey + * will unconditionally remove all left over files when this function returns. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_deconfigure(const kms_handle_t handle) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + + pr_verbose(&ph->pd, "Deconfigure"); + + plugin_clear_error(&ph->pd); + + return 0; +} + +/** + * Allows the KMS plugin to perform a login to the KMS (if required). This + * function is called at least once before any key operation function, typically + * shortly after opening the repository. + * The KMS plugin may prompt the user (by reading from stdin) for its + * credentials, if needed. + * + * It is suggested that a KMS plugin performs a login with the KMS once, and + * stores a login token (or similar) in its config directory. The next time + * the kms_login function is called, the login token can be reused (if still + * valid). This avoids to prompt the user for every key operation. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_login(const kms_handle_t handle) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + + pr_verbose(&ph->pd, "Login"); + + plugin_clear_error(&ph->pd); + + return 0; +} + +/** + * Called when the master keys of an APQN associated with the KMS plugin has + * been changed. The KMS plugin can then re-encipher all its secure keys (if + * any) that it has stored in its config directory. + * + * Keys that have been generated by the KMS plugin and stored in the zkey + * repository do not need to be re-enciphered by the KMS plugin. Those are + * re-enciphered by zkey without the help of the KMS plugin. + * + * HSM have different master key registers. Typically a CURRENT and a NEW master + * key register exists. The NEW register may be loaded with the new to be set + * master key, and secure keys can be re-enciphered with it proactively. + * + * CCA also supports an OLD master key register, that contains the previously + * used master key. You thus can re-encipher a secure key that is currently + * enciphered with the master key from the OLD register with the master key + * from the CURRENT register. + * + * HSMs may also support different master keys for different key types or + * algorithms. It is up to the KMS plugin to know which master key registers + * are used for its secure keys + * + * A staged re-encipherment is performed by re-enciphering a secure key with + * the new HSM master key, without making it available for use in the first + * stage. Only when the staged re-encipherment is completed, then the previously + * re-enciphered secure key is make available for use and the old on is removed. + * + * An in-place re-encipherment replaces the secure key right away with its + * re-enciphered version. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param mode Re-encipherment mode + * @param mkreg Re-encipherment register selection + * @param options a list of options as specified by the user. These + * options are a subset of the possible options as + * returned by kms_get_command_options() with command + * KMS_COMMAND_REENCIPHER. + * @param num_options number of options in above array. + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_reenciper(const kms_handle_t handle, enum kms_reencipher_mode mode, + enum kms_reenc_mkreg mkreg, + const struct kms_option *options, size_t num_options) +{ + struct plugin_handle *ph = handle; + size_t i; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(num_options == 0 || options != NULL, + "Internal error: options is NULL but num_options > 0 "); + + pr_verbose(&ph->pd, "Re-encipher mode: %d, kmreg=%d", mode, mkreg); + for (i = 0; i < num_options; i++) { + if (isalnum(options[i].option)) + pr_verbose(&ph->pd, " Option '%c': '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + else + pr_verbose(&ph->pd, " Option %d: '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + } + + plugin_clear_error(&ph->pd); + + return -ENOTSUP; +} + +/** + * Generates a key in or with the KMS and returns a secure key that is + * enciphered under the current HSM master key. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param key_type the zkey key type, euch as 'CCA-AESDATA', + * 'CCA-AESCIPHER', 'EP11-AES'. + * @param key_bits the key bit size (e.g. 256 for an AES 256 bit key). + * @param properties a list of properties to associate the key with + * @param num_properties the number of properties in above array + * @param options a list of options as specified by the user. These + * options are a subset of the possible options as + * returned by kms_get_command_options() with command + * KMS_COMMAND_GENERATE. + * @param num_options number of options in above array. + * @param key_blob a buffer to return the key blob. The size of the + * buffer is specified in key_blob_length + * @param key_blob_length on entry: the size of the key_blob buffer. + * on exit: the size of the key blob returned. + * @param key_id a buffer to return the key-ID of the generated key. + * The key-id is a textual identifier uniquely + * identifying a key in the KMS and the KMS plugin. + * The returned key-id contains the terminating zero. + * @paran key_id_size size of the key_id buffer. It should be at least + * KMS_KEY_ID_SIZE + 1 bytes large. + * @param key_label a buffer to return the key-label of the generated + * key. The key-label is a textual identifier used to + * identify a key in the user interface of the KMS. + * A key label may be equal to the key-ID, or it may + * different. The returned key-label contains the + * terminating zero. + * @paran key_label_size size of the key_lanble buffer. It should be at least + * KMS_KEY_LABEL_SIZE + 1 bytes large. + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_generate_key(const kms_handle_t handle, const char *key_type, + size_t key_bits, enum kms_key_mode key_mode, + const struct kms_property *properties, + size_t num_properties, + const struct kms_option *options, size_t num_options, + unsigned char *key_blob, size_t *key_blob_length, + char *key_id, size_t key_id_size, + char *key_label, size_t key_label_size) +{ + struct plugin_handle *ph = handle; + size_t i; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(num_properties == 0 || properties != NULL, + "Internal error: properties is NULL but num_properties" + " > 0 "); + util_assert(num_options == 0 || options != NULL, + "Internal error: options is NULL but num_options > 0 "); + util_assert(key_blob != NULL, "Internal error: key_blob is NULL"); + util_assert(key_blob_length != NULL, "Internal error: key_blob_length " + "is NULL"); + util_assert(key_id != NULL, "Internal error: key_id is NULL"); + util_assert(key_label != NULL, "Internal error: key_label is NULL"); + + pr_verbose(&ph->pd, "Generate key: key-type: '%s', keybits: %lu, " + "mode: %d", key_type, key_bits, key_mode); + for (i = 0; i < num_properties; i++) { + util_assert(properties[i].name != NULL, + "Internal error: property name is NULL"); + util_assert(properties[i].value != NULL, + "Internal error: property value is NULL"); + pr_verbose(&ph->pd, " Property '%s': '%s'", properties[i].name, + properties[i].value); + } + for (i = 0; i < num_options; i++) { + if (isalnum(options[i].option)) + pr_verbose(&ph->pd, " Option '%c': '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + else + pr_verbose(&ph->pd, " Option %d: '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + } + + plugin_clear_error(&ph->pd); + + return -ENOTSUP; +} + +/** + * Sets (adds/replaces/removes) properties of a key. Already existing properties + * with the same property name are replaced, non-existing properties are added. + * To remove a property, set the property value to NULL. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param key_id the key-ID to set the properties for + * @param properties a list of properties to set + * @param num_properties the number of properties in above array + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_set_key_properties(const kms_handle_t handle, const char *key_id, + const struct kms_property *properties, + size_t num_properties) +{ + struct plugin_handle *ph = handle; + size_t i; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(key_id != NULL, "Internal error: key_id is NULL"); + util_assert(num_properties == 0 || properties != NULL, + "Internal error: properties is NULL but num_properties" + " > 0 "); + + pr_verbose(&ph->pd, "Set key properties: key-ID: '%s'", key_id); + for (i = 0; i < num_properties; i++) { + util_assert(properties[i].name != NULL, + "Internal error: property name is NULL"); + + pr_verbose(&ph->pd, " Property '%s': '%s'", properties[i].name, + properties[i].value != NULL ? properties[i].value : + "(null)"); + } + + plugin_clear_error(&ph->pd); + + return -ENOTSUP; +} + +/** + * Gets properties of a key. + * + * The returned list of properties must be freed by the caller. Each property + * name and value must be freed individually (using free()), as well as the + * complete array. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param key_id the key-ID to set the properties for + * @param properties On return: a list of properties + * @param num_properties On return: the number of properties in above array + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_get_key_properties(const kms_handle_t handle, const char *key_id, + struct kms_property **properties, + size_t *num_properties) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(key_id != NULL, "Internal error: key_id is NULL"); + util_assert(properties != NULL, "Internal error: properties is NULL"); + util_assert(num_properties != NULL, + "Internal error: num_properties is NULL"); + + pr_verbose(&ph->pd, "Get key properties: key-ID: '%s'", key_id); + + plugin_clear_error(&ph->pd); + + return -ENOTSUP; +} + +/** + * Called when zkey removes a KMS-bound key from the zkey repository. The KMS + * plugin can then set the state of the key in the KMS, or remove it also from + * the KMS (this is usually not done). + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param key_id the key-ID to set the properties for + * @param options a list of options as specified by the user. These + * options are a subset of the possible options as + * returned by kms_get_command_options() with command + * KMS_COMMAND_REMOVE. + * @param num_options number of options in above array. + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_remove_key(const kms_handle_t handle, const char *key_id, + const struct kms_option *options, size_t num_options) +{ + struct plugin_handle *ph = handle; + size_t i; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(key_id != NULL, "Internal error: key_id is NULL"); + util_assert(num_options == 0 || options != NULL, + "Internal error: options is NULL but num_options > 0 "); + + pr_verbose(&ph->pd, "Remove key: key-ID: '%s'", key_id); + for (i = 0; i < num_options; i++) { + if (isalnum(options[i].option)) + pr_verbose(&ph->pd, " Option '%c': '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + else + pr_verbose(&ph->pd, " Option %d: '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + } + + plugin_clear_error(&ph->pd); + + return -ENOTSUP; +} + +/** + * List keys managed by the KMS. This list is independent of the zkey key + * repository. It lists keys as known by the KMS. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param label_pattern a pattern of the label used to filter the keys, or + * NULL if no label pattern is specified. + * @param properties a list of properties used to filter the keys, or + * NULL if no properties filter is specified. + * @param num_properties the number of properties in above array. + * @param options a list of options as specified by the user. These + * options are a subset of the possible options as + * returned by kms_get_command_options() with command + * KMS_COMMAND_LIST. + * @param num_options number of options in above array.* + * @param callback a callback function that is called for each key that + * matches the filter (if any). + * @private_data a private pointer passed as is to the callback + * function. Can be used to pass user specific + * information to the callback. + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_list_keys(const kms_handle_t handle, const char *label_pattern, + const struct kms_property *properties, size_t num_properties, + const struct kms_option *options, size_t num_options, + kms_list_callback callback, void *private_data) +{ + struct plugin_handle *ph = handle; + size_t i; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(num_properties == 0 || properties != NULL, + "Internal error: properties is NULL but num_properties " + "> 0 "); + util_assert(callback != NULL, "Internal error: callback is NULL"); + + pr_verbose(&ph->pd, "List Keys, label-pattern: '%s'", + label_pattern != NULL ? label_pattern : "(null)"); + for (i = 0; i < num_properties; i++) { + util_assert(properties[i].name != NULL, + "Internal error: property name is NULL"); + util_assert(properties[i].value != NULL, + "Internal error: property value is NULL"); + pr_verbose(&ph->pd, " Property '%s': '%s'", properties[i].name, + properties[i].value); + } + for (i = 0; i < num_options; i++) { + if (isalnum(options[i].option)) + pr_verbose(&ph->pd, " Option '%c': '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + else + pr_verbose(&ph->pd, " Option %d: '%s'", + options[i].option, + options[i].argument != NULL ? + options[i].argument : "(null)"); + } + + plugin_clear_error(&ph->pd); + + return -ENOTSUP; +} + +/** + * Imports a key from the KMS and returns a secure key that is + * enciphered under the current HSM master key. + * + * @param handle the KMS plugin handle obtained from kms_initialize() + * @param key_id the key-ID of the key to import + * @param key_type the zkey key type, like 'CCA-AESDATA', + * 'CCA-AESCIPHER', 'EP11-AES'. + * @param key_blob a buffer to return the key blob. The size of the + * buffer is specified in key_blob_length + * @param key_blob_length on entry: the size of the key_blob buffer. + * on exit: the size of the key blob returned. + * + * @returns 0 on success, or a negative errno in case of an error. + * Function kms_get_last_error() can be used to obtain more details about the + * error. + */ +int kms_import_key2(const kms_handle_t handle, const char *key_id, + const char *key_type, + unsigned char *key_blob, size_t *key_blob_length) +{ + struct plugin_handle *ph = handle; + + util_assert(handle != NULL, "Internal error: handle is NULL"); + util_assert(key_blob != NULL, "Internal error: key_blob is NULL"); + util_assert(key_blob_length != NULL, "Internal error: key_blob_length " + "is NULL"); + + pr_verbose(&ph->pd, "Import Key, key-ID: '%s'", key_id); + + plugin_clear_error(&ph->pd); + + return -ENOTSUP; +} + +static const struct kms_functions kms_functions = { + .api_version = KMS_API_VERSION_2, + .kms_bind = kms_bind, + .kms_initialize = kms_initialize, + .kms_terminate = kms_terminate, + .kms_get_last_error = kms_get_last_error, + .kms_supports_key_type = kms_supports_key_type, + .kms_display_info = kms_display_info, + .kms_get_command_options = kms_get_command_options, + .kms_configure = kms_configure, + .kms_deconfigure = kms_deconfigure, + .kms_login = kms_login, + .kms_reenciper = kms_reenciper, + .kms_generate_key = kms_generate_key, + .kms_set_key_properties = kms_set_key_properties, + .kms_get_key_properties = kms_get_key_properties, + .kms_remove_key = kms_remove_key, + .kms_list_keys = kms_list_keys, + .kms_import_key2 = kms_import_key2, +}; + +/** + * Returns an address of a structure containing the KMS plugin functions. + * This function is exported by the KMS plugin, and its address is obtain + * via dlsym() after loading the plugin via dlopen(). + * * + * @returns the address of a structure or NULL in case of an error. + */ +const struct kms_functions *kms_get_functions(void) +{ + return &kms_functions; +} diff --git a/zkey/kmip/zkey-kmip.h b/zkey/kmip/zkey-kmip.h new file mode 100644 index 00000000..6e72a383 --- /dev/null +++ b/zkey/kmip/zkey-kmip.h @@ -0,0 +1,26 @@ +/* + * zkey-kmip - KMIP zkey KMS plugin + * + * Copyright IBM Corp. 2021 + * + * 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 ZKEY_KMIP_H +#define ZKEY_KMIP_H + +#include +#include + +#include "kmipclient/kmipclient.h" + +#include "../plugin-utils.h" + +struct plugin_handle { + struct plugin_data pd; +}; + +#define KMIP_CONFIG_FILE "kmip.conf" + +#endif diff --git a/zkey/kmip/zkey-kmip.map b/zkey/kmip/zkey-kmip.map new file mode 100644 index 00000000..b6958b25 --- /dev/null +++ b/zkey/kmip/zkey-kmip.map @@ -0,0 +1,5 @@ +ZKEY_KMIP_1.0 { + global: + kms_get_functions; + local: *; +}; diff --git a/zkey/kms-plugins.conf b/zkey/kms-plugins.conf index 6dc77e71..bc634dd5 100644 --- a/zkey/kms-plugins.conf +++ b/zkey/kms-plugins.conf @@ -1,4 +1,5 @@ # List of zkey KMS plugins # Format: # = -EKMFWeb=zkey-ekmfweb.so \ No newline at end of file +EKMFWeb=zkey-ekmfweb.so +KMIP=zkey-kmip.so \ No newline at end of file