diff options
Diffstat (limited to 'gck/gck-uri.c')
-rw-r--r-- | gck/gck-uri.c | 456 |
1 files changed, 121 insertions, 335 deletions
diff --git a/gck/gck-uri.c b/gck/gck-uri.c index e4c5082..12e535b 100644 --- a/gck/gck-uri.c +++ b/gck/gck-uri.c @@ -29,9 +29,10 @@ #include <glib/gi18n-lib.h> -#include <string.h> +#include <p11-kit/uri.h> -#include "egg/egg-hex.h" +#include <string.h> +#include <stdlib.h> /** * SECTION:gck-uri @@ -56,7 +57,7 @@ **/ /** - * GckUriInfo: + * GckUriData: * @any_unrecognized: whether any parts of the PKCS\#11 URI were unsupported or unrecognized. * @module_info: information about the PKCS\#11 modules matching the URI. * @token_info: information about the PKCS\#11 tokens matching the URI. @@ -71,11 +72,11 @@ */ /** - * GckUriParseFlags: - * @GCK_URI_PARSE_MODULE: the URI will be used to match modules. - * @GCK_URI_PARSE_TOKEN: the URI will be used to match tokens. - * @GCK_URI_PARSE_OBJECT: the URI will be used to match objects. - * @GCK_URI_PARSE_ANY: parse all recognized components of the URI. + * GckUriFlags: + * @GCK_URI_CONTEXT_MODULE: the URI will be used to match modules. + * @GCK_URI_CONTEXT_TOKEN: the URI will be used to match tokens. + * @GCK_URI_CONTEXT_OBJECT: the URI will be used to match objects. + * @GCK_URI_CONTEXT_ANY: parse all recognized components of the URI. * * Which context the PKCS\#11 URI will be used in. */ @@ -103,380 +104,165 @@ gck_uri_get_error_quark (void) return domain; } -GckUriInfo* -_gck_uri_info_new (void) -{ - return g_slice_new0 (GckUriInfo); -} - -static gint -parse_string_attribute (const gchar *name, const gchar *start, const gchar *end, - GckAttributes *attrs, GError **error) -{ - gchar *value; - gint res = 0; - - g_assert (name); - g_assert (start); - g_assert (end); - - if (!g_str_equal (name, "object") && !g_str_equal (name, "objecttype")) - return 0; - - value = g_uri_unescape_segment (start, end, ""); - if (value == NULL) { - g_set_error (error, GCK_URI_ERROR, GCK_URI_BAD_ENCODING, - _("The URI has invalid syntax. The '%s' field encoding is invalid."), name); - return -1; - } - - if (g_str_equal (name, "object")) { - gck_attributes_add_string (attrs, CKA_LABEL, value); - res = 1; - - } else if (g_str_equal (name, "objecttype")) { - - res = 1; - if (g_str_equal (value, "cert")) - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE); - else if (g_str_equal (value, "public")) - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY); - else if (g_str_equal (value, "private")) - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PRIVATE_KEY); - else if (g_str_equal (value, "secretkey")) - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_SECRET_KEY); - else if (g_str_equal (value, "data")) - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_DATA); - else { - g_message ("ignoring unsupported value for '%s'", value); - res = 0; - } - } else { - g_assert_not_reached (); - } - - g_free (value); - return res; -} - -static gint -parse_binary_attribute (const gchar *name, const gchar *start, const gchar *end, - GckAttributes *attrs, GError **error) -{ - guchar *data; - gsize n_data; - - g_assert (name); - g_assert (start); - g_assert (end); - g_assert (attrs); - - if (!g_str_equal (name, "id")) - return 0; - - /* - * TODO: This requires some work. We're not yet sure about the actual - * encoding that's supported here. - */ - - g_assert (end >= start); - data = egg_hex_decode_full (start, end - start, ':', 1, &n_data); - if (data == NULL) { - g_set_error (error, GCK_URI_ERROR, GCK_URI_BAD_ENCODING, - _("The URI has invalid syntax. The '%s' field encoding is invalid."), name); - return -1; - } - - gck_attributes_add_data (attrs, CKA_ID, data, n_data); - g_free (data); - return 1; -} - -static gint -parse_token_attribute (const gchar *name, const gchar *start, const gchar *end, - GckTokenInfo *token, GError **error) -{ - gchar **value; - gchar *string; - - g_assert (name); - g_assert (start); - g_assert (end); - g_assert (token); - - if (g_str_equal (name, "model")) - value = &(token->model); - else if (g_str_equal (name, "manufacturer")) - value = &(token->manufacturer_id); - else if (g_str_equal (name, "serial")) - value = &(token->serial_number); - else if (g_str_equal (name, "token")) - value = &(token->label); - else - return 0; - - string = g_uri_unescape_segment (start, end, ""); - if (string == NULL) { - g_set_error (error, GCK_URI_ERROR, GCK_URI_BAD_ENCODING, - _("The URI has invalid syntax. The '%s' field encoding is invalid."), name); - return -1; - } - - g_free (*value); - *value = string; - - return 1; -} - -static gint -parse_library_attribute (const gchar *name, const gchar *start, const gchar *end, - GckModuleInfo *library, GError **error) +/** + * gck_uri_new: + * + * Allocate a new GckUriData structure. None of the fields + * will be set. + * + * Returns: A newly allocated GckUriData, free with gck_uri_data_free(). + */ +GckUriData* +gck_uri_data_new (void) { - gchar **value; - gchar *string; - - g_assert (name); - g_assert (start); - g_assert (end); - g_assert (library); - - if (g_str_equal (name, "library-description")) - value = &(library->library_description); - else if (g_str_equal (name, "library-manufacturer")) - value = &(library->manufacturer_id); - else - return 0; - - string = g_uri_unescape_segment (start, end, ""); - if (string == NULL) { - g_set_error (error, GCK_URI_ERROR, GCK_URI_BAD_ENCODING, - _("The URI has invalid syntax. The '%s' field encoding is invalid."), name); - return -1; - } - - g_free (*value); - *value = string; - - return 1; + return g_slice_new0 (GckUriData); } /** * gck_uri_parse: - * @uri: the URI to parse. + * @string: the URI to parse. * @flags: the context in which the URI will be used. * @error: a #GError, or %NULL. * * Parse a PKCS\#11 URI for use in a given context. * * The result will contain the fields that are relevant for - * the given context. See #GckUriInfo for more info. + * the given context. See #GckUriData for more info. * Other fields will be set to %NULL. * - * Return value: a newly allocated #GckUriInfo, which should be freed with + * Return value: a newly allocated #GckUriData, which should be freed with * gck_uri_info_free(). */ -GckUriInfo* -gck_uri_parse (const gchar *uri, GckUriParseFlags flags, GError **error) +GckUriData* +gck_uri_parse (const gchar *string, GckUriFlags flags, GError **error) { - const gchar *spos, *epos; - gchar *key = NULL; - gboolean ret = FALSE; - GckUriInfo *uri_info = NULL; + GckUriData *uri_data = NULL; + CK_ATTRIBUTE_PTR attrs; + CK_ULONG i, n_attrs; + P11KitUri *p11_uri; gint res; - g_return_val_if_fail (uri, FALSE); + g_return_val_if_fail (string, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - if (!g_str_has_prefix (uri, URI_PREFIX)) { - g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_PREFIX, - _("The URI does not have the 'pkcs11' scheme.")); - goto cleanup; - } - - uri += N_URI_PREFIX; - - uri_info = _gck_uri_info_new (); - if ((flags & GCK_URI_PARSE_MODULE) == GCK_URI_PARSE_MODULE) - uri_info->module_info = g_new0 (GckModuleInfo, 1); - if ((flags & GCK_URI_PARSE_TOKEN) == GCK_URI_PARSE_TOKEN) - uri_info->token_info = g_new0 (GckTokenInfo, 1); - if ((flags & GCK_URI_PARSE_OBJECT) == GCK_URI_PARSE_OBJECT) - uri_info->attributes = gck_attributes_new (); - - for (;;) { - spos = strchr (uri, ';'); - if (spos == NULL) { - spos = uri + strlen (uri); - g_assert (*spos == '\0'); - if (spos == uri) - break; - } + p11_uri = p11_kit_uri_new (); + if (!p11_uri) + g_error ("failed to allocate P11KitUri"); - epos = strchr (uri, '='); - if (epos == NULL || spos == uri || epos == uri || epos >= spos) { + res = p11_kit_uri_parse (string, flags, p11_uri); + if (res != P11_KIT_URI_OK) { + p11_kit_uri_free (p11_uri); + switch (res) { + case P11_KIT_URI_NO_MEMORY: + g_error ("failed to allocate memory in p11_kit_uri_parse()"); + break; + case P11_KIT_URI_BAD_ENCODING: + g_set_error (error, GCK_URI_ERROR, GCK_URI_BAD_ENCODING, + _("The URI has invalid encoding.")); + break; + case P11_KIT_URI_BAD_SCHEME: + g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SCHEME, + _("The URI has does not have the 'pkcs11' scheme.")); + break; + case P11_KIT_URI_BAD_SYNTAX: g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SYNTAX, - "The URI has invalid syntax. It must consist of key=value pairs."); - goto cleanup; - } - - g_free (key); - key = g_strndup (uri, epos - uri); - epos++; - - res = 0; - if (uri_info->attributes) - res = parse_string_attribute (key, epos, spos, uri_info->attributes, error); - if (res == 0 && uri_info->attributes) - res = parse_binary_attribute (key, epos, spos, uri_info->attributes, error); - if (res == 0 && uri_info->token_info) - res = parse_token_attribute (key, epos, spos, uri_info->token_info, error); - if (res == 0 && uri_info->module_info) - res = parse_library_attribute (key, epos, spos, uri_info->module_info, error); - if (res < 0) - goto cleanup; - if (res == 0) { - g_message ("Ignoring unrecognized or unsupported field '%s'", key); - uri_info->any_unrecognized = TRUE; - } - - if (*spos == '\0') + _("The URI has bad syntax.")); + break; + case P11_KIT_URI_BAD_VERSION: + g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SYNTAX, + _("The URI has a bad version number.")); break; - uri = spos + 1; + case P11_KIT_URI_NOT_FOUND: + g_assert_not_reached (); + break; + }; + return NULL; } - ret = TRUE; - -cleanup: - if (!ret) { - gck_uri_info_free (uri_info); - uri_info = NULL; + /* Convert it to a GckUri */ + uri_data = gck_uri_data_new (); + if ((flags & GCK_URI_CONTEXT_MODULE) == GCK_URI_CONTEXT_MODULE) + uri_data->module_info = _gck_module_info_from_pkcs11 (p11_kit_uri_get_module_info (p11_uri)); + if ((flags & GCK_URI_CONTEXT_TOKEN) == GCK_URI_CONTEXT_TOKEN) + uri_data->token_info = _gck_token_info_from_pkcs11 (p11_kit_uri_get_token_info (p11_uri)); + if ((flags & GCK_URI_CONTEXT_OBJECT) == GCK_URI_CONTEXT_OBJECT) { + attrs = p11_kit_uri_get_attributes (p11_uri, &n_attrs); + uri_data->attributes = gck_attributes_new (); + for (i = 0; i < n_attrs; ++i) + gck_attributes_add (uri_data->attributes, (GckAttribute*)&attrs[i]); } + uri_data->any_unrecognized = p11_kit_uri_any_unrecognized (p11_uri); - g_free (key); - return uri_info; -} - -static void -build_string_attribute (const gchar *name, const gchar *value, - GString *result, gboolean *first) -{ - gchar *segment; - - g_assert (first); - g_assert (result); - g_assert (name); - - if (!value) - return; - - segment = g_uri_escape_string (value, "", FALSE); - if (!*first) - g_string_append_c (result, ';'); - *first = FALSE; - - g_string_append (result, name); - g_string_append_c (result, '='); - g_string_append (result, segment); - g_free (segment); -} - -static void -build_binary_attribute (const gchar *name, gconstpointer data, gsize n_data, - GString *result, gboolean *first) -{ - gchar *segment; - - g_assert (first); - g_assert (result); - g_assert (name); - g_assert (!n_data || data); - - segment = egg_hex_encode_full (data, n_data, FALSE, ':', 1); - if (!*first) - g_string_append_c (result, ';'); - *first = FALSE; - - g_string_append (result, name); - g_string_append_c (result, '='); - g_string_append (result, segment); - g_free (segment); + p11_kit_uri_free (p11_uri); + return uri_data; } /** * gck_uri_build: - * @uri_info: the info to build the URI from. + * @uri_data: the info to build the URI from. + * @flags: The context that the URI is for * - * Build a PKCS\#11 URI. Any set fields of @uri_info will be used to build - * the URI. + * Build a PKCS\#11 URI. The various parts relevant to the flags + * specified will be used to build the URI. * * Return value: a newly allocated string containing a PKCS\#11 URI. */ gchar* -gck_uri_build (GckUriInfo *uri_info) +gck_uri_build (GckUriData *uri_data, GckUriFlags flags) { GckAttribute *attr; - GString *result; - gchar *value; - gulong klass; - gboolean first = TRUE; - - g_return_val_if_fail (uri_info, NULL); - - result = g_string_new (URI_PREFIX); - - if (uri_info->module_info) { - build_string_attribute ("library-description", uri_info->module_info->library_description, result, &first); - build_string_attribute ("library-manufacturer", uri_info->module_info->manufacturer_id, result, &first); - } - - if (uri_info->token_info) { - build_string_attribute ("model", uri_info->token_info->model, result, &first); - build_string_attribute ("manufacturer", uri_info->token_info->manufacturer_id, result, &first); - build_string_attribute ("serial", uri_info->token_info->serial_number, result, &first); - build_string_attribute ("token", uri_info->token_info->label, result, &first); - } - - if (uri_info->attributes) { - if (gck_attributes_find_string (uri_info->attributes, CKA_LABEL, &value)) { - build_string_attribute ("object", value, result, &first); - g_free (value); - } - if (gck_attributes_find_ulong (uri_info->attributes, CKA_CLASS, &klass)) { - if (klass == CKO_CERTIFICATE) - build_string_attribute ("objecttype", "cert", result, &first); - else if (klass == CKO_PUBLIC_KEY) - build_string_attribute ("objecttype", "public", result, &first); - else if (klass == CKO_PRIVATE_KEY) - build_string_attribute ("objecttype", "private", result, &first); - else if (klass == CKO_SECRET_KEY) - build_string_attribute ("objecttype", "secretkey", result, &first); - else if (klass == CKO_DATA) - build_string_attribute ("objecttype", "data", result, &first); + P11KitUri *p11_uri = 0; + gchar *string; + int res; + guint i; + + g_return_val_if_fail (uri_data, NULL); + + p11_uri = p11_kit_uri_new (); + + if ((flags & GCK_URI_CONTEXT_MODULE) == GCK_URI_CONTEXT_MODULE && uri_data->module_info) + _gck_module_info_to_pkcs11 (uri_data->module_info, + p11_kit_uri_get_module_info (p11_uri)); + if ((flags & GCK_URI_CONTEXT_TOKEN) == GCK_URI_CONTEXT_TOKEN && uri_data->token_info) + _gck_token_info_to_pkcs11 (uri_data->token_info, + p11_kit_uri_get_token_info (p11_uri)); + if ((flags & GCK_URI_CONTEXT_OBJECT) == GCK_URI_CONTEXT_OBJECT && uri_data->attributes) { + for (i = 0; i < gck_attributes_count (uri_data->attributes); ++i) { + attr = gck_attributes_at (uri_data->attributes, i); + res = p11_kit_uri_set_attribute (p11_uri, (CK_ATTRIBUTE_PTR)attr); + if (res == P11_KIT_URI_NO_MEMORY) + g_error ("failed to allocate memory in p11_kit_uri_set_attribute()"); + else if (res != P11_KIT_URI_NOT_FOUND && res != P11_KIT_URI_OK) + g_return_val_if_reached (NULL); } - attr = gck_attributes_find (uri_info->attributes, CKA_ID); - if (attr != NULL) - build_binary_attribute ("id", attr->value, attr->length, result, &first); } - return g_string_free (result, FALSE); + res = p11_kit_uri_format (p11_uri, flags & GCK_URI_CONTEXT_ANY, &string); + if (res == P11_KIT_URI_NO_MEMORY) + g_error ("failed to allocate memory in p11_kit_uri_format()"); + else if (res != P11_KIT_URI_OK) + g_return_val_if_reached (NULL); + + p11_kit_uri_free (p11_uri); + return string; } /** - * gck_uri_info_free: - * @uri_info: URI info to free. + * gck_uri_data_free: + * @uri_data: URI data to free. * - * Free a #GckUriInfo. + * Free a #GckUriData. */ void -gck_uri_info_free (GckUriInfo *uri_info) +gck_uri_data_free (GckUriData *uri_data) { - if (uri_info) { - if (uri_info->attributes) - gck_attributes_unref (uri_info->attributes); - if (uri_info->module_info) - gck_module_info_free (uri_info->module_info); - if (uri_info->token_info) - gck_token_info_free (uri_info->token_info); - g_slice_free (GckUriInfo, uri_info); + if (uri_data) { + if (uri_data->attributes) + gck_attributes_unref (uri_data->attributes); + if (uri_data->module_info) + gck_module_info_free (uri_data->module_info); + if (uri_data->token_info) + gck_token_info_free (uri_data->token_info); + g_slice_free (GckUriData, uri_data); } } |