libekmfweb: Retrieve information about key templates

Key templates are used by EKMF Web to generate new keys. The template
specifies the key algorithm, the key size, and type (e.g. CCA DATA or
CIPHER). It also determines how a newly generated key is named through
a key label template containing label tags.

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
2020-05-07 17:21:54 +02:00
committed by Jan Höppner
parent 9f99706c26
commit cc9b202a9b
5 changed files with 1109 additions and 0 deletions

View File

@@ -421,6 +421,197 @@ int ekmf_retrieve_key(const struct ekmf_config *config, CURL **curl_handle,
size_t *key_blob_length, char **error_msg,
const struct ekmf_ext_lib *ext_lib, bool verbose);
struct ekmf_tag_definition {
/** name of the tag */
const char *name;
/** Optional: description of the tag (can be NULL) */
const char *description;
};
struct ekmf_tag_def_list {
/** array of tag definitions */
struct ekmf_tag_definition *tag_defs;
/** number of tag definitions in array above */
size_t num_tag_defs;
};
struct ekmf_template_info {
/** name of the template */
const char *name;
/** UUID of the template */
const char *uuid;
/** type of the keys generated with this template , e.g. CIPHER */
const char *key_type;
/** algorithm of the keys generated with this template, e.g. AES */
const char *algorithm;
/** bit size of the keys generated with this template */
size_t key_size;
/** state of the template , e.g. ACTIVE */
const char *state;
/** state of the keys generated with this template , e.g. ACTIVE */
const char *key_state;
/** label template when generating keys with this template */
const char *label_template;
/** label tag definition list */
struct ekmf_tag_def_list label_tags;
/** true if keys generated with this template can be exported */
bool export_allowed;
/** the keystore type of the keys generated with this template */
const char *keystore_type;
/** Type of ECC curve, e.g. PRIME_CURVE (for algorithm = ECC) */
const char *curve;
/** timestamp when the template was created */
const char *created_on;
/** timestamp when the template was updated */
const char *updated_on;
};
/**
* Callback function used with the ekmf_list_templates function. This
* callback is called for each template found.
*
* @param curl_handle a CURL handle that can be used to perform further
* EKMFWeb functions within the callback.
* @param template_info a struct containing information about the template.
* If any of the information needs to be kept, then the
* callback function must make a copy of the
* information. The memory holding the information
* passed to the callback is no longer valid after the
* callback has returned.
* @param private the private pointer that was specified with the
* ekmf_list_templates invocation.
*
* @returns zero for success, a negative errno in case of an error.
* When a nonzero return code is returned, the template listing process stops,
* and ekmf_list_templates returns the return code from the callback.
*/
typedef int (*ekmf_template_cb_t)(CURL *curl_handle,
struct ekmf_template_info *template_info,
void *private);
/**
* List available key templates. Only templates in state ACTIVE, with key
* algorithm AES and keystore type PERVASIVE_ENCRYPTION are listed. The
* templates are ordered by name in ascending order.
*
* To perform a single request, set curl_handle to NULL. This will cause the
* function to initialize a new CURL handle, use it, and destroy it.
* If you plan to perform multiple requests to the same host, supply the address
* of a CURL pointer that is initially NULL. This function will then initialize
* a new CURL handle on the first call. On subsequent calls, pass in the address
* of the same CURL pointer so that the CURL handle is reused. After the last
* request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
*
* @param config the configuration structure
* @param curl_handle address of a CURL handle used for reusing the same
* CURL handle with multiple requests.
* @param template_cb a callback function that is called for each template
* found
* @param private a pointer that is passed as-is to the callback
* @param name_pattern a pattern to filter by name, or NULL to list all.
* @param state the state of the templates to list. If NULL then
* templates in state 'ACTIVE' are listed
* @param error_msg on return: If not NULL, then a textual error message
* is returned in case of a failing request. The caller
* must free the error string when it is not NULL.
* @param verbose if true, verbose messages are printed
*
* @returns zero for success, a negative errno in case of an error.
* -EACCES is returned, if no or no valid login token is available.
* -EPERM is returned if the login token does not have permission to
* list the templates
*/
int ekmf_list_templates(const struct ekmf_config *config, CURL **curl_handle,
ekmf_template_cb_t template_cb, void *private,
const char *name_pattern, const char *state,
char **error_msg, bool verbose);
/**
* Get a template by its UUID.
*
* To perform a single request, set curl_handle to NULL. This will cause the
* function to initialize a new CURL handle, use it, and destroy it.
* If you plan to perform multiple requests to the same host, supply the address
* of a CURL pointer that is initially NULL. This function will then initialize
* a new CURL handle on the first call. On subsequent calls, pass in the address
* of the same CURL pointer so that the CURL handle is reused. After the last
* request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
*
* @param config the configuration structure
* @param curl_handle address of a CURL handle used for reusing the same
* CURL handle with multiple requests.
* @param template_uuid the UUID of the template to get
* @param template an address of a template info pointer. On return
* the pointer is updated to point to a newly allocated
* template info struct. It must be freed by the caller
* using ekmf_free_template_info when no longer needed.
* @param error_msg on return: If not NULL, then a textual error message
* is returned in case of a failing request. The caller
* must free the error string when it is not NULL.
* @param verbose if true, verbose messages are printed
*
* @returns zero for success, a negative errno in case of an error.
* -EACCES is returned, if no or no valid login token is available.
* -EPERM is returned if the login token does not have permission to
* get the template
*/
int ekmf_get_template(const struct ekmf_config *config, CURL **curl_handle,
const char *template_uuid,
struct ekmf_template_info **template, char **error_msg,
bool verbose);
/**
* Get the last used sequence number of a template by its UUID.
*
* To perform a single request, set curl_handle to NULL. This will cause the
* function to initialize a new CURL handle, use it, and destroy it.
* If you plan to perform multiple requests to the same host, supply the address
* of a CURL pointer that is initially NULL. This function will then initialize
* a new CURL handle on the first call. On subsequent calls, pass in the address
* of the same CURL pointer so that the CURL handle is reused. After the last
* request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
*
* @param config the configuration structure
* @param curl_handle address of a CURL handle used for reusing the same
* CURL handle with multiple requests.
* @param template_uuid the UUID of the template to get
* @param seqNumber On return: the last used sequence number of this
* template.
* @param error_msg on return: If not NULL, then a textual error message
* is returned in case of a failing request. The caller
* must free the error string when it is not NULL.
* @param verbose if true, verbose messages are printed
*
* @returns zero for success, a negative errno in case of an error.
* -EACCES is returned, if no or no valid login token is available.
* -EPERM is returned if the login token does not have permission to
* get the template
*/
int ekmf_get_last_seq_no(const struct ekmf_config *config, CURL **curl_handle,
const char *template_uuid, unsigned int *seqNumber,
char **error_msg, bool verbose);
/**
* Clones a template info structure by making a deep copy of all strings and
* arrays.
* The copied template info must be freed using ekmf_free_template_info() by
* the caller.
*
* @param src the source template info structure
* @param dest the destination template info structure
*
* @returns zero for success, a negative errno in case of an error
*/
int ekmf_clone_template_info(const struct ekmf_template_info *src,
struct ekmf_template_info **dest);
/**
* Free a template info structure.
*
* @param template the template to free
*/
void ekmf_free_template_info(struct ekmf_template_info *template);
/**
* Close the connection to the EKMFWeb server by destroying the CURL handle.
*

View File

@@ -44,6 +44,18 @@
#define EKMF_URI_SYSTEM_PUBKEY "/api/v1/system/publicKey"
#define EKMF_URI_KEYS_EXPORT "/api/v1/keys/%s/export"
#define EKMF_URI_TEMPLATE_GET "/api/v1/templates/%s"
#define EKMF_URI_TEMPLATE_LIST "/api/v1/templates" \
"?templateStates=%s" \
"&orderBy=%s" \
"&namePattern=%s"
#define EKMF_URI_TEMPLATE_SEQNO "/api/v1/templates/%s/sequenceNumber"
#define LIST_ELEMENTS_PER_PAGE 20
#define TEMPLATE_STATE_ACTIVE "ACTIVE"
#define KEY_ALGORITHM_AES "AES"
#define KEYSTORE_TYPE_PERV_ENCR "PERVASIVE_ENCRYPTION"
#define ORDER_BY_NAME_ASC "name%3Aasc"
#define pr_verbose(verbose, fmt...) do { \
if (verbose) \
@@ -2118,6 +2130,601 @@ out:
return rc;
}
/**
* Callback function for the _ekmf_list_request function. This callback
* is called for each result element. The curl handle can be used to perform
* further requests within the callback. However, the curl handle must not be
* closed/destroyed!
*/
typedef int (*ekmf_element_cb_t)(CURL *curl, json_object *element,
void *private, bool verbose);
/**
* Performs a list request (GET) on a base list_uri and iterates over
* multiple pages. The response of a list request is expected to be a
* JSON array of elements. For each element, the element callback is called
* with the element.
* The list_uri must contain anything required to list the desired objects,
* except the page and perPage UTL parameters. Those are added by this function.
*/
static int _ekmf_list_request(const struct ekmf_config *config,
const char *list_uri, CURL *curl,
ekmf_element_cb_t element_cb, void *private,
const char *login_token, char **error_msg,
bool verbose)
{
json_object *response_obj = NULL;
json_object *element_obj;
int num, i, rc = 0;
unsigned int page;
char *uri = NULL;
long status_code;
bool has_query;
if (config == NULL || list_uri == NULL || element_cb == NULL ||
curl == NULL)
return -EINVAL;
has_query = strchr(list_uri, '?') != NULL;
for (page = 1; ; page++) {
if (asprintf(&uri, "%s%sperPage=%u&page=%u", list_uri,
has_query ? "&" : "?", LIST_ELEMENTS_PER_PAGE,
page) < 0) {
pr_verbose(verbose, "asprintf failed");
rc = -ENOMEM;
goto out;
}
rc = _ekmf_perform_request(config, uri, "GET", NULL, NULL,
login_token, &response_obj, NULL,
&status_code, error_msg, curl,
verbose);
free(uri);
uri = NULL;
if (rc != 0) {
pr_verbose(verbose, "Failed perform the REST call");
if (rc > 0)
rc = -EIO;
goto out;
}
switch (status_code) {
case 200:
break;
case 400:
pr_verbose(verbose, "Bad request");
rc = -EBADMSG;
goto out;
case 401:
pr_verbose(verbose, "Not authorized");
rc = -EACCES;
goto out;
case 403:
pr_verbose(verbose, "Insufficient permissions");
rc = -EPERM;
goto out;
default:
pr_verbose(verbose, "REST Call failed with HTTP "
"status code: %ld", status_code);
rc = -EIO;
goto out;
}
JSON_CHECK_OBJ(response_obj, json_type_array, rc, -EIO,
"No or invalid response content", verbose, out);
num = json_object_array_length(response_obj);
if (num == 0)
break;
for (i = 0; i < num; i++) {
element_obj = json_object_array_get_idx(response_obj,
i);
if (element_obj == NULL) {
pr_verbose(verbose, "Failed to get array "
"element for index %d", i);
rc = -EBADMSG;
goto out;
}
rc = element_cb(curl, element_obj, private, verbose);
if (rc != 0) {
pr_verbose(verbose, "Element-callback failed "
"for index %d", i);
goto out;
}
}
if (response_obj != NULL)
json_object_put(response_obj);
response_obj = NULL;
if (num < LIST_ELEMENTS_PER_PAGE)
break;
}
out:
if (uri != NULL)
free(uri);
if (response_obj != NULL)
json_object_put(response_obj);
return rc;
}
struct ekmf_template_cb_data_t {
ekmf_template_cb_t template_cb;
void *cb_private;
};
/**
* Callback for template list function. Builds the template info structure
* and calls the application callback.
*/
static int _ekmf_template_cb(CURL *curl, json_object *element,
void *private, bool verbose)
{
struct ekmf_template_cb_data_t *cb_data = private;
struct ekmf_template_info template = { 0 };
int rc;
if (cb_data->template_cb == NULL) {
pr_verbose(verbose, "No template callback function");
return -EINVAL;
}
rc = json_build_template_info(element, &template, false);
if (rc != 0) {
pr_verbose(verbose, "Failed to build template info");
goto out;
}
rc = cb_data->template_cb(curl, &template, cb_data->cb_private);
if (rc != 0) {
pr_verbose(verbose, "Template callback rc: %d", rc);
goto out;
}
out:
free_tag_def_list(&template.label_tags, false);
return rc;
}
/**
* List available key templates. Only templates in state ACTIVE, with key
* algorithm AES and keystore type PERVASIVE_ENCRYPTION are listed. The
* templates are ordered by name in ascending order.
*
* To perform a single request, set curl_handle to NULL. This will cause the
* function to initialize a new CURL handle, use it, and destroy it.
* If you plan to perform multiple requests to the same host, supply the address
* of a CURL pointer that is initially NULL. This function will then initialize
* a new CURL handle on the first call. On subsequent calls, pass in the address
* of the same CURL pointer so that the CURL handle is reused. After the last
* request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
*
* @param config the configuration structure
* @param curl_handle address of a CURL handle used for reusing the same
* CURL handle with multiple requests.
* @param template_cb a callback function that is called for each template
* found
* @param private a pointer that is passed as-is to the callback
* @param name_pattern a pattern to filter by name, or NULL to list all.
* @param state the state of the templates to list. If NULL then
* templates in state 'ACTIVE' are listed
* @param error_msg on return: If not NULL, then a textual error message
* is returned in case of a failing request. The caller
* must free the error string when it is not NULL.
* @param verbose if true, verbose messages are printed
*
* @returns zero for success, a negative errno in case of an error.
* -EACCES is returned, if no or no valid login token is available.
* -EPERM is returned if the login token does not have permission to
* list the templates
*/
int ekmf_list_templates(const struct ekmf_config *config, CURL **curl_handle,
ekmf_template_cb_t template_cb, void *private,
const char *name_pattern, const char *state,
char **error_msg, bool verbose)
{
struct ekmf_template_cb_data_t cb_data;
char *escaped_name_pattern = NULL;
char *escaped_state = NULL;
char *login_token = NULL;
bool token_valid = false;
CURL *curl = NULL;
char *uri = NULL;
int rc;
if (config == NULL || template_cb == NULL)
return -EINVAL;
rc = ekmf_check_login_token(config, &token_valid, &login_token,
verbose);
if (rc != 0 || !token_valid) {
pr_verbose(verbose, "No valid login token available");
rc = -EACCES;
goto out;
}
rc = _ekmf_get_curl_handle(curl_handle, &curl);
if (rc != 0) {
pr_verbose(verbose, "Failed to get CURL handle");
rc = -EIO;
goto out;
}
cb_data.template_cb = template_cb;
cb_data.cb_private = private;
escaped_name_pattern = curl_easy_escape(curl, name_pattern != NULL ?
name_pattern : "*", 0);
if (escaped_name_pattern == NULL) {
pr_verbose(verbose, "Failed to url-escape the name pattern");
rc = -EIO;
goto out;
}
escaped_state = curl_easy_escape(curl, state != NULL ? state :
TEMPLATE_STATE_ACTIVE, 0);
if (escaped_state == NULL) {
pr_verbose(verbose, "Failed to url-escape the state");
rc = -EIO;
goto out;
}
if (asprintf(&uri, EKMF_URI_TEMPLATE_LIST, escaped_state,
ORDER_BY_NAME_ASC, escaped_name_pattern) < 0) {
pr_verbose(verbose, "asprintf failed");
rc = -ENOMEM;
goto out;
}
rc = _ekmf_list_request(config, uri, curl, _ekmf_template_cb,
&cb_data, login_token, error_msg, verbose);
if (rc != 0) {
pr_verbose(verbose, "Failed to perform the list request");
if (rc > 0)
rc = -EIO;
goto out;
}
out:
_ekmf_release_curl_handle(curl_handle, curl);
if (login_token != NULL)
free(login_token);
if (uri != NULL)
free(uri);
if (escaped_name_pattern != NULL)
curl_free(escaped_name_pattern);
if (escaped_state != NULL)
curl_free(escaped_state);
return rc;
}
/**
* Get a template by its UUID.
*
* To perform a single request, set curl_handle to NULL. This will cause the
* function to initialize a new CURL handle, use it, and destroy it.
* If you plan to perform multiple requests to the same host, supply the address
* of a CURL pointer that is initially NULL. This function will then initialize
* a new CURL handle on the first call. On subsequent calls, pass in the address
* of the same CURL pointer so that the CURL handle is reused. After the last
* request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
*
* @param config the configuration structure
* @param curl_handle address of a CURL handle used for reusing the same
* CURL handle with multiple requests.
* @param template_uuid the UUID of the template to get
* @param template an address of a template info pointer. On return
* the pointer is updated to point to a newly allocated
* template info struct. It must be freed by the caller
* using ekmf_free_template_info when no longer needed.
* @param error_msg on return: If not NULL, then a textual error message
* is returned in case of a failing request. The caller
* must free the error string when it is not NULL.
* @param verbose if true, verbose messages are printed
*
* @returns zero for success, a negative errno in case of an error.
* -EACCES is returned, if no or no valid login token is available.
* -EPERM is returned if the login token does not have permission to
* get the template
*/
int ekmf_get_template(const struct ekmf_config *config, CURL **curl_handle,
const char *template_uuid,
struct ekmf_template_info **template, char **error_msg,
bool verbose)
{
json_object *response_obj = NULL;
char *escaped_uuid = NULL;
char *login_token = NULL;
bool token_valid = false;
CURL *curl = NULL;
char *uri = NULL;
long status_code;
int rc;
if (config == NULL || template_uuid == NULL || template == NULL)
return -EINVAL;
*template = NULL;
rc = ekmf_check_login_token(config, &token_valid, &login_token,
verbose);
if (rc != 0 || !token_valid) {
pr_verbose(verbose, "No valid login token available");
rc = -EACCES;
goto out;
}
rc = _ekmf_get_curl_handle(curl_handle, &curl);
if (rc != 0) {
pr_verbose(verbose, "Failed to get CURL handle");
rc = -EIO;
goto out;
}
escaped_uuid = curl_easy_escape(curl, template_uuid, 0);
if (escaped_uuid == NULL) {
pr_verbose(verbose, "Failed to url-escape the template uuid");
rc = -EIO;
goto out;
}
if (asprintf(&uri, EKMF_URI_TEMPLATE_GET, escaped_uuid) < 0) {
pr_verbose(verbose, "asprintf failed");
rc = -ENOMEM;
goto out;
}
rc = _ekmf_perform_request(config, uri, "GET", NULL, NULL,
login_token, &response_obj, NULL,
&status_code, error_msg, curl, verbose);
if (rc != 0) {
pr_verbose(verbose, "Failed perform the REST call");
if (rc > 0)
rc = -EIO;
goto out;
}
switch (status_code) {
case 200:
break;
case 400:
pr_verbose(verbose, "Bad request");
rc = -EBADMSG;
goto out;
case 401:
pr_verbose(verbose, "Not authorized");
rc = -EACCES;
goto out;
case 403:
pr_verbose(verbose, "Insufficient permissions");
rc = -EPERM;
goto out;
case 404:
pr_verbose(verbose, "Not found");
rc = -ENOENT;
goto out;
default:
pr_verbose(verbose, "REST Call failed with HTTP status code: "
"%ld", status_code);
rc = -EIO;
goto out;
}
JSON_CHECK_OBJ(response_obj, json_type_object, rc, -EBADMSG,
"No or invalid response", verbose, out);
*template = calloc(1, sizeof(struct ekmf_template_info));
if (*template == NULL) {
pr_verbose(verbose, "calloc failed");
rc = -ENOMEM;
goto out;
}
rc = json_build_template_info(response_obj, *template, true);
if (rc != 0) {
pr_verbose(verbose, "Failed to build template info");
goto out;
}
out:
_ekmf_release_curl_handle(curl_handle, curl);
if (response_obj != NULL)
json_object_put(response_obj);
if (login_token != NULL)
free(login_token);
if (uri != NULL)
free(uri);
if (escaped_uuid != NULL)
curl_free(escaped_uuid);
if (rc != 0 && *template != NULL) {
free_template_info(*template);
free(*template);
*template = NULL;
}
return rc;
}
/**
* Get the last used sequence number of a template by its UUID.
*
* To perform a single request, set curl_handle to NULL. This will cause the
* function to initialize a new CURL handle, use it, and destroy it.
* If you plan to perform multiple requests to the same host, supply the address
* of a CURL pointer that is initially NULL. This function will then initialize
* a new CURL handle on the first call. On subsequent calls, pass in the address
* of the same CURL pointer so that the CURL handle is reused. After the last
* request, the CURL handle must be destroyed by calling ekmf_curl_destroy).
*
* @param config the configuration structure
* @param curl_handle address of a CURL handle used for reusing the same
* CURL handle with multiple requests.
* @param template_uuid the UUID of the template to get
* @param seqNumber On return: the last used sequence number of this
* template.
* @param error_msg on return: If not NULL, then a textual error message
* is returned in case of a failing request. The caller
* must free the error string when it is not NULL.
* @param verbose if true, verbose messages are printed
*
* @returns zero for success, a negative errno in case of an error.
* -EACCES is returned, if no or no valid login token is available.
* -EPERM is returned if the login token does not have permission to
* get the template
*/
int ekmf_get_last_seq_no(const struct ekmf_config *config, CURL **curl_handle,
const char *template_uuid, unsigned int *seqNumber,
char **error_msg, bool verbose)
{
json_object *response_obj = NULL, *field = NULL;
char *escaped_uuid = NULL;
char *login_token = NULL;
bool token_valid = false;
CURL *curl = NULL;
char *uri = NULL;
long status_code;
int rc;
if (config == NULL || template_uuid == NULL || seqNumber == NULL)
return -EINVAL;
*seqNumber = 0;
rc = ekmf_check_login_token(config, &token_valid, &login_token,
verbose);
if (rc != 0 || !token_valid) {
pr_verbose(verbose, "No valid login token available");
rc = -EACCES;
goto out;
}
rc = _ekmf_get_curl_handle(curl_handle, &curl);
if (rc != 0) {
pr_verbose(verbose, "Failed to get CURL handle");
rc = -EIO;
goto out;
}
escaped_uuid = curl_easy_escape(curl, template_uuid, 0);
if (escaped_uuid == NULL) {
pr_verbose(verbose, "Failed to url-escape the template uuid");
rc = -EIO;
goto out;
}
if (asprintf(&uri, EKMF_URI_TEMPLATE_SEQNO, escaped_uuid) < 0) {
pr_verbose(verbose, "asprintf failed");
rc = -ENOMEM;
goto out;
}
rc = _ekmf_perform_request(config, uri, "GET", NULL, NULL,
login_token, &response_obj, NULL,
&status_code, error_msg, curl, verbose);
if (rc != 0) {
pr_verbose(verbose, "Failed perform the REST call");
if (rc > 0)
rc = -EIO;
goto out;
}
switch (status_code) {
case 200:
break;
case 400:
pr_verbose(verbose, "Bad request");
rc = -EBADMSG;
goto out;
case 401:
pr_verbose(verbose, "Not authorized");
rc = -EACCES;
goto out;
case 403:
pr_verbose(verbose, "Insufficient permissions");
rc = -EPERM;
goto out;
case 404:
pr_verbose(verbose, "Not found");
rc = -ENOENT;
goto out;
default:
pr_verbose(verbose, "REST Call failed with HTTP status code: "
"%ld", status_code);
rc = -EIO;
goto out;
}
JSON_CHECK_OBJ(response_obj, json_type_object, rc, -EBADMSG,
"No or invalid response", verbose, out);
json_object_object_get_ex(response_obj, "lastSequenceNumber", &field);
JSON_CHECK_OBJ(field, json_type_int, rc, -EBADMSG,
"Invalid response", verbose, out);
*seqNumber = json_object_get_int(field);
out:
_ekmf_release_curl_handle(curl_handle, curl);
if (response_obj != NULL)
json_object_put(response_obj);
if (login_token != NULL)
free(login_token);
if (uri != NULL)
free(uri);
if (escaped_uuid != NULL)
curl_free(escaped_uuid);
return rc;
}
/**
* Clones a template info structure by making a deep copy of all strings and
* arrays.
* The copied template info must be freed using ekmf_free_template_info() by
* the caller.
*
* @param src the source template info structure
* @param dest the destination template info structure
*
* @returns zero for success, a negative errno in case of an error
*/
int ekmf_clone_template_info(const struct ekmf_template_info *src,
struct ekmf_template_info **dest)
{
if (src == NULL || dest == NULL)
return -EINVAL;
*dest = calloc(1, sizeof(struct ekmf_template_info));
if (*dest == NULL)
return -ENOMEM;
return clone_template_info(src, *dest);
}
/**
* Free a template info structure.
*
* @param template the template to free
*/
void ekmf_free_template_info(struct ekmf_template_info *template)
{
free_template_info(template);
free(template);
}
/**
* Generate a secure identity key used to identify the client to EKMFWeb.
* The secure key blob is stored in a file specified in field

View File

@@ -9,6 +9,11 @@ LIBEKMFWEB_1.0 {
ekmf_generate_ss_cert;
ekmf_get_public_key;
ekmf_retrieve_key;
ekmf_list_templates;
ekmf_get_template;
ekmf_get_last_seq_no;
ekmf_clone_template_info;
ekmf_free_template_info;
ekmf_curl_destroy;
local: *;
};

View File

@@ -912,6 +912,298 @@ json_object *get_json_timestamp(void)
return json_object_new_string(timestamp);
}
/**
* If copy is true, returns a copy of str (via strdup), else returns str itself.
* If str is NULL, then NULL is returned.
*/
static char *cond_strdup(const char *str, bool copy)
{
if (str == NULL)
return NULL;
if (copy)
return strdup(str);
else
return (char *)str;
}
/**
* Builds a list of tag definitions from a JSON array.
*
* @param array a JSON array of tag definitions
* @param tag_def_list the tag definition list to build
* @param copy if true, the string values are copied (via strdup),
* if false, the string values re-use the JSON object's
* string buffer (see json_object_get_string).
*
* @returns zero for success, a negative errno in case of an error
*/
int json_build_tag_def_list(json_object *array,
struct ekmf_tag_def_list *tag_def_list,
bool copy)
{
const char *descr;
json_object *obj;
int rc = 0;
size_t i;
if (array == NULL || tag_def_list == NULL ||
!json_object_is_type(array, json_type_array))
return -EINVAL;
tag_def_list->num_tag_defs = json_object_array_length(array);
tag_def_list->tag_defs = calloc(tag_def_list->num_tag_defs,
sizeof(struct ekmf_tag_definition));
if (tag_def_list->tag_defs == NULL)
return -ENOMEM;
for (i = 0; i < tag_def_list->num_tag_defs; i++) {
obj = json_object_array_get_idx(array, i);
if (obj == NULL) {
rc = -EBADMSG;
goto out;
}
tag_def_list->tag_defs[i].name = cond_strdup(
json_get_string(obj, "name"), copy);
if (tag_def_list->tag_defs[i].name == NULL) {
rc = -ENOMEM;
goto out;
}
descr = json_get_string(obj, "description");
if (descr != NULL) {
tag_def_list->tag_defs[i].description =
cond_strdup(descr, copy);
if (tag_def_list->tag_defs[i].description == NULL) {
rc = -ENOMEM;
goto out;
}
}
}
out:
if (rc != 0)
free_tag_def_list(tag_def_list, copy);
return rc;
}
/**
* Clones (copies) a tag definition list
*
* @param src the source tag definition list
* @param dest the destination tag definition list
*
* @returns zero for success, a negative errno in case of an error
*/
int clone_tag_def_list(const struct ekmf_tag_def_list *src,
struct ekmf_tag_def_list *dest)
{
int rc = 0;
size_t i;
if (src == NULL || dest == NULL)
return -EINVAL;
dest->num_tag_defs = src->num_tag_defs;
dest->tag_defs = calloc(dest->num_tag_defs,
sizeof(struct ekmf_tag_definition));
if (dest->tag_defs == NULL)
return -ENOMEM;
for (i = 0; i < dest->num_tag_defs; i++) {
dest->tag_defs[i].name = cond_strdup(src->tag_defs[i].name,
true);
if (dest->tag_defs[i].name == NULL) {
rc = -ENOMEM;
goto out;
}
if (src->tag_defs[i].description != NULL) {
dest->tag_defs[i].description =
strdup(src->tag_defs[i].description);
if (dest->tag_defs[i].description != NULL) {
rc = -ENOMEM;
goto out;
}
}
}
out:
if (rc != 0)
free_tag_def_list(dest, true);
return rc;
}
/**
* Free a tag definition list
*
* @param tag_def_list the tag definition list to free
* @param free_tags if true, the tag name and description string s are
* freed, otherwise only the array is freed.
*/
void free_tag_def_list(struct ekmf_tag_def_list *tag_def_list, bool free_tags)
{
size_t i;
if (tag_def_list == NULL || tag_def_list->tag_defs == NULL)
return;
for (i = 0; free_tags && i < tag_def_list->num_tag_defs; i++) {
free((char *)tag_def_list->tag_defs[i].name);
free((char *)tag_def_list->tag_defs[i].description);
}
free(tag_def_list->tag_defs);
tag_def_list->tag_defs = NULL;
tag_def_list->num_tag_defs = 0;
}
/**
* Builds a template info structure from a JSON object.
*
* @param obj a JSON object containing the template info
* @param template the template info struct build
* @param copy if true, the string values are copied (via strdup),
* if false, the string values re-use the JSON object's
* string buffer (see json_object_get_string).
*
* @returns zero for success, a negative errno in case of an error
*/
int json_build_template_info(json_object *obj,
struct ekmf_template_info *template,
bool copy)
{
json_object *field, *label_tags = NULL;
int rc;
if (obj == NULL || template == NULL ||
!json_object_is_type(obj, json_type_object))
return -EINVAL;
template->name = cond_strdup(json_get_string(obj, "name"), copy);
template->uuid = cond_strdup(json_get_string(obj, "templateId"), copy);
template->key_type = cond_strdup(json_get_string(obj, "keyType"), copy);
template->algorithm = cond_strdup(json_get_string(obj, "algorithm"),
copy);
if (json_object_object_get_ex(obj, "keyLength", &field) &&
json_object_is_type(field, json_type_int))
template->key_size = json_object_get_int(field);
template->state = cond_strdup(json_get_string(obj, "templateState"),
copy);
template->key_state = cond_strdup(json_get_string(obj, "keyState"),
copy);
template->label_template = cond_strdup(json_get_string(obj,
"labelTemplate"), copy);
if (json_object_object_get_ex(obj, "exportAllowed", &field) &&
json_object_is_type(field, json_type_boolean))
template->export_allowed = json_object_get_boolean(field);
template->keystore_type = cond_strdup(json_get_string(obj,
"keystoreType"),
copy);
template->curve = cond_strdup(json_get_string(obj, "curve"), copy);
template->created_on = cond_strdup(json_get_string(obj, "createdOn"),
copy);
template->updated_on = cond_strdup(json_get_string(obj, "updatedOn"),
copy);
if (template->name == NULL || template->uuid == NULL ||
template->algorithm == NULL || template->label_template == NULL ||
template->state == NULL || template->key_state == NULL ||
template->keystore_type == NULL || template->created_on == NULL ||
template->updated_on == NULL) {
rc = -ENOMEM;
goto out;
}
json_object_object_get_ex(obj, "labelTags", &label_tags);
rc = json_build_tag_def_list(label_tags, &template->label_tags, copy);
if (rc != 0)
goto out;
out:
if (rc != 0) {
free_tag_def_list(&template->label_tags, copy);
if (copy)
free_template_info(template);
}
return rc;
}
/**
* Clones (copies) a template info structure
*
* @param src the source template info structure
* @param dest the destination template info structure
*
* @returns zero for success, a negative errno in case of an error
*/
int clone_template_info(const struct ekmf_template_info *src,
struct ekmf_template_info *dest)
{
int rc;
if (src == NULL || dest == NULL)
return -EINVAL;
dest->name = cond_strdup(src->name, true);
dest->uuid = cond_strdup(src->uuid, true);
dest->key_type = cond_strdup(src->key_type, true);
dest->algorithm = cond_strdup(src->algorithm, true);
dest->key_size = src->key_size;
dest->state = cond_strdup(src->state, true);
dest->key_state = cond_strdup(src->key_state, true);
dest->label_template = cond_strdup(src->label_template, true);
dest->export_allowed = src->export_allowed;
dest->keystore_type = cond_strdup(src->keystore_type, true);
dest->curve = cond_strdup(src->curve, true);
dest->created_on = cond_strdup(src->created_on, true);
dest->updated_on = cond_strdup(src->updated_on, true);
if (dest->name == NULL || dest->uuid == NULL ||
dest->algorithm == NULL || dest->state == NULL ||
dest->key_state == NULL || dest->label_template == NULL ||
dest->keystore_type == NULL || dest->created_on == NULL ||
dest->updated_on == NULL) {
rc = -ENOMEM;
goto out;
}
rc = clone_tag_def_list(&src->label_tags, &dest->label_tags);
if (rc != 0)
goto out;
out:
if (rc != 0)
free_template_info(dest);
return rc;
}
/**
* Free a template info structure
*
* @param template the template to free
*/
void free_template_info(struct ekmf_template_info *template)
{
if (template == NULL)
return;
free((char *)template->name);
free((char *)template->uuid);
free((char *)template->key_type);
free((char *)template->algorithm);
free((char *)template->state);
free((char *)template->key_state);
free((char *)template->label_template);
free((char *)template->keystore_type);
free((char *)template->curve);
free((char *)template->created_on);
free((char *)template->updated_on);
free_tag_def_list(&template->label_tags, true);
}
struct ecc_curve_info {
int curve_nid;
enum {

View File

@@ -41,6 +41,20 @@ int verify_json_web_signature(const char *jws, const unsigned char *payload,
json_object *get_json_timestamp(void);
int json_build_tag_def_list(json_object *array,
struct ekmf_tag_def_list *tag_def_list,
bool copy);
int clone_tag_def_list(const struct ekmf_tag_def_list *src,
struct ekmf_tag_def_list *dest);
void free_tag_def_list(struct ekmf_tag_def_list *tag_def_list, bool free_tags);
int json_build_template_info(json_object *obj,
struct ekmf_template_info *template,
bool copy);
int clone_template_info(const struct ekmf_template_info *src,
struct ekmf_template_info *dest);
void free_template_info(struct ekmf_template_info *template);
size_t ecc_get_curve_prime_bits(int curve_nid);
size_t ecc_get_curve_prime_length(int curve_nid);
const char *ecc_get_curve_id(int curve_nid);