zkey-kmip: Add support for KMIP server profiles

KMIP server profiles (not to be confused with profiles defined by
the KMIP standard) define how the KMIP plugin talks to the KMIP
server. Profiles can be used to configure certain KMIP usages for
certain KMIP servers.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2021-05-26 15:03:35 +02:00
committed by Jan Höppner
parent 52b6e57743
commit a2359dbe5f
6 changed files with 902 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ libs = $(rootdir)/libutil/libutil.a $(rootdir)/libseckey/libseckey.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
profiles.o: profiles.c zkey-kmip.h ../properties.h
plugin-utils.o: ../plugin-utils.c ../plugin-utils.h ../kms-plugin.h
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
@@ -34,7 +35,7 @@ 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)
utils.o profiles.o $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
install-libkmipclient.dep:
@@ -48,6 +49,9 @@ 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
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/kmip
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/kmip/profiles
$(INSTALL) -m 644 -c profiles/*.profile $(DESTDIR)$(SYSCONFDIR)/zkey/kmip/profiles
clean:
rm -f *.o zkey-kmip.so install-libkmipclient.dep libkmipclient.dep

596
zkey/kmip/profiles.c Normal file
View File

@@ -0,0 +1,596 @@
/*
* 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.
*/
#define _DEFAULT_SOURCE
#include <dirent.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <regex.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#include "lib/zt_common.h"
#include "lib/util_libc.h"
#include "zkey-kmip.h"
#include "../properties.h"
#define _set_error(ph, fmt...) plugin_set_error(&(ph)->pd, fmt)
/**
* Returns the profile directory. If environment variable ZKEY_KMIP_PROFILES
* is set, then its value specifies the profile directory, otherwise the
* default profile directory '/etc/zkey/kmip/profiles' is returned.
*/
static const char *get_profiles_directory(void)
{
const char *dir;
dir = secure_getenv(KMIP_PROFILES_LOCATION_ENVVAR);
return dir != NULL ? dir : KMIP_PROFILES_LOCATION;
}
static int profile_get_bool(struct plugin_handle *ph, struct properties *props,
const char *file_name, const char *prop_name,
bool default_val, bool *bool_var)
{
int rc = 0;
char *val;
val = properties_get(props, prop_name);
if (val == NULL) {
*bool_var = default_val;
goto ret;
}
if (strcasecmp(val, KMIP_PROFILES_BOOLEAN_FALSE) == 0) {
*bool_var = false;
} else if (strcasecmp(val, KMIP_PROFILES_BOOLEAN_TRUE) == 0) {
*bool_var = true;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': '%s'",
file_name, prop_name,
val);
rc = -EINVAL;
goto out;
}
out:
free(val);
ret:
if (rc == 0)
pr_verbose(&ph->pd, "Profile: '%s': '%s'", prop_name,
*bool_var ? "True" : "False");
return rc;
}
/**
* Reads a profile from a file
*
* @param ph the plugin handle
* @param profile_dir the directory containing the profiles. If NULL, then
* the default profile directory or the one specified
* by environment variable ZKEY_KMIP_PROFILES is used.
* @param profile_file name of the profile file to read
* @param profile On return: the allocated profile. The caller must
* free the profile with profile_free.
*
* @returns 0 on success, a negative errno in case of an error.
*/
int profile_read(struct plugin_handle *ph, const char *profile_dir,
const char *profile_file, struct kmip_profile **profile)
{
struct kmip_profile *prof = NULL;
struct properties *props;
char *file_name = NULL;
char *val = NULL, *tok;
int rc;
if (profile_dir == NULL)
profile_dir = get_profiles_directory();
util_asprintf(&file_name, "%s/%s", profile_dir, profile_file);
pr_verbose(&ph->pd, "Read profile from '%s'", file_name);
props = properties_new();
rc = properties_load(props, file_name, false);
if (rc != 0) {
_set_error(ph, "Failed to read profile from file '%s': %s",
file_name, strerror(-rc));
goto out;
}
prof = util_zalloc(sizeof(struct kmip_profile));
tok = strrchr(profile_file, '/');
if (tok == NULL)
tok = (char *)profile_file;
prof->name = util_strdup(tok);
tok = strchr(prof->name, '.');
if (tok != NULL)
*tok = 0;
pr_verbose(&ph->pd, "Profile name: '%s'", prof->name);
prof->server_regex = properties_get(props, KMIP_PROFILES_SERVER_REGEX);
if (prof->server_regex == NULL) {
_set_error(ph, "Profile '%s': Missing value for '%s'",
file_name, KMIP_PROFILES_SERVER_REGEX);
rc = -EINVAL;
goto out;
}
pr_verbose(&ph->pd, "Profile: '%s': '%s'", KMIP_PROFILES_SERVER_REGEX,
prof->server_regex);
val = properties_get(props, KMIP_PROFILES_KMIP_VERSION);
if (val == NULL)
val = util_strdup(KMIP_PROFILES_VERSION_AUTO);
pr_verbose(&ph->pd, "Profile: '%s': '%s'", KMIP_PROFILES_KMIP_VERSION,
val);
if (strcasecmp(val, KMIP_PROFILES_VERSION_AUTO) == 0) {
prof->kmip_version.major = 0;
prof->kmip_version.minor = 0;
} else {
if (sscanf(val, "%u.%u", &prof->kmip_version.major,
&prof->kmip_version.minor) != 2) {
_set_error(ph, "Profile '%s': Invalid value for '%s': "
"'%s'", file_name,
KMIP_PROFILES_KMIP_VERSION, val);
rc = -EINVAL;
goto out;
}
if (prof->kmip_version.major == 0) {
_set_error(ph, "Profile '%s': Invalid value for '%s': "
"'%s'", file_name,
KMIP_PROFILES_KMIP_VERSION, val);
rc = -EINVAL;
goto out;
}
}
free(val);
val = properties_get(props, KMIP_PROFILES_TRANSPORT);
if (val == NULL)
val = util_strdup(KMIP_PROFILES_TRANSPORT_TLS);
pr_verbose(&ph->pd, "Profile: '%s': '%s'", KMIP_PROFILES_TRANSPORT,
val);
if (strcasecmp(val, KMIP_PROFILES_TRANSPORT_TLS) == 0) {
prof->transport = KMIP_TRANSPORT_PLAIN_TLS;
} else if (strcasecmp(val, KMIP_PROFILES_TRANSPORT_HTTPS) == 0) {
prof->transport = KMIP_TRANSPORT_HTTPS;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': '%s'",
file_name, KMIP_PROFILES_TRANSPORT, val);
rc = -EINVAL;
goto out;
}
free(val);
val = properties_get(props, KMIP_PROFILES_ENCODING);
if (val == NULL)
val = util_strdup(KMIP_PROFILES_ENCODING_TTLV);
pr_verbose(&ph->pd, "Profile: '%s': '%s'", KMIP_PROFILES_ENCODING,
val);
if (strcasecmp(val, KMIP_PROFILES_ENCODING_TTLV) == 0) {
prof->encoding = KMIP_ENCODING_TTLV;
} else if (strcasecmp(val, KMIP_PROFILES_ENCODING_JSON) == 0) {
if (prof->transport != KMIP_TRANSPORT_HTTPS) {
_set_error(ph, "Profile '%s': JSON encoding is only "
"possible with HTTP transport",
file_name);
rc = -EINVAL;
goto out;
}
prof->encoding = KMIP_ENCODING_JSON;
} else if (strcasecmp(val, KMIP_PROFILES_ENCODING_XML) == 0) {
prof->encoding = KMIP_ENCODING_XML;
if (prof->transport != KMIP_TRANSPORT_HTTPS) {
_set_error(ph, "Profile '%s': XML encoding is only "
"possible with HTTP transport",
file_name);
rc = -EINVAL;
goto out;
}
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': '%s'",
file_name, KMIP_PROFILES_ENCODING, val);
rc = -EINVAL;
goto out;
}
free(val);
val = properties_get(props, KMIP_PROFILES_HTTPS_URI);
switch (prof->transport) {
case KMIP_TRANSPORT_HTTPS:
if (val == NULL)
val = util_strdup(KMIP_PROFILES_HTTPS_URI_DEFAULT);
prof->https_uri = val;
pr_verbose(&ph->pd, "Profile: '%s': '%s'",
KMIP_PROFILES_HTTPS_URI, prof->https_uri);
break;
default:
if (val != NULL) {
pr_verbose(&ph->pd, "Profile: '%s': ignored '%s'",
KMIP_PROFILES_HTTPS_URI, val);
free(val);
}
break;
}
val = properties_get(props, KMIP_PROFILES_AUTH_SCHEME);
if (val == NULL)
val = util_strdup(KMIP_PROFILES_AUTH_TLS_CLIENT_CERT);
pr_verbose(&ph->pd, "Profile: '%s': '%s'", KMIP_PROFILES_AUTH_SCHEME,
val);
if (strcasecmp(val, KMIP_PROFILES_AUTH_TLS_CLIENT_CERT) == 0) {
prof->auth_scheme = KMIP_PROFILE_AUTH_TLS_CLIENT_CERT;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': '%s'",
file_name, KMIP_PROFILES_AUTH_SCHEME, val);
rc = -EINVAL;
goto out;
}
free(val);
val = properties_get(props, KMIP_PROFILES_WRAP_KEY_ALGORITHM);
if (val == NULL)
val = util_strdup(KMIP_PROFILES_WRAP_KEY_ALGORITHM_RSA);
pr_verbose(&ph->pd, "Profile: '%s': '%s'",
KMIP_PROFILES_WRAP_KEY_ALGORITHM, val);
if (strcasecmp(val, KMIP_PROFILES_WRAP_KEY_ALGORITHM_RSA) == 0) {
prof->wrap_key_algo = KMIP_CRYPTO_ALGO_RSA;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': '%s'",
file_name, KMIP_PROFILES_WRAP_KEY_ALGORITHM, val);
rc = -EINVAL;
goto out;
}
free(val);
val = properties_get(props, KMIP_PROFILES_WRAP_KEY_PARAMS);
if (prof->wrap_key_algo == KMIP_CRYPTO_ALGO_RSA) {
if (val == NULL) {
_set_error(ph, "Profile '%s': Missing value for '%s'",
file_name, KMIP_PROFILES_WRAP_KEY_PARAMS);
rc = -EINVAL;
goto out;
}
pr_verbose(&ph->pd, "Profile: '%s': '%s'",
KMIP_PROFILES_WRAP_KEY_PARAMS, val);
prof->wrap_key_size = atoi(val);
if (prof->wrap_key_size == 0) {
_set_error(ph, "Profile '%s': Invalid value for '%s' "
"(RSA modulus size): '%s'", file_name,
KMIP_PROFILES_WRAP_KEY_PARAMS, val);
rc = -EINVAL;
goto out;
}
} else if (val != NULL) {
pr_verbose(&ph->pd, "Profile: '%s': ignored '%s'",
KMIP_PROFILES_WRAP_KEY_PARAMS, val);
}
free(val);
val = properties_get(props, KMIP_PROFILES_WRAP_KEY_FORMAT);
switch (prof->wrap_key_algo) {
case KMIP_CRYPTO_ALGO_RSA:
if (val == NULL)
val = util_strdup(KMIP_PROFILES_WRAP_KEY_FORMAT_PKCS1);
pr_verbose(&ph->pd, "Profile: '%s': '%s'",
KMIP_PROFILES_WRAP_KEY_FORMAT, val);
if (strcasecmp(val, KMIP_PROFILES_WRAP_KEY_FORMAT_PKCS1) == 0) {
prof->wrap_key_format = KMIP_KEY_FORMAT_TYPE_PKCS_1;
} else if (strcasecmp(val,
KMIP_PROFILES_WRAP_KEY_FORMAT_PKCS8) == 0) {
prof->wrap_key_format = KMIP_KEY_FORMAT_TYPE_PKCS_8;
} else if (strcasecmp(val,
KMIP_PROFILES_WRAP_KEY_FORMAT_TRANSP) == 0) {
prof->wrap_key_format =
KMIP_KEY_FORMAT_TYPE_TRANSPARENT_RSA_PUBLIC_KEY;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': "
"'%s'", file_name,
KMIP_PROFILES_WRAP_KEY_FORMAT, val);
rc = -EINVAL;
goto out;
}
break;
default:
if (val != NULL)
pr_verbose(&ph->pd, "Profile: '%s': ignored '%s'",
KMIP_PROFILES_WRAP_KEY_FORMAT, val);
break;
}
free(val);
val = properties_get(props, KMIP_PROFILES_WRAP_PADDING_METHOD);
switch (prof->wrap_key_algo) {
case KMIP_CRYPTO_ALGO_RSA:
if (val == NULL)
val = util_strdup(KMIP_PROFILES_WRAP_PADDING_PKCS1_5);
pr_verbose(&ph->pd, "Profile: '%s': '%s'",
KMIP_PROFILES_WRAP_PADDING_METHOD, val);
if (strcasecmp(val, KMIP_PROFILES_WRAP_PADDING_PKCS1_5) == 0) {
prof->wrap_padding_method =
KMIP_PADDING_METHOD_PKCS_1_5;
} else if (strcasecmp(val,
KMIP_PROFILES_WRAP_PADDING_OAEP) == 0) {
prof->wrap_padding_method = KMIP_PADDING_METHOD_OAEP;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': "
"'%s'", file_name,
KMIP_PROFILES_WRAP_PADDING_METHOD, val);
rc = -EINVAL;
goto out;
}
break;
default:
if (val != NULL)
pr_verbose(&ph->pd, "Profile: '%s': ignored '%s'",
KMIP_PROFILES_WRAP_PADDING_METHOD, val);
break;
}
free(val);
val = properties_get(props, KMIP_PROFILES_WRAP_HASHING_ALOGRITHM);
switch (prof->wrap_padding_method) {
case KMIP_PADDING_METHOD_OAEP:
if (val == NULL)
val = util_strdup(KMIP_PROFILES_WRAP_HASHING_ALGO_SHA1);
pr_verbose(&ph->pd, "Profile: '%s': '%s'",
KMIP_PROFILES_WRAP_HASHING_ALOGRITHM, val);
if (strcasecmp(val,
KMIP_PROFILES_WRAP_HASHING_ALGO_SHA1) == 0) {
prof->wrap_hashing_algo = KMIP_HASHING_ALGO_SHA_1;
} else if (strcasecmp(val,
KMIP_PROFILES_WRAP_HASHING_ALGO_SHA256) == 0) {
prof->wrap_hashing_algo = KMIP_HASHING_ALGO_SHA_256;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': "
"'%s'", file_name,
KMIP_PROFILES_WRAP_PADDING_METHOD, val);
rc = -EINVAL;
goto out;
}
break;
default:
if (val != NULL)
pr_verbose(&ph->pd, "Profile: '%s': ignored '%s'",
KMIP_PROFILES_WRAP_HASHING_ALOGRITHM, val);
break;
}
free(val);
rc = profile_get_bool(ph, props, file_name,
KMIP_PROFILES_SUPPORTS_LINK_ATTR, false,
&prof->supports_link_attr);
if (rc != 0)
goto out;
rc = profile_get_bool(ph, props, file_name,
KMIP_PROFILES_SUPPORTS_DESCRIPTION_ATTR, false,
&prof->supports_description_attr);
if (rc != 0)
goto out;
rc = profile_get_bool(ph, props, file_name,
KMIP_PROFILES_SUPPORTS_COMMENT_ATTR, false,
&prof->supports_comment_attr);
if (rc != 0)
goto out;
val = properties_get(props, KMIP_PROFILES_CUSTOM_ATTR_SCHEME);
if (val == NULL)
val = util_strdup(KMIP_PROFILES_CUST_ATTR_SCHEME_V1);
pr_verbose(&ph->pd, "Profile: '%s': '%s'",
KMIP_PROFILES_CUSTOM_ATTR_SCHEME, val);
if (strcasecmp(val, KMIP_PROFILES_CUST_ATTR_SCHEME_V1) == 0) {
prof->cust_attr_scheme = KMIP_PROFILE_CUST_ATTR_V1_STYLE;
} else if (strcasecmp(val, KMIP_PROFILES_CUST_ATTR_SCHEME_V2) == 0) {
prof->cust_attr_scheme = KMIP_PROFILE_CUST_ATTR_V2_STYLE;
} else {
_set_error(ph, "Profile '%s': Invalid value for '%s': '%s'",
file_name, KMIP_PROFILES_CUSTOM_ATTR_SCHEME, val);
rc = -EINVAL;
goto out;
}
free(val);
rc = profile_get_bool(ph, props, file_name,
KMIP_PROFILES_SUPPORTS_SENSITIVE_ATTR, false,
&prof->supports_sensitive_attr);
if (rc != 0)
goto out;
rc = profile_get_bool(ph, props, file_name,
KMIP_PROFILES_CHECK_ALWAYS_SENS_ATTR, false,
&prof->check_always_sensitive_attr);
if (rc != 0)
goto out;
val = NULL;
out:
properties_free(props);
if (file_name != NULL)
free(file_name);
if (val != NULL)
free(val);
if (rc != 0)
profile_free(prof);
else
*profile = prof;
return rc;
}
/**
* Frees a profile
*
* @param profile On return: the allocated profile
*
* @returns 0 on success, a negative errno in case of an error.
*/
void profile_free(struct kmip_profile *profile)
{
if (profile == NULL)
return;
if (profile->name != NULL)
free((char *)profile->name);
if (profile->server_regex != NULL)
free((char *)profile->server_regex);
if (profile->https_uri != NULL)
free((char *)profile->https_uri);
free(profile);
}
/**
* Filters directory entries for scanfile(). Only entries that are regular
* files and who's name ends with '.info' are matched.
*/
static int profile_file_filter(const struct dirent *dirent)
{
size_t len;
if (dirent->d_type != DT_REG && dirent->d_type != DT_UNKNOWN)
return 0;
len = strlen(dirent->d_name);
if (len > KMIP_PROFILES_FILE_TYPE_LEN &&
strcmp(&dirent->d_name[len - KMIP_PROFILES_FILE_TYPE_LEN],
KMIP_PROFILES_FILE_TYPE) == 0)
return 1;
return 0;
}
/**
* Scans the default profile directory or the one specified by environment
* variable ZKEY_KMIP_PROFILES for profiles that match the server info.
* Returns the first profile that matches, or the default profile if none
* matches.
*
* @param ph the plugin handle
* @param server_info the server info string to match the profiles against
* @param profile On return: the matched profile. The caller must free
* the profile with profile_free.
*
* @returns 0 on success, a negative errno in case of an error.
*/
int profile_find_by_server_info(struct plugin_handle *ph,
const char *server_info,
struct kmip_profile **profile)
{
struct kmip_profile *prof = NULL;
struct dirent **namelist;
const char *profile_dir;
regmatch_t pmatch[1];
char err_buf[256];
int i, n, rc = 0;
regex_t reg_buf;
profile_dir = get_profiles_directory();
pr_verbose(&ph->pd, "profile_dir: %s", profile_dir);
n = scandir(profile_dir, &namelist, profile_file_filter, alphasort);
if (n < 0) {
rc = -errno;
pr_verbose(&ph->pd, "scandir failed with: %s", strerror(-rc));
return rc;
}
for (i = 0; i < n; i++) {
if (strcmp(namelist[i]->d_name,
KMIP_PROFILES_DEFAULT_PROFILE) == 0)
continue;
pr_verbose(&ph->pd, "Found profile '%s'", namelist[i]->d_name);
rc = profile_read(ph, profile_dir, namelist[i]->d_name, &prof);
if (rc != 0) {
pr_verbose(&ph->pd, "profile_read failed with: %s",
strerror(-rc));
goto out;
}
rc = regcomp(&reg_buf, prof->server_regex, REG_EXTENDED);
if (rc != 0) {
regerror(rc, &reg_buf, err_buf, sizeof(err_buf));
_set_error(ph, "Profile '%s': Regular expression "
"error: '%s'", namelist[i]->d_name, err_buf);
rc = -EINVAL;
goto out;
}
rc = regexec(&reg_buf, server_info, (size_t)1, pmatch, 0);
regfree(&reg_buf);
if (rc == 0)
break;
profile_free(prof);
prof = NULL;
}
if (prof == NULL) {
rc = profile_read(ph, profile_dir,
KMIP_PROFILES_DEFAULT_PROFILE, &prof);
if (rc != 0) {
pr_verbose(&ph->pd, "default profile_read failed with: "
"%s", strerror(-rc));
goto out;
}
}
*profile = prof;
out:
for (i = 0; i < n; i++)
free(namelist[i]);
free(namelist);
return rc;
}
/**
* Reads a profile by its name. Tries to find a profile with the specified name
* in the default profile directory or the one specified by environment
* variable ZKEY_KMIP_PROFILES and loads it.
*
* @param ph the plugin handle
* @param profile_name name of the profile to read
* @param profile On return: the allocated profile. The caller must
* free the profile with profile_free.
*
* @returns 0 on success, a negative errno in case of an error.
*/
int profile_find_by_name(struct plugin_handle *ph, const char *profile_name,
struct kmip_profile **profile)
{
char *profile_file;
int rc;
util_asprintf(&profile_file, "%s%s", profile_name,
KMIP_PROFILES_FILE_TYPE);
rc = profile_read(ph, NULL, profile_file, profile);
free(profile_file);
return rc;
}

View File

@@ -0,0 +1,68 @@
# KMIP server profile for IBM-GDE (IBM Security Guardium Data Encryption).
# Regular expression to match the KMIP server information obtained from the
# KMIP server via the QUERY request.
server-regex=Vormetric.*
# KMIP protocol version to use. Either major.minor, or AUTO. AUTO means that
# the supported KMIP protocol version is automatically discovered using the
# DISCOVER VERSIONS request.
kmip-version=2.1
# Transport method for the KMIP protocol: TLS or HTTPS
transport=TLS
# Encoding method for the KMIP protocol: TTLV, JSON or XML.
# JSON and XML are only posisble with HTTPS transport.
encoding=TTLV
# URI used for HTTPS transport. Can be overridden by user via --kmip-server
# option. Ignored if not HTTPS transport.
https-uri=/kmip
# Authentication scheme. Currently only TLS client authentication is supported.
auth-scheme=TLSClientCert
# Key wrapping algorithm for retrieving keys from the KMIP server.
# Currently only RSA is supported.
wrap-key-algorithm=RSA
# For RSA key wrapping: the modulus size of the RSA key: 512, 1024, 2048, 4096
wrap-key-params=4096
# Format used to register the public wrapping key with the KMIP server.
# For RSA: PKCS1, PKCS8, TransparentPublicKey
wrap-key-format=PKCS1
# Padding method used with key wrapping.
# For RSA: PKCS1.5 or OAEP
wrap-padding-method=OAEP
# Hashing algorithm used with key wrapping.
# For RSA with OAEP: SHA-1 or SHA-256
wrap-hashing-algorithm=SHA-1
# KMIP server supports 'Link' attribute. If TRUE, use to link the 2 keys of an
# XTS key together.
supports-link-attr=TRUE
# KMIP server supports 'Description' attribute.
supports-description-attr=TRUE
# KMIP server supports 'Comment' attribute.
supports-comment-attr=TRUE
# Custom/Vendor attribute usage for KMIP v2.x servers.
# V1-style means to set 'Vendor Identifier' to 'x', and 'Attribute Name' to
# 'zkey-<something>'. This coresponds to the KMIP v1.x Custom attribute style.
# V2-style means to set 'Vendor Identifier' to 'zkey', and 'Attribute Name' to
# '<something>'.
custom-attr-scheme=v1-style
# KMIP server supports 'Sensitive' attribute. If TRUE, all keys are generated
# with Sensitive=True to prevent the key from being retrieved in clear.
supports-sensitive-attr=TRUE
# KMIP server supports 'Always Sensitive' attribute and it is checked to be
# True for all keys retrieved by the zkey-kmip plugin.
check-always-sensitive-attr=TRUE

View File

@@ -0,0 +1,71 @@
# KMIP server profile for IBM-GKLM (IBM Security Guardium Key Lifecycle Manager,
# formerly SKLM).
# Regular expression to match the KMIP server information obtained from the
# KMIP server via the QUERY request. GKLM identifies itself with a string like:
# 'SKLM 4.1.0.1 KMIP 2.0 BUILD 202103261314 KMIP_SSL_TIMEOUT 5'
# Also check the version to be 4.1.x or later.
server-regex=(SKLM|GKLM) (4\.[1-9]\.|[5..9]\.\d*.).*
# KMIP protocol version to use. Either major.minor, or AUTO. AUTO means that
# the supported KMIP protocol version is automatically discovered using the
# DISCOVER VERSIONS request.
kmip-version=2.1
# Transport method for the KMIP protocol: TLS or HTTPS
transport=TLS
# Encoding method for the KMIP protocol: TTLV, JSON or XML.
# JSON and XML are only posisble with HTTPS transport.
encoding=TTLV
# URI used for HTTPS transport. Can be overridden by user via --kmip-server
# option. Ignored if not HTTPS transport.
https-uri=/kmip
# Authentication scheme. Currently only TLS client authentication is supported.
auth-scheme=TLSClientCert
# Key wrapping algorithm for retrieving keys from the KMIP server.
# Currently only RSA is supported.
wrap-key-algorithm=RSA
# For RSA key wrapping: the modulus size of the RSA key: 512, 1024, 2048, 4096
wrap-key-params=4096
# Format used to register the public wrapping key with the KMIP server.
# For RSA: PKCS1, PKCS8, TransparentPublicKey
wrap-key-format=PKCS1
# Padding method used with key wrapping.
# For RSA: PKCS1.5 or OAEP
wrap-padding-method=OAEP
# Hashing algorithm used with key wrapping.
# For RSA with OAEP: SHA-1 or SHA-256
wrap-hashing-algorithm=SHA-1
# KMIP server supports 'Link' attribute. If TRUE, use to link the 2 keys of an
# XTS key together.
supports-link-attr=TRUE
# KMIP server supports 'Description' attribute.
supports-description-attr=FALSE
# KMIP server supports 'Comment' attribute.
supports-comment-attr=FALSE
# Custom/Vendor attribute usage for KMIP v2.x servers.
# V1-style means to set 'Vendor Identifier' to 'x', and 'Attribute Name' to
# 'zkey-<something>'. This coresponds to the KMIP v1.x Custom attribute style.
# V2-style means to set 'Vendor Identifier' to 'zkey', and 'Attribute Name' to
# '<something>'.
custom-attr-scheme=v1-style
# KMIP server supports 'Sensitive' attribute. If TRUE, all keys are generated
# with Sensitive=True to prevent the key from being retrieved in clear.
supports-sensitive-attr=TRUE
# KMIP server supports 'Always Sensitive' attribute and it is checked to be
# True for all keys retrieved by the zkey-kmip plugin.
check-always-sensitive-attr=TRUE

View File

@@ -0,0 +1,69 @@
# Default KMIP server profile.
# If no other profile matches, this one is used.
# Regular expression to match the KMIP server information obtained from the
# KMIP server via the QUERY request.
server-regex=.*
# KMIP protocol version to use. Either major.minor, or AUTO. AUTO means that
# the supported KMIP protocol version is automatically discovered using the
# DISCOVER VERSIONS request.
kmip-version=AUTO
# Transport method for the KMIP protocol: TLS or HTTPS
transport=TLS
# Encoding method for the KMIP protocol: TTLV, JSON or XML.
# JSON and XML are only posisble with HTTPS transport.
encoding=TTLV
# URI used for HTTPS transport. Can be overridden by user via --kmip-server
# option. Ignored if not HTTPS transport.
https-uri=/kmip
# Authentication scheme. Currently only TLS client authentication is supported.
auth-scheme=TLSClientCert
# Key wrapping algorithm for retrieving keys from the KMIP server.
# Currently only RSA is supported.
wrap-key-algorithm=RSA
# For RSA key wrapping: the modulus size of the RSA key: 512, 1024, 2048, 4096
wrap-key-params=2048
# Format used to register the public wrapping key with the KMIP server.
# For RSA: PKCS1, PKCS8, TransparentPublicKey
wrap-key-format=PKCS1
# Padding method used with key wrapping.
# For RSA: PKCS1.5 or OAEP
wrap-padding-method=PKCS1.5
# Hashing algorithm used with key wrapping.
# For RSA with OAEP: SHA-1 or SHA-256
wrap-hashing-algorithm=SHA-1
# KMIP server supports 'Link' attribute. If TRUE, use to link the 2 keys of an
# XTS key together.
supports-link-attr=FALSE
# KMIP server supports 'Description' attribute.
supports-description-attr=FALSE
# KMIP server supports 'Comment' attribute.
supports-comment-attr=FALSE
# Custom/Vendor attribute usage for KMIP v2.x servers.
# V1-style means to set 'Vendor Identifier' to 'x', and 'Attribute Name' to
# 'zkey-<something>'. This coresponds to the KMIP v1.x Custom attribute style.
# V2-style means to set 'Vendor Identifier' to 'zkey', and 'Attribute Name' to
# '<something>'.
custom-attr-scheme=v1-style
# KMIP server supports 'Sensitive' attribute. If TRUE, all keys are generated
# with Sensitive=True to prevent the key from being retrieved in clear.
supports-sensitive-attr=FALSE
# KMIP server supports 'Always Sensitive' attribute and it is checked to be
# True for all keys retrieved by the zkey-kmip plugin.
check-always-sensitive-attr=FALSE

View File

@@ -65,5 +65,98 @@ struct plugin_handle {
#define KMIP_CERT_EXT_SUBJECT_ALT_NAME "subjectAltName"
#define KMIP_CERT_EXT_SUBJECT_ALT_NAME_DNS "subjectAltName=DNS:%s"
#define KMIP_PROFILES_LOCATION "/etc/zkey/kmip/profiles"
#define KMIP_PROFILES_LOCATION_ENVVAR "ZKEY_KMIP_PROFILES"
#define KMIP_PROFILES_FILE_TYPE ".profile"
#define KMIP_PROFILES_FILE_TYPE_LEN 8
#define KMIP_PROFILES_DEFAULT_PROFILE "default.profile"
#define KMIP_PROFILES_SERVER_REGEX "server-regex"
#define KMIP_PROFILES_KMIP_VERSION "kmip-version"
#define KMIP_PROFILES_TRANSPORT "transport"
#define KMIP_PROFILES_ENCODING "encoding"
#define KMIP_PROFILES_HTTPS_URI "https-uri"
#define KMIP_PROFILES_AUTH_SCHEME "auth-scheme"
#define KMIP_PROFILES_WRAP_KEY_ALGORITHM "wrap-key-algorithm"
#define KMIP_PROFILES_WRAP_KEY_PARAMS "wrap-key-params"
#define KMIP_PROFILES_WRAP_KEY_FORMAT "wrap-key-format"
#define KMIP_PROFILES_WRAP_PADDING_METHOD "wrap-padding-method"
#define KMIP_PROFILES_WRAP_HASHING_ALOGRITHM "wrap-hashing-algorithm"
#define KMIP_PROFILES_SUPPORTS_LINK_ATTR "supports-link-attr"
#define KMIP_PROFILES_SUPPORTS_DESCRIPTION_ATTR "supports-description-attr"
#define KMIP_PROFILES_SUPPORTS_COMMENT_ATTR "supports-comment-attr"
#define KMIP_PROFILES_CUSTOM_ATTR_SCHEME "custom-attr-scheme"
#define KMIP_PROFILES_SUPPORTS_SENSITIVE_ATTR "supports-sensitive-attr"
#define KMIP_PROFILES_CHECK_ALWAYS_SENS_ATTR "check-always-sensitive-attr"
#define KMIP_PROFILES_VERSION_AUTO "AUTO"
#define KMIP_PROFILES_TRANSPORT_TLS "TLS"
#define KMIP_PROFILES_TRANSPORT_HTTPS "HTTPS"
#define KMIP_PROFILES_ENCODING_TTLV "TTLV"
#define KMIP_PROFILES_ENCODING_JSON "JSON"
#define KMIP_PROFILES_ENCODING_XML "XML"
#define KMIP_PROFILES_HTTPS_URI_DEFAULT "/kmip"
#define KMIP_PROFILES_AUTH_TLS_CLIENT_CERT "TLSClientCert"
#define KMIP_PROFILES_WRAP_KEY_ALGORITHM_RSA "RSA"
#define KMIP_PROFILES_WRAP_KEY_FORMAT_PKCS1 "PKCS1"
#define KMIP_PROFILES_WRAP_KEY_FORMAT_PKCS8 "PKCS8"
#define KMIP_PROFILES_WRAP_KEY_FORMAT_TRANSP "TransparentPublicKey"
#define KMIP_PROFILES_WRAP_PADDING_PKCS1_5 "PKCS1.5"
#define KMIP_PROFILES_WRAP_PADDING_OAEP "OAEP"
#define KMIP_PROFILES_WRAP_HASHING_ALGO_SHA1 "SHA-1"
#define KMIP_PROFILES_WRAP_HASHING_ALGO_SHA256 "SHA-256"
#define KMIP_PROFILES_BOOLEAN_TRUE "TRUE"
#define KMIP_PROFILES_BOOLEAN_FALSE "FALSE"
#define KMIP_PROFILES_CUST_ATTR_SCHEME_V1 "v1-style"
#define KMIP_PROFILES_CUST_ATTR_SCHEME_V2 "v2-style"
enum kmip_profile_auth_scheme {
KMIP_PROFILE_AUTH_TLS_CLIENT_CERT = 1,
};
enum kmip_profile_cust_attr_scheme {
KMIP_PROFILE_CUST_ATTR_V1_STYLE = 1, /* x-zkey-something */
KMIP_PROFILE_CUST_ATTR_V2_STYLE = 2, /* zkey-something */
};
struct kmip_profile {
const char *name;
const char *server_regex;
struct kmip_version kmip_version; /* 0.0 means AUTO */
enum kmip_transport transport; /* Default: TLS */
enum kmip_encoding encoding; /* Default : TTLV */
const char *https_uri; /* Default '/kmip' for HTTPS transport */
enum kmip_profile_auth_scheme auth_scheme; /* Default: TLSClientCert */
enum kmip_crypto_algo wrap_key_algo; /* only RSA supported currently */
size_t wrap_key_size; /* Required for RSA */
enum kmip_key_format_type wrap_key_format; /* Default for RSA: PKCS1 */
enum kmip_padding_method wrap_padding_method; /* RSA default: PKCS 1.5*/
enum kmip_hashing_algo wrap_hashing_algo; /* OAEP default: SHA-1 */
bool supports_link_attr; /* Default: FALSE */
bool supports_description_attr; /* Default: FALSE */
bool supports_comment_attr; /* Default: FALSE */
enum kmip_profile_cust_attr_scheme cust_attr_scheme;
bool supports_sensitive_attr; /* Default: FALSE */
bool check_always_sensitive_attr; /* Default: FALSE */
};
int profile_read(struct plugin_handle *ph, const char *profile_dir,
const char *profile_file, struct kmip_profile **profile);
void profile_free(struct kmip_profile *profile);
int profile_find_by_server_info(struct plugin_handle *ph,
const char *server_info,
struct kmip_profile **profile);
int profile_find_by_name(struct plugin_handle *ph, const char *profile_name,
struct kmip_profile **profile);
#endif