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