mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
libekmfweb: Add, change and delete key tags
Allow to add, change and delete custom tags of a key. Custom tags can be used store any kind of textual information with a key. Tags have a name and a value. 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
3be8be4ac7
commit
e44ae22989
@@ -815,6 +815,86 @@ int ekmf_set_key_state(const struct ekmf_config *config, CURL **curl_handle,
|
||||
const char *key_uuid, const char *new_state,
|
||||
const char *updated_on, char **error_msg, bool verbose);
|
||||
|
||||
/**
|
||||
* Sets (changed/adds) custom tags of a key identified by its UUID. To update a
|
||||
* key, the timestamp from the last update is required. This can be found in
|
||||
* the key info struct in field update_on.
|
||||
*
|
||||
* 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 tags a list of tags to set
|
||||
* @param updated_on the timestamp of the last update (must match)
|
||||
* @param new_updated_on on return: if not NULL, the new timestamp of the
|
||||
* current update. Can be used for subsequent updates
|
||||
* on the key.
|
||||
* @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
|
||||
* update the key.
|
||||
* -EAGAIN is returned if the timestamp does not match, indicating that
|
||||
* the key has been updated in the meantime.
|
||||
*/
|
||||
int ekmf_set_key_tags(const struct ekmf_config *config, CURL **curl_handle,
|
||||
const char *key_uuid, const struct ekmf_tag_list *tags,
|
||||
const char *updated_on, char **new_updated_on,
|
||||
char **error_msg, bool verbose);
|
||||
|
||||
/**
|
||||
* Deletes custom tags of a key identified by its UUID. To update a
|
||||
* key, the timestamp from the last update is required. This can be found in
|
||||
* the key info struct in field update_on.
|
||||
*
|
||||
* 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 tags a list of tags to delete. Only the name of the tags
|
||||
* must be present in the tag structs of the list, the
|
||||
* values are ignored.
|
||||
* @param updated_on the timestamp of the last update (must match)
|
||||
* @param new_updated_on on return: if not NULL, the new timestamp of the
|
||||
* current update. Can be used for subsequent updates
|
||||
* on the key.
|
||||
* @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
|
||||
* update the key.
|
||||
* -EAGAIN is returned if the timestamp does not match, indicating that
|
||||
* the key has been updated in the meantime.
|
||||
*/
|
||||
int ekmf_delete_key_tags(const struct ekmf_config *config, CURL **curl_handle,
|
||||
const char *key_uuid, const struct ekmf_tag_list *tags,
|
||||
const char *updated_on, char **new_updated_on,
|
||||
char **error_msg, bool verbose);
|
||||
|
||||
/**
|
||||
* Clones a key info structure by making a deep copy of all strings and
|
||||
* arrays.
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#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_SET_TAG "/api/v1/keys/%s/tags/%s"
|
||||
#define EKMF_URI_KEYS_GET "/api/v1/keys/%s"
|
||||
#define EKMF_URI_KEYS_SET_STATE "/api/v1/keys/%s"
|
||||
#define EKMF_URI_KEYS_LIST "/api/v1/keys" \
|
||||
@@ -3502,6 +3503,359 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (adds/changes) a custom tag of a key identified by its UUID. To update
|
||||
* a key, the timestamp from the last update is required. This can be found in
|
||||
* the key info struct in field update_on.
|
||||
*
|
||||
* @param config the configuration structure
|
||||
* @param curl the CURL handle
|
||||
* @param login_token the login token to authenticate
|
||||
* @param key_uuid the UUID of the key to get info for
|
||||
* @param tag the tag to set
|
||||
* @param updated_on the timestamp of the last update (must match)
|
||||
* @param delete if true, the tag is deleted, otherwise it is updated
|
||||
* @param etag On return: the new update timestamp returned via
|
||||
* the etag HTTP header. Must be freed by the caller.
|
||||
* @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
|
||||
* update the key.
|
||||
* -EAGAIN is returned if the timestamp does not match, indicating that
|
||||
* the key has been updated in the meantime.
|
||||
*/
|
||||
static int _ekmf_set_key_tag(const struct ekmf_config *config, CURL *curl,
|
||||
const char *login_token, const char *key_uuid,
|
||||
const struct ekmf_tag *tag, const char *updated_on,
|
||||
bool delete, char **etag, char **error_msg,
|
||||
bool verbose)
|
||||
{
|
||||
struct curl_slist *response_headers = NULL;
|
||||
char *request_headers[2] = { NULL, NULL };
|
||||
json_object *request_obj = NULL;
|
||||
char *escaped_tag_name = NULL;
|
||||
char *escaped_uuid = NULL;
|
||||
char *if_match_hdr = NULL;
|
||||
char *uri = NULL;
|
||||
long status_code;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || curl == NULL || login_token == NULL ||
|
||||
key_uuid == NULL || tag == NULL || updated_on == NULL ||
|
||||
etag == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
*etag = NULL;
|
||||
|
||||
if (!delete) {
|
||||
request_obj = json_object_new_object();
|
||||
JSON_CHECK_ERROR(request_obj == NULL, rc, -ENOMEM,
|
||||
"Failed to generate JSON object", verbose,
|
||||
out);
|
||||
|
||||
rc = json_object_object_add_ex(request_obj, "value",
|
||||
json_object_new_string(tag->value), 0);
|
||||
JSON_CHECK_ERROR(rc != 0, rc, -EIO, "Failed to add data to "
|
||||
"JSON object", verbose, 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;
|
||||
}
|
||||
|
||||
escaped_tag_name = curl_easy_escape(curl, tag->name, 0);
|
||||
if (escaped_tag_name == NULL) {
|
||||
pr_verbose(verbose, "Failed to url-escape the tag name");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&uri, EKMF_URI_KEYS_SET_TAG, escaped_uuid,
|
||||
escaped_tag_name) < 0) {
|
||||
pr_verbose(verbose, "asprintf failed");
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&if_match_hdr, "If-Match : %s", updated_on) < 0) {
|
||||
pr_verbose(verbose, "asprintf failed");
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
request_headers[0] = if_match_hdr;
|
||||
|
||||
rc = _ekmf_perform_request(config, uri, delete ? "DELETE" : "PUT",
|
||||
request_obj, request_headers, login_token,
|
||||
NULL, &response_headers, &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:
|
||||
case 204:
|
||||
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;
|
||||
case 409:
|
||||
pr_verbose(verbose, "Key was updated in the meantime");
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
default:
|
||||
pr_verbose(verbose, "REST Call failed with HTTP status code: "
|
||||
"%ld", status_code);
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*etag = get_http_header_value(response_headers, "Etag");
|
||||
if (*etag == NULL) {
|
||||
pr_verbose(verbose, "No ETag in response headers");
|
||||
rc = -EBADMSG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (request_obj != NULL)
|
||||
json_object_put(request_obj);
|
||||
if (uri != NULL)
|
||||
free(uri);
|
||||
if (escaped_uuid != NULL)
|
||||
curl_free(escaped_uuid);
|
||||
if (escaped_tag_name != NULL)
|
||||
curl_free(escaped_tag_name);
|
||||
if (if_match_hdr != NULL)
|
||||
free(if_match_hdr);
|
||||
if (response_headers != NULL)
|
||||
curl_slist_free_all(response_headers);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (changed/adds) custom tags of a key identified by its UUID. To update a
|
||||
* key, the timestamp from the last update is required. This can be found in
|
||||
* the key info struct in field update_on.
|
||||
*
|
||||
* 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 tags a list of tags to set
|
||||
* @param updated_on the timestamp of the last update (must match)
|
||||
* @param new_updated_on on return: if not NULL, the new timestamp of the
|
||||
* current update. Can be used for subsequent updates
|
||||
* on the key.
|
||||
* @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
|
||||
* update the key.
|
||||
* -EAGAIN is returned if the timestamp does not match, indicating that
|
||||
* the key has been updated in the meantime.
|
||||
*/
|
||||
int ekmf_set_key_tags(const struct ekmf_config *config, CURL **curl_handle,
|
||||
const char *key_uuid, const struct ekmf_tag_list *tags,
|
||||
const char *updated_on, char **new_updated_on,
|
||||
char **error_msg, bool verbose)
|
||||
{
|
||||
char *update_ts = (char *)updated_on;
|
||||
char *login_token = NULL;
|
||||
bool token_valid = false;
|
||||
CURL *curl = NULL;
|
||||
char *etag = NULL;
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || key_uuid == NULL || tags == NULL ||
|
||||
updated_on == 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;
|
||||
}
|
||||
|
||||
for (i = 0; i < tags->num_tags; i++) {
|
||||
rc = _ekmf_set_key_tag(config, curl, login_token, key_uuid,
|
||||
&tags->tags[i], update_ts, false, &etag,
|
||||
error_msg, verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to set tag '%s'",
|
||||
tags->tags[i].name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (update_ts != NULL && update_ts != updated_on)
|
||||
free(update_ts);
|
||||
update_ts = etag;
|
||||
etag = NULL;
|
||||
}
|
||||
|
||||
if (new_updated_on != NULL)
|
||||
*new_updated_on = strdup(update_ts);
|
||||
|
||||
out:
|
||||
_ekmf_release_curl_handle(curl_handle, curl);
|
||||
|
||||
if (login_token != NULL)
|
||||
free(login_token);
|
||||
if (update_ts != NULL && update_ts != updated_on)
|
||||
free(update_ts);
|
||||
if (etag != NULL)
|
||||
free(etag);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes custom tags of a key identified by its UUID. To update a
|
||||
* key, the timestamp from the last update is required. This can be found in
|
||||
* the key info struct in field update_on.
|
||||
*
|
||||
* 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 tags a list of tags to delete. Only the name of the tags
|
||||
* must be present in the tag structs of the list, the
|
||||
* values are ignored.
|
||||
* @param updated_on the timestamp of the last update (must match)
|
||||
* @param new_updated_on on return: if not NULL, the new timestamp of the
|
||||
* current update. Can be used for subsequent updates
|
||||
* on the key.
|
||||
* @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
|
||||
* update the key.
|
||||
* -EAGAIN is returned if the timestamp does not match, indicating that
|
||||
* the key has been updated in the meantime.
|
||||
*/
|
||||
int ekmf_delete_key_tags(const struct ekmf_config *config, CURL **curl_handle,
|
||||
const char *key_uuid, const struct ekmf_tag_list *tags,
|
||||
const char *updated_on, char **new_updated_on,
|
||||
char **error_msg, bool verbose)
|
||||
{
|
||||
char *update_ts = (char *)updated_on;
|
||||
char *login_token = NULL;
|
||||
bool token_valid = false;
|
||||
CURL *curl = NULL;
|
||||
char *etag = NULL;
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
if (config == NULL || key_uuid == NULL || tags == NULL ||
|
||||
updated_on == 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;
|
||||
}
|
||||
|
||||
for (i = 0; i < tags->num_tags; i++) {
|
||||
rc = _ekmf_set_key_tag(config, curl, login_token, key_uuid,
|
||||
&tags->tags[i], update_ts, true, &etag,
|
||||
error_msg, verbose);
|
||||
if (rc != 0) {
|
||||
pr_verbose(verbose, "Failed to delete tag '%s'",
|
||||
tags->tags[i].name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (update_ts != NULL && update_ts != updated_on)
|
||||
free(update_ts);
|
||||
update_ts = etag;
|
||||
etag = NULL;
|
||||
}
|
||||
|
||||
if (new_updated_on != NULL)
|
||||
*new_updated_on = strdup(update_ts);
|
||||
|
||||
out:
|
||||
_ekmf_release_curl_handle(curl_handle, curl);
|
||||
|
||||
if (login_token != NULL)
|
||||
free(login_token);
|
||||
if (update_ts != NULL && update_ts != updated_on)
|
||||
free(update_ts);
|
||||
if (etag != NULL)
|
||||
free(etag);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones a key info structure by making a deep copy of all strings and
|
||||
* arrays.
|
||||
|
||||
@@ -17,6 +17,8 @@ LIBEKMFWEB_1.0 {
|
||||
ekmf_list_keys;
|
||||
ekmf_get_key_info;
|
||||
ekmf_set_key_state;
|
||||
ekmf_set_key_tags;
|
||||
ekmf_delete_key_tags;
|
||||
ekmf_clone_key_info;
|
||||
ekmf_free_key_info;
|
||||
ekmf_generate_key;
|
||||
|
||||
@@ -1734,6 +1734,43 @@ void free_key_info(struct ekmf_key_info *key)
|
||||
free_export_control(&key->export_control, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the specified HTTP header in the list of HTTP headers. Returns a newly
|
||||
* allocated string containing the header value. The caller must free the string
|
||||
* when no longer needed.
|
||||
*
|
||||
* @param headers the list of HTTP headers
|
||||
* @param name the name of the header to look for.
|
||||
*
|
||||
* @returns a newly allocated string, or NULL if the header is not found
|
||||
*/
|
||||
char *get_http_header_value(const struct curl_slist *headers, const char *name)
|
||||
{
|
||||
const struct curl_slist *hdr
|
||||
;
|
||||
char *ch;
|
||||
|
||||
if (headers == NULL || name == NULL)
|
||||
return NULL;
|
||||
|
||||
for (hdr = headers; hdr != NULL; hdr = hdr->next) {
|
||||
if (hdr->data == NULL)
|
||||
continue;
|
||||
|
||||
ch = strchr(hdr->data, ':');
|
||||
if (ch == NULL)
|
||||
continue;
|
||||
if (strncasecmp(hdr->data, name, ch - hdr->data) != 0)
|
||||
continue;
|
||||
|
||||
for (ch++; *ch == ' '; ch++)
|
||||
;
|
||||
return strdup(ch);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ecc_curve_info {
|
||||
int curve_nid;
|
||||
enum {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include <json-c/json.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "ekmfweb/ekmfweb.h"
|
||||
|
||||
@@ -78,6 +79,8 @@ int clone_key_info(const struct ekmf_key_info *src,
|
||||
struct ekmf_key_info *dest);
|
||||
void free_key_info(struct ekmf_key_info *key);
|
||||
|
||||
char *get_http_header_value(const struct curl_slist *headers, const char *name);
|
||||
|
||||
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