1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gck-uri.c - the GObject PKCS#11 wrapper library
3 
4    Copyright (C) 2010, Stefan Walter
5 
6    The Gnome Keyring Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10 
11    The Gnome Keyring Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    see <http://www.gnu.org/licenses/>.
19 
20    Author: Stef Walter <stef@memberwebs.com>
21 */
22 
23 #include "config.h"
24 
25 #include "gck.h"
26 #include "gck-private.h"
27 
28 #include "gck/gck-marshal.h"
29 
30 #include <glib/gi18n-lib.h>
31 
32 #include <p11-kit/uri.h>
33 
34 #include <string.h>
35 #include <stdlib.h>
36 
37 /**
38  * SECTION:gck-uri
39  * @title: PKCS11 URIs
40  * @short_description: Parsing and building PKCS\#11 URIs.
41  *
42  * <ulink href='http://tools.ietf.org/html/draft-pechanec-pkcs11uri-03'>PKCS\#11 URIs</ulink>
43  * are a standard for referring to PKCS\#11 modules, tokens, or objects. What the
44  * PKCS\#11 URI refers to depends on the context in which it is used.
45  *
46  * A PKCS\#11 URI can always resolve to more than one object, token or module. A
47  * PKCS\#11 URI that refers to a token, would (when used in a context that expects
48  * objects) refer to all the token on that module.
49  *
50  * In most cases the parsing or building of URIs is handled elsewhere in the GCK
51  * library. For example to enumerate objects that match a PKCS\#11 URI use the
52  * gck_modules_enumerate_uri() function.
53  *
54  * To parse a PKCS\#11 URI use the gck_uri_parse() function passing in the type of
55  * context in which you're using the URI. To build a URI use the gck_uri_build()
56  * function.
57  **/
58 
59 /**
60  * GckUriData:
61  * @any_unrecognized: whether any parts of the PKCS\#11 URI were unsupported or unrecognized.
62  * @module_info: information about the PKCS\#11 modules matching the URI.
63  * @token_info: information about the PKCS\#11 tokens matching the URI.
64  * @attributes: information about the PKCS\#11 objects matching the URI.
65  *
66  * Information about the contents of a PKCS\#11 URI. Various fields may be %NULL
67  * depending on the context that the URI was parsed for.
68  *
69  * Since PKCS\#11 URIs represent a set which results from the intersections of
70  * all of the URI parts, if @any_recognized is set to %TRUE then usually the URI
71  * should be treated as not matching anything.
72  */
73 
74 /**
75  * GckUriFlags:
76  * @GCK_URI_FOR_MODULE: the URI will be used to match modules.
77  * @GCK_URI_FOR_TOKEN: the URI will be used to match tokens.
78  * @GCK_URI_FOR_OBJECT: the URI will be used to match objects.
79  * @GCK_URI_WITH_VERSION: the URI has specific version numbers for module and/or token
80  * @GCK_URI_FOR_ANY: parse all recognized components of the URI.
81  *
82  * Which parts of the PKCS\#11 URI will be parsed or formatted. These can be
83  * combined.
84  */
85 
86 /**
87  * GCK_URI_FOR_MODULE_WITH_VERSION:
88  *
89  * The URI will match specific version of modules. To be used as a GckUriFlags argument.
90  */
91 
92 /**
93  * GCK_URI_FOR_OBJECT_ON_TOKEN:
94  *
95  * The URI will match objects on a specific token. To be used as a GckUriFlags argument.
96  */
97 
98 /**
99  * GCK_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE:
100  *
101  * The token inserted into a device with a specific module.
102  */
103 
104 /**
105  * GckUriError:
106  * @GCK_URI_BAD_SCHEME: invalid URI scheme
107  * @GCK_URI_BAD_ENCODING: bad URI encoding
108  * @GCK_URI_BAD_SYNTAX: bad URI syntax
109  * @GCK_URI_BAD_VERSION: bad URI version component
110  * @GCK_URI_NOT_FOUND: piece of the URI was not found
111  *
112  * Various error codes used with PKCS\#11 URIs
113  */
114 
115 /**
116  * GCK_URI_ERROR:
117  *
118  * Error domain for URI errors.
119  */
120 
121 /**
122  * GCK_URI_BAD_PREFIX:
123  *
124  * Use %GCK_URI_BAD_SCHEME instead.
125  *
126  * Deprecated: Since 3.2
127  */
128 
129 /**
130  * CKR_GCK_MODULE_PROBLEM:
131  *
132  * Use %GCK_ERROR_MODULE_PROBLEM instead.
133  *
134  * Deprecated: Since 3.4
135  */
136 
137 #define URI_PREFIX "pkcs11:"
138 #define N_URI_PREFIX 7
139 
140 struct _GckUri {
141 	gboolean any_unrecognized;
142 	GckModuleInfo *module_info;
143 	GckTokenInfo *token_info;
144 	GckAttributes *attributes;
145 };
146 
147 GQuark
gck_uri_get_error_quark(void)148 gck_uri_get_error_quark (void)
149 {
150 	/* This is deprecated version */
151 	return gck_uri_error_get_quark ();
152 }
153 
154 GQuark
gck_uri_error_get_quark(void)155 gck_uri_error_get_quark (void)
156 {
157 	static GQuark domain = 0;
158 	static volatile gsize quark_inited = 0;
159 
160 	if (g_once_init_enter (&quark_inited)) {
161 		domain = g_quark_from_static_string ("gck-uri-error");
162 		g_once_init_leave (&quark_inited, 1);
163 	}
164 
165 	return domain;
166 }
167 
168 /**
169  * gck_uri_data_new:
170  *
171  * Allocate a new GckUriData structure. None of the fields
172  * will be set.
173  *
174  * Returns: (transfer full): a newly allocated GckUriData, free with
175  *          gck_uri_data_free()
176  */
177 GckUriData *
gck_uri_data_new(void)178 gck_uri_data_new (void)
179 {
180 	return g_slice_new0 (GckUriData);
181 }
182 
183 /**
184  * gck_uri_parse:
185  * @string: the URI to parse.
186  * @flags: the context in which the URI will be used.
187  * @error: a #GError, or %NULL.
188  *
189  * Parse a PKCS\#11 URI for use in a given context.
190  *
191  * The result will contain the fields that are relevant for
192  * the given context. See #GckUriData  for more info.
193  * Other fields will be set to %NULL.
194  *
195  * Returns: (transfer full): a newly allocated #GckUriData; which should be
196  *          freed with gck_uri_data_free()
197  */
198 GckUriData*
gck_uri_parse(const gchar * string,GckUriFlags flags,GError ** error)199 gck_uri_parse (const gchar *string, GckUriFlags flags, GError **error)
200 {
201 	GckUriData *uri_data = NULL;
202 	GckBuilder builder;
203 	CK_ATTRIBUTE_PTR attrs;
204 	CK_ULONG i, n_attrs;
205 	P11KitUri *p11_uri;
206 	gint res;
207 
208 	g_return_val_if_fail (string, FALSE);
209 	g_return_val_if_fail (!error || !*error, FALSE);
210 
211 	p11_uri = p11_kit_uri_new ();
212 	if (!p11_uri)
213 		g_error ("failed to allocate P11KitUri");
214 
215 	res = p11_kit_uri_parse (string, flags, p11_uri);
216 	if (res != P11_KIT_URI_OK) {
217 		p11_kit_uri_free (p11_uri);
218 		switch (res) {
219 		case P11_KIT_URI_NO_MEMORY:
220 			g_error ("failed to allocate memory in p11_kit_uri_parse()");
221 			break;
222 		case P11_KIT_URI_BAD_ENCODING:
223 			g_set_error (error, GCK_URI_ERROR, GCK_URI_BAD_ENCODING,
224 				     _("The URI has invalid encoding."));
225 			break;
226 		case P11_KIT_URI_BAD_SCHEME:
227 			g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SCHEME,
228 			                     _("The URI does not have the “pkcs11” scheme."));
229 			break;
230 		case P11_KIT_URI_BAD_SYNTAX:
231 			g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SYNTAX,
232 			                     _("The URI has bad syntax."));
233 			break;
234 		case P11_KIT_URI_BAD_VERSION:
235 			g_set_error_literal (error, GCK_URI_ERROR, GCK_URI_BAD_SYNTAX,
236 			                     _("The URI has a bad version number."));
237 			break;
238 		case P11_KIT_URI_NOT_FOUND:
239 			g_assert_not_reached ();
240 			break;
241 		};
242 		return NULL;
243 	}
244 
245 	/* Convert it to a GckUri */
246 	uri_data = gck_uri_data_new ();
247 	if (flags & GCK_URI_FOR_MODULE_WITH_VERSION)
248 		uri_data->module_info = _gck_module_info_from_pkcs11 (p11_kit_uri_get_module_info (p11_uri));
249 	if (flags & GCK_URI_FOR_TOKEN)
250 		uri_data->token_info = _gck_token_info_from_pkcs11 (p11_kit_uri_get_token_info (p11_uri));
251 	if (flags & GCK_URI_FOR_OBJECT) {
252 		attrs = p11_kit_uri_get_attributes (p11_uri, &n_attrs);
253 		gck_builder_init (&builder);
254 		for (i = 0; i < n_attrs; ++i)
255 			gck_builder_add_data (&builder, attrs[i].type, attrs[i].pValue, attrs[i].ulValueLen);
256 		uri_data->attributes = gck_attributes_ref_sink (gck_builder_end (&builder));
257 	}
258 	uri_data->any_unrecognized = p11_kit_uri_any_unrecognized (p11_uri);
259 
260 	p11_kit_uri_free (p11_uri);
261 	return uri_data;
262 }
263 
264 /**
265  * gck_uri_build:
266  * @uri_data: the info to build the URI from.
267  * @flags: The context that the URI is for
268  *
269  * Build a PKCS\#11 URI. The various parts relevant to the flags
270  * specified will be used to build the URI.
271  *
272  * Return value: a newly allocated string containing a PKCS\#11 URI.
273  */
274 gchar*
gck_uri_build(GckUriData * uri_data,GckUriFlags flags)275 gck_uri_build (GckUriData *uri_data, GckUriFlags flags)
276 {
277 	const GckAttribute *attr;
278 	P11KitUri *p11_uri = 0;
279 	gchar *string;
280 	int res;
281 	guint i;
282 
283 	g_return_val_if_fail (uri_data != NULL, NULL);
284 
285 	p11_uri = p11_kit_uri_new ();
286 
287 	if ((flags & GCK_URI_FOR_MODULE_WITH_VERSION) && uri_data->module_info)
288 		_gck_module_info_to_pkcs11 (uri_data->module_info,
289 		                            p11_kit_uri_get_module_info (p11_uri));
290 	if ((flags & GCK_URI_FOR_TOKEN) && uri_data->token_info)
291 		_gck_token_info_to_pkcs11 (uri_data->token_info,
292 		                           p11_kit_uri_get_token_info (p11_uri));
293 	if ((flags & GCK_URI_FOR_OBJECT) && uri_data->attributes) {
294 		for (i = 0; i < gck_attributes_count (uri_data->attributes); ++i) {
295 			attr = gck_attributes_at (uri_data->attributes, i);
296 			res = p11_kit_uri_set_attribute (p11_uri, (CK_ATTRIBUTE_PTR)attr);
297 			if (res == P11_KIT_URI_NO_MEMORY)
298 				g_error ("failed to allocate memory in p11_kit_uri_set_attribute()");
299 			else if (res != P11_KIT_URI_NOT_FOUND && res != P11_KIT_URI_OK)
300 				g_return_val_if_reached (NULL);
301 		}
302 	}
303 
304 	res = p11_kit_uri_format (p11_uri, flags & GCK_URI_FOR_ANY, &string);
305 	if (res == P11_KIT_URI_NO_MEMORY)
306 		g_error ("failed to allocate memory in p11_kit_uri_format()");
307 	else if (res != P11_KIT_URI_OK)
308 		g_return_val_if_reached (NULL);
309 
310 	p11_kit_uri_free (p11_uri);
311 	return string;
312 }
313 
G_DEFINE_BOXED_TYPE(GckUriData,gck_uri_data,gck_uri_data_copy,gck_uri_data_free)314 G_DEFINE_BOXED_TYPE (GckUriData, gck_uri_data,
315                      gck_uri_data_copy, gck_uri_data_free)
316 
317 /**
318  * gck_uri_data_copy:
319  * @uri_data: URI data to copy
320  *
321  * Copy a #GckUriData
322  *
323  * Returns: (transfer full): newly allocated copy of the uri data
324  */
325 GckUriData *
326 gck_uri_data_copy (GckUriData *uri_data)
327 {
328 	GckUriData *copy;
329 
330 	copy = g_memdup (uri_data, sizeof (GckUriData));
331 	copy->attributes = gck_attributes_ref (uri_data->attributes);
332 	copy->module_info = gck_module_info_copy (copy->module_info);
333 	copy->token_info = gck_token_info_copy (copy->token_info);
334 	return copy;
335 }
336 
337 /**
338  * gck_uri_data_free:
339  * @uri_data: URI data to free.
340  *
341  * Free a #GckUriData.
342  */
343 void
gck_uri_data_free(GckUriData * uri_data)344 gck_uri_data_free (GckUriData *uri_data)
345 {
346 	if (uri_data) {
347 		if (uri_data->attributes)
348 			gck_attributes_unref (uri_data->attributes);
349 		if (uri_data->module_info)
350 			gck_module_info_free (uri_data->module_info);
351 		if (uri_data->token_info)
352 			gck_token_info_free (uri_data->token_info);
353 		g_slice_free (GckUriData, uri_data);
354 	}
355 }
356