/* * 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 #include #include "kmip.h" #include "names.h" /** * Constructs a Protocol Version node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protocol Version Structure v1.0 * Protocol Version Major Yes Integer v1.0 * Protocol Version Minor Yes Integer v1.0 * * @param version the protocol version * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protocol_version(const struct kmip_version *version) { struct kmip_node *ret = NULL, *maj, *min; if (version == NULL) return NULL; maj = kmip_node_new_integer(KMIP_TAG_PROTOCOL_VERSION_MAJOR, NULL, version->major); min = kmip_node_new_integer(KMIP_TAG_PROTOCOL_VERSION_MINOR, NULL, version->minor); if (maj == NULL || min == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_PROTOCOL_VERSION, NULL, 2, maj, min); out: kmip_node_free(maj); kmip_node_free(min); return ret; } /** * Constructs a Profile Version node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Profile Version Structure v1.0 * Profile Version Major Yes Integer v1.0 * Profile Version Minor Yes Integer v1.0 * * @param version the profile version * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_profile_version(const struct kmip_version *version) { struct kmip_node *ret = NULL, *maj, *min; if (version == NULL) return NULL; maj = kmip_node_new_integer(KMIP_TAG_PROFILE_VERSION_MAJOR, NULL, version->major); min = kmip_node_new_integer(KMIP_TAG_PROFILE_VERSION_MINOR, NULL, version->minor); if (maj == NULL || min == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_PROFILE_VERSION, NULL, 2, maj, min); out: kmip_node_free(maj); kmip_node_free(min); return ret; } /** * Constructs a Request Header node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Request Header Yes Structure v1.0 * Protocol Version Yes Structure v1.0 * Maximum Response Size No Integer v1.0 * Client Correlation Value No Text String v1.4 * Server Correlation Value No Text String v1.4 * Asynchronous Indicator No Boolean v1.0 * Attestation Capable Indic. No Boolean v1.2 * Attestation Type No Enumeration v1.2 * ... may be repeated * Authentication No Structure v1.0 * Batch Error Cont. Option No Enumeration v1.0 * Batch Order Option No Boolean v1.0 * Time Stamp No Date Time v1.0 * Batch Count Yes Integer v1.0 * * @param version the protocol version. If NULL, the default * protocol version is used * @param max_response_size the maximum response size. Ignored if <= 0. * @param client_corr_value the client correlation value. Ignored if NULL. * @param server_corr_value the server correlation value. Ignored if NULL. * @param asynchronous if true the request is asynchronous * @param authentication the authentication node (can be NULL) * @param batch_err_opt the batch error continuation option. Ignored if 0, * or if batch_count is less than 2. * @param batch_order_option the batch order option (true = execute in order) * @param batch_count the batch count * * @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_request_header(const struct kmip_version *version, int32_t max_response_size, const char *client_corr_value, const char *server_corr_value, bool asynchronous, struct kmip_node *authentication, enum kmip_batch_error_cont_option batch_err_opt, bool batch_order_option, int32_t batch_count) { struct kmip_node *ret = NULL, *err = NULL, *async = NULL, *tim = NULL; struct kmip_node *max = NULL, *cnt = NULL, *ord = NULL, *ver = NULL; struct kmip_node *ccorr = NULL, *scorr = NULL; if (version == NULL) version = kmip_get_default_protocol_version(); ver = kmip_new_protocol_version(version); if (ver == NULL) goto out; if (max_response_size > 0) { max = kmip_node_new_integer(KMIP_TAG_MAXIMUM_RESPONSE_SIZE, NULL, max_response_size); if (max == NULL) goto out; } if (version->major == 1 && version->minor <= 3) { client_corr_value = NULL; server_corr_value = NULL; } if (client_corr_value) { ccorr = kmip_node_new_text_string( KMIP_TAG_CLIENT_CORRELATION_VALUE, NULL, client_corr_value); if (ccorr == NULL) goto out; } if (server_corr_value) { scorr = kmip_node_new_text_string( KMIP_TAG_SERVER_CORRELATION_VALUE, NULL, server_corr_value); if (scorr == NULL) goto out; } if (asynchronous) { async = kmip_node_new_boolean(KMIP_TAG_ASYNCHRONOUS_INDICATOR, NULL, asynchronous); if (async == NULL) goto out; } if (batch_err_opt != 0 && batch_count > 1) { err = kmip_node_new_enumeration( KMIP_TAG_BATCH_ERROR_CONTINUATION_OPTION, NULL, batch_err_opt); if (err == NULL) goto out; } ord = kmip_node_new_boolean(KMIP_TAG_BATCH_ORDER_OPTION, NULL, batch_order_option); if (ord == NULL) goto out; tim = kmip_node_new_date_time(KMIP_TAG_TIME_STAMP, NULL, time(NULL)); if (tim == NULL) goto out; cnt = kmip_node_new_integer(KMIP_TAG_BATCH_COUNT, NULL, batch_count); if (cnt == NULL) goto out; ret = kmip_node_new_structure_va(KMIP_TAG_REQUEST_HEADER, NULL, 10, ver, max, ccorr, scorr, authentication, async, err, ord, tim, cnt); out: kmip_node_free(ver); kmip_node_free(max); kmip_node_free(async); kmip_node_free(err); kmip_node_free(ord); kmip_node_free(tim); kmip_node_free(cnt); return ret; } /** * Constructs a Request Batch Item node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Batch Item Yes Structure v1.0 * Operation Yes Enumeration v1.0 * Ephemeral No Boolean v2.0 * Unique Batch Item ID No Byte String v1.0 * Request Payload Yes Structure v1.0 * Message Extension No Structure v1.0 * * @param operation the operation * @param authentication A batch_id (can be NULL, req. if batch count > 0) * @param batch_id_length the size of the batch ID * @param payload the payload 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_request_batch_item(enum kmip_operation operation, unsigned char *batch_id, uint32_t batch_id_length, struct kmip_node *payload) { struct kmip_node *ret = NULL, *op, *bid = NULL; if (payload == NULL) return NULL; op = kmip_node_new_enumeration(KMIP_TAG_OPERATION, NULL, operation); if (op == NULL) return NULL; if (batch_id != NULL && batch_id_length > 0) { bid = kmip_node_new_byte_string(KMIP_TAG_UNIQUE_BATCH_ITEM_ID, NULL, batch_id, batch_id_length); if (bid == NULL) goto out; } ret = kmip_node_new_structure_va(KMIP_TAG_BATCH_ITEM, NULL, 3, op, bid, payload); out: kmip_node_free(op); kmip_node_free(bid); return ret; } /** * Constructs a Request Message node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Request Message Yes Structure v1.0 * Request Header Yes Structure v1.0 * Batch Item Yes Structure v1.0 * ... may be repeated * * @param request_header the request header node * @param batch_count the number of batch items to add * @parambatch_items array of batch items * * @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_request(struct kmip_node *request_header, int32_t batch_count, struct kmip_node **batch_items) { struct kmip_node *ret; int rc = 0; if (request_header == NULL) return NULL; ret = kmip_node_new_structure_va(KMIP_TAG_REQUEST_MESSAGE, NULL, 1, request_header); if (ret == NULL) return NULL; rc = kmip_node_add_structure_elements(ret, batch_count, batch_items); if (rc != 0) goto error; return ret; error: kmip_node_free(ret); return NULL; } /** * Constructs a Request Message node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Request Message Yes Structure v1.0 * Request Header Yes Structure v1.0 * Batch Item Yes Structure v1.0 * ... may be repeated * * @param request_header the request header node * @param batch_count the number of batch items following * @param batch items (struct kmip_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_request_va(struct kmip_node *request_header, int32_t batch_count, ...) { struct kmip_node *ret, **bis = NULL; va_list ap; int32_t i; if (request_header == NULL) return NULL; if (batch_count > 0) { bis = calloc(batch_count, sizeof(struct kmip_node *)); if (bis == NULL) return NULL; } va_start(ap, batch_count); for (i = 0; i < batch_count; i++) bis[i] = va_arg(ap, struct kmip_node *); va_end(ap); ret = kmip_new_request(request_header, batch_count, bis); if (bis != NULL) free(bis); return ret; } /** * Constructs a Query request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Query Function Yes Enumeration v1.0 * ... may be repeated * * @param query_count the number of query function items following * @param functions query function items * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_query_request_payload(unsigned int query_count, const enum kmip_query_function *functions) { struct kmip_node *rpl, *qf = NULL; unsigned int i; int rc = 0; if (query_count > 0 && functions == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 0); if (rpl == NULL) return NULL; for (i = 0; i < query_count; i++) { qf = kmip_node_new_enumeration(KMIP_TAG_QUERY_FUNCTION, NULL, functions[i]); if (qf == NULL) goto error; rc = kmip_node_add_structure_element(rpl, qf); if (rc != 0) break; kmip_node_free(qf); qf = NULL; } if (rc != 0) goto error; return rpl; error: kmip_node_free(rpl); kmip_node_free(qf); return NULL; } /** * Constructs a Query request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Query Function Yes Enumeration v1.0 * ... may be repeated * * @param query_count the number of query function items following * @param query items (enum kmip_query_function) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_query_request_payload_va(unsigned int query_count, ...) { enum kmip_query_function *qfs = NULL; struct kmip_node *rpl; unsigned int i; va_list ap; if (query_count > 0) { qfs = calloc(query_count, sizeof(enum kmip_query_function)); if (qfs == NULL) return NULL; } va_start(ap, query_count); for (i = 0; i < query_count; i++) qfs[i] = va_arg(ap, enum kmip_query_function); va_end(ap); rpl = kmip_new_query_request_payload(query_count, qfs); if (qfs != NULL) free(qfs); return rpl; } static const struct kmip_version kmip_versions[] = { { .major = 1, .minor = 0 }, { .major = 1, .minor = 1 }, { .major = 1, .minor = 2 }, { .major = 1, .minor = 3 }, { .major = 1, .minor = 4 }, { .major = 2, .minor = 0 }, { .major = 2, .minor = 1 }, }; /** * Constructs a Discover Versions request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Protocol Version No Structure v1.2 * ... may be repeated * * @param version_count the number of version items following. If -1 then * all currently supported versions are added. * @param versions array of version items * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_discover_versions_payload(int version_count, const struct kmip_version *versions) { struct kmip_node *rpl, *ver = NULL; int rc = 0; int i; if (version_count > 0 && versions == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 0); if (rpl == NULL) return NULL; if (version_count < 0) { versions = kmip_versions; version_count = sizeof(kmip_versions) / sizeof(struct kmip_version); } for (i = 0; i < version_count; i++) { ver = kmip_new_protocol_version(&versions[i]); if (ver == NULL) goto error; rc = kmip_node_add_structure_element(rpl, ver); if (rc != 0) break; kmip_node_free(ver); ver = NULL; } if (rc != 0) goto error; return rpl; error: kmip_node_free(rpl); kmip_node_free(ver); return NULL; } /** * Constructs a Discover Versions request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Protocol Version No Structure v1.2 * ... may be repeated * * @param version_count the number of version items following. If -1 then * all currently supported versions are added. * @param version items (struct kmip_version) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_discover_versions_payload_va(int version_count, ...) { struct kmip_version *versions = NULL; struct kmip_node *rpl; va_list ap; int i; if (version_count > 0) { versions = calloc(version_count, sizeof(struct kmip_version)); if (versions == NULL) return NULL; } va_start(ap, version_count); for (i = 0; i < version_count; i++) versions[i] = *va_arg(ap, struct kmip_version *); va_end(ap); rpl = kmip_new_discover_versions_payload(version_count, versions); if (versions != NULL) free(versions); return rpl; } /** * Constructs a Protection Storage Masks node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Storage Masks Yes Structure v2.0 * Protection Storage Mask Yes Integer v2.0 * ... may be repeated * * @param masks_count the number of protection storage masks * @param masks array of mask items * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protection_storage_masks(unsigned int masks_count, int32_t *masks) { struct kmip_node *ret, *psm; unsigned int i; int rc = 0; if (masks_count > 0 && masks == NULL) return NULL; ret = kmip_node_new_structure_va(KMIP_TAG_PROTECTION_STORAGE_MASKS, NULL, 0); if (ret == NULL) return NULL; for (i = 0; i < masks_count; i++) { psm = kmip_node_new_integer(KMIP_TAG_PROTECTION_STORAGE_MASK, NULL, masks[i]); if (psm == NULL) break; rc = kmip_node_add_structure_element(ret, psm); if (rc != 0) break; kmip_node_free(psm); psm = NULL; } if (rc != 0) goto error; return ret; error: kmip_node_free(ret); kmip_node_free(psm); return NULL; } /** * Constructs a Protection Storage Masks node: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Protection Storage Masks Yes Structure v2.0 * Protection Storage Mask Yes Integer v2.0 * ... may be repeated * * @param masks_count the number of protection storage masks following * @param mask items (int32_t) * * @returns the allocated node, or NULL in case of an error. */ struct kmip_node *kmip_new_protection_storage_masks_va(unsigned int masks_count, ...) { int32_t *masks = NULL; struct kmip_node *ret; unsigned int i; va_list ap; if (masks_count > 0) { masks = calloc(masks_count, sizeof(int32_t)); if (masks == NULL) return NULL; } va_start(ap, masks_count); for (i = 0; i < masks_count; i++) masks[i] = va_arg(ap, int32_t); va_end(ap); ret = kmip_new_protection_storage_masks(masks_count, masks); if (masks != NULL) free(masks); return ret; } /** * Constructs a Create request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to create * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param 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_create_request_payload( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *prot_storage_masks, unsigned int attrs_count, struct kmip_node **attrs) { struct kmip_node *rpl = NULL, *otyp = NULL, *att; if (attrs_count > 0 && attrs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); otyp = kmip_new_object_type(obj_type); if (otyp == NULL) return NULL; if (version->major < 2) prot_storage_masks = NULL; att = kmip_new_attributes(version, KMIP_TAG_ATTRIBUTES, attrs_count, attrs); if (att == NULL) goto out; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, otyp, att, prot_storage_masks); out: kmip_node_free(otyp); kmip_node_free(att); return rpl; } /** * Constructs a Create request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to create * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param 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_create_request_payload_va( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *prot_storage_masks, 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_create_request_payload(version, obj_type, prot_storage_masks, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** * Constructs a Get Attribute List request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address (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_get_attribute_list_request_payload( struct kmip_node *unique_id) { struct kmip_node *rpl; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); return rpl; } /** * Constructs a Get Attributes request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Name No Text String v1.x only * ... may be repeated * Attribute Reference No Enumeration v2.x only * Structure v2.x only * ... may be repeated * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param num_attrs number of attribute references following * @param attr_refs array of attribute references (struct kmip_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_get_attributes_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, unsigned int num_attrs, struct kmip_node **attr_refs) { struct kmip_node *rpl, *v2_attr_ref, *v1_attr_name; unsigned int i; int rc = 0; if (num_attrs > 0 && attr_refs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); for (i = 0; i < num_attrs; i++) { v2_attr_ref = attr_refs[i]; if (v2_attr_ref == NULL) continue; if (version->major == 1) { /* KMIP v1.x */ v1_attr_name = kmip_new_attribute_name_v1(v2_attr_ref); if (v1_attr_name == NULL) { rc = -EBADMSG; break; } rc = kmip_node_add_structure_element(rpl, v1_attr_name); kmip_node_free(v1_attr_name); } else { /* KMIP >= v2.0 */ rc = kmip_node_add_structure_element(rpl, v2_attr_ref); } if (rc != 0) break; } if (rc != 0) goto error; return rpl; error: kmip_node_free(rpl); return NULL; } /** * Constructs a Get Attributes request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Name No Text String v1.x only * ... may be repeated * Attribute Reference No Enumeration v2.x only * Structure v2.x only * ... may be repeated * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param num_attrs number of attribute references following * @param attribute references (struct kmip_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_get_attributes_request_payload_va( const struct kmip_version *version, struct kmip_node *unique_id, unsigned int num_attrs, ...) { struct kmip_node *ret, **attr_refs = NULL; unsigned int i, k; va_list ap; if (num_attrs > 0) { attr_refs = calloc(num_attrs, sizeof(struct kmip_node *)); if (attr_refs == NULL) return NULL; } va_start(ap, num_attrs); for (i = 0, k = 0; i < num_attrs; i++) { attr_refs[k] = va_arg(ap, struct kmip_node *); if (attr_refs[k] != NULL) k++; } va_end(ap); ret = kmip_new_get_attributes_request_payload(version, unique_id, k, attr_refs); if (attr_refs != NULL) free(attr_refs); return ret; } /** * Constructs a Add Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * or * New Attribute Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param v2_attr the attribute to add (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_add_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_attr) { struct kmip_node *rpl, *new_attr, *v1_attr; int rc; if (v2_attr == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x */ rc = kmip_v1_attr_from_v2_attr(v2_attr, &v1_attr); if (rc != 0) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, v1_attr); kmip_node_free(v1_attr); } else { /* KMIP >= v2.0 */ new_attr = kmip_new_current_new_attribute(true, v2_attr); if (new_attr == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, new_attr); kmip_node_free(new_attr); } return rpl; } /** * Constructs a Modify Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Yes Structure v1.x only * or * Current Attribute No Structure v2.x only * New Attribute Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param v2_current the current attribute (as KMIP v2.x attribute). * Can be NULL, ignored for KMIP v1.x. * @param v2_attr the attribute to modify (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_modify_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_current, struct kmip_node *v2_attr) { struct kmip_node *rpl, *new_attr, *cur_attr = NULL, *v1_attr; int rc; if (v2_attr == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x */ rc = kmip_v1_attr_from_v2_attr(v2_attr, &v1_attr); if (rc != 0) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, v1_attr); kmip_node_free(v1_attr); } else { /* KMIP >= v2.0 */ new_attr = kmip_new_current_new_attribute(true, v2_attr); if (new_attr == NULL) return NULL; if (v2_current != NULL) { cur_attr = kmip_new_current_new_attribute(false, v2_current); if (cur_attr == NULL) { kmip_node_free(new_attr); return NULL; } } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, unique_id, cur_attr, new_attr); kmip_node_free(new_attr); if (cur_attr != NULL) kmip_node_free(cur_attr); } return rpl; } /** * Constructs a Set Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * New Attribute Yes Structure v2.x only * * KMIP v1.x does not have a Set Attribute operation. * * @param unique_id the unique id of the object to address * @param v2_attr the attribute to set (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_set_attribute_v2_request_payload( struct kmip_node *unique_id, struct kmip_node *v2_attr) { struct kmip_node *rpl, *new_attr; if (v2_attr == NULL) return NULL; new_attr = kmip_new_current_new_attribute(true, v2_attr); if (new_attr == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, new_attr); kmip_node_free(new_attr); return rpl; } /** * Constructs a Delete Attribute request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Attribute Name Yes Text String v1.x only * Attribute Index No Integer v1.x only * or * Current Attribute No Structure v2.x only * Attribute Reference No Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to address * @param v2_current the current attribute (as KMIP v2.x attribute). * Can be NULL. * @param attr_ref the attribute to modify (as KMIP v2.x attribute * reference). Either v2_current or attr_ref can be * specified. * * @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_delete_attribute_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, struct kmip_node *v2_current, struct kmip_node *attr_ref) { struct kmip_node *rpl, *cur_attr = NULL, *nam = NULL; const char *vendor_id, *attr_name, *name; char *custom_name = NULL; int rc; if (v2_current != NULL && attr_ref != NULL) return NULL; if (v2_current == NULL && attr_ref == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (version->major == 1) { /* KMIP v1.x */ if (v2_current != NULL) { if (kmip_node_get_tag(v2_current) == KMIP_TAG_ATTRIBUTE) { /* Special handling for v2.x Vendor Attribute */ rc = kmip_get_vendor_attribute(v2_current, &vendor_id, &attr_name, NULL); if (rc != 0) return NULL; custom_name = kmip_build_v1_custom_attr_name( vendor_id, attr_name); if (custom_name == NULL) return NULL; name = custom_name; } else { name = kmip_v1_attr_name_by_tag( kmip_node_get_tag(v2_current)); } nam = kmip_node_new_text_string(KMIP_TAG_ATTRIBUTE_NAME, NULL, name); if (custom_name != NULL) free(custom_name); } else if (attr_ref != NULL) { nam = kmip_new_attribute_name_v1(attr_ref); } if (nam == NULL) return NULL; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 2, unique_id, nam); kmip_node_free(nam); } else { /* KMIP >= v2.0 */ if (v2_current != NULL) { cur_attr = kmip_new_current_new_attribute(false, v2_current); if (cur_attr == NULL) return NULL; } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, unique_id, cur_attr, attr_ref); if (cur_attr != NULL) kmip_node_free(cur_attr); } return rpl; } /** * Constructs an Activate request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @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_activate_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Destroy request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @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_destroy_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Archive request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @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_archive_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Recover request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * * @param unique_id the unique id of the object to address * * @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_recover_request_payload(struct kmip_node *unique_id) { return kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 1, unique_id); } /** * Constructs an Revoke request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Revocation Reason Yes Structure v1.0 * Revocation Reason Code Yes Enumeration v1.0 * Revocation Message No Text String v1.0 * Compromise Occurrence Date No Date Time v1.0 * * @param unique_id the unique id of the object to address * @param rsn the revocation reason * @param message the revocation message (can be NULL) * @param compromise_date the date when he compromise happened (can be 0) * * @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_revoke_request_payload(struct kmip_node *unique_id, enum kmip_revoke_reason rsn, const char *message, uint64_t compromise_date) { struct kmip_node *rsn_code, *reason = NULL, *rsn_msg = NULL; struct kmip_node *rpl = NULL, *date = NULL; rsn_code = kmip_node_new_enumeration(KMIP_TAG_REVOCATION_REASON_CODE, NULL, rsn); if (rsn_code == NULL) return NULL; if (message != NULL) { rsn_msg = kmip_node_new_text_string(KMIP_TAG_REVOCATION_MESSAGE, NULL, message); if (rsn_msg == NULL) goto out; } reason = kmip_node_new_structure_va(KMIP_TAG_REVOCATION_REASON, NULL, 2, rsn_code, rsn_msg); if (reason == NULL) goto out; switch (rsn) { case KMIP_REVOK_RSN_KEY_COMPROMISE: case KMIP_REVOK_RSN_CA_COMPROMISE: if (compromise_date != 0) { date = kmip_node_new_date_time( KMIP_TAG_COMPROMISE_OCCURRENCE_DATE, NULL, compromise_date); if (date == NULL) goto out; } break; default: /*Compromise date is ignored on other reasons */ break; } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 3, unique_id, reason, date); out: kmip_node_free(rsn_code); kmip_node_free(rsn_msg); kmip_node_free(reason); kmip_node_free(date); return rpl; } /** * Constructs an Locate request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Maximum Items No Integer v1.0 * Offset Items No Integer v1.3 * Storage Status Mask No Integer v1.0 * Object Group Member No Enumeration v1.2 * Attribute No Structure v1.x only * ... may be repeated * Attributes Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param max_items the maximum numbers of items to return. If <= 0 * then no limit is assumed. * @param offset_items the number of items to skip If <= 0 then no offset * is assumed. Ignored for KMIP <= v1.2. * @param storage_status the storage status filter. If 0, then no filter is * used and only on-line objects are returned. * @param obj_group the object group filter. If 0 then no object group * filter is used. Ignored for KMIP <= v1.1. * @param attrs_count the number of attributes following (can be 0) * @param 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_locate_request_payload( const struct kmip_version *version, int32_t max_items, int32_t offset_items, enum kmip_storage_status_mask storage_status, enum kmip_object_group_member obj_group, unsigned int attrs_count, struct kmip_node **attrs) { struct kmip_node *max = NULL, *ofs = NULL, *stm = NULL, *grp = NULL; struct kmip_node *rpl = NULL, *att, *v2_attr, *v1_attr; unsigned int i; int rc; if (attrs_count > 0 && attrs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (max_items > 0) { max = kmip_node_new_integer(KMIP_TAG_MAXIMUM_ITEMS, NULL, max_items); if (max == NULL) return NULL; } if (offset_items > 0 && (version->major > 1 || (version->major == 1 && version->minor > 2))) { ofs = kmip_node_new_integer(KMIP_TAG_OFFSET_ITEMS, NULL, offset_items); if (ofs == NULL) goto out; } if (storage_status != 0) { stm = kmip_node_new_integer(KMIP_TAG_STORAGE_STATUS_MASK, NULL, storage_status); if (stm == NULL) goto out; } if (obj_group > 0 && (version->major > 1 || version->minor > 1)) { grp = kmip_node_new_enumeration(KMIP_TAG_OBJECT_GROUP_MEMBER, NULL, obj_group); if (grp == NULL) goto out; } if (version->major == 1) { /* KMIP v1.x */ rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 4, max, ofs, stm, grp); if (rpl == NULL) goto out; for (i = 0; i < attrs_count; i++) { v2_attr = 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(rpl, v1_attr); kmip_node_free(v1_attr); if (rc != 0) goto error; } } else { /* KMIP >= v2.0 */ att = kmip_new_attributes(version, KMIP_TAG_ATTRIBUTES, attrs_count, attrs); if (att == NULL) goto out; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 5, max, ofs, stm, grp, att); kmip_node_free(att); } goto out; error: kmip_node_free(rpl); rpl = NULL; out: kmip_node_free(max); kmip_node_free(ofs); kmip_node_free(stm); kmip_node_free(grp); return rpl; } /** * Constructs an Locate request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Maximum Items No Integer v1.0 * Offset Items No Integer v1.3 * Storage Status Mask No Integer v1.0 * Object Group Member No Enumeration v1.2 * Attribute No Structure v1.x only * ... may be repeated * Attributes Yes Structure v2.x only * * @param version the protocol version. If null, the current default * protocol version is used. * @param max_items the maximum numbers of items to return. If <= 0 * then no limit is assumed. * @param offset_items the number of items to skip If <= 0 then no offset * is assumed. Ignored for KMIP <= v1.2. * @param storage_status the storage status filter. If 0, then no filter is * used and only on-line objects are returned. * @param obj_group the object group filter. If 0 then no object group * filter is used. Ignored for KMIP <= v1.1. * @param attrs_count the number of attributes following (can be 0) * @param 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_locate_request_payload_va( const struct kmip_version *version, int32_t max_items, int32_t offset_items, enum kmip_storage_status_mask storage_status, enum kmip_object_group_member obj_group, 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_locate_request_payload(version, max_items, offset_items, storage_status, obj_group, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** * Constructs an Register request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Yes Structure v1.0 * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to register * @param object the object to register * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param 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_register_request_payload( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *object, struct kmip_node *prot_storage_masks, unsigned int attrs_count, struct kmip_node **attrs) { struct kmip_node *rpl = NULL, *otyp = NULL, *att; if (object == NULL) return NULL; if (attrs_count > 0 && attrs == NULL) return NULL; if (version == NULL) version = kmip_get_default_protocol_version(); otyp = kmip_new_object_type(obj_type); if (otyp == NULL) return NULL; if (version->major < 2) prot_storage_masks = NULL; att = kmip_new_attributes(version, KMIP_TAG_ATTRIBUTES, attrs_count, attrs); if (att == NULL) goto out; rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 4, otyp, att, object, prot_storage_masks); out: kmip_node_free(otyp); kmip_node_free(att); return rpl; } /** * Constructs an Register request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Object Type Yes Enumeration v1.0 * Template-Attribute Yes(v1.x) Structure v1.x only * Attributes Yes(v2.x) Structure v2.x only * Yes Structure v1.0 * Protection Storage Masks No Structure v2.x * * @param version the protocol version. If null, the current default * protocol version is used. * @param obj_type the object type to register * @param object the object to register * @paran prot_storage_masks the protection storage masks (can be NULL) * @param attrs_count the number of attributes following (can be 0) * @param 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_register_request_payload_va( const struct kmip_version *version, enum kmip_object_type obj_type, struct kmip_node *object, struct kmip_node *prot_storage_masks, 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_register_request_payload(version, obj_type, object, prot_storage_masks, k, attrs); if (attrs != NULL) free(attrs); return ret; } /** * Constructs an Get request payload: * * Object Required Encoding KMIP version * --------------------------------------------------------------------- * Payload Yes Structure v1.0 * Unique Identifier No Text String v1.0 * Enumeration v2.0 * Integer v2.0 * Key Format Type No Enumeration v1.0 * Key Wrap Type No Enumeration v1.4 * Key Compression Type No Enumeration v1.0 * Key Wrapping Specification No Structure v1.0 * * @param version the protocol version. If null, the current default * protocol version is used. * @param unique_id the unique id of the object to get * @param format_type the format type of the key (ignored if 0) * @paran wrap_type the wrap type (ignored if 0) * @param compr_type the compression type (ignored if 0) * @param wrap_specification the key wrapping specification 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_get_request_payload( const struct kmip_version *version, struct kmip_node *unique_id, enum kmip_key_format_type format_type, enum kmip_key_wrap_type wrap_type, enum kmip_key_compression_type compr_type, struct kmip_node *wrap_specification) { struct kmip_node *rpl = NULL, *fmt = NULL, *wt = NULL, *cmpt = NULL; if (version == NULL) version = kmip_get_default_protocol_version(); if (format_type != 0) { fmt = kmip_node_new_enumeration(KMIP_TAG_KEY_FORMAT_TYPE, NULL, format_type); if (fmt == NULL) goto out; } if (wrap_type != 0 && (version->major > 1 || (version->major == 1 && version->minor > 3))) { wt = kmip_node_new_enumeration(KMIP_TAG_KEY_WRAP_TYPE, NULL, wrap_type); if (wt == NULL) goto out; } if (compr_type != 0) { cmpt = kmip_node_new_enumeration(KMIP_TAG_KEY_COMPRESSION_TYPE, NULL, compr_type); if (cmpt == NULL) goto out; } rpl = kmip_node_new_structure_va(KMIP_TAG_REQUEST_PAYLOAD, NULL, 5, unique_id, fmt, wt, cmpt, wrap_specification); out: kmip_node_free(fmt); kmip_node_free(wt); kmip_node_free(cmpt); return rpl; }