mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
libekmfweb: Retrieve information about keys
Retrieve information about keys managed by EKMF Web, such as the key algorithm, the key size and type. Additional, the key's tags are retrieved. Label tags are used to build the label name of a key. Custom tags can be used to store any kind of textual data together with a key. Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
cc9b202a9b
commit
c7afb5baec
@@ -44,6 +44,15 @@
|
||||
|
||||
#define EKMF_URI_SYSTEM_PUBKEY "/api/v1/system/publicKey"
|
||||
#define EKMF_URI_KEYS_EXPORT "/api/v1/keys/%s/export"
|
||||
#define EKMF_URI_KEYS_TAGS "/api/v1/keys/%s/tags"
|
||||
#define EKMF_URI_KEYS_EXPORT_CONTROL "/api/v1/keys/%s/exportControl"
|
||||
#define EKMF_URI_KEYS_GET "/api/v1/keys/%s"
|
||||
#define EKMF_URI_KEYS_LIST "/api/v1/keys" \
|
||||
"?state=%s" \
|
||||
"&orderBy=%s" \
|
||||
"&namePattern=%s" \
|
||||
"&tags=%s"
|
||||
#define EKMF_URI_KEYS_LIST_STATE "&state="
|
||||
#define EKMF_URI_TEMPLATE_GET "/api/v1/templates/%s"
|
||||
#define EKMF_URI_TEMPLATE_LIST "/api/v1/templates" \
|
||||
"?templateStates=%s" \
|
||||
@@ -53,9 +62,11 @@
|
||||
|
||||
#define LIST_ELEMENTS_PER_PAGE 20
|
||||
#define TEMPLATE_STATE_ACTIVE "ACTIVE"
|
||||
#define KEY_STATE_ACTIVE "ACTIVE"
|
||||
#define KEY_ALGORITHM_AES "AES"
|
||||
#define KEYSTORE_TYPE_PERV_ENCR "PERVASIVE_ENCRYPTION"
|
||||
#define ORDER_BY_NAME_ASC "name%3Aasc"
|
||||
#define ORDER_BY_LABEL_ASC "label%3Aasc"
|
||||
|
||||
#define pr_verbose(verbose, fmt...) do { \
|
||||
if (verbose) \
|
||||
@@ -2725,6 +2736,655 @@ void ekmf_free_template_info(struct ekmf_template_info *template)
|
||||
free(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the custom tags of a key by key-uuid. The custom tags are returned as
|
||||
* JSON array. The returned JSON array must be freed by the caller using
|
||||
* json_object_put().
|
||||
*/
|
||||
static int _ekmf_get_custom_tags(const struct ekmf_config *config,
|
||||
const char *key_uuid, CURL *curl,
|
||||
json_object **custom_tags,
|
||||
const char *login_token, char **error_msg,
|
||||
bool verbose)
|
||||
{
|
||||
json_object *response_obj = NULL;
|
||||
char *escaped_uuid = NULL;
|
||||
char *uri = NULL;
|
||||
long status_code;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || key_uuid == NULL || custom_tags == NULL ||
|
||||
curl == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
escaped_uuid = curl_easy_escape(curl, key_uuid, 0);
|
||||
if (escaped_uuid == NULL) {
|
||||
pr_verbose(verbose, "Failed to url-escape the key uuid");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&uri, EKMF_URI_KEYS_TAGS, 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;
|
||||
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);
|
||||
|
||||
*custom_tags = response_obj;
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (uri != NULL)
|
||||
free(uri);
|
||||
if (escaped_uuid != NULL)
|
||||
curl_free(escaped_uuid);
|
||||
if (rc != 0 && response_obj != NULL)
|
||||
json_object_put(response_obj);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the export control infos of a key by key-uuid. The export control info
|
||||
* is returned as JSON object. The returned JSON object must be freed by the
|
||||
* caller using json_object_put().
|
||||
*/
|
||||
static int _ekmf_get_export_control(const struct ekmf_config *config,
|
||||
const char *key_uuid, CURL *curl,
|
||||
json_object **export_control,
|
||||
const char *login_token, char **error_msg,
|
||||
bool verbose)
|
||||
{
|
||||
json_object *response_obj = NULL;
|
||||
char *escaped_uuid = NULL;
|
||||
char *uri = NULL;
|
||||
long status_code;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || key_uuid == NULL || export_control == NULL ||
|
||||
curl == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
escaped_uuid = curl_easy_escape(curl, key_uuid, 0);
|
||||
if (escaped_uuid == NULL) {
|
||||
pr_verbose(verbose, "Failed to url-escape the key uuid");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&uri, EKMF_URI_KEYS_EXPORT_CONTROL, 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;
|
||||
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, -EIO,
|
||||
"No or invalid response content", verbose, out);
|
||||
|
||||
*export_control = response_obj;
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (uri != NULL)
|
||||
free(uri);
|
||||
if (escaped_uuid != NULL)
|
||||
curl_free(escaped_uuid);
|
||||
if (rc != 0 && response_obj != NULL)
|
||||
json_object_put(response_obj);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the custom tags for a key and build the key info structure
|
||||
*/
|
||||
static int _ekmf_build_key_info(const struct ekmf_config *config, CURL *curl,
|
||||
const char *login_token, json_object *obj,
|
||||
struct ekmf_key_info *key, bool copy,
|
||||
char **error_msg, bool verbose)
|
||||
{
|
||||
json_object *export_control = NULL;
|
||||
json_object *custom_tags = NULL;
|
||||
int rc;
|
||||
|
||||
rc = _ekmf_get_custom_tags(config, json_get_string(obj, "keyId"),
|
||||
curl, &custom_tags, login_token, error_msg,
|
||||
verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to get the custom tags for key %s",
|
||||
json_get_string(obj, "keyId"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _ekmf_get_export_control(config, json_get_string(obj, "keyId"),
|
||||
curl, &export_control, login_token,
|
||||
error_msg, verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to get the custom tags for key %s",
|
||||
json_get_string(obj, "keyId"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = json_build_key_info(obj, custom_tags, export_control, key, copy);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to build key info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Add custom tags and export control JSON objects to the key object,
|
||||
* so that these objects are also owned by the key object, and thus are
|
||||
* freed together with it, when the caller puts/frees the key object.
|
||||
*/
|
||||
if (custom_tags != NULL)
|
||||
json_object_object_add_ex(obj, "_custom_tags_", custom_tags, 0);
|
||||
if (export_control != NULL)
|
||||
json_object_object_add_ex(obj, "_export_control_",
|
||||
export_control, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
struct ekmf_key_cb_data_t {
|
||||
const struct ekmf_config *config;
|
||||
const char *login_token;
|
||||
char **error_msg;
|
||||
ekmf_key_cb_t key_cb;
|
||||
void *cb_private;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for key list function. Builds the key info structure
|
||||
* and calls the application callback.
|
||||
*/
|
||||
static int _ekmf_key_cb(CURL *curl, json_object *element,
|
||||
void *private, bool verbose)
|
||||
{
|
||||
struct ekmf_key_cb_data_t *cb_data = private;
|
||||
struct ekmf_key_info key = { 0 };
|
||||
int rc;
|
||||
|
||||
if (cb_data->key_cb == NULL) {
|
||||
pr_verbose(verbose, "No key callback function");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = _ekmf_build_key_info(cb_data->config, curl, cb_data->login_token,
|
||||
element, &key, false, cb_data->error_msg,
|
||||
verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to build key info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = cb_data->key_cb(curl, &key, cb_data->cb_private);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Key callback rc: %d", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
free_tag_list(&key.label_tags, false);
|
||||
free_tag_list(&key.custom_tags, false);
|
||||
free_export_control(&key.export_control, false);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the state URL parameter(s) from a comma separated list of states
|
||||
*
|
||||
* @param curl the curl handle
|
||||
* @param states a comma separaed list of states
|
||||
*
|
||||
* @returns an allocated URL parameter value, or NULL in case of an error
|
||||
*/
|
||||
static char *_ekmf_build_state_filter(CURL *curl, const char *states)
|
||||
{
|
||||
char *list, *tok, *ret = NULL, *tmp;
|
||||
char *escaped_state;
|
||||
|
||||
if (states == NULL)
|
||||
goto error;
|
||||
|
||||
list = strdup(states);
|
||||
if (list == NULL)
|
||||
goto error;
|
||||
|
||||
tok = strtok(list, ",");
|
||||
while (tok != NULL) {
|
||||
escaped_state = curl_easy_escape(curl, tok, 0);
|
||||
if (escaped_state == NULL)
|
||||
goto error;
|
||||
|
||||
if (asprintf(&tmp, "%s%s%s", ret != NULL ? ret : "",
|
||||
ret == NULL ? "" : EKMF_URI_KEYS_LIST_STATE,
|
||||
escaped_state) < 0)
|
||||
tmp = NULL;
|
||||
curl_free(escaped_state);
|
||||
if (tmp == NULL)
|
||||
goto error;
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
ret = tmp;
|
||||
|
||||
tok = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
free(list);
|
||||
return ret;
|
||||
|
||||
error:
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* List available keys. The keys 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 key_cb a callback function that is called for each key
|
||||
* 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 states the states of the keys to list, or NULL to list keys
|
||||
* in ACTIVE state only. Multiple states can be
|
||||
* specified separated by comma.
|
||||
* @param tags a list of custom tags to use as filter, or NULL
|
||||
* @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 keys
|
||||
*/
|
||||
int ekmf_list_keys(const struct ekmf_config *config, CURL **curl_handle,
|
||||
ekmf_key_cb_t key_cb, void *private,
|
||||
const char *name_pattern, const char *states,
|
||||
const struct ekmf_tag_list *tags,
|
||||
char **error_msg, bool verbose)
|
||||
{
|
||||
struct ekmf_key_cb_data_t cb_data;
|
||||
char *escaped_name_pattern = NULL;
|
||||
json_object *tags_obj = NULL;
|
||||
char *state_filter = NULL;
|
||||
char *escaped_tags = NULL;
|
||||
char *login_token = NULL;
|
||||
bool token_valid = false;
|
||||
CURL *curl = NULL;
|
||||
char *uri = NULL;
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || key_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.config = config;
|
||||
cb_data.login_token = login_token;
|
||||
cb_data.error_msg = error_msg;
|
||||
cb_data.key_cb = key_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;
|
||||
}
|
||||
|
||||
state_filter = _ekmf_build_state_filter(curl, states != NULL ? states :
|
||||
KEY_STATE_ACTIVE);
|
||||
if (state_filter == NULL) {
|
||||
pr_verbose(verbose, "Failed to build the state filter");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tags_obj = json_object_new_object();
|
||||
JSON_CHECK_ERROR(tags_obj == NULL, rc, -ENOMEM,
|
||||
"Failed to generate JSON object", verbose, out);
|
||||
for (i = 0; tags != NULL && i < tags->num_tags; i++) {
|
||||
if (tags->tags[i].name == NULL || tags->tags[i].value == NULL) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = json_object_object_add_ex(tags_obj, tags->tags[i].name,
|
||||
json_object_new_string(
|
||||
tags->tags[i].value),
|
||||
0);
|
||||
JSON_CHECK_ERROR(rc != 0, rc, -EIO, "Failed to add data to "
|
||||
"JSON object", verbose, out);
|
||||
}
|
||||
|
||||
escaped_tags = curl_easy_escape(curl, json_object_to_json_string_ext(
|
||||
tags_obj, JSON_C_TO_STRING_PLAIN |
|
||||
JSON_C_TO_STRING_NOSLASHESCAPE), 0);
|
||||
if (escaped_tags == NULL) {
|
||||
pr_verbose(verbose, "Failed to url-escape the tags");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&uri, EKMF_URI_KEYS_LIST, state_filter,
|
||||
ORDER_BY_LABEL_ASC, escaped_name_pattern,
|
||||
escaped_tags) < 0) {
|
||||
pr_verbose(verbose, "asprintf failed");
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _ekmf_list_request(config, uri, curl, _ekmf_key_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 (state_filter != NULL)
|
||||
free(state_filter);
|
||||
if (escaped_name_pattern != NULL)
|
||||
curl_free(escaped_name_pattern);
|
||||
if (escaped_tags != NULL)
|
||||
curl_free(escaped_tags);
|
||||
if (tags_obj != NULL)
|
||||
json_object_put(tags_obj);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about a key 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 key_uuid the UUID of the key to get info for
|
||||
* @param key an address of a key info pointer. On return
|
||||
* the pointer is updated to point to a newly allocated
|
||||
* key info struct. It must be freed by the caller
|
||||
* using ekmf_free_key_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 key info
|
||||
*/
|
||||
int ekmf_get_key_info(const struct ekmf_config *config, CURL **curl_handle,
|
||||
const char *key_uuid, struct ekmf_key_info **key,
|
||||
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 || key_uuid == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
*key = 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, key_uuid, 0);
|
||||
if (escaped_uuid == NULL) {
|
||||
pr_verbose(verbose, "Failed to url-escape the key uuid");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&uri, EKMF_URI_KEYS_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);
|
||||
|
||||
*key = calloc(1, sizeof(struct ekmf_key_info));
|
||||
if (*key == NULL) {
|
||||
pr_verbose(verbose, "calloc failed");
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _ekmf_build_key_info(config, curl, login_token, response_obj,
|
||||
*key, true, error_msg, verbose);
|
||||
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 && *key != NULL) {
|
||||
free_key_info(*key);
|
||||
free(*key);
|
||||
*key = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones a key info structure by making a deep copy of all strings and
|
||||
* arrays.
|
||||
* The copied key info must be freed using ekmf_free_key_info() by
|
||||
* the caller.
|
||||
*
|
||||
* @param src the source key info structure
|
||||
* @param dest the destination key info structure
|
||||
*
|
||||
* @returns zero for success, a negative errno in case of an error
|
||||
*/
|
||||
int ekmf_clone_key_info(const struct ekmf_key_info *src,
|
||||
struct ekmf_key_info **dest)
|
||||
{
|
||||
if (src == NULL || dest == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
*dest = calloc(1, sizeof(struct ekmf_key_info));
|
||||
if (*dest == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
return clone_key_info(src, *dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a key info structure.
|
||||
*
|
||||
* @param key the key info to free
|
||||
*/
|
||||
void ekmf_free_key_info(struct ekmf_key_info *key)
|
||||
{
|
||||
free_key_info(key);
|
||||
|
||||
free(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure identity key used to identify the client to EKMFWeb.
|
||||
* The secure key blob is stored in a file specified in field
|
||||
|
||||
@@ -14,6 +14,10 @@ LIBEKMFWEB_1.0 {
|
||||
ekmf_get_last_seq_no;
|
||||
ekmf_clone_template_info;
|
||||
ekmf_free_template_info;
|
||||
ekmf_list_keys;
|
||||
ekmf_get_key_info;
|
||||
ekmf_clone_key_info;
|
||||
ekmf_free_key_info;
|
||||
ekmf_curl_destroy;
|
||||
local: *;
|
||||
};
|
||||
|
||||
@@ -927,6 +927,25 @@ static char *cond_strdup(const char *str, bool copy)
|
||||
return (char *)str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start of the UUId part of a href link.
|
||||
* Returns NULL if href is NULL, or if the UUID is not found.
|
||||
* The returned pointer (if not NULL) is within the specified href string!
|
||||
*/
|
||||
static const char *get_uuid_from_href(const char *href)
|
||||
{
|
||||
const char *ch;
|
||||
|
||||
if (href == NULL)
|
||||
return NULL;
|
||||
|
||||
ch = strrchr(href, '/');
|
||||
if (ch == NULL)
|
||||
return NULL;
|
||||
|
||||
return ch + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a list of tag definitions from a JSON array.
|
||||
*
|
||||
@@ -1204,6 +1223,441 @@ void free_template_info(struct ekmf_template_info *template)
|
||||
free_tag_def_list(&template->label_tags, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a list of tags from a JSON array.
|
||||
*
|
||||
* @param array a JSON array of tags
|
||||
* @param tag_list the tag 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_list(json_object *array, struct ekmf_tag_list *tag_list,
|
||||
bool copy)
|
||||
{
|
||||
json_object *obj;
|
||||
size_t i;
|
||||
int rc = 0;
|
||||
|
||||
if (array == NULL || tag_list == NULL ||
|
||||
!json_object_is_type(array, json_type_array))
|
||||
return -EINVAL;
|
||||
|
||||
tag_list->num_tags = json_object_array_length(array);
|
||||
tag_list->tags = calloc(tag_list->num_tags, sizeof(struct ekmf_tag));
|
||||
if (tag_list->tags == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < tag_list->num_tags; i++) {
|
||||
obj = json_object_array_get_idx(array, i);
|
||||
if (obj == NULL)
|
||||
return -EBADMSG;
|
||||
|
||||
tag_list->tags[i].name = cond_strdup(
|
||||
json_get_string(obj, "name"), copy);
|
||||
tag_list->tags[i].value = cond_strdup(
|
||||
json_get_string(obj, "value"), copy);
|
||||
|
||||
if (tag_list->tags[i].name == NULL ||
|
||||
tag_list->tags[i].value == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (rc != 0)
|
||||
free_tag_list(tag_list, copy);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones (copies) a tag list
|
||||
*
|
||||
* @param src the source tag list
|
||||
* @param dest the destination tag list
|
||||
*
|
||||
* @returns zero for success, a negative errno in case of an error
|
||||
*/
|
||||
int clone_tag_list(const struct ekmf_tag_list *src,
|
||||
struct ekmf_tag_list *dest)
|
||||
{
|
||||
size_t i;
|
||||
int rc = 0;
|
||||
|
||||
if (src == NULL || dest == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
dest->num_tags = src->num_tags;
|
||||
if (dest->num_tags == 0) {
|
||||
dest->tags = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dest->tags = calloc(dest->num_tags, sizeof(struct ekmf_tag));
|
||||
if (dest->tags == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < dest->num_tags; i++) {
|
||||
dest->tags[i].name = cond_strdup(src->tags[i].name, true);
|
||||
if (dest->tags[i].name == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
dest->tags[i].value = cond_strdup(src->tags[i].value, true);
|
||||
if (dest->tags[i].value == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (rc != 0)
|
||||
free_tag_list(dest, true);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a tag list
|
||||
*
|
||||
* @param tag_list the tag list to free
|
||||
* @param free_tags if true, the tag name and value string s are
|
||||
* freed, otherwise only the array is freed.
|
||||
*/
|
||||
void free_tag_list(struct ekmf_tag_list *tag_list, bool free_tags)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (tag_list == NULL || tag_list->tags == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; free_tags && i < tag_list->num_tags; i++) {
|
||||
free((char *)tag_list->tags[i].name);
|
||||
free((char *)tag_list->tags[i].value);
|
||||
}
|
||||
|
||||
free(tag_list->tags);
|
||||
tag_list->tags = NULL;
|
||||
tag_list->num_tags = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the export control information from a JSON object.
|
||||
*
|
||||
* @param export_control the JSON oibject
|
||||
* @param tag_def_list the tag 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_export_control(json_object *export_control,
|
||||
struct ekmf_export_control *export_info,
|
||||
bool copy)
|
||||
{
|
||||
json_object *obj, *array;
|
||||
size_t i;
|
||||
int rc = 0;
|
||||
|
||||
if (export_control == NULL || export_info == NULL ||
|
||||
!json_object_is_type(export_control, json_type_object))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(export_control, "exportAllowed", &obj) ||
|
||||
!json_object_is_type(obj, json_type_boolean))
|
||||
return -EINVAL;
|
||||
|
||||
export_info->export_allowed = json_object_get_boolean(obj);
|
||||
|
||||
if (!json_object_object_get_ex(export_control, "allowedKeys", &array) ||
|
||||
!json_object_is_type(array, json_type_array))
|
||||
return -EINVAL;
|
||||
|
||||
export_info->num_exporting_keys = json_object_array_length(array);
|
||||
export_info->exporting_keys = calloc(export_info->num_exporting_keys,
|
||||
sizeof(struct ekmf_exporting_key));
|
||||
if (export_info->exporting_keys == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < export_info->num_exporting_keys; i++) {
|
||||
obj = json_object_array_get_idx(array, i);
|
||||
if (obj == NULL)
|
||||
return -EBADMSG;
|
||||
|
||||
export_info->exporting_keys[i].name = cond_strdup(
|
||||
json_get_string(obj, "title"), copy);
|
||||
export_info->exporting_keys[i].uuid = cond_strdup(
|
||||
get_uuid_from_href(
|
||||
json_get_string(obj, "href")), copy);
|
||||
|
||||
if (export_info->exporting_keys[i].name == NULL ||
|
||||
export_info->exporting_keys[i].uuid == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (rc != 0)
|
||||
free_export_control(export_info, copy);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones (copies) an export control info
|
||||
*
|
||||
* @param src the source export control
|
||||
* @param dest the destination export control
|
||||
*
|
||||
* @returns zero for success, a negative errno in case of an error
|
||||
*/
|
||||
int clone_export_control(const struct ekmf_export_control *src,
|
||||
struct ekmf_export_control *dest)
|
||||
{
|
||||
size_t i;
|
||||
int rc = 0;
|
||||
|
||||
if (src == NULL || dest == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
dest->export_allowed = src->export_allowed;
|
||||
|
||||
dest->num_exporting_keys = src->num_exporting_keys;
|
||||
if (dest->num_exporting_keys == 0) {
|
||||
dest->exporting_keys = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dest->exporting_keys = calloc(dest->num_exporting_keys,
|
||||
sizeof(struct ekmf_exporting_key));
|
||||
if (dest->exporting_keys == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < dest->num_exporting_keys; i++) {
|
||||
dest->exporting_keys[i].name =
|
||||
cond_strdup(src->exporting_keys[i].name, true);
|
||||
if (dest->exporting_keys[i].name == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
dest->exporting_keys[i].uuid =
|
||||
cond_strdup(src->exporting_keys[i].uuid, true);
|
||||
if (dest->exporting_keys[i].uuid == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (rc != 0)
|
||||
free_export_control(dest, true);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free export control infos
|
||||
*
|
||||
* @param export_control the export control infos to free
|
||||
* @param free_tags if true, the exporting keys name and uuid strings
|
||||
* are freed, otherwise only the array is freed.
|
||||
*/
|
||||
void free_export_control(struct ekmf_export_control *export_control,
|
||||
bool free_keys)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (export_control == NULL || export_control->exporting_keys == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; free_keys && i < export_control->num_exporting_keys; i++) {
|
||||
free((char *)export_control->exporting_keys[i].name);
|
||||
free((char *)export_control->exporting_keys[i].uuid);
|
||||
}
|
||||
|
||||
free(export_control->exporting_keys);
|
||||
export_control->exporting_keys = NULL;
|
||||
export_control->num_exporting_keys = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a key info structure from a JSON object.
|
||||
*
|
||||
* @param obj a JSON object containing the key info
|
||||
* @param custom_tags a JSON array containing the custom tags
|
||||
* @param export_control a JSON object containing the export_control infos
|
||||
* @param key the key info struct 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_key_info(json_object *obj, json_object *custom_tags,
|
||||
json_object *export_control,
|
||||
struct ekmf_key_info *key, bool copy)
|
||||
{
|
||||
json_object *field, *label_tags = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (obj == NULL || custom_tags == NULL || key == NULL ||
|
||||
!json_object_is_type(obj, json_type_object) ||
|
||||
!json_object_is_type(custom_tags, json_type_array))
|
||||
return -EINVAL;
|
||||
|
||||
key->label = cond_strdup(json_get_string(obj, "label"), copy);
|
||||
key->description = cond_strdup(json_get_string(obj, "description"),
|
||||
copy);
|
||||
key->uuid = cond_strdup(json_get_string(obj, "keyId"), copy);
|
||||
key->key_type = cond_strdup(json_get_string(obj, "type"), copy);
|
||||
key->algorithm = cond_strdup(json_get_string(obj, "algorithm"), copy);
|
||||
if (json_object_object_get_ex(obj, "length", &field) &&
|
||||
json_object_is_type(field, json_type_int))
|
||||
key->key_size = json_object_get_int(field);
|
||||
else
|
||||
rc = -EBADMSG;
|
||||
|
||||
key->state = cond_strdup(json_get_string(obj, "state"), copy);
|
||||
key->keystore_type = cond_strdup(json_get_string(obj, "keystoreType"),
|
||||
copy);
|
||||
if (json_object_object_get_ex(obj, "template", &field) &&
|
||||
json_object_is_type(field, json_type_object)) {
|
||||
key->template = cond_strdup(json_get_string(field, "title"),
|
||||
copy);
|
||||
key->template_uuid = cond_strdup(get_uuid_from_href(
|
||||
json_get_string(field, "href")), copy);
|
||||
} else {
|
||||
rc = -EBADMSG;
|
||||
}
|
||||
key->activate_on = cond_strdup(json_get_string(obj, "activationDate"),
|
||||
copy);
|
||||
key->expires_on = cond_strdup(json_get_string(obj, "expirationDate"),
|
||||
copy);
|
||||
key->created_on = cond_strdup(json_get_string(obj, "createdOn"), copy);
|
||||
key->updated_on = cond_strdup(json_get_string(obj, "updatedOn"), copy);
|
||||
|
||||
if (rc != 0 || key->label == NULL || key->uuid == NULL ||
|
||||
key->algorithm == NULL || key->state == NULL ||
|
||||
key->keystore_type == NULL || key->template == NULL ||
|
||||
key->template_uuid == NULL || key->activate_on == NULL ||
|
||||
key->expires_on == NULL || key->created_on == NULL ||
|
||||
key->updated_on == NULL) {
|
||||
rc = (rc != 0 ? rc : -ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
json_object_object_get_ex(obj, "labelTags", &label_tags);
|
||||
rc = json_build_tag_list(label_tags, &key->label_tags, copy);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = json_build_tag_list(custom_tags, &key->custom_tags, copy);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = json_build_export_control(export_control, &key->export_control,
|
||||
copy);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (rc != 0) {
|
||||
free_tag_list(&key->label_tags, copy);
|
||||
free_tag_list(&key->custom_tags, copy);
|
||||
free_export_control(&key->export_control, copy);
|
||||
if (copy)
|
||||
free_key_info(key);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones (copies) a key info structure
|
||||
*
|
||||
* @param src the source key info structure
|
||||
* @param dest the destination key info structure
|
||||
*
|
||||
* @returns zero for success, a negative errno in case of an error
|
||||
*/
|
||||
int clone_key_info(const struct ekmf_key_info *src,
|
||||
struct ekmf_key_info *dest)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (src == NULL || dest == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
dest->label = cond_strdup(src->label, true);
|
||||
dest->description = cond_strdup(src->description, 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->keystore_type = cond_strdup(src->keystore_type, true);
|
||||
dest->template = cond_strdup(src->template, true);
|
||||
dest->template_uuid = cond_strdup(src->template_uuid, true);
|
||||
dest->activate_on = cond_strdup(src->activate_on, true);
|
||||
dest->expires_on = cond_strdup(src->expires_on, true);
|
||||
dest->created_on = cond_strdup(src->created_on, true);
|
||||
dest->updated_on = cond_strdup(src->updated_on, true);
|
||||
if (dest->label == NULL || dest->uuid == NULL ||
|
||||
dest->algorithm == NULL || dest->state == NULL ||
|
||||
dest->keystore_type == NULL || dest->template == NULL ||
|
||||
dest->template_uuid == NULL || dest->activate_on == NULL ||
|
||||
dest->expires_on == NULL || dest->created_on == NULL ||
|
||||
dest->updated_on == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = clone_tag_list(&src->label_tags, &dest->label_tags);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = clone_tag_list(&src->custom_tags, &dest->custom_tags);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
out:
|
||||
if (rc != 0)
|
||||
free_key_info(dest);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a key info structure
|
||||
*
|
||||
* @param key the key info to free
|
||||
*/
|
||||
void free_key_info(struct ekmf_key_info *key)
|
||||
{
|
||||
if (key == NULL)
|
||||
return;
|
||||
|
||||
free((char *)key->label);
|
||||
free((char *)key->description);
|
||||
free((char *)key->uuid);
|
||||
free((char *)key->key_type);
|
||||
free((char *)key->algorithm);
|
||||
free((char *)key->state);
|
||||
free((char *)key->keystore_type);
|
||||
free((char *)key->template);
|
||||
free((char *)key->template_uuid);
|
||||
free((char *)key->activate_on);
|
||||
free((char *)key->expires_on);
|
||||
free((char *)key->created_on);
|
||||
free((char *)key->updated_on);
|
||||
|
||||
free_tag_list(&key->label_tags, true);
|
||||
free_tag_list(&key->custom_tags, true);
|
||||
free_export_control(&key->export_control, true);
|
||||
}
|
||||
|
||||
struct ecc_curve_info {
|
||||
int curve_nid;
|
||||
enum {
|
||||
|
||||
@@ -55,6 +55,27 @@ int clone_template_info(const struct ekmf_template_info *src,
|
||||
struct ekmf_template_info *dest);
|
||||
void free_template_info(struct ekmf_template_info *template);
|
||||
|
||||
int json_build_tag_list(json_object *array, struct ekmf_tag_list *tag_list,
|
||||
bool copy);
|
||||
int clone_tag_list(const struct ekmf_tag_list *src,
|
||||
struct ekmf_tag_list *dest);
|
||||
void free_tag_list(struct ekmf_tag_list *tag_list, bool free_tags);
|
||||
|
||||
int json_build_export_control(json_object *export_control,
|
||||
struct ekmf_export_control *export_info,
|
||||
bool copy);
|
||||
int clone_export_control(const struct ekmf_export_control *src,
|
||||
struct ekmf_export_control *dest);
|
||||
void free_export_control(struct ekmf_export_control *export_control,
|
||||
bool free_keys);
|
||||
|
||||
int json_build_key_info(json_object *obj, json_object *custom_tags,
|
||||
json_object *export_control,
|
||||
struct ekmf_key_info *key, bool copy);
|
||||
int clone_key_info(const struct ekmf_key_info *src,
|
||||
struct ekmf_key_info *dest);
|
||||
void free_key_info(struct ekmf_key_info *key);
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user