summaryrefslogtreecommitdiff
path: root/module/p11-kit-uri.c
diff options
context:
space:
mode:
authorStef Walter <stefw@collabora.co.uk>2011-02-19 16:33:36 +0100
committerStef Walter <stefw@collabora.co.uk>2011-02-19 16:33:36 +0100
commit1d9ca2ddb4df85b7235ec78e4996cf2d1fd775a2 (patch)
tree027f6df6ca2207daa687f8775a4442e68d065965 /module/p11-kit-uri.c
parent65509aa3a7c35d8bd5a947ca87c14d4de11deb21 (diff)
Reference implementation of PKCS#11 URIs
Diffstat (limited to 'module/p11-kit-uri.c')
-rw-r--r--module/p11-kit-uri.c886
1 files changed, 886 insertions, 0 deletions
diff --git a/module/p11-kit-uri.c b/module/p11-kit-uri.c
new file mode 100644
index 0000000..8c65301
--- /dev/null
+++ b/module/p11-kit-uri.c
@@ -0,0 +1,886 @@
+/*
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "pkcs11.h"
+#include "p11-kit-uri.h"
+#include "util.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+enum {
+ CLASS_IDX,
+ LABEL_IDX,
+ ID_IDX,
+ NUM_ATTRS,
+};
+
+struct _P11KitUri {
+ int unrecognized;
+ CK_INFO module;
+ CK_TOKEN_INFO token;
+ CK_ATTRIBUTE attrs[NUM_ATTRS];
+};
+
+const static char HEX_CHARS[] = "0123456789abcdef";
+
+static int
+url_decode (const char *value, const char *end,
+ unsigned char** output, size_t *length)
+{
+ char *a, *b;
+ unsigned char *result, *p;
+
+ assert (output);
+ assert (value <= end);
+
+ /* String can only get shorter */
+ result = malloc ((end - value) + 1);
+ if (!result)
+ return P11_KIT_URI_NO_MEMORY;
+
+ /* Now loop through looking for escapes */
+ p = result;
+ while (value != end) {
+ /*
+ * A percent sign followed by two hex digits means
+ * that the digits represent an escaped character.
+ */
+ if (*value == '%') {
+ value++;
+ if (value + 2 > end) {
+ free (result);
+ return P11_KIT_URI_BAD_ENCODING;
+ }
+ a = strchr (HEX_CHARS, tolower (value[0]));
+ b = strchr (HEX_CHARS, tolower (value[1]));
+ if (!a || !b) {
+ free (result);
+ return P11_KIT_URI_BAD_ENCODING;
+ }
+ *p = (a - HEX_CHARS) << 4;
+ *(p++) |= (b - HEX_CHARS);
+ value += 2;
+ } else {
+ *(p++) = *(value++);
+ }
+ }
+
+ *p = 0;
+ if (length)
+ *length = p - result;
+ *output = result;
+ return P11_KIT_URI_OK;
+}
+
+static char*
+url_encode (const unsigned char *value, const unsigned char *end, size_t *length)
+{
+ char *p;
+ char *result;
+
+ assert (value <= end);
+
+ /* Just allocate for worst case */
+ result = malloc (((end - value) * 3) + 1);
+ if (!result)
+ return NULL;
+
+ /* Now loop through looking for escapes */
+ p = result;
+ while (value != end) {
+
+ /* These characters we let through verbatim */
+ if (isalnum (*value) || strchr ("_-.", *value) != NULL) {
+ *(p++) = *(value++);
+
+ /* All others get encoded */
+ } else {
+ *(p++) = '%';
+ *(p++) = HEX_CHARS[((unsigned char)*value) >> 4];
+ *(p++) = HEX_CHARS[((unsigned char)*value) & 0x0F];
+ ++value;
+ }
+ }
+
+ *p = 0;
+ if (length)
+ *length = p - result;
+ return result;
+}
+
+static int
+attribute_to_idx (CK_ATTRIBUTE_TYPE type)
+{
+ switch (type) {
+ case CKA_CLASS:
+ return CLASS_IDX;
+ case CKA_LABEL:
+ return LABEL_IDX;
+ case CKA_ID:
+ return ID_IDX;
+ default:
+ return -1;
+ }
+}
+
+static CK_ATTRIBUTE_TYPE
+idx_to_attribute (int idx)
+{
+ switch (idx) {
+ case CLASS_IDX:
+ return CKA_CLASS;
+ case LABEL_IDX:
+ return CKA_LABEL;
+ case ID_IDX:
+ return CKA_ID;
+ default:
+ assert (0);
+ }
+}
+
+static int
+match_struct_string (const unsigned char *inuri, const unsigned char *real,
+ size_t length)
+{
+ assert (inuri);
+ assert (real);
+ assert (length > 0);
+
+ /* NULL matches anything */
+ if (inuri[0] == 0)
+ return 1;
+
+ return memcmp (inuri, real, length) == 0 ? 1 : 0;
+}
+
+static int
+match_struct_version (CK_VERSION_PTR inuri, CK_VERSION_PTR real)
+{
+ /* This matches anything */
+ if (inuri->major == (CK_BYTE)-1 && inuri->minor == (CK_BYTE)-1)
+ return 1;
+
+ return memcmp (inuri, real, sizeof (CK_VERSION));
+}
+
+CK_INFO_PTR
+p11_kit_uri_get_module_info (P11KitUri *uri)
+{
+ assert (uri);
+ return &uri->module;
+}
+
+int
+p11_kit_uri_match_module_info (P11KitUri *uri, CK_INFO_PTR info)
+{
+ assert (uri);
+ assert (info);
+
+ if (uri->unrecognized)
+ return 0;
+
+ return (match_struct_string (uri->module.libraryDescription,
+ info->libraryDescription,
+ sizeof (info->libraryDescription)) &&
+ match_struct_string (uri->module.manufacturerID,
+ info->manufacturerID,
+ sizeof (info->manufacturerID)) &&
+ match_struct_version (&uri->module.libraryVersion,
+ &info->libraryVersion));
+}
+
+CK_TOKEN_INFO_PTR
+p11_kit_uri_get_token_info (P11KitUri *uri)
+{
+ assert (uri);
+ return &uri->token;
+}
+
+int
+p11_kit_uri_match_token_info (P11KitUri *uri, CK_TOKEN_INFO_PTR token_info)
+{
+ assert (uri);
+ assert (token_info);
+
+ if (uri->unrecognized)
+ return 0;
+
+ return (match_struct_string (uri->token.label,
+ token_info->label,
+ sizeof (token_info->label)) &&
+ match_struct_string (uri->token.manufacturerID,
+ token_info->manufacturerID,
+ sizeof (token_info->manufacturerID)) &&
+ match_struct_string (uri->token.model,
+ token_info->model,
+ sizeof (token_info->model)) &&
+ match_struct_string (uri->token.serialNumber,
+ token_info->serialNumber,
+ sizeof (token_info->serialNumber)));
+}
+
+CK_ATTRIBUTE_PTR
+p11_kit_uri_get_attribute (P11KitUri *uri, CK_ATTRIBUTE_TYPE type)
+{
+ int idx;
+
+ assert (uri);
+
+ idx = attribute_to_idx (type);
+ if (idx < 0)
+ return NULL;
+
+ assert (idx < NUM_ATTRS);
+ if (uri->attrs[idx].ulValueLen == (CK_ULONG)-1)
+ return NULL;
+ return &uri->attrs[idx];
+}
+
+int
+p11_kit_uri_set_attribute (P11KitUri *uri, CK_ATTRIBUTE_PTR attr)
+{
+ void *value = NULL;
+ int idx;
+ int ret;
+
+ assert (uri);
+ assert (attr);
+
+ if (attr->pValue && attr->ulValueLen && attr->ulValueLen != (CK_ULONG)-1) {
+ value = malloc (attr->ulValueLen);
+ if (!value)
+ return P11_KIT_URI_NO_MEMORY;
+ memcpy (value, attr->pValue, attr->ulValueLen);
+ }
+
+ ret = p11_kit_uri_clear_attribute (uri, attr->type);
+ if (ret < 0){
+ free (value);
+ return ret;
+ }
+
+ idx = attribute_to_idx (attr->type);
+ assert (idx >= 0 && idx < NUM_ATTRS);
+
+ memcpy (&uri->attrs[idx], attr, sizeof (CK_ATTRIBUTE));
+ uri->attrs[idx].pValue = value;
+
+ return P11_KIT_URI_OK;
+}
+
+int
+p11_kit_uri_clear_attribute (P11KitUri *uri, CK_ATTRIBUTE_TYPE type)
+{
+ int idx;
+
+ assert (uri);
+
+ idx = attribute_to_idx (type);
+ if (idx < 0)
+ return P11_KIT_URI_NOT_FOUND;
+ assert (idx < NUM_ATTRS);
+
+ free (uri->attrs[idx].pValue);
+ uri->attrs[idx].pValue = NULL;
+ uri->attrs[idx].ulValueLen = (CK_ULONG)-1;
+ return 0;
+}
+
+static int
+match_attributes (CK_ATTRIBUTE_PTR one, CK_ATTRIBUTE_PTR two)
+{
+ assert (one);
+ assert (two);
+
+ if (one->type != two->type)
+ return 0;
+ if (one->ulValueLen != two->ulValueLen)
+ return 0;
+ if (one->pValue == two->pValue)
+ return 1;
+ if (!one->pValue || !two->pValue)
+ return 0;
+ return memcmp (one->pValue, two->pValue, one->ulValueLen) == 0;
+}
+
+int
+p11_kit_uri_match_attributes (P11KitUri *uri, CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs)
+{
+ CK_ULONG j;
+ int i;
+
+ assert (uri);
+ assert (attrs || !n_attrs);
+
+ if (uri->unrecognized)
+ return 0;
+
+ for (i = 0; i < NUM_ATTRS; ++i) {
+ if (uri->attrs[i].ulValueLen == (CK_ULONG)-1)
+ continue;
+ for (j = 0; j < n_attrs; ++j) {
+ if (attrs[j].type == uri->attrs[i].type) {
+ if (!match_attributes (&uri->attrs[i], &attrs[j]))
+ return 0;
+ break;
+ }
+ }
+ }
+
+ return 1;
+}
+
+void
+p11_kit_uri_set_unrecognized (P11KitUri *uri, int unrecognized)
+{
+ assert (uri);
+ uri->unrecognized = unrecognized;
+}
+
+int
+p11_kit_uri_any_unrecognized (P11KitUri *uri)
+{
+ assert (uri);
+ return uri->unrecognized;
+}
+
+P11KitUri*
+p11_kit_uri_new (void)
+{
+ P11KitUri *uri;
+ int i;
+
+ uri = calloc (1, sizeof (P11KitUri));
+ if (!uri)
+ return NULL;
+
+ /* So that it matches anything */
+ uri->module.libraryVersion.major = (CK_BYTE)-1;
+ uri->module.libraryVersion.minor = (CK_BYTE)-1;
+
+ for (i = 0; i < NUM_ATTRS; ++i) {
+ uri->attrs[i].type = idx_to_attribute (i);
+ uri->attrs[i].ulValueLen = (CK_ULONG)-1;
+ }
+
+ return uri;
+}
+
+static size_t
+space_strlen (const unsigned char *string, size_t max_length)
+{
+ size_t i = max_length - 1;
+
+ assert (string);
+
+ while (i > 0 && string[i] == ' ')
+ --i;
+ return i + 1;
+}
+
+static int
+format_raw_string (char **string, size_t *length, int *is_first,
+ const char *name, const char *value)
+{
+ size_t namelen;
+ size_t vallen;
+
+ /* Not set */
+ if (!value)
+ return 1;
+
+ namelen = strlen (name);
+ vallen = strlen (value);
+
+ *string = xrealloc (*string, *length + namelen + vallen + 3);
+ if (!*string)
+ return 0;
+
+ if (!*is_first)
+ (*string)[(*length)++] = ';';
+ memcpy ((*string) + *length, name, namelen);
+ *length += namelen;
+ (*string)[(*length)++] = '=';
+ memcpy ((*string) + *length, value, vallen);
+ *length += vallen;
+ (*string)[*length] = 0;
+ *is_first = 0;
+
+ return 1;
+}
+
+
+static int
+format_struct_string (char **string, size_t *length, int *is_first,
+ const char *name, const unsigned char *value,
+ size_t value_max)
+{
+ char *encoded;
+ size_t len;
+ int ret;
+
+ /* Not set */
+ if (!value[0])
+ return 1;
+
+ len = space_strlen (value, value_max);
+ encoded = url_encode (value, value + len, NULL);
+ if (!encoded)
+ return 0;
+
+ ret = format_raw_string (string, length, is_first, name, encoded);
+ free (encoded);
+
+ return ret;
+}
+
+static int
+format_attribute_string (char **string, size_t *length, int *is_first,
+ const char *name, CK_ATTRIBUTE_PTR attr)
+{
+ unsigned char *value;
+ char *encoded;
+ int ret;
+
+ /* Not set */;
+ if (attr->ulValueLen == (CK_ULONG)-1)
+ return 1;
+
+ value = attr->pValue;
+ encoded = url_encode (value, value + attr->ulValueLen, NULL);
+ if (!encoded)
+ return 0;
+
+ ret = format_raw_string (string, length, is_first, name, encoded);
+ free (encoded);
+
+ return ret;
+}
+
+static int
+format_attribute_class (char **string, size_t *length, int *is_first,
+ const char *name, CK_ATTRIBUTE_PTR attr)
+{
+ CK_OBJECT_CLASS klass;
+ const char *value;
+
+ /* Not set */;
+ if (attr->ulValueLen != sizeof (klass))
+ return 1;
+
+ klass = *((CK_OBJECT_CLASS*)attr->pValue);
+ switch (klass) {
+ case CKO_DATA:
+ value = "data";
+ break;
+ case CKO_SECRET_KEY:
+ value = "secretkey";
+ break;
+ case CKO_CERTIFICATE:
+ value = "cert";
+ break;
+ case CKO_PUBLIC_KEY:
+ value = "public";
+ break;
+ case CKO_PRIVATE_KEY:
+ value = "private";
+ break;
+ }
+
+ return format_raw_string (string, length, is_first, name, value);
+}
+
+static int
+format_struct_version (char **string, size_t *length, int *is_first,
+ const char *name, CK_VERSION_PTR version)
+{
+ char buffer[64];
+
+ /* Not set */
+ if (version->major == (CK_BYTE)-1 && version->minor == (CK_BYTE)-1)
+ return 1;
+
+ snprintf (buffer, sizeof (buffer), "%d.%d",
+ (int)version->major, (int)version->minor);
+ return format_raw_string (string, length, is_first, name, buffer);
+}
+
+int
+p11_kit_uri_format (P11KitUri *uri, char **string)
+{
+ char *result = NULL;
+ size_t length = 0;
+ int is_first = 1;
+
+ result = malloc (128);
+ if (!result)
+ return P11_KIT_URI_NO_MEMORY;
+
+ length = P11_KIT_URI_PREFIX_LEN;
+ memcpy (result, P11_KIT_URI_PREFIX, length);
+ result[length] = 0;
+
+ if (!format_struct_string (&result, &length, &is_first, "library-description",
+ uri->module.libraryDescription,
+ sizeof (uri->module.libraryDescription)) ||
+ !format_struct_string (&result, &length, &is_first, "library-manufacturer",
+ uri->module.manufacturerID,
+ sizeof (uri->module.manufacturerID)) ||
+ !format_struct_string (&result, &length, &is_first, "model",
+ uri->token.model,
+ sizeof (uri->token.model)) ||
+ !format_struct_string (&result, &length, &is_first, "manufacturer",
+ uri->token.manufacturerID,
+ sizeof (uri->token.manufacturerID)) ||
+ !format_struct_string (&result, &length, &is_first, "serial",
+ uri->token.serialNumber,
+ sizeof (uri->token.serialNumber)) ||
+ !format_struct_string (&result, &length, &is_first, "token",
+ uri->token.label,
+ sizeof (uri->token.label)) ||
+ !format_struct_version (&result, &length, &is_first, "library-version",
+ &uri->module.libraryVersion)) {
+ free (result);
+ return P11_KIT_URI_NO_MEMORY;
+ }
+
+ if (!format_attribute_string (&result, &length, &is_first, "id",
+ &uri->attrs[ID_IDX]) ||
+ !format_attribute_string (&result, &length, &is_first, "object",
+ &uri->attrs[LABEL_IDX])) {
+ free (result);
+ return P11_KIT_URI_NO_MEMORY;
+ }
+
+ if (!format_attribute_class (&result, &length, &is_first, "objecttype",
+ &uri->attrs[CLASS_IDX])) {
+ free (result);
+ return P11_KIT_URI_NO_MEMORY;
+ }
+
+ *string = result;
+ return P11_KIT_URI_OK;
+}
+
+static int
+parse_string_attribute (const char *name, const char *start, const char *end,
+ P11KitUri *uri)
+{
+ unsigned char *value;
+ size_t length;
+ int idx, ret;
+
+ assert (start <= end);
+
+ if (strcmp ("id", name) == 0)
+ idx = ID_IDX;
+ else if (strcmp ("object", name) == 0)
+ idx = LABEL_IDX;
+ else
+ return 0;
+
+ ret = url_decode (start, end, &value, &length);
+ if (ret < 0)
+ return ret;
+
+ free (uri->attrs[idx].pValue);
+ uri->attrs[idx].pValue = value;
+ uri->attrs[idx].ulValueLen = length;
+ return 1;
+}
+
+static int
+equals_segment (const char *start, const char *end, const char *match)
+{
+ size_t len = strlen (match);
+ assert (start <= end);
+ return (end - start == len) && memcmp (start, match, len) == 0;
+}
+
+static int
+parse_class_attribute (const char *name, const char *start, const char *end,
+ P11KitUri *uri)
+{
+ CK_OBJECT_CLASS klass = 0;
+ void *value;
+
+ assert (start <= end);
+
+ if (strcmp ("objecttype", name) != 0)
+ return 0;
+
+ if (equals_segment (start, end, "cert"))
+ klass = CKO_CERTIFICATE;
+ else if (equals_segment (start, end, "public"))
+ klass = CKO_PUBLIC_KEY;
+ else if (equals_segment (start, end, "private"))
+ klass = CKO_PRIVATE_KEY;
+ else if (equals_segment (start, end, "secretkey"))
+ klass = CKO_SECRET_KEY;
+ else if (equals_segment (start, end, "data"))
+ klass = CKO_DATA;
+ else {
+ uri->unrecognized = 1;
+ return 1;
+ }
+
+ value = malloc (sizeof (klass));
+ if (value == NULL)
+ return P11_KIT_URI_NO_MEMORY;
+
+ free (uri->attrs[CLASS_IDX].pValue);
+ memcpy (value, &klass, sizeof (klass));
+ uri->attrs[CLASS_IDX].pValue = value;
+ uri->attrs[CLASS_IDX].ulValueLen = sizeof (klass);
+
+ return 1;
+}
+
+static int
+parse_struct_info (unsigned char *where, size_t length, const char *start,
+ const char *end, P11KitUri *uri)
+{
+ unsigned char *value;
+ size_t value_length;
+ int ret;
+
+ assert (start <= end);
+
+ ret = url_decode (start, end, &value, &value_length);
+ if (ret < 0)
+ return ret;
+
+ /* Too long, shouldn't match anything */
+ if (value_length > length) {
+ free (value);
+ uri->unrecognized = 1;
+ return 1;
+ }
+
+ memset (where, ' ', length);
+ memcpy (where, value, value_length);
+
+ free (value);
+ return 1;
+}
+
+static int
+parse_token_info (const char *name, const char *start, const char *end,
+ P11KitUri *uri)
+{
+ unsigned char *where;
+ size_t length;
+
+ assert (start <= end);
+
+ if (strcmp (name, "model") == 0) {
+ where = uri->token.model;
+ length = sizeof (uri->token.model);
+ } else if (strcmp (name, "manufacturer") == 0) {
+ where = uri->token.manufacturerID;
+ length = sizeof (uri->token.manufacturerID);
+ } else if (strcmp (name, "serial") == 0) {
+ where = uri->token.serialNumber;
+ length = sizeof (uri->token.serialNumber);
+ } else if (strcmp (name, "token") == 0) {
+ where = uri->token.label;
+ length = sizeof (uri->token.label);
+ } else {
+ return 0;
+ }
+
+ return parse_struct_info (where, length, start, end, uri);
+}
+
+static int
+atoin (const char *start, const char *end)
+{
+ int ret = 0;
+ while (start != end) {
+ if (*start < '0' || *start > '9')
+ return -1;
+ ret *= 10;
+ ret += (*start - '0');
+ ++start;
+ }
+ return ret;
+}
+
+static int
+parse_struct_version (const char *start, const char *end, CK_VERSION_PTR version)
+{
+ const char *dot;
+ int val;
+
+ assert (start <= end);
+
+ dot = memchr (start, '.', end - start);
+ if (!dot)
+ dot = end;
+
+ if (dot == start)
+ return P11_KIT_URI_BAD_VERSION;
+ val = atoin (start, dot);
+ if (val < 0 || val >= 255)
+ return P11_KIT_URI_BAD_VERSION;
+ version->major = (CK_BYTE)val;
+ version->minor = 0;
+
+ if (dot != end) {
+ if (dot + 1 == end)
+ return P11_KIT_URI_BAD_VERSION;
+ val = atoin (dot + 1, end);
+ if (val < 0 || val >= 255)
+ return P11_KIT_URI_BAD_VERSION;
+ version->minor = (CK_BYTE)val;
+ }
+
+ return 1;
+}
+
+static int
+parse_module_info (const char *name, const char *start, const char *end,
+ P11KitUri *uri)
+{
+ unsigned char *where;
+ size_t length;
+
+ assert (start <= end);
+
+ if (strcmp (name, "library-description") == 0) {
+ where = uri->module.libraryDescription;
+ length = sizeof (uri->module.libraryDescription);
+ } else if (strcmp (name, "library-manufacturer") == 0) {
+ where = uri->module.manufacturerID;
+ length = sizeof (uri->module.manufacturerID);
+ } else if (strcmp (name, "library-version") == 0) {
+ return parse_struct_version (start, end,
+ &uri->module.libraryVersion);
+ } else {
+ return 0;
+ }
+
+ return parse_struct_info (where, length, start, end, uri);
+}
+
+int
+p11_kit_uri_parse (const char *string, P11KitUriContext context,
+ P11KitUri *uri)
+{
+ const char *spos, *epos;
+ char *key = NULL;
+ int ret = -1;
+ int i;
+
+ assert (string);
+ assert (uri);
+
+ if (strncmp (string, P11_KIT_URI_PREFIX, P11_KIT_URI_PREFIX_LEN) != 0)
+ return P11_KIT_URI_BAD_PREFIX;
+
+ string += P11_KIT_URI_PREFIX_LEN;
+
+ /* Clear everything out */
+ memset (&uri->module, 0, sizeof (uri->module));
+ memset (&uri->token, 0, sizeof (uri->module));
+ for (i = 0; i < NUM_ATTRS; ++i)
+ uri->attrs[i].ulValueLen = (CK_ULONG)-1;
+ uri->module.libraryVersion.major = (CK_BYTE)-1;
+ uri->module.libraryVersion.minor = (CK_BYTE)-1;
+ uri->unrecognized = 0;
+
+ for (;;) {
+ spos = strchr (string, ';');
+ if (spos == NULL) {
+ spos = string + strlen (string);
+ assert (*spos == '\0');
+ if (spos == string)
+ break;
+ }
+
+ epos = strchr (string, '=');
+ if (epos == NULL || spos == string || epos == string || epos >= spos)
+ return P11_KIT_URI_BAD_SYNTAX;
+
+ key = malloc ((epos - string) + 1);
+ if (key == NULL)
+ return P11_KIT_URI_NO_MEMORY;
+ memcpy (key, string, epos - string);
+ key[epos - string] = 0;
+ epos++;
+
+ ret = 0;
+ if (context & P11_KIT_URI_PARSE_OBJECT)
+ ret = parse_string_attribute (key, epos, spos, uri);
+ if (ret == 0 && context & P11_KIT_URI_PARSE_OBJECT)
+ ret = parse_class_attribute (key, epos, spos, uri);
+ if (ret == 0 && context & P11_KIT_URI_PARSE_TOKEN)
+ ret = parse_token_info (key, epos, spos, uri);
+ if (ret == 0 && context & P11_KIT_URI_PARSE_MODULE)
+ ret = parse_module_info (key, epos, spos, uri);
+ free (key);
+
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ uri->unrecognized = 1;
+
+ if (*spos == '\0')
+ break;
+ string = spos + 1;
+ }
+
+ return P11_KIT_URI_OK;
+}
+
+void
+p11_kit_uri_free (P11KitUri *uri)
+{
+ int i;
+
+ if (!uri)
+ return;
+
+ for (i = 0; i < NUM_ATTRS; ++i)
+ free (uri->attrs[i].pValue);
+
+ free (uri);
+}