Files
s390-tools/libkmipclient/key.c
Ingo Franzki de688f350f libkmipclient: Fix invalid return of -1 for an unsigned int
Functions kmip_node_get_structure_element_count() and
kmip_node_get_structure_element_by_tag_count() return an unsigned int,
but the error case returns -1. This leads to a wrap around actually
returning 0xffffffff which the caller might interpret as a very large
number of elements.

Return 0 in case of an error instead.

Also fix some callers to not unconditionally subtract -1 from the
returned value,  but return an error if the returned value is zero.
These callers check the preconditions upfront, so the error case
won't be hit anyway.

Assisted-by: IBM Bob:2.0.0
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-07-20 15:25:58 +02:00

1446 lines
44 KiB
C

/*
* libkmipclient - KMIP client library
*
* 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 _XOPEN_SOURCE
#define _DEFAULT_SOURCE
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "kmip.h"
#include "names.h"
/**
* Constructs a Key Block node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Block Structure v1.0
* Key Format Type Yes Enumeration v1.0
* Key Compression Type No Enumeration v1.0
* Key Value Yes various v1.0
* Cryptographic Algorithm Yes Enumeration v1.0
* Cryptographic Length Yes Integer v1.0
* Key Wrapping Data No Structure v1.0
*
* @param format_type the key format type
* @param format_type the key compression type (if 0 it is ignored)
* @param key_value the key value node
* @param algorithm the key algorithm (if 0 it is ignored)
* @param length the cryptographic length (if <= 0 it is ignored)
* @param wrappig_data the key wrapping data (can be NULL)
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_key_block(enum kmip_key_format_type format_type,
enum kmip_key_compression_type compr_type,
struct kmip_node *key_value,
enum kmip_crypto_algo algorithm,
int32_t length,
struct kmip_node *wrappig_data)
{
struct kmip_node *ret = NULL, *fmt, *cmp = NULL, *algo = NULL;
struct kmip_node *len = NULL;
if (format_type == 0 || key_value == NULL)
return NULL;
fmt = kmip_node_new_enumeration(KMIP_TAG_KEY_FORMAT_TYPE, NULL,
format_type);
if (fmt == NULL)
goto out;
if (compr_type != 0) {
cmp = kmip_node_new_enumeration(KMIP_TAG_KEY_COMPRESSION_TYPE,
NULL, compr_type);
if (cmp == NULL)
goto out;
}
if (algorithm != 0) {
algo = kmip_node_new_enumeration(
KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM,
NULL, algorithm);
if (algo == NULL)
goto out;
}
if (length > 0) {
len = kmip_node_new_integer(KMIP_TAG_CRYPTOGRAPHIC_LENGTH, NULL,
length);
if (len == NULL)
goto out;
}
ret = kmip_node_new_structure_va(KMIP_TAG_KEY_BLOCK, NULL, 6, fmt, cmp,
key_value, algo, len, wrappig_data);
out:
kmip_node_free(fmt);
kmip_node_free(cmp);
kmip_node_free(algo);
kmip_node_free(len);
return ret;
}
/**
* Gets information from a Key Block node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Block Structure v1.0
* Key Format Type Yes Enumeration v1.0
* Key Compression Type No Enumeration v1.0
* Key Value Yes various v1.0
* Cryptographic Algorithm Yes Enumeration v1.0
* Cryptographic Length Yes Integer v1.0
* Key Wrapping Data No Structure v1.0
*
* @param node the KMIP node
* @param format_type On return: the key format type
* @param format_type On return: the key compression type (0 if not avail,
* can be NULL)
* @param key_value On return: the key value node (can be NULL)
* @param algorithm On return: the key algorithm (0 if not avail, can
* be NULL)
* @param length On return: the cryptographic length (0 if not avail,
* can be NULL)
* @param wrappig_data On return: the key wrapping data (can be NULL)
*
* @returns 0 on success, or a negative errno in case of an error.
* The reference count of the returned nodes is increased. The caller must
* free the node via kmip_node_free() when no longer needed.
*/
int kmip_get_key_block(const struct kmip_node *node,
enum kmip_key_format_type *format_type,
enum kmip_key_compression_type *compr_type,
struct kmip_node **key_value,
enum kmip_crypto_algo *algorithm,
int32_t *length,
struct kmip_node **wrappig_data)
{
struct kmip_node *n;
if (node == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_BLOCK)
return -EBADMSG;
if (format_type != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_KEY_FORMAT_TYPE, 0);
if (n == NULL)
return -EBADMSG;
*format_type = kmip_node_get_enumeration(n);
kmip_node_free(n);
}
if (compr_type != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_KEY_COMPRESSION_TYPE, 0);
if (n != NULL)
*compr_type = kmip_node_get_enumeration(n);
else
*compr_type = 0;
kmip_node_free(n);
}
if (algorithm != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_CRYPTOGRAPHIC_ALGORITHM, 0);
if (n != NULL)
*algorithm = kmip_node_get_enumeration(n);
else
*algorithm = 0;
kmip_node_free(n);
}
if (length != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_CRYPTOGRAPHIC_LENGTH, 0);
if (n != NULL)
*length = kmip_node_get_integer(n);
else
*length = -1;
kmip_node_free(n);
}
if (key_value != NULL) {
*key_value = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_KEY_VALUE, 0);
if (*key_value == NULL)
return -EBADMSG;
}
if (wrappig_data != NULL)
*wrappig_data = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_KEY_WRAPPING_DATA, 0);
return 0;
}
/**
* Constructs a Key Value node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Value Structure v1.0
* Key Material Yes various v1.0
* Attribute No Structure v1.x only
* ... may be repeated
* Attributes No Structure v2.x only
*
* @param version the protocol version. If null, the current default
* protocol version is used.
* @param key_material the key material node
* @param attrs_count the number of attributes following (can be 0)
* @param v2_attrs the array of attributes (as KMIP v2.x attribute)
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_key_value(const struct kmip_version *version,
struct kmip_node *key_material,
unsigned int attrs_count,
struct kmip_node **v2_attrs)
{
struct kmip_node *ret = NULL, *v2_attr, *v1_attr, *attrs = NULL;
unsigned int i;
int rc;
if (key_material == NULL)
return NULL;
if (attrs_count > 0 && v2_attrs == NULL)
return NULL;
if (version == NULL)
version = kmip_get_default_protocol_version();
if (version->major == 1) {
/* KMIP v1.x */
ret = kmip_node_new_structure_va(KMIP_TAG_KEY_VALUE, NULL, 1,
key_material);
if (ret == NULL)
return NULL;
for (i = 0; i < attrs_count; i++) {
v2_attr = v2_attrs[i];
if (v2_attr == NULL)
continue;
rc = kmip_v1_attr_from_v2_attr(v2_attr, &v1_attr);
if (rc != 0)
goto error;
rc = kmip_node_add_structure_element(ret, v1_attr);
kmip_node_free(v1_attr);
if (rc != 0)
goto error;
}
} else {
/* KMIP >= v2.0 */
if (attrs_count > 0) {
attrs = kmip_new_attributes(version,
KMIP_TAG_ATTRIBUTES,
attrs_count, v2_attrs);
if (attrs == NULL)
return NULL;
}
ret = kmip_node_new_structure_va(KMIP_TAG_KEY_VALUE, NULL, 2,
key_material, attrs);
kmip_node_free(attrs);
}
return ret;
error:
kmip_node_free(ret);
return NULL;
}
/**
* Constructs a Key Value node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Value Structure v1.0
* Key Material Yes various v1.0
* Attribute No Structure v1.x only
* ... may be repeated
* Attributes No Structure v2.x only
*
* @param version the protocol version. If null, the current default
* protocol version is used.
* @param key_material the key material node
* @param attrs_count the number of attributes following (can be 0)
* @param <attributes> the attributes (as KMIP v2.x attribute)
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_key_value_va(const struct kmip_version *version,
struct kmip_node *key_material,
unsigned int attrs_count, ...)
{
struct kmip_node *ret, **attrs = NULL;
unsigned int i, k;
va_list ap;
if (attrs_count > 0) {
attrs = calloc(attrs_count, sizeof(struct kmip_node *));
if (attrs == NULL)
return NULL;
}
va_start(ap, attrs_count);
for (i = 0, k = 0; i < attrs_count; i++) {
attrs[k] = va_arg(ap, struct kmip_node *);
if (attrs[k] != NULL)
k++;
}
va_end(ap);
ret = kmip_new_key_value(version, key_material, k, attrs);
if (attrs != NULL)
free(attrs);
return ret;
}
/**
*Gets information from a Key Value node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Value (wrapped key value) Byte String v1.0
* Key Value (plaintext key value) Structure v1.0
* Key Material Yes various v1.0
* Attribute No Structure v1.x only
* ... may be repeated
* Attributes No Structure v2.x only
*
* @param node the KMIP node
* @param key_material On return: the key material node (can be NULL)
* @param num_attrs On return: the number of attributes (can be NULL).
* @param index the index of the attribute to get
* @param v2_attr On return: the attribute (as v2.x attribute) at the
* specified index. Function returns -ENOENT if no
* attribute is available at the index.
*
* @returns 0 on success, or a negative errno in case of an error.
* The reference count of the returned nodes is increased. The caller must
* free the node via kmip_node_free() when no longer needed.
*/
int kmip_get_key_value(const struct kmip_node *node,
struct kmip_node **key_material,
unsigned int *num_attrs, unsigned int index,
struct kmip_node **v2_attr)
{
struct kmip_node *attr;
int rc;
if (node == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_VALUE)
return -EBADMSG;
if (key_material != NULL) {
switch (kmip_node_get_type(node)) {
case KMIP_TYPE_BYTE_STRING:
/* Wrapped key value */
*key_material = (struct kmip_node *)node;
kmip_node_upref(*key_material);
break;
case KMIP_TYPE_STRUCTURE:
/* plaintext key value */
*key_material =
kmip_node_get_structure_element_by_index(node,
0);
if (*key_material == NULL)
return -EBADMSG;
switch (kmip_node_get_type(*key_material)) {
case KMIP_TYPE_BYTE_STRING:
/* Raw, Opaque, PKCS1, PKCS8, ECPrivateKey */
break;
case KMIP_TYPE_STRUCTURE:
/* Transparent key formats */
switch (kmip_node_get_tag(*key_material)) {
/* Transparent key formats: TAG_KEY_MATERIAL */
case KMIP_TAG_KEY_MATERIAL:
break;
default:
rc = -EBADMSG;
goto error;
}
break;
default:
rc = -EBADMSG;
goto error;
}
break;
default:
return -EBADMSG;
}
}
if (v2_attr == NULL || kmip_node_get_type(node) != KMIP_TYPE_STRUCTURE)
return 0;
attr = kmip_node_get_structure_element_by_index(node, 1);
if (attr == NULL) {
rc = -ENOENT;
goto error;
}
if (kmip_node_get_tag(attr) == KMIP_TAG_ATTRIBUTES) {
/* Its already a KMIP v2.x attributes structure */
rc = kmip_get_attributes(attr, num_attrs, index, v2_attr);
kmip_node_free(attr);
if (rc != 0)
goto error;
return 0;
}
/* Must be a KMIP v1.x attribute then */
kmip_node_free(attr);
if (num_attrs != NULL) {
*num_attrs = kmip_node_get_structure_element_count(node);
if (*num_attrs == 0) {
rc = -EBADMSG;
goto error;
}
(*num_attrs)--;
}
if (v2_attr == NULL)
return 0;
attr = kmip_node_get_structure_element_by_index(node, index + 1);
if (attr == NULL) {
rc = -ENOENT;
goto error;
}
rc = kmip_v2_attr_from_v1_attr(attr, v2_attr);
kmip_node_free(attr);
if (rc != 0)
goto error;
return 0;
error:
if (key_material != NULL) {
kmip_node_free(*key_material);
*key_material = NULL;
}
return rc;
}
/**
* Constructs a Key Wrapping Data node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Wrapping Data Structure v1.0
* Wrapping Method Yes Enumeration v1.0
* Encryption Key Information No Structure v1.0
* MAC/Signature Key Info. No Structure v1.0
* MAC/Signature No Byte String v1.0
* IV/Counter/Nonce No Byte String v1.0
* Encoding Option No Enumeration v1.2
*
* @param version the protocol version. If null, the current default
* protocol version is used.
* @param wrap_method the key wrapping method
* @param encr_key_info the encryption key info node (can be NULL)
* @param mac_sign_key_info the MAC/Sign key info node (can be NULL)
* @param mac_signature MAC/signature (can be NULL)
* @param mac_signature_len the length of the MAC/Signature
* @param iv_counter_nonce IV/Counter/Nonce (can be NULL)
* @param iv_counter_nonce_len the length of theIV/Counter/Nonce
* @param encoding the encoding option (can be 0, defaults to TTLV)
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_key_wrapping_data(
const struct kmip_version *version,
enum kmip_wrapping_method wrap_method,
struct kmip_node *encr_key_info,
struct kmip_node *mac_sign_key_info,
const unsigned char *mac_signature,
uint32_t mac_signature_len,
const unsigned char *iv_counter_nonce,
uint32_t iv_counter_nonce_len,
enum kmip_encoding_option encoding)
{
struct kmip_node *ret = NULL, *wmeth, *mac = NULL, *iv = NULL;
struct kmip_node *enc = NULL;
if (wrap_method == 0)
return NULL;
if (version == NULL)
version = kmip_get_default_protocol_version();
wmeth = kmip_node_new_enumeration(KMIP_TAG_WRAPPING_METHOD, NULL,
wrap_method);
if (wmeth == NULL)
goto out;
if (mac_signature != NULL && mac_signature_len > 0) {
mac = kmip_node_new_byte_string(KMIP_TAG_MAC_SIGNATURE,
NULL, mac_signature,
mac_signature_len);
if (mac == NULL)
goto out;
}
if (iv_counter_nonce != NULL && iv_counter_nonce_len > 0) {
iv = kmip_node_new_byte_string(KMIP_TAG_IV_COUNTER_NONCE,
NULL, iv_counter_nonce,
iv_counter_nonce_len);
if (iv == NULL)
goto out;
}
if (encoding != 0 && (version->major > 1 ||
(version->major == 1 && version->minor > 1))) {
enc = kmip_node_new_enumeration(KMIP_TAG_ENCODING_OPTION, NULL,
encoding);
if (enc == NULL)
goto out;
}
ret = kmip_node_new_structure_va(KMIP_TAG_KEY_WRAPPING_DATA, NULL, 6,
wmeth, encr_key_info,
mac_sign_key_info, mac, iv, enc);
out:
kmip_node_free(wmeth);
kmip_node_free(mac);
kmip_node_free(iv);
kmip_node_free(enc);
return ret;
}
/**
*Gets information from a Key Wrapping Data node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Wrapping Data Structure v1.0
* Wrapping Method Yes Enumeration v1.0
* Encryption Key Information No Structure v1.0
* MAC/Signature Key Info. No Structure v1.0
* MAC/Signature No Byte String v1.0
* IV/Counter/Nonce No Byte String v1.0
* Encoding Option No Enumeration v1.2
*
* @param node the KMIP node
* @param wrap_method On return: the key wrapping method (can be NULL)
* @param encr_key_info On return: the encryption key info node
* (can be NULL)
* @param mac_sign_key_info On return: the MAC/Sign key info node (can be NULL)
* @param mac_signature On return: MAC/signature (can be NULL)
* @param mac_signature_len On return: the length of the MAC/Signature
* (can be NULL)
* @param iv_counter_nonce On return: IV/Counter/Nonce (can be NULL)
* @param iv_counter_nonce_len On return: the length of theIV/Counter/Nonce
* (can be NULL)
* @param encoding On return: the encoding option (can be NULL)
*
* @returns 0 on success, or a negative errno in case of an error.
* The reference count of the returned nodes is increased. The caller must
* free the node via kmip_node_free() when no longer needed.
*/
int kmip_get_key_wrapping_data(const struct kmip_node *node,
enum kmip_wrapping_method *wrap_method,
struct kmip_node **encr_key_info,
struct kmip_node **mac_sign_key_info,
const unsigned char **mac_signature,
uint32_t *mac_signature_len,
const unsigned char **iv_counter_nonce,
uint32_t *iv_counter_nonce_len,
enum kmip_encoding_option *encoding)
{
struct kmip_node *n;
if (node == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_WRAPPING_DATA)
return -EBADMSG;
if (wrap_method != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_WRAPPING_METHOD, 0);
if (n == NULL)
return -EBADMSG;
*wrap_method = kmip_node_get_enumeration(n);
kmip_node_free(n);
}
if (mac_signature != NULL && mac_signature_len != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_MAC_SIGNATURE, 0);
if (n != NULL) {
*mac_signature = kmip_node_get_byte_string(n,
mac_signature_len);
} else {
*mac_signature = NULL;
*mac_signature_len = 0;
}
kmip_node_free(n);
}
if (iv_counter_nonce != NULL && iv_counter_nonce_len != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_IV_COUNTER_NONCE, 0);
if (n != NULL) {
*iv_counter_nonce = kmip_node_get_byte_string(n,
iv_counter_nonce_len);
} else {
*iv_counter_nonce = NULL;
*iv_counter_nonce_len = 0;
}
kmip_node_free(n);
}
if (encoding != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_ENCODING_OPTION, 0);
*encoding = (n != NULL ? kmip_node_get_enumeration(n) : 0);
kmip_node_free(n);
}
if (encr_key_info != NULL)
*encr_key_info = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_ENCRYPTION_KEY_INFORMATION, 0);
if (mac_sign_key_info != NULL)
*mac_sign_key_info =
kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION, 0);
return 0;
}
/**
* Constructs a Key Wrapping Specification node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Wrapping Specification Structure v1.0
* Wrapping Method Yes Enumeration v1.0
* Encryption Key Information No Structure v1.0
* MAC/Signature Key Info. No Structure v1.0
* Attribute Name No Text String v1.0
* ... may be repeated
* Encoding Option No Enumeration v1.2
*
* @param version the protocol version. If null, the current default
* protocol version is used.
* @param wrap_method the key wrapping method
* @param encr_key_info the encryption key info node (can be NULL)
* @param mac_sign_key_info the MAC/Sign key info node (can be NULL)
* @param encoding the encoding option (can be 0, defaults to TTLV)
* @param attr_name_count the number of attribute names following
* @param attr_names the array of attributes names (as const char *)
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_key_wrapping_specification(
const struct kmip_version *version,
enum kmip_wrapping_method wrap_method,
struct kmip_node *encr_key_info,
struct kmip_node *mac_sign_key_info,
enum kmip_encoding_option encoding,
unsigned int attr_name_count,
const char **attr_names)
{
struct kmip_node *ret = NULL, *wmeth, *enc = NULL, *name;
unsigned int i;
int rc;
if (wrap_method == 0)
return NULL;
if (version == NULL)
version = kmip_get_default_protocol_version();
wmeth = kmip_node_new_enumeration(KMIP_TAG_WRAPPING_METHOD, NULL,
wrap_method);
if (wmeth == NULL)
goto out;
ret = kmip_node_new_structure_va(KMIP_TAG_KEY_WRAPPING_SPECIFICATION,
NULL, 3, wmeth, encr_key_info,
mac_sign_key_info);
for (i = 0; i < attr_name_count; i++) {
if (attr_names[i] == NULL)
continue;
name = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL,
attr_names[i]);
if (name == NULL)
goto error;
rc = kmip_node_add_structure_element(ret, name);
kmip_node_free(name);
if (rc != 0)
goto error;
}
if (encoding != 0 && (version->major > 1 ||
(version->major == 1 && version->minor > 1))) {
enc = kmip_node_new_enumeration(KMIP_TAG_ENCODING_OPTION, NULL,
encoding);
if (enc == NULL)
goto error;
rc = kmip_node_add_structure_element(ret, enc);
if (rc != 0)
goto error;
}
goto out;
error:
kmip_node_free(ret);
ret = NULL;
out:
kmip_node_free(wmeth);
kmip_node_free(enc);
return ret;
}
/**
* Constructs a Key Wrapping Specification node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Wrapping Specification Structure v1.0
* Wrapping Method Yes Enumeration v1.0
* Encryption Key Information No Structure v1.0
* MAC/Signature Key Info. No Structure v1.0
* Attribute Name No Text String v1.0
* ... may be repeated
* Encoding Option No Enumeration v1.2
*
* @param version the protocol version. If null, the current default
* protocol version is used.
* @param wrap_method the key wrapping method
* @param encr_key_info the encryption key info node (can be NULL)
* @param mac_sign_key_info the MAC/Sign key info node (can be NULL)
* @param encoding the encoding option (can be 0, defaults to TTLV)
* @param attr_name_count the number of atribute names following
* @param <attr names> the attributes names (as const char *)
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_key_wrapping_specification_va(
const struct kmip_version *version,
enum kmip_wrapping_method wrap_method,
struct kmip_node *encr_key_info,
struct kmip_node *mac_sign_key_info,
enum kmip_encoding_option encoding,
unsigned int attr_name_count, ...)
{
const char **names = NULL;
struct kmip_node *ret;
unsigned int i;
va_list ap;
if (attr_name_count > 0) {
names = calloc(attr_name_count, sizeof(const char *));
if (names == NULL)
return NULL;
}
va_start(ap, attr_name_count);
for (i = 0; i < attr_name_count; i++)
names[i] = va_arg(ap, const char *);
va_end(ap);
ret = kmip_new_key_wrapping_specification(version, wrap_method,
encr_key_info,
mac_sign_key_info, encoding,
attr_name_count, names);
if (names != NULL)
free(names);
return ret;
}
/**
*Gets information from a Key Wrapping Specification node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Wrapping Specification Structure v1.0
* Wrapping Method Yes Enumeration v1.0
* Encryption Key Information No Structure v1.0
* MAC/Signature Key Info. No Structure v1.0
* Attribute Name No Text String v1.0
* ... may be repeated
* Encoding Option No Enumeration v1.2
*
* @param node the KMIP node
* @param wrap_method On return: the key wrapping method (can be NULL)
* @param encr_key_info On return: the encryption key info node
* (can be NULL)
* @param mac_sign_key_info On return: the MAC/Sign key info node (can be NULL)
* @param encoding On return: the encoding option (can be NULL)
* @param num_attr_names On return: the number of attributes (can be NULL).
* @param attr_name_index The index of the attribute name to return
* @param attr_name On return: the attribute name at the specified index
* (can be NULL). Function returns -ENOENT if no name
* is available at the index.
*
* @returns 0 on success, or a negative errno in case of an error.
* The reference count of the returned nodes is increased. The caller must
* free the node via kmip_node_free() when no longer needed.
*/
int kmip_get_key_wrapping_specification(const struct kmip_node *node,
enum kmip_wrapping_method *wrap_method,
struct kmip_node **encr_key_info,
struct kmip_node **mac_sign_key_info,
enum kmip_encoding_option *encoding,
unsigned int *num_attr_names,
unsigned int attr_name_index,
const char **attr_name)
{
struct kmip_node *n;
if (node == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_WRAPPING_SPECIFICATION)
return -EBADMSG;
if (wrap_method != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_WRAPPING_METHOD, 0);
if (n == NULL)
return -EBADMSG;
*wrap_method = kmip_node_get_enumeration(n);
kmip_node_free(n);
}
if (encoding != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_ENCODING_OPTION, 0);
*encoding = (n != NULL ? kmip_node_get_enumeration(n) : 0);
kmip_node_free(n);
}
if (num_attr_names != NULL)
*num_attr_names = kmip_node_get_structure_element_by_tag_count(
node, KMIP_TAG_ATTRIBUTE_NAME);
if (attr_name != NULL) {
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_ATTRIBUTE_NAME, attr_name_index);
if (n == NULL)
return -ENOENT;
*attr_name = kmip_node_get_text_string(n);
kmip_node_free(n);
}
if (encr_key_info != NULL)
*encr_key_info = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_ENCRYPTION_KEY_INFORMATION, 0);
if (mac_sign_key_info != NULL)
*mac_sign_key_info =
kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION, 0);
return 0;
}
/**
* Constructs a Encryption Key Information or MAC/Signature Key Information
* node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Information Structure v1.0
* Unique Identifier Yes Text String v1.0
* Enumeration v2.0
* Integer v2.0
* Cryptographic Parameters No Structure v1.0
*
* @param mac_sign if true a MAC/Signature Key Information node is
* created, otherwise a Encryption Key Information
* node.
* @param unique_id the unique ID node
* @param crypto_params the cryptographic parameters node (can be NULL)
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_key_info(bool mac_sign, struct kmip_node *unique_id,
struct kmip_node *crypto_params)
{
enum kmip_tag tag;
if (unique_id == NULL)
return NULL;
tag = (mac_sign ? KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION :
KMIP_TAG_ENCRYPTION_KEY_INFORMATION);
return kmip_node_new_structure_va(tag, NULL, 2, unique_id,
crypto_params);
}
/**
* Gets the information from an Encryption Key Information or MAC/Signature Key
* Information node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Information Structure v1.0
* Unique Identifier Yes Text String v1.0
* Enumeration v2.0
* Integer v2.0
* Cryptographic Parameters No Structure v1.0
*
* @param node the KMIP node
* @param unique_id On return: the unique ID node (can be NULL)
* @param crypto_params On return: the cryptographic parameters node (can
* be NULL)
*
* @returns 0 on success, or a negative errno in case of an error
* The reference count of the returned nodes is increased. The caller must
* free the node via kmip_node_free() when no longer needed.
*/
int kmip_get_key_info(const struct kmip_node *node,
struct kmip_node **unique_id,
struct kmip_node **crypto_params)
{
if (node == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_ENCRYPTION_KEY_INFORMATION &&
kmip_node_get_tag(node) != KMIP_TAG_MAC_SIGNATURE_KEY_INFORMATION)
return -EBADMSG;
if (unique_id != NULL) {
*unique_id = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_UNIQUE_IDENTIFIER, 0);
if (*unique_id == NULL)
return -EBADMSG;
}
if (crypto_params != NULL)
*crypto_params = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_CRYPTOGRAPHIC_PARAMETERS, 0);
return 0;
}
/**
* Constructs a Transparent Symmetric Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Structure v1.0
* Key Yes Byte String v1.0
*
* @param key the key
* @param key_length the key length
*
* @returns the allocated node, or NULL in case of an error.
*/
struct kmip_node *kmip_new_transparent_symmetric_key(const unsigned char *key,
uint32_t key_length)
{
struct kmip_node *k, *ret;
if (key == NULL || key_length == 0)
return NULL;
k = kmip_node_new_byte_string(KMIP_TAG_KEY, NULL, key, key_length);
if (k == NULL)
return NULL;
ret = kmip_node_new_structure_va(KMIP_TAG_KEY_MATERIAL, NULL, 1, k);
kmip_node_free(k);
return ret;
}
/**
* Gets the information from a Transparent Symmetric Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Structure v1.0
* Key Yes Byte String v1.0
*
* @param node the KMIP node
* @param key On return: the key
* @param key_length On return: the key length
*
* @returns 0 on success, or a negative errno in case of an error
*/
int kmip_get_transparent_symmetric_key(const struct kmip_node *node,
const unsigned char **key,
uint32_t *key_length)
{
struct kmip_node *k;
if (node == NULL || key == NULL || key_length == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL)
return -EBADMSG;
k = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_KEY, 0);
if (k == NULL)
return -EBADMSG;
*key = kmip_node_get_byte_string(k, key_length);
kmip_node_free(k);
return 0;
}
/**
* Constructs a Transparent RSA Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Structure v1.0
* Modulus Yes Big Integer v1.0
* Public Exponent Yes Big Integer v1.0
*
* @param modulus the modulus as OpenSSL BIGNUM
* @param pub_ext the public exponent as OpenSSL BIGNUM
*
* @returns the allocated node, or NULL in case of an error.
*/
struct kmip_node *kmip_new_transparent_rsa_public_key(const BIGNUM *modulus,
const BIGNUM *pub_exp)
{
struct kmip_node *mod, *exp, *ret = NULL;
if (modulus == NULL || pub_exp == NULL)
return NULL;
mod = kmip_node_new_bigint(KMIP_TAG_MODULUS, NULL, modulus);
exp = kmip_node_new_bigint(KMIP_TAG_PUBLIC_EXPONENT, NULL, pub_exp);
if (mod == NULL || exp == NULL)
goto out;
ret = kmip_node_new_structure_va(KMIP_TAG_KEY_MATERIAL, NULL, 2, mod,
exp);
out:
kmip_node_free(mod);
kmip_node_free(exp);
return ret;
}
/**
* Gets the information from a Transparent RSA Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Structure v1.0
* Modulus Yes Big Integer v1.0
* Public Exponent Yes Big Integer v1.0
*
* @param node the KMIP node
* @param modulus On return: the modulus as OpenSSL BIGNUM
* @param pub_ext On return: the public exponent as OpenSSL BIGNUM
*
* @returns 0 on success, or a negative errno in case of an error
*/
int kmip_get_transparent_rsa_public_key(const struct kmip_node *node,
const BIGNUM **modulus,
const BIGNUM **pub_exp)
{
struct kmip_node *n;
if (node == NULL || modulus == NULL || pub_exp == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL)
return -EBADMSG;
n = kmip_node_get_structure_element_by_tag(node, KMIP_TAG_MODULUS, 0);
if (n == NULL)
return -EBADMSG;
*modulus = kmip_node_get_bigint(n);
kmip_node_free(n);
n = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_PUBLIC_EXPONENT, 0);
if (n == NULL)
return -EBADMSG;
*pub_exp = kmip_node_get_bigint(n);
kmip_node_free(n);
return 0;
}
/**
* Constructs a PKCS#1 Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Byte String v1.0
*
* @param pub_key the public key as OpenSSL PKEY
*
* @returns the allocated node, or NULL in case of an error.
*/
struct kmip_node *kmip_new_pkcs1_public_key(EVP_PKEY *pub_key)
{
struct kmip_node *ret = NULL;
unsigned char *buf = NULL;
int len;
if (pub_key == NULL)
return NULL;
len = i2d_PublicKey(pub_key, &buf);
if (len <= 0)
return NULL;
ret = kmip_node_new_byte_string(KMIP_TAG_KEY_MATERIAL, NULL, buf, len);
OPENSSL_free(buf);
return ret;
}
/**
* Gets the information from a PKCS#1 Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Byte String v1.0
*
* @param node the KMIP node
* @param algo the algorithm of the key
* @param pub_key On return: the public key as OpenSSL PKEY. Must be
* freed by the caller using EVP_PKEY_free() when no
* longer needed.
*
* @returns 0 on success, or a negative errno in case of an error
*/
int kmip_get_pkcs1_public_key(const struct kmip_node *node,
enum kmip_crypto_algo algo,
EVP_PKEY **pub_key)
{
const unsigned char *buf;
uint32_t len = 0;
int type;
if (node == NULL || pub_key == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL)
return -EBADMSG;
buf = kmip_node_get_byte_string(node, &len);
if (buf == NULL || len == 0)
return -EBADMSG;
switch (algo) {
case KMIP_CRYPTO_ALGO_RSA:
type = EVP_PKEY_RSA;
break;
case KMIP_CRYPTO_ALGO_DSA:
type = EVP_PKEY_DSA;
break;
case KMIP_CRYPTO_ALGO_ECDSA:
type = EVP_PKEY_EC;
break;
default:
return -EINVAL;
}
*pub_key = d2i_PublicKey(type, NULL, &buf, len);
if (*pub_key == NULL)
return -EIO;
return 0;
}
/**
* Constructs a PKCS#8 Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Byte String v1.0
*
* @param pub_key the public key as OpenSSL PKEY
*
* @returns the allocated node, or NULL in case of an error.
*/
struct kmip_node *kmip_new_pkcs8_public_key(EVP_PKEY *pub_key)
{
struct kmip_node *ret = NULL;
unsigned char *buf = NULL;
int len;
if (pub_key == NULL)
return NULL;
len = i2d_PUBKEY(pub_key, &buf);
if (len <= 0)
return NULL;
ret = kmip_node_new_byte_string(KMIP_TAG_KEY_MATERIAL, NULL, buf, len);
OPENSSL_free(buf);
return ret;
}
/**
* Gets the information from a PKCS#8 Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Byte String v1.0
*
* @param node the KMIP node
* @param pub_key On return: the public key as OpenSSL PKEY. Must be
* freed by the caller using EVP_PKEY_free() when no
* longer needed.
*
* @returns 0 on success, or a negative errno in case of an error
*/
int kmip_get_pkcs8_public_key(const struct kmip_node *node,
EVP_PKEY **pub_key)
{
const unsigned char *buf;
uint32_t len = 0;
if (node == NULL || pub_key == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL)
return -EBADMSG;
buf = kmip_node_get_byte_string(node, &len);
if (buf == NULL || len == 0)
return -EBADMSG;
*pub_key = d2i_PUBKEY(NULL, &buf, len);
if (*pub_key == NULL)
return -EIO;
return 0;
}
/**
* Constructs a Raw Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Byte String v1.0
*
* @param key the raw key
* @param key_len the length of the key
*
* @returns the allocated node, or NULL in case of an error.
*/
struct kmip_node *kmip_new_raw_key(const unsigned char *key, uint32_t key_len)
{
if (key == NULL)
return NULL;
return kmip_node_new_byte_string(KMIP_TAG_KEY_MATERIAL, NULL, key,
key_len);
}
/**
* Gets the information from a Raw Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Key Material Byte String v1.0
*
* @param node the KMIP node
* @param key On return: the raw key
* @param key_len On return: the length of the key
*
* @returns 0 on success, or a negative errno in case of an error
*/
int kmip_get_raw_key(const struct kmip_node *node, const unsigned char **key,
uint32_t *key_len)
{
if (node == NULL || key == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_KEY_MATERIAL)
return -EBADMSG;
*key = kmip_node_get_byte_string(node, key_len);
if (*key == NULL)
return -EBADMSG;
return 0;
}
/**
* Constructs a Symmetric Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Symmetric Key Structure v1.0
* Key Block Yes Structure v1.0
*
* @param keyblock the key block node
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_symmetric_key(struct kmip_node *keyblock)
{
if (keyblock == NULL)
return NULL;
return kmip_node_new_structure_va(KMIP_TAG_SYMMETRIC_KEY, NULL, 1,
keyblock);
}
/**
* Gets the information from a Symmetric Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Symmetric Key Structure v1.0
* Key Block Yes Structure v1.0
*
* @param node the KMIP node
* @param keyblock On return: the key block node
*
* @returns 0 on success, or a negative errno in case of an error
*/
int kmip_get_symmetric_key(const struct kmip_node *node,
struct kmip_node **keyblock)
{
if (node == NULL || keyblock == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_SYMMETRIC_KEY)
return -EBADMSG;
*keyblock = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_KEY_BLOCK,
0);
if (*keyblock == NULL)
return -EBADMSG;
return 0;
}
/**
* Constructs a Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Public Key Structure v1.0
* Key Block Yes Structure v1.0
*
* @param keyblock the key block node
*
* @returns the allocated node, or NULL in case of an error.
* The reference counts of the nodes specified as parameters which are added to
* the newly allocated node are increased. The caller must free its reference
* via kmip_node_free() if no longer needed.
*/
struct kmip_node *kmip_new_public_key(struct kmip_node *keyblock)
{
if (keyblock == NULL)
return NULL;
return kmip_node_new_structure_va(KMIP_TAG_PUBLIC_KEY, NULL, 1,
keyblock);
}
/**
* Gets the information from a Public Key node:
*
* Object Required Encoding KMIP version
* ---------------------------------------------------------------------
* Public Key Structure v1.0
* Key Block Yes Structure v1.0
*
* @param node the KMIP node
* @param keyblock On return: the key block node
*
* @returns 0 on success, or a negative errno in case of an error
*/
int kmip_get_public_key(const struct kmip_node *node,
struct kmip_node **keyblock)
{
if (node == NULL || keyblock == NULL)
return -EINVAL;
if (kmip_node_get_tag(node) != KMIP_TAG_PUBLIC_KEY)
return -EBADMSG;
*keyblock = kmip_node_get_structure_element_by_tag(node,
KMIP_TAG_KEY_BLOCK,
0);
if (*keyblock == NULL)
return -EBADMSG;
return 0;
}