mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zkey: Add support for key management system plugins
Add support to integrate external key management systems into zkey by using a plugin concept. Add helper functions to load, bind, and unbind a key management system plugin. Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
13f8709ec2
commit
f25aaf32b8
@@ -73,9 +73,10 @@ properties.o: check-dep-zkey properties.c properties.h
|
||||
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
|
||||
|
||||
zkey: LDLIBS = -ldl -lcrypto
|
||||
zkey: zkey.o pkey.o cca.o ep11.o properties.o keystore.o utils.o $(libs)
|
||||
zkey: zkey.o pkey.o cca.o ep11.o properties.o keystore.o utils.o kms.o $(libs)
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c -lcrypto
|
||||
@@ -86,13 +87,14 @@ install-common:
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
install-zkey:
|
||||
install-zkey: zkey
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1
|
||||
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey
|
||||
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository
|
||||
$(INSTALL) -m 644 -c kms-plugins.conf $(DESTDIR)$(SYSCONFDIR)/zkey
|
||||
|
||||
install-zkey-cryptsetup:
|
||||
install-zkey-cryptsetup: zkey-cryptsetup
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey-cryptsetup $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -m 644 -c zkey-cryptsetup.1 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
|
||||
539
zkey/kms-plugin.h
Normal file
539
zkey/kms-plugin.h
Normal file
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* zkey - Generate, re-encipher, and validate secure keys
|
||||
*
|
||||
* This header file defines the interface to a Key Management System (KMS)
|
||||
* Plugin.
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* 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 KMS_PLUGIN_H
|
||||
#define KMS_PLUGIN_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lib/util_opt.h"
|
||||
|
||||
/**
|
||||
* 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 *config_path);
|
||||
|
||||
typedef void *kms_handle_t;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#define KMS_COMMAND_CONFIGURE "configure"
|
||||
#define KMS_COMMAND_REENCIPHER "reencipher"
|
||||
#define KMS_COMMAND_GENERATE "generate"
|
||||
#define KMS_COMMAND_REMOVE "remove"
|
||||
#define KMS_COMMAND_LIST "list"
|
||||
#define KMS_COMMAND_LIST_IMPORT "list-import"
|
||||
|
||||
/**
|
||||
* 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 max_opts);
|
||||
|
||||
struct kms_apqn {
|
||||
unsigned short card;
|
||||
unsigned short domain;
|
||||
};
|
||||
|
||||
struct kms_option {
|
||||
int option; /** option character as in struct option */
|
||||
const char *argument; /** argument of the option (if any) */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* No kms_login is performed before calling this function. If the KMS plugin
|
||||
* requires a login for the configuration, it must perform it itself within this
|
||||
* function.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
enum kms_reencipher_mode {
|
||||
KMS_REENC_MODE_AUTO = 0,
|
||||
KMS_REENC_MODE_IN_PLACE = 1,
|
||||
KMS_REENC_MODE_STAGED = 2,
|
||||
KMS_REENC_MODE_STAGED_COMPLETE = 3,
|
||||
};
|
||||
|
||||
enum kms_reenc_mkreg {
|
||||
KMS_REENC_MKREG_AUTO = 0,
|
||||
KMS_REENC_MKREG_FROM_OLD = 1,
|
||||
KMS_REENC_MKREG_TO_NEW = 2,
|
||||
KMS_REENC_MKREG_FROM_OLD_TO_NEW = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 kms_property {
|
||||
const char *name;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
#define KMS_KEY_ID_SIZE 256
|
||||
#define KMS_KEY_LABEL_SIZE 256
|
||||
|
||||
enum kms_key_mode {
|
||||
KMS_KEY_MODE_NON_XTS = 0,
|
||||
KMS_KEY_MODE_XTS_1 = 1,
|
||||
KMS_KEY_MODE_XTS_2 = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* 0 to use the plugin's default key size.
|
||||
* @param key_mode mode of the key, e.g. non-XTS key, or first/second
|
||||
* XTS key to be generated. A KMS plugin may need to
|
||||
* use different key templates for the different key
|
||||
* modes (i.e. key parts).
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Callback used with the kms_list_keys() function. Called for each key.
|
||||
*
|
||||
* @param key_id the key-ID of the key
|
||||
* @param label the label of the key.
|
||||
* @param key_type the type of the key (CCA-AESDATA, etc)
|
||||
* @param key_bits the key size in bits
|
||||
* @param properties a list of properties of the key
|
||||
* @param num_properties the number of properties in above array
|
||||
* @param addl_info_argz an argz string containing additional KMS plugin
|
||||
* specific infos to be displayed, or NULL if none.
|
||||
* @param addl_info_len length of the argz string in addl_info_argz
|
||||
* @param private_data the private data pointer
|
||||
*
|
||||
* @returns 0 on success, or a negative errno in case of an error.
|
||||
*/
|
||||
typedef int (*kms_list_callback)(const char *key_id, const char *label,
|
||||
const char *key_type, size_t key_bits,
|
||||
const struct kms_property *properties,
|
||||
size_t num_properties,
|
||||
const char *addl_info_argz,
|
||||
size_t addl_info_len, void *private_data);
|
||||
|
||||
/**
|
||||
* List keys managed by the KMS. This list is independent of the zkey key
|
||||
* repository. It lists keys as known by the KMS.
|
||||
*
|
||||
* Note: The list function is used to display a list of keys managed by the KMS,
|
||||
* but also for producing a list of keys to import. Because the two use cases
|
||||
* might require different plugin specific options, kms_get_command_options()
|
||||
* allows two commands to get options for:
|
||||
* - KMS_COMMAND_LIST: Options for displaying a list.
|
||||
* - KMS_COMMAND_LIST_IMPORT: Options for building a list to import keys.
|
||||
* Functionkms_list_keys() is called for both cases with the appropriate
|
||||
* options as returned by kms_get_command_options() for the case.
|
||||
*
|
||||
* @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 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 or KMS_COMMAND_LIST_IMPORT.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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_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_key(const kms_handle_t handle, const char *key_id,
|
||||
unsigned char *key_blob, size_t *key_blob_length);
|
||||
|
||||
#define KMS_API_VERSION_1 1
|
||||
|
||||
struct kms_functions {
|
||||
unsigned int api_version;
|
||||
int (*kms_bind)(const char *config_path);
|
||||
kms_handle_t (*kms_initialize)(const char *config_path, bool verbose);
|
||||
int (*kms_terminate)(const kms_handle_t handle);
|
||||
const char *(*kms_get_last_error)(const kms_handle_t handle);
|
||||
bool (*kms_supports_key_type)(const kms_handle_t handle,
|
||||
const char *key_type);
|
||||
int (*kms_display_info)(const kms_handle_t handle);
|
||||
const struct util_opt *(*kms_get_command_options)(
|
||||
const char *command, int max_opts);
|
||||
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);
|
||||
int (*kms_deconfigure)(const kms_handle_t handle);
|
||||
int (*kms_login)(const kms_handle_t handle);
|
||||
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);
|
||||
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);
|
||||
int (*kms_set_key_properties)(const kms_handle_t handle,
|
||||
const char *key_id,
|
||||
const struct kms_property *properties,
|
||||
size_t num_properties);
|
||||
int (*kms_get_key_properties)(const kms_handle_t handle,
|
||||
const char *key_id,
|
||||
struct kms_property **properties,
|
||||
size_t *num_properties);
|
||||
int (*kms_remove_key)(const kms_handle_t handle, const char *key_id,
|
||||
const struct kms_option *options,
|
||||
size_t num_options);
|
||||
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);
|
||||
int (*kms_import_key)(const kms_handle_t handle, const char *key_id,
|
||||
unsigned char *key_blob,
|
||||
size_t *key_blob_length);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
3
zkey/kms-plugins.conf
Normal file
3
zkey/kms-plugins.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
# List of zkey KMS plugins
|
||||
# Format:
|
||||
# <plugin-name>=<shared-library-file>
|
||||
741
zkey/kms.c
Normal file
741
zkey/kms.c
Normal file
@@ -0,0 +1,741 @@
|
||||
/*
|
||||
* zkey - Generate, re-encipher, and validate secure keys
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* 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 <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_rec.h"
|
||||
#include "lib/util_panic.h"
|
||||
|
||||
#include "kms.h"
|
||||
|
||||
#define ENVVAR_ZKEY_REPOSITORY "ZKEY_REPOSITORY"
|
||||
#define DEFAULT_KEYSTORE "/etc/zkey/repository"
|
||||
|
||||
#define ENVVAR_ZKEY_KMS_PLUGINS "ZKEY_KMS_PLUGINS"
|
||||
#define DEFAULT_KMS_PLUGINS "/etc/zkey/kms-plugins.conf"
|
||||
|
||||
#define KMS_CONFIG_FILE "kms.conf"
|
||||
#define KMS_CONFIG_PROP_KMS "kms"
|
||||
#define KMS_CONFIG_PROP_KMS_CONFIG "config"
|
||||
#define KMS_CONFIG_PROP_APQNS "apqns"
|
||||
#define KMS_CONFIG_LOCAL "local"
|
||||
|
||||
typedef const struct kms_functions *(*kms_get_functions_t)(void);
|
||||
|
||||
#define pr_verbose(verbose, fmt...) do { \
|
||||
if (verbose) \
|
||||
warnx(fmt); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Opens kms-plugins.conf. Looks for the file in /etc/zkey/, or if environment
|
||||
* variable ZKEY_KMS_PLUGINS is set then it uses the file name and path
|
||||
* specified there.
|
||||
*/
|
||||
static FILE *open_kms_plugins_file(bool verbose)
|
||||
{
|
||||
char *conf;
|
||||
FILE *fp;
|
||||
|
||||
conf = getenv(ENVVAR_ZKEY_KMS_PLUGINS);
|
||||
if (conf == NULL)
|
||||
conf = DEFAULT_KMS_PLUGINS;
|
||||
|
||||
pr_verbose(verbose, "Opening KMS plugins config file '%s'", conf);
|
||||
fp = fopen(conf, "r");
|
||||
if (fp == NULL) {
|
||||
warnx("File '%s': %s", conf, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the KMS plugins defined in kms-plugins.conf
|
||||
*
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
int list_kms_plugins(bool verbose)
|
||||
{
|
||||
struct util_rec *rec;
|
||||
char line[4096];
|
||||
int rc = 0;
|
||||
size_t len;
|
||||
FILE *fp;
|
||||
char *ch;
|
||||
|
||||
fp = open_kms_plugins_file(verbose);
|
||||
if (fp == NULL)
|
||||
return -EIO;
|
||||
|
||||
rec = util_rec_new_wide("-");
|
||||
util_rec_def(rec, "PLUGIN", UTIL_REC_ALIGN_LEFT, 25, "KMS-Plugin");
|
||||
util_rec_def(rec, "LIB", UTIL_REC_ALIGN_LEFT, 25, "Shared library");
|
||||
util_rec_print_hdr(rec);
|
||||
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
len = strlen(line);
|
||||
if (len < 1)
|
||||
continue;
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
ch = strchr(line, '=');
|
||||
if (ch == NULL) {
|
||||
rc = -EPERM;
|
||||
warnx("Syntax error in kms-plugins.conf. Line: '%s'",
|
||||
line);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*ch = '\0';
|
||||
ch++;
|
||||
|
||||
util_rec_set(rec, "PLUGIN", line);
|
||||
util_rec_set(rec, "LIB", ch);
|
||||
util_rec_print(rec);
|
||||
}
|
||||
|
||||
out:
|
||||
util_rec_free(rec);
|
||||
fclose(fp);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a KMS plugin by its plugin name. Looks up the shared library in
|
||||
* kms-plugins.conf for the specified plugin name, and loads the shared library
|
||||
* via dlopen
|
||||
*
|
||||
* @param[in] plugin the plugin name (as in kms-plugins.conf)
|
||||
* @param[out] kms_functions the plugin functions obtain from the plugin
|
||||
* @param[out] plugin_lib the library handle (free with dlclose)
|
||||
* @param[out] plugin_name the full name of the plugin loaded
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
static int load_kms_plugin(const char *plugin,
|
||||
const struct kms_functions **kms_functions,
|
||||
void **plugin_lib, char **plugin_name, bool verbose)
|
||||
{
|
||||
kms_get_functions_t _kms_get_functions;
|
||||
char *so_name = NULL;
|
||||
FILE *fp = NULL;
|
||||
char line[4096];
|
||||
int rc = 0;
|
||||
size_t len;
|
||||
char *ch;
|
||||
|
||||
util_assert(plugin != NULL, "Internal error: plugin is NULL");
|
||||
util_assert(kms_functions != NULL,
|
||||
"Internal error: kms_functions is NULL");
|
||||
util_assert(plugin_lib != NULL, "Internal error: plugin_lib is NULL");
|
||||
util_assert(plugin_name != NULL, "Internal error: plugin_name is NULL");
|
||||
|
||||
fp = open_kms_plugins_file(verbose);
|
||||
if (fp == NULL)
|
||||
return -EIO;
|
||||
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
len = strlen(line);
|
||||
if (len < 1)
|
||||
continue;
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
ch = strchr(line, '=');
|
||||
if (ch == NULL) {
|
||||
rc = -EPERM;
|
||||
warnx("Syntax error in kms-plugins.conf. Line: '%s'",
|
||||
line);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*ch = '\0';
|
||||
ch++;
|
||||
|
||||
if (strcasecmp(line, plugin) == 0) {
|
||||
so_name = ch;
|
||||
*plugin_name = util_strdup(line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (so_name == NULL) {
|
||||
rc = -ENOENT;
|
||||
warnx("KMS plugin '%s' not found.", plugin);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_verbose(verbose, "Loading KMS plugin '%s': '%s'", *plugin_name,
|
||||
so_name);
|
||||
*plugin_lib = dlopen(so_name, RTLD_GLOBAL | RTLD_NOW);
|
||||
if (*plugin_lib == NULL) {
|
||||
pr_verbose(verbose, "%s", dlerror());
|
||||
warnx("Failed to load KMS plugin '%s': '%s'", *plugin_name,
|
||||
so_name);
|
||||
rc = -ELIBACC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
_kms_get_functions = (kms_get_functions_t)dlsym(*plugin_lib,
|
||||
"kms_get_functions");
|
||||
if (_kms_get_functions == NULL) {
|
||||
pr_verbose(verbose, "%s", dlerror());
|
||||
warnx("Failed to load KMS plugin '%s': '%s'", *plugin_name,
|
||||
so_name);
|
||||
rc = -ELIBACC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*kms_functions = _kms_get_functions();
|
||||
if (*kms_functions == NULL) {
|
||||
pr_verbose(verbose, "kms_get_functions() reutned NULL");
|
||||
warnx("Failed to load KMS plugin '%s': '%s'", *plugin_name,
|
||||
so_name);
|
||||
rc = -ELIBACC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_verbose(verbose, "Successfully loaded KMS plugin '%s': '%s' (API "
|
||||
"version: %u)", *plugin_name, so_name,
|
||||
(*kms_functions)->api_version);
|
||||
|
||||
out:
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
if (rc != 0 && *plugin_lib != NULL) {
|
||||
dlclose(*plugin_lib);
|
||||
*plugin_lib = NULL;
|
||||
}
|
||||
if (rc != 0 && *plugin_name != NULL) {
|
||||
free(*plugin_name);
|
||||
*plugin_name = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the kms.conf properties file that is located in the repository
|
||||
* directory. The returned properties object must be freed by the caller using
|
||||
* properties_free() when no longer needed.
|
||||
*
|
||||
* @param[in] repository the repository directory
|
||||
* @param[out] kms_props On return: a new properties object with the
|
||||
* properties read from kms.conf.
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
static int load_kms_properties(const char *repository,
|
||||
struct properties **kms_props, bool verbose)
|
||||
{
|
||||
struct properties *props = NULL;
|
||||
char *filename = NULL;
|
||||
int rc;
|
||||
|
||||
util_assert(repository != NULL, "Internal error: repository is NULL");
|
||||
util_assert(kms_props != NULL, "Internal error: kms_props is NULL");
|
||||
|
||||
util_asprintf(&filename, "%s/%s", repository, KMS_CONFIG_FILE);
|
||||
|
||||
pr_verbose(verbose, "Trying to load '%s'", filename);
|
||||
|
||||
props = properties_new();
|
||||
rc = properties_load(props, filename, true);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to load '%s': %s", filename,
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
*kms_props = props;
|
||||
|
||||
out:
|
||||
if (filename != NULL)
|
||||
free(filename);
|
||||
if (rc != 0)
|
||||
properties_free(props);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the kms.conf properties file that is located in the repository
|
||||
* directory.
|
||||
*
|
||||
* @param[in] keystore the keystore
|
||||
* @param[in] kms_props The properties object to save to kms.conf.
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
static int _save_kms_properties(const struct keystore *keystore,
|
||||
struct properties *kms_props, bool verbose)
|
||||
{
|
||||
char *filename = NULL;
|
||||
int rc;
|
||||
|
||||
util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
util_assert(kms_props != NULL, "Internal error: kms_props is NULL");
|
||||
|
||||
util_asprintf(&filename, "%s/%s", keystore->directory, KMS_CONFIG_FILE);
|
||||
|
||||
pr_verbose(verbose, "Saving '%s'", filename);
|
||||
|
||||
rc = properties_save(kms_props, filename, true);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to save '%s': %s", filename,
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chmod(filename, keystore->mode) != 0) {
|
||||
rc = -errno;
|
||||
warnx("chmod failed on file '%s': %s", filename, strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (chown(filename, geteuid(), keystore->owner) != 0) {
|
||||
rc = -errno;
|
||||
warnx("chown failed on file '%s': %s", filename, strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
out:
|
||||
if (filename != NULL)
|
||||
free(filename);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a KMS plugin is configured for the current repository, and if so,
|
||||
* load the KMS plugin.
|
||||
*
|
||||
* @param[out] kms_info Filled with information about the KMS plugin and
|
||||
* configuration. If no KMS plugin is configured,
|
||||
* all fields are set to NULL.
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
* Note: It is not an error case of no plugin is configured.
|
||||
*/
|
||||
int check_for_kms_plugin(struct kms_info *kms_info, bool verbose)
|
||||
{
|
||||
char *directory, *plugin = NULL;
|
||||
int rc;
|
||||
|
||||
util_assert(kms_info != NULL, "Internal error: kms_info is NULL");
|
||||
|
||||
memset(kms_info, 0, sizeof(*kms_info));
|
||||
|
||||
directory = getenv(ENVVAR_ZKEY_REPOSITORY);
|
||||
if (directory == NULL)
|
||||
directory = DEFAULT_KEYSTORE;
|
||||
|
||||
rc = load_kms_properties(directory, &kms_info->props, verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "No KMS plugin is configured");
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
plugin = properties_get(kms_info->props, KMS_CONFIG_PROP_KMS);
|
||||
if (plugin == NULL || strcasecmp(plugin, KMS_CONFIG_LOCAL) == 0) {
|
||||
pr_verbose(verbose, "No KMS plugin is configured");
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = load_kms_plugin(plugin, &kms_info->funcs, &kms_info->plugin_lib,
|
||||
&kms_info->plugin_name, verbose);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (plugin != NULL)
|
||||
free(plugin);
|
||||
if (rc != 0)
|
||||
free_kms_plugin(kms_info);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the KMS plugin.
|
||||
*
|
||||
* @param[in] kms_info The KMS Plugin info
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
int init_kms_plugin(struct kms_info *kms_info, bool verbose)
|
||||
{
|
||||
char *config_path = NULL;
|
||||
char **apqn_list = NULL;
|
||||
char *apqns = NULL;
|
||||
int i, rc = 0;
|
||||
|
||||
util_assert(kms_info != NULL, "Internal error: kms_info is NULL");
|
||||
|
||||
config_path = properties_get(kms_info->props,
|
||||
KMS_CONFIG_PROP_KMS_CONFIG);
|
||||
if (config_path == NULL) {
|
||||
warnx("Incomplete KMS configuration");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kms_info->funcs->kms_initialize != NULL) {
|
||||
kms_info->handle = kms_info->funcs->kms_initialize(config_path,
|
||||
verbose);
|
||||
if (kms_info->handle == NULL) {
|
||||
warnx("KMS plugin '%s' failed to initialize",
|
||||
kms_info->plugin_name);
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
apqns = properties_get(kms_info->props, KMS_CONFIG_PROP_APQNS);
|
||||
if (apqns != NULL && strlen(apqns) > 0) {
|
||||
apqn_list = str_list_split(apqns);
|
||||
for (i = 0; apqn_list[i] != NULL; i++)
|
||||
;
|
||||
kms_info->num_apqns = i;
|
||||
kms_info->apqns = util_malloc(i * sizeof(struct kms_apqn));
|
||||
for (i = 0; apqn_list[i] != NULL; i++) {
|
||||
if (sscanf(apqn_list[i], "%hx.%hx",
|
||||
&kms_info->apqns[i].card,
|
||||
&kms_info->apqns[i].domain) != 2) {
|
||||
warnx("The APQN '%s' is not valid",
|
||||
apqn_list[i]);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (config_path != NULL)
|
||||
free(config_path);
|
||||
if (apqns != NULL)
|
||||
free(apqns);
|
||||
if (apqn_list != NULL)
|
||||
str_list_free_string_array(apqn_list);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates, free and close a KMS plugin
|
||||
*
|
||||
* @param[in] kms_info The KMS Plugin info to free
|
||||
*/
|
||||
void free_kms_plugin(struct kms_info *kms_info)
|
||||
{
|
||||
if (kms_info == NULL)
|
||||
return;
|
||||
|
||||
if (kms_info->handle != NULL && kms_info->funcs != NULL &&
|
||||
kms_info->funcs->kms_terminate != NULL)
|
||||
kms_info->funcs->kms_terminate(kms_info->handle);
|
||||
kms_info->handle = NULL;
|
||||
|
||||
if (kms_info->props != NULL)
|
||||
properties_free(kms_info->props);
|
||||
kms_info->props = NULL;
|
||||
|
||||
if (kms_info->plugin_lib != NULL)
|
||||
dlclose(kms_info->plugin_lib);
|
||||
kms_info->plugin_lib = NULL;
|
||||
kms_info->funcs = NULL;
|
||||
|
||||
if (kms_info->plugin_name != NULL)
|
||||
free(kms_info->plugin_name);
|
||||
kms_info->plugin_name = NULL;
|
||||
|
||||
if (kms_info->apqns != NULL)
|
||||
free(kms_info->apqns);
|
||||
kms_info->apqns = NULL;
|
||||
kms_info->num_apqns = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the error message from the KMS plugin's last error
|
||||
*/
|
||||
void print_last_kms_error(const struct kms_info *kms_info)
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
if (kms_info == NULL || kms_info->funcs == NULL ||
|
||||
kms_info->funcs->kms_get_last_error == NULL ||
|
||||
kms_info->handle == NULL)
|
||||
return;
|
||||
|
||||
msg = kms_info->funcs->kms_get_last_error(kms_info->handle);
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
util_print_indented(msg, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the specified KMS plugin to the current repository.
|
||||
* If the repository is already bound to a KMS plugin, then -EALREADY is
|
||||
* returned.
|
||||
*
|
||||
* @param[in] keystore the keystore to bind to the plugin
|
||||
* @param[in] plugin the name of the KMS plugin to bind
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
int bind_kms_plugin(struct keystore *keystore, const char *plugin,
|
||||
bool verbose)
|
||||
{
|
||||
char *directory, *config_dir = NULL;
|
||||
const struct kms_functions *funcs;
|
||||
struct properties *props = NULL;
|
||||
char *plugin_name = NULL;
|
||||
void *plugin_lib = NULL;
|
||||
bool created = false;
|
||||
int rc;
|
||||
|
||||
util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
util_assert(plugin != NULL, "Internal error: plugin is NULL");
|
||||
|
||||
rc = load_kms_properties(keystore->directory, &props, verbose);
|
||||
if (rc == 0) {
|
||||
plugin_name = properties_get(props, KMS_CONFIG_PROP_KMS);
|
||||
if (plugin_name != NULL &&
|
||||
strcasecmp(plugin_name, KMS_CONFIG_LOCAL) != 0) {
|
||||
warnx("The repository is already bound to KMS plugin "
|
||||
"'%s'", plugin_name);
|
||||
rc = -EALREADY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
properties_free(props);
|
||||
props = NULL;
|
||||
}
|
||||
|
||||
rc = load_kms_plugin(plugin, &funcs, &plugin_lib, &plugin_name,
|
||||
verbose);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
directory = getenv(ENVVAR_ZKEY_REPOSITORY);
|
||||
if (directory == NULL)
|
||||
directory = DEFAULT_KEYSTORE;
|
||||
util_asprintf(&config_dir, "%s/%s", directory, plugin_name);
|
||||
pr_verbose(verbose, "Plugin config dir: '%s'", config_dir);
|
||||
|
||||
rc = mkdir(config_dir, keystore->mode);
|
||||
if (rc != 0) {
|
||||
rc = -errno;
|
||||
warnx("Failed to create directory '%s': %s", config_dir,
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
created = true;
|
||||
|
||||
if (chmod(config_dir, keystore->mode) != 0) {
|
||||
rc = -errno;
|
||||
warnx("chmod failed on directory '%s': %s", config_dir,
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (chown(config_dir, geteuid(), keystore->owner) != 0) {
|
||||
rc = -errno;
|
||||
warnx("chown failed on directory '%s': %s", config_dir,
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (funcs->kms_bind != NULL) {
|
||||
rc = funcs->kms_bind(config_dir);
|
||||
if (rc != 0) {
|
||||
warnx("KMS plugin '%s' failed to bind to the "
|
||||
"repository: %s", plugin_name, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
props = properties_new();
|
||||
rc = properties_set(props, KMS_CONFIG_PROP_KMS, plugin_name);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = properties_set(props, KMS_CONFIG_PROP_KMS_CONFIG, config_dir);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = _save_kms_properties(keystore, props, verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to save kms.conf into repository directory");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (plugin_name != NULL)
|
||||
free(plugin_name);
|
||||
if (props != NULL)
|
||||
properties_free(props);
|
||||
if (plugin_lib != NULL)
|
||||
dlclose(plugin_lib);
|
||||
if (config_dir != NULL) {
|
||||
if (rc != 0 && created)
|
||||
rmdir(config_dir);
|
||||
free(config_dir);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a directory and all its contents.
|
||||
*/
|
||||
static int remove_directory_recursively(const char *directory)
|
||||
{
|
||||
char *filename = NULL;
|
||||
struct dirent *de;
|
||||
DIR *dirp;
|
||||
int rc = 0;
|
||||
|
||||
dirp = opendir(directory);
|
||||
if (dirp == NULL) {
|
||||
rc = -errno;
|
||||
warnx("Failed to open directory '%s'", directory);
|
||||
return rc;
|
||||
}
|
||||
|
||||
while ((de = readdir(dirp))) {
|
||||
util_asprintf(&filename, "%s/%s", directory, de->d_name);
|
||||
if (de->d_type == DT_DIR) {
|
||||
if (strcmp(de->d_name, ".") != 0 &&
|
||||
strcmp(de->d_name, "..") != 0)
|
||||
rc = remove_directory_recursively(filename);
|
||||
} else {
|
||||
rc = remove(filename);
|
||||
if (rc != 0) {
|
||||
rc = -errno;
|
||||
warnx("Failed to remove '%s': %s", filename,
|
||||
strerror(-rc));
|
||||
}
|
||||
}
|
||||
free(filename);
|
||||
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
closedir(dirp);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
if (rmdir(directory) != 0) {
|
||||
rc = -errno;
|
||||
warnx("Failed to remove '%s': %s", filename, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbinds the currently bound KMS plugin from the current repository.
|
||||
* If the repository is not bound to a KMS plugin, then -ENOENT is
|
||||
* returned.
|
||||
*
|
||||
* @param[in] kms_info information of the currently bound plugin.
|
||||
* This function does NOT free the plugin, this must
|
||||
* be done by the caller using free_kms_plugin().
|
||||
* @param[in] keystore the keystore to bind to the plugin
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error.
|
||||
*/
|
||||
int unbind_kms_plugin(struct kms_info *kms_info, struct keystore *keystore,
|
||||
bool UNUSED(verbose))
|
||||
{
|
||||
char *config_dir = NULL;
|
||||
char *filename = NULL;
|
||||
int rc;
|
||||
|
||||
util_assert(kms_info != NULL, "Internal error: kms_info is NULL");
|
||||
util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
|
||||
if (kms_info->plugin_lib == NULL) {
|
||||
rc = -ENOENT;
|
||||
warnx("The repository is not bound to a KMS plugin");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kms_info->funcs->kms_deconfigure != NULL &&
|
||||
kms_info->handle != NULL) {
|
||||
rc = kms_info->funcs->kms_deconfigure(kms_info->handle);
|
||||
if (rc != 0) {
|
||||
warnx("KMS plugin '%s' failed to unbind from the "
|
||||
"repository: %s", kms_info->plugin_name,
|
||||
strerror(-rc));
|
||||
print_last_kms_error(kms_info);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
config_dir = properties_get(kms_info->props,
|
||||
KMS_CONFIG_PROP_KMS_CONFIG);
|
||||
if (config_dir != NULL) {
|
||||
rc = remove_directory_recursively(config_dir);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to remove the KMS plugin's config "
|
||||
"directory: %s", strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
util_asprintf(&filename, "%s/%s", keystore->directory, KMS_CONFIG_FILE);
|
||||
rc = remove(filename);
|
||||
if (rc != 0) {
|
||||
rc = -errno;
|
||||
warnx("Failed to remove '%s': %s", filename, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (config_dir != NULL)
|
||||
free(config_dir);
|
||||
if (filename != NULL)
|
||||
free(filename);
|
||||
return rc;
|
||||
}
|
||||
46
zkey/kms.h
Normal file
46
zkey/kms.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* zkey - Generate, re-encipher, and validate secure keys
|
||||
*
|
||||
* This header file defines functions for Key Management System (KMS) plugin
|
||||
* handling
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* 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 KMS_H
|
||||
#define KMS_H
|
||||
|
||||
#include "kms-plugin.h"
|
||||
#include "properties.h"
|
||||
#include "keystore.h"
|
||||
|
||||
struct kms_info {
|
||||
void *plugin_lib;
|
||||
const struct kms_functions *funcs;
|
||||
char *plugin_name;
|
||||
struct properties *props;
|
||||
struct kms_apqn *apqns;
|
||||
size_t num_apqns;
|
||||
kms_handle_t handle;
|
||||
};
|
||||
|
||||
int list_kms_plugins(bool verbose);
|
||||
|
||||
int check_for_kms_plugin(struct kms_info *kms_info, bool verbose);
|
||||
|
||||
int init_kms_plugin(struct kms_info *kms_info, bool verbose);
|
||||
|
||||
void free_kms_plugin(struct kms_info *kms_info);
|
||||
|
||||
void print_last_kms_error(const struct kms_info *kms_info);
|
||||
|
||||
int bind_kms_plugin(struct keystore *keystore, const char *plugin,
|
||||
bool verbose);
|
||||
|
||||
int unbind_kms_plugin(struct kms_info *kms_info, struct keystore *keystore,
|
||||
bool verbose);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user