1 /*
2  * Copyright (C) 2011 Collabora Ltd.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *     * Redistributions of source code must retain the above
9  *       copyright notice, this list of conditions and the
10  *       following disclaimer.
11  *     * Redistributions in binary form must reproduce the
12  *       above copyright notice, this list of conditions and
13  *       the following disclaimer in the documentation and/or
14  *       other materials provided with the distribution.
15  *     * The names of contributors to this software may not be
16  *       used to endorse or promote products derived from this
17  *       software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  * DAMAGE.
31  *
32  * Author: Stef Walter <stefw@collabora.co.uk>
33  */
34 
35 #include "config.h"
36 
37 #include "array.h"
38 #include "attrs.h"
39 #include "buffer.h"
40 #define P11_DEBUG_FLAG P11_DEBUG_URI
41 #include "debug.h"
42 #include "message.h"
43 #include "pkcs11.h"
44 #include "private.h"
45 #include "p11-kit.h"
46 #include "uri.h"
47 #include "url.h"
48 
49 #include <assert.h>
50 #include <ctype.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 
55 /**
56  * SECTION:p11-kit-uri
57  * @title: URIs
58  * @short_description: Parsing and formatting PKCS\#11 URIs
59  *
60  * PKCS\#11 URIs can be used in configuration files or applications to represent
61  * PKCS\#11 modules, tokens or objects. An example of a URI might be:
62  *
63  * <code><literallayout>
64  *      pkcs11:token=The\%20Software\%20PKCS\#11\%20softtoken;
65  *          manufacturer=Snake\%20Oil,\%20Inc.;serial=;object=my-certificate;
66  *          model=1.0;type=cert;id=\%69\%95\%3e\%5c\%f4\%bd\%ec\%91
67  * </literallayout></code>
68  *
69  * You can use p11_kit_uri_parse() to parse such a URI, and p11_kit_uri_format()
70  * to build one. URIs are represented by the #P11KitUri structure. You can match
71  * a parsed URI against PKCS\#11 tokens with p11_kit_uri_match_token_info()
72  * or attributes with p11_kit_uri_match_attributes().
73  *
74  * Since URIs can represent different sorts of things, when parsing or formatting
75  * a URI a 'context' can be used to indicate which sort of URI is expected.
76  *
77  * URIs have an <code>unrecognized</code> flag. This flag is set during parsing
78  * if any parts of the URI are not recognized. This may be because the part is
79  * from a newer version of the PKCS\#11 spec or because that part was not valid
80  * inside of the desired context used when parsing.
81  */
82 
83 /**
84  * P11KitUri:
85  *
86  * A structure representing a PKCS\#11 URI. There are no public fields
87  * visible in this structure. Use the various accessor functions.
88  */
89 
90 /**
91  * P11KitUriType:
92  * @P11_KIT_URI_FOR_OBJECT: The URI represents one or more objects
93  * @P11_KIT_URI_FOR_TOKEN: The URI represents one or more tokens
94  * @P11_KIT_URI_FOR_SLOT: The URI represents one or more slots
95  * @P11_KIT_URI_FOR_MODULE: The URI represents one or more modules
96  * @P11_KIT_URI_FOR_MODULE_WITH_VERSION: The URI represents a module with
97  *     a specific version.
98  * @P11_KIT_URI_FOR_OBJECT_ON_TOKEN: The URI represents one or more objects
99  *     that are present on a specific token.
100  * @P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE: The URI represents one or more
101  *     objects that are present on a specific token, being used with a certain
102  *     module.
103  * @P11_KIT_URI_FOR_ANY: The URI can represent anything
104  *
105  * A PKCS\#11 URI can represent different kinds of things. This flag is used by
106  * p11_kit_uri_parse() to denote in what context the URI will be used.
107  *
108  * The various types can be combined.
109  */
110 
111 /**
112  * P11KitUriResult:
113  * @P11_KIT_URI_OK: Success
114  * @P11_KIT_URI_UNEXPECTED: Unexpected or internal system error
115  * @P11_KIT_URI_BAD_SCHEME: The URI had a bad scheme
116  * @P11_KIT_URI_BAD_ENCODING: The URI had a bad encoding
117  * @P11_KIT_URI_BAD_SYNTAX: The URI had a bad syntax
118  * @P11_KIT_URI_BAD_VERSION: The URI contained a bad version number
119  * @P11_KIT_URI_NOT_FOUND: A requested part of the URI was not found
120  *
121  * Error codes returned by various functions. The functions each clearly state
122  * which error codes they are capable of returning.
123  */
124 
125 /**
126  * P11_KIT_URI_NO_MEMORY:
127  *
128  * Unexpected memory allocation failure result. Same as #P11_KIT_URI_UNEXPECTED.
129  */
130 
131 /**
132  * P11_KIT_URI_SCHEME:
133  *
134  * String of URI scheme for PKCS\#11 URIs.
135  */
136 
137 /**
138  * P11_KIT_URI_SCHEME_LEN:
139  *
140  * Length of %P11_KIT_URI_SCHEME.
141  */
142 
143 typedef struct _Attribute {
144 	char *name;
145 	char *value;
146 } Attribute;
147 
148 struct p11_kit_uri {
149 	bool unrecognized;
150 	CK_INFO module;
151 	CK_SLOT_INFO slot;
152 	CK_TOKEN_INFO token;
153 	CK_ATTRIBUTE *attrs;
154 	CK_SLOT_ID slot_id;
155 	char *pin_source;
156 	char *pin_value;
157 	char *module_name;
158 	char *module_path;
159 	p11_array *qattrs;
160 };
161 
162 static char *
strip_whitespace(const char * value)163 strip_whitespace (const char *value)
164 {
165 	size_t length = strlen (value);
166 	char *at, *pos;
167 	char *key;
168 
169 	key = malloc (length + 1);
170 	return_val_if_fail (key != NULL, NULL);
171 
172 	memcpy (key, value, length);
173 	key[length] = '\0';
174 
175 	/* Do we have any whitespace? Strip it out. */
176 	if (strcspn (key, P11_URL_WHITESPACE) != length) {
177 		for (at = key, pos = key; pos != key + length + 1; ++pos) {
178 			if (!strchr (P11_URL_WHITESPACE, *pos))
179 				*(at++) = *pos;
180 		}
181 		*at = '\0';
182 	}
183 
184 	return key;
185 }
186 
187 static bool
match_struct_string(const unsigned char * inuri,const unsigned char * real,size_t length)188 match_struct_string (const unsigned char *inuri, const unsigned char *real,
189                      size_t length)
190 {
191 	assert (inuri);
192 	assert (real);
193 	assert (length > 0);
194 
195 	/* NULL matches anything */
196 	if (inuri[0] == 0)
197 		return true;
198 
199 	return memcmp (inuri, real, length) == 0 ? true : false;
200 }
201 
202 static bool
match_struct_version(CK_VERSION const * inuri,CK_VERSION const * real)203 match_struct_version (CK_VERSION const *inuri, CK_VERSION const *real)
204 {
205 	/* This matches anything */
206 	if (inuri->major == (CK_BYTE)-1 && inuri->minor == (CK_BYTE)-1)
207 		return true;
208 
209 	return memcmp (inuri, real, sizeof (CK_VERSION)) == 0 ? true : false;
210 }
211 
212 /**
213  * p11_kit_uri_get_module_info:
214  * @uri: the URI
215  *
216  * Get the <code>CK_INFO</code> structure associated with this URI.
217  *
218  * If this is a parsed URI, then the fields corresponding to library parts of
219  * the URI will be filled in. Any library URI parts that were missing will have
220  * their fields filled with zeros.
221  *
222  * If the caller wishes to setup information for building a URI, then relevant
223  * fields should be filled in. Fields that should not appear as parts in the
224  * resulting URI should be filled with zeros.
225  *
226  * Returns: A pointer to the <code>CK_INFO</code> structure.
227  */
228 CK_INFO_PTR
p11_kit_uri_get_module_info(P11KitUri * uri)229 p11_kit_uri_get_module_info (P11KitUri *uri)
230 {
231 	return_val_if_fail (uri != NULL, NULL);
232 	return &uri->module;
233 }
234 
235 int
p11_match_uri_module_info(CK_INFO const * one,CK_INFO const * two)236 p11_match_uri_module_info (CK_INFO const *one,
237                            CK_INFO const *two)
238 {
239 	return (match_struct_string (one->libraryDescription,
240 	                             two->libraryDescription,
241 	                             sizeof (one->libraryDescription)) &&
242 	        match_struct_string (one->manufacturerID,
243 	                             two->manufacturerID,
244 	                             sizeof (one->manufacturerID)) &&
245 	        match_struct_version (&one->libraryVersion,
246 	                              &two->libraryVersion));
247 }
248 
249 /**
250  * p11_kit_uri_match_module_info:
251  * @uri: the URI
252  * @info: the structure to match against the URI
253  *
254  * Match a <code>CK_INFO</code> structure against the library parts of this URI.
255  *
256  * Only the fields of the <code>CK_INFO</code> structure that are valid for use
257  * in a URI will be matched. A URI part that was not specified in the URI will
258  * match any value in the structure. If during the URI parsing any unrecognized
259  * parts were encountered then this match will fail.
260  *
261  * Returns: 1 if the URI matches, 0 if not.
262  */
263 int
p11_kit_uri_match_module_info(const P11KitUri * uri,const CK_INFO * info)264 p11_kit_uri_match_module_info (const P11KitUri *uri, const CK_INFO *info)
265 {
266 	return_val_if_fail (uri != NULL, 0);
267 	return_val_if_fail (info != NULL, 0);
268 
269 	if (uri->unrecognized)
270 		return 0;
271 
272 	return p11_match_uri_module_info (&uri->module, info);
273 }
274 
275 /**
276  * p11_kit_uri_get_slot_info:
277  * @uri: the URI
278  *
279  * Get the <code>CK_SLOT_INFO</code> structure associated with this URI.
280  *
281  * If this is a parsed URI, then the fields corresponding to slot parts of
282  * the URI will be filled in. Any slot URI parts that were missing will have
283  * their fields filled with zeros.
284  *
285  * If the caller wishes to setup information for building a URI, then relevant
286  * fields should be filled in. Fields that should not appear as parts in the
287  * resulting URI should be filled with zeros.
288  *
289  * Returns: A pointer to the <code>CK_INFO</code> structure.
290  */
291 CK_SLOT_INFO_PTR
p11_kit_uri_get_slot_info(P11KitUri * uri)292 p11_kit_uri_get_slot_info (P11KitUri *uri)
293 {
294 	return_val_if_fail (uri != NULL, NULL);
295 	return &uri->slot;
296 }
297 
298 int
p11_match_uri_slot_info(CK_SLOT_INFO const * one,CK_SLOT_INFO const * two)299 p11_match_uri_slot_info (CK_SLOT_INFO const *one,
300                          CK_SLOT_INFO const *two)
301 {
302 	return (match_struct_string (one->slotDescription,
303 				     two->slotDescription,
304 				     sizeof (one->slotDescription)) &&
305 		match_struct_string (one->manufacturerID,
306 				     two->manufacturerID,
307 				     sizeof (one->manufacturerID)));
308 }
309 
310 /**
311  * p11_kit_uri_match_slot_info:
312  * @uri: the URI
313  * @slot_info: the structure to match against the URI
314  *
315  * Match a <code>CK_SLOT_INFO</code> structure against the slot parts of this
316  * URI.
317  *
318  * Only the fields of the <code>CK_SLOT_INFO</code> structure that are valid
319  * for use in a URI will be matched. A URI part that was not specified in the
320  * URI will match any value in the structure. If during the URI parsing any
321  * unrecognized parts were encountered then this match will fail.
322  *
323  * Returns: 1 if the URI matches, 0 if not.
324  */
325 int
p11_kit_uri_match_slot_info(const P11KitUri * uri,const CK_SLOT_INFO * slot_info)326 p11_kit_uri_match_slot_info (const P11KitUri *uri, const CK_SLOT_INFO *slot_info)
327 {
328 	return_val_if_fail (uri != NULL, 0);
329 	return_val_if_fail (slot_info != NULL, 0);
330 
331 	if (uri->unrecognized)
332 		return 0;
333 
334 	return p11_match_uri_slot_info (&uri->slot, slot_info);
335 }
336 
337 /**
338  * p11_kit_uri_get_slot_id:
339  * @uri: The URI
340  *
341  * Get the 'slot-id' part of the URI.
342  *
343  * Returns: The slot-id or <code>(CK_SLOT_ID)-1</code> if not set.
344  */
345 CK_SLOT_ID
p11_kit_uri_get_slot_id(P11KitUri * uri)346 p11_kit_uri_get_slot_id (P11KitUri *uri)
347 {
348 	return_val_if_fail (uri != NULL, (CK_SLOT_ID)-1);
349 	return uri->slot_id;
350 }
351 
352 /**
353  * p11_kit_uri_set_slot_id:
354  * @uri: The URI
355  * @slot_id: The new slot-id
356  *
357  * Set the 'slot-id' part of the URI.
358  */
359 void
p11_kit_uri_set_slot_id(P11KitUri * uri,CK_SLOT_ID slot_id)360 p11_kit_uri_set_slot_id (P11KitUri  *uri,
361 			 CK_SLOT_ID  slot_id)
362 {
363 	return_if_fail (uri != NULL);
364 	uri->slot_id = slot_id;
365 }
366 
367 /**
368  * p11_kit_uri_get_token_info:
369  * @uri: the URI
370  *
371  * Get the <code>CK_TOKEN_INFO</code> structure associated with this URI.
372  *
373  * If this is a parsed URI, then the fields corresponding to token parts of
374  * the URI will be filled in. Any token URI parts that were missing will have
375  * their fields filled with zeros.
376  *
377  * If the caller wishes to setup information for building a URI, then relevant
378  * fields should be filled in. Fields that should not appear as parts in the
379  * resulting URI should be filled with zeros.
380  *
381  * Returns: A pointer to the <code>CK_INFO</code> structure.
382  */
383 CK_TOKEN_INFO_PTR
p11_kit_uri_get_token_info(P11KitUri * uri)384 p11_kit_uri_get_token_info (P11KitUri *uri)
385 {
386 	return_val_if_fail (uri != NULL, NULL);
387 	return &uri->token;
388 }
389 
390 int
p11_match_uri_token_info(CK_TOKEN_INFO const * one,CK_TOKEN_INFO const * two)391 p11_match_uri_token_info (CK_TOKEN_INFO const *one,
392                           CK_TOKEN_INFO const *two)
393 {
394 	return (match_struct_string (one->label,
395 	                             two->label,
396 	                             sizeof (one->label)) &&
397 	        match_struct_string (one->manufacturerID,
398 	                             two->manufacturerID,
399 	                             sizeof (one->manufacturerID)) &&
400 	        match_struct_string (one->model,
401 	                             two->model,
402 	                             sizeof (one->model)) &&
403 	        match_struct_string (one->serialNumber,
404 	                             two->serialNumber,
405 	                             sizeof (one->serialNumber)));
406 }
407 
408 /**
409  * p11_kit_uri_match_token_info:
410  * @uri: the URI
411  * @token_info: the structure to match against the URI
412  *
413  * Match a <code>CK_TOKEN_INFO</code> structure against the token parts of this
414  * URI.
415  *
416  * Only the fields of the <code>CK_TOKEN_INFO</code> structure that are valid
417  * for use in a URI will be matched. A URI part that was not specified in the
418  * URI will match any value in the structure. If during the URI parsing any
419  * unrecognized parts were encountered then this match will fail.
420  *
421  * Returns: 1 if the URI matches, 0 if not.
422  */
423 int
p11_kit_uri_match_token_info(const P11KitUri * uri,const CK_TOKEN_INFO * token_info)424 p11_kit_uri_match_token_info (const P11KitUri *uri, const CK_TOKEN_INFO *token_info)
425 {
426 	return_val_if_fail (uri != NULL, 0);
427 	return_val_if_fail (token_info != NULL, 0);
428 
429 	if (uri->unrecognized)
430 		return 0;
431 
432 	return p11_match_uri_token_info (&uri->token, token_info);
433 }
434 
435 /**
436  * p11_kit_uri_get_attribute:
437  * @uri: The URI
438  * @attr_type: The attribute type
439  *
440  * Get a pointer to an attribute present in this URI.
441  *
442  * Returns: A pointer to the attribute, or <code>NULL</code> if not present.
443  *     The attribute is owned by the URI and should not be freed.
444  */
445 CK_ATTRIBUTE_PTR
p11_kit_uri_get_attribute(P11KitUri * uri,CK_ATTRIBUTE_TYPE attr_type)446 p11_kit_uri_get_attribute (P11KitUri *uri, CK_ATTRIBUTE_TYPE attr_type)
447 {
448 	return_val_if_fail (uri != NULL, NULL);
449 
450 	if (uri->attrs == NULL)
451 		return NULL;
452 
453 	return p11_attrs_find (uri->attrs, attr_type);
454 }
455 
456 /**
457  * p11_kit_uri_set_attribute:
458  * @uri: The URI
459  * @attr: The attribute to set
460  *
461  * Set an attribute on the URI.
462  *
463  * Only attributes that map to parts in a PKCS\#11 URI will be accepted.
464  *
465  * Returns: %P11_KIT_URI_OK if the attribute was successfully set.
466  *     %P11_KIT_URI_NOT_FOUND if the attribute was not valid for a URI.
467  */
468 int
p11_kit_uri_set_attribute(P11KitUri * uri,CK_ATTRIBUTE_PTR attr)469 p11_kit_uri_set_attribute (P11KitUri *uri, CK_ATTRIBUTE_PTR attr)
470 {
471 	return_val_if_fail (uri != NULL, P11_KIT_URI_UNEXPECTED);
472 
473 	uri->attrs = p11_attrs_buildn (uri->attrs, attr, 1);
474 	return_val_if_fail (uri->attrs != NULL, P11_KIT_URI_UNEXPECTED);
475 
476 	return P11_KIT_URI_OK;
477 }
478 
479 /**
480  * p11_kit_uri_clear_attribute:
481  * @uri: The URI
482  * @attr_type: The type of the attribute to clear
483  *
484  * Clear an attribute on the URI.
485  *
486  * Only attributes that map to parts in a PKCS\#11 URI will be accepted.
487  *
488  * Returns: %P11_KIT_URI_OK if the attribute was successfully cleared.
489  *     %P11_KIT_URI_NOT_FOUND if the attribute was not valid for a URI.
490  */
491 int
p11_kit_uri_clear_attribute(P11KitUri * uri,CK_ATTRIBUTE_TYPE attr_type)492 p11_kit_uri_clear_attribute (P11KitUri *uri, CK_ATTRIBUTE_TYPE attr_type)
493 {
494 	return_val_if_fail (uri != NULL, P11_KIT_URI_UNEXPECTED);
495 
496 	if (attr_type != CKA_CLASS &&
497 	    attr_type != CKA_LABEL &&
498 	    attr_type != CKA_ID)
499 		return P11_KIT_URI_NOT_FOUND;
500 
501 	if (uri->attrs)
502 		p11_attrs_remove (uri->attrs, attr_type);
503 
504 	return P11_KIT_URI_OK;
505 }
506 
507 /**
508  * p11_kit_uri_get_attribute_types:
509  * @uri: The URI
510  * @n_attrs: A location to store the number of attributes returned.
511  *
512  * Get the attributes present in this URI. The attributes and values are
513  * owned by the URI. If the URI is modified, then the attributes that were
514  * returned from this function will not remain consistent.
515  *
516  * Returns: The attributes for this URI. These are owned by the URI.
517  */
518 CK_ATTRIBUTE_PTR
p11_kit_uri_get_attributes(P11KitUri * uri,CK_ULONG_PTR n_attrs)519 p11_kit_uri_get_attributes (P11KitUri *uri, CK_ULONG_PTR n_attrs)
520 {
521 	static const CK_ATTRIBUTE terminator = { CKA_INVALID, NULL, 0UL };
522 
523 	return_val_if_fail (uri != NULL, NULL);
524 
525 	if (!uri->attrs) {
526 		if (n_attrs)
527 			*n_attrs = 0;
528 		return (CK_ATTRIBUTE_PTR)&terminator;
529 	}
530 
531 	if (n_attrs)
532 		*n_attrs = p11_attrs_count (uri->attrs);
533 	return uri->attrs;
534 }
535 
536 int
p11_kit_uri_set_attributes(P11KitUri * uri,CK_ATTRIBUTE_PTR attrs,CK_ULONG n_attrs)537 p11_kit_uri_set_attributes (P11KitUri *uri, CK_ATTRIBUTE_PTR attrs,
538                             CK_ULONG n_attrs)
539 {
540 	CK_ULONG i;
541 	int ret;
542 
543 	return_val_if_fail (uri != NULL, P11_KIT_URI_UNEXPECTED);
544 
545 	p11_kit_uri_clear_attributes (uri);
546 
547 	for (i = 0; i < n_attrs; i++) {
548 		ret = p11_kit_uri_set_attribute (uri, &attrs[i]);
549 		if (ret != P11_KIT_URI_OK && ret != P11_KIT_URI_NOT_FOUND)
550 			return ret;
551 	}
552 
553 	return P11_KIT_URI_OK;
554 }
555 
556 void
p11_kit_uri_clear_attributes(P11KitUri * uri)557 p11_kit_uri_clear_attributes (P11KitUri *uri)
558 {
559 	return_if_fail (uri != NULL);
560 
561 	p11_attrs_free (uri->attrs);
562 	uri->attrs = NULL;
563 }
564 
565 /**
566  * p11_kit_uri_match_attributes:
567  * @uri: The URI
568  * @attrs: The attributes to match
569  * @n_attrs: The number of attributes
570  *
571  * Match a attributes against the object parts of this URI.
572  *
573  * Only the attributes that are valid for use in a URI will be matched. A URI
574  * part that was not specified in the URI will match any attribute value. If
575  * during the URI parsing any unrecognized parts were encountered then this
576  * match will fail.
577  *
578  * Returns: 1 if the URI matches, 0 if not.
579  */
580 int
p11_kit_uri_match_attributes(const P11KitUri * uri,const CK_ATTRIBUTE * attrs,CK_ULONG n_attrs)581 p11_kit_uri_match_attributes (const P11KitUri *uri, const CK_ATTRIBUTE *attrs,
582                               CK_ULONG n_attrs)
583 {
584 	CK_ATTRIBUTE *attr;
585 	CK_ULONG i;
586 
587 	return_val_if_fail (uri != NULL, 0);
588 	return_val_if_fail (attrs != NULL || n_attrs == 0, 0);
589 
590 	if (uri->unrecognized)
591 		return 0;
592 
593 	for (i = 0; i < n_attrs; i++) {
594 		if (attrs[i].type != CKA_CLASS &&
595 		    attrs[i].type != CKA_LABEL &&
596 		    attrs[i].type != CKA_ID)
597 			continue;
598 		attr = NULL;
599 		if (uri->attrs)
600 			attr = p11_attrs_find (uri->attrs, attrs[i].type);
601 		if (!attr)
602 			continue;
603 		if (!p11_attr_equal (attr, attrs + i))
604 			return 0;
605 	}
606 
607 	return 1;
608 }
609 
610 /**
611  * p11_kit_uri_set_unrecognized:
612  * @uri: The URI
613  * @unrecognized: The new unregognized flag value
614  *
615  * Set the unrecognized flag on this URI.
616  *
617  * The unrecognized flag is automatically set to 1 when during parsing any part
618  * of the URI is unrecognized. If the unrecognized flag is set to 1, then
619  * matching against this URI will always fail.
620  */
621 void
p11_kit_uri_set_unrecognized(P11KitUri * uri,int unrecognized)622 p11_kit_uri_set_unrecognized (P11KitUri *uri, int unrecognized)
623 {
624 	return_if_fail (uri != NULL);
625 	uri->unrecognized = unrecognized ? true : false;
626 }
627 
628 /**
629  * p11_kit_uri_any_unrecognized:
630  * @uri: The URI
631  *
632  * Get the unrecognized flag for this URI.
633  *
634  * The unrecognized flag is automatically set to 1 when during parsing any part
635  * of the URI is unrecognized. If the unrecognized flag is set to 1, then
636  * matching against this URI will always fail.
637  *
638  * Returns: 1 if unrecognized flag is set, 0 otherwise.
639  */
640 int
p11_kit_uri_any_unrecognized(P11KitUri * uri)641 p11_kit_uri_any_unrecognized (P11KitUri *uri)
642 {
643 	return_val_if_fail (uri != NULL, 1);
644 	return uri->unrecognized;
645 }
646 
647 /**
648  * p11_kit_uri_get_pin_value:
649  * @uri: The URI
650  *
651  * Get the 'pin-value' part of the URI. This is used by some applications to
652  * read the PIN for logging into a PKCS\#11 token.
653  *
654  * Returns: The pin-value or %NULL if not present.
655  */
656 const char*
p11_kit_uri_get_pin_value(const P11KitUri * uri)657 p11_kit_uri_get_pin_value (const P11KitUri *uri)
658 {
659 	return_val_if_fail (uri != NULL, NULL);
660 	return uri->pin_value;
661 }
662 
663 /**
664  * p11_kit_uri_set_pin_value:
665  * @uri: The URI
666  * @pin: The new pin-value
667  *
668  * Set the 'pin-value' part of the URI. This is used by some applications to
669  * specify the PIN for logging into a PKCS\#11 token.
670  */
671 void
p11_kit_uri_set_pin_value(P11KitUri * uri,const char * pin)672 p11_kit_uri_set_pin_value (P11KitUri *uri, const char *pin)
673 {
674 	return_if_fail (uri != NULL);
675 	free (uri->pin_value);
676 	uri->pin_value = pin ? strdup (pin) : NULL;
677 }
678 
679 
680 /**
681  * p11_kit_uri_get_pin_source:
682  * @uri: The URI
683  *
684  * Get the 'pin-source' part of the URI. This is used by some applications to
685  * lookup a PIN for logging into a PKCS\#11 token.
686  *
687  * Returns: The pin-source or %NULL if not present.
688  */
689 const char*
p11_kit_uri_get_pin_source(const P11KitUri * uri)690 p11_kit_uri_get_pin_source (const P11KitUri *uri)
691 {
692 	return_val_if_fail (uri != NULL, NULL);
693 	return uri->pin_source;
694 }
695 
696 /**
697  * p11_kit_uri_get_pinfile:
698  * @uri: The URI
699  *
700  * Deprecated: use p11_kit_uri_get_pin_source().
701  */
702 const char*
p11_kit_uri_get_pinfile(const P11KitUri * uri)703 p11_kit_uri_get_pinfile (const P11KitUri *uri)
704 {
705 	return_val_if_fail (uri != NULL, NULL);
706 	return p11_kit_uri_get_pin_source (uri);
707 }
708 
709 /**
710  * p11_kit_uri_set_pin_source:
711  * @uri: The URI
712  * @pin_source: The new pin-source
713  *
714  * Set the 'pin-source' part of the URI. This is used by some applications to
715  * lookup a PIN for logging into a PKCS\#11 token.
716  */
717 void
p11_kit_uri_set_pin_source(P11KitUri * uri,const char * pin_source)718 p11_kit_uri_set_pin_source (P11KitUri *uri, const char *pin_source)
719 {
720 	return_if_fail (uri != NULL);
721 	free (uri->pin_source);
722 	uri->pin_source = pin_source ? strdup (pin_source) : NULL;
723 }
724 
725 /**
726  * p11_kit_uri_set_pinfile:
727  * @uri: The URI
728  * @pinfile: The pinfile
729  *
730  * Deprecated: use p11_kit_uri_set_pin_source().
731  */
732 void
p11_kit_uri_set_pinfile(P11KitUri * uri,const char * pinfile)733 p11_kit_uri_set_pinfile (P11KitUri *uri, const char *pinfile)
734 {
735 	return_if_fail (uri != NULL);
736 	p11_kit_uri_set_pin_source (uri, pinfile);
737 }
738 
739 
740 /**
741  * p11_kit_uri_get_module_name:
742  * @uri: The URI
743  *
744  * Get the 'module-name' part of the URI. This is used by some
745  * applications to explicitly specify the name of a PKCS\#11 module.
746  *
747  * Returns: The module-name or %NULL if not present.
748  */
749 const char*
p11_kit_uri_get_module_name(const P11KitUri * uri)750 p11_kit_uri_get_module_name (const P11KitUri *uri)
751 {
752 	return_val_if_fail (uri != NULL, NULL);
753 	return uri->module_name;
754 }
755 
756 /**
757  * p11_kit_uri_set_module_name:
758  * @uri: The URI
759  * @name: The new module-name
760  *
761  * Set the 'module-name' part of the URI. This is used by some
762  * applications to explicitly specify the name of a PKCS\#11 module.
763  */
764 void
p11_kit_uri_set_module_name(P11KitUri * uri,const char * name)765 p11_kit_uri_set_module_name (P11KitUri *uri, const char *name)
766 {
767 	return_if_fail (uri != NULL);
768 	free (uri->module_name);
769 	uri->module_name = name ? strdup (name) : NULL;
770 }
771 
772 /**
773  * p11_kit_uri_get_module_path:
774  * @uri: The URI
775  *
776  * Get the 'module-path' part of the URI. This is used by some
777  * applications to explicitly specify the path of a PKCS\#11 module.
778  *
779  * Returns: The module-path or %NULL if not present.
780  */
781 const char*
p11_kit_uri_get_module_path(const P11KitUri * uri)782 p11_kit_uri_get_module_path (const P11KitUri *uri)
783 {
784 	return_val_if_fail (uri != NULL, NULL);
785 	return uri->module_path;
786 }
787 
788 /**
789  * p11_kit_uri_set_module_path:
790  * @uri: The URI
791  * @path: The new module-path
792  *
793  * Set the 'module-path' part of the URI. This is used by some
794  * applications to explicitly specify the path of a PKCS\#11 module.
795  */
796 void
p11_kit_uri_set_module_path(P11KitUri * uri,const char * path)797 p11_kit_uri_set_module_path (P11KitUri *uri, const char *path)
798 {
799 	return_if_fail (uri != NULL);
800 	free (uri->module_path);
801 	uri->module_path = path ? strdup (path) : NULL;
802 }
803 
804 /**
805  * p11_kit_uri_get_vendor_query:
806  * @uri: The URI
807  * @name: The name of vendor query
808  *
809  * Get the vendor query part of the URI, identified by @name. This is
810  * used by some applications to explicitly specify the path of a
811  * PKCS\#11 module.
812  *
813  * Returns: The value of vendor query or %NULL if not present.
814  */
815 const char*
p11_kit_uri_get_vendor_query(const P11KitUri * uri,const char * name)816 p11_kit_uri_get_vendor_query (const P11KitUri *uri, const char *name)
817 {
818 	size_t i;
819 
820 	return_val_if_fail (uri != NULL, NULL);
821 
822 	for (i = 0; i < uri->qattrs->num; i++) {
823 		Attribute *attr = uri->qattrs->elem[i];
824 		if (strcmp (attr->name, name) == 0)
825 			return attr->value;
826 	}
827 	return NULL;
828 }
829 
830 static void
free_attribute(Attribute * attr)831 free_attribute (Attribute *attr)
832 {
833 	free (attr->name);
834 	free (attr->value);
835 	free (attr);
836 }
837 
838 static bool
insert_attribute(p11_array * attrs,char * name,char * value)839 insert_attribute (p11_array *attrs, char *name, char *value)
840 {
841 	Attribute *attr;
842 	size_t i;
843 
844 	return_val_if_fail (attrs != NULL, false);
845 	return_val_if_fail (name != NULL, false);
846 	return_val_if_fail (value != NULL, false);
847 
848 	for (i = 0; i < attrs->num; i++) {
849 		attr = attrs->elem[i];
850 		if (strcmp (attr->name, (char *)name) > 0)
851 			break;
852 	}
853 
854 	attr = calloc (1, sizeof (Attribute));
855 	return_val_if_fail (attr, false);
856 
857 	attr->name = name;
858 	attr->value = value;
859 
860 	return p11_array_insert (attrs, i, attr);
861 }
862 
863 /**
864  * p11_kit_uri_set_vendor_query:
865  * @uri: The URI
866  * @name: The name of vendor query
867  * @value: (allow-none): The value of vendor query
868  *
869  * Set the vendor query part of the URI, identified by @name. This is
870  * used by some applications to explicitly specify the path of a
871  * PKCS\#11 module.
872  *
873  * Returns: 1 if the vendor query is set or removed, 0 if not.
874  */
875 int
p11_kit_uri_set_vendor_query(P11KitUri * uri,const char * name,const char * value)876 p11_kit_uri_set_vendor_query (P11KitUri *uri, const char *name,
877 			      const char *value)
878 {
879 	Attribute *attr;
880 	size_t i;
881 
882 	return_val_if_fail (uri != NULL, 0);
883 	return_val_if_fail (name != NULL, 0);
884 
885 	for (i = 0; i < uri->qattrs->num; i++) {
886 		attr = uri->qattrs->elem[i];
887 		if (strcmp (attr->name, name) == 0)
888 			break;
889 	}
890 	if (i == uri->qattrs->num) {
891 		if (value == NULL)
892 			return 0;
893 		return insert_attribute (uri->qattrs,
894 					 strdup (name), strdup (value));
895 	}
896 	if (value == NULL)
897 		p11_array_remove (uri->qattrs, i);
898 	else {
899 		free (attr->value);
900 		attr->value = strdup (value);
901 	}
902 
903 	return 1;
904 }
905 
906 /**
907  * p11_kit_uri_new:
908  *
909  * Create a new blank PKCS\#11 URI.
910  *
911  * The new URI is in the right state to parse a string into. All relevant fields
912  * are zeroed out. Formatting this URI will produce a valid but empty URI.
913  *
914  * Returns: A newly allocated URI. This should be freed with p11_kit_uri_free().
915  */
916 P11KitUri*
p11_kit_uri_new(void)917 p11_kit_uri_new (void)
918 {
919 	P11KitUri *uri;
920 
921 	uri = calloc (1, sizeof (P11KitUri));
922 	return_val_if_fail (uri != NULL, NULL);
923 
924 	/* So that it matches anything */
925 	uri->module.libraryVersion.major = (CK_BYTE)-1;
926 	uri->module.libraryVersion.minor = (CK_BYTE)-1;
927 	uri->slot_id = (CK_SLOT_ID)-1;
928 	uri->qattrs = p11_array_new ((p11_destroyer)free_attribute);
929 
930 	return uri;
931 }
932 
933 enum uri_sep {
934 	sep_path = '\0',
935 	sep_pattr = ';',
936 	sep_query = '?',
937 	sep_qattr = '&',
938 };
939 
940 static void
format_name_equals(p11_buffer * buffer,enum uri_sep * sep,const char * name)941 format_name_equals (p11_buffer *buffer,
942                     enum uri_sep *sep,
943                     const char *name)
944 {
945 	if (*sep) {
946 		char c = *sep;
947 		p11_buffer_add (buffer, &c, 1);
948 	}
949 	p11_buffer_add (buffer, name, -1);
950 	p11_buffer_add (buffer, "=", 1);
951 
952 	if (*sep == sep_path)
953 		*sep = sep_pattr;
954 	else if (*sep == sep_query)
955 		*sep = sep_qattr;
956 }
957 
958 static bool
format_raw_string(p11_buffer * buffer,enum uri_sep * sep,const char * name,const char * value)959 format_raw_string (p11_buffer *buffer,
960                    enum uri_sep *sep,
961                    const char *name,
962                    const char *value)
963 {
964 	/* Not set */
965 	if (!value)
966 		return true;
967 
968 	format_name_equals (buffer, sep, name);
969 	p11_buffer_add (buffer, value, -1);
970 
971 	return p11_buffer_ok (buffer);
972 }
973 
974 static bool
format_encode_string(p11_buffer * buffer,enum uri_sep * sep,const char * name,const unsigned char * value,size_t n_value,bool force)975 format_encode_string (p11_buffer *buffer,
976                       enum uri_sep *sep,
977                       const char *name,
978                       const unsigned char *value,
979                       size_t n_value,
980                       bool force)
981 {
982 	/* Not set */
983 	if (!value)
984 		return true;
985 
986 	format_name_equals (buffer, sep, name);
987 	p11_url_encode (value, value + n_value, force ? "" : P11_URL_VERBATIM, buffer);
988 
989 	return p11_buffer_ok (buffer);
990 }
991 
992 
993 static bool
format_struct_string(p11_buffer * buffer,enum uri_sep * sep,const char * name,const unsigned char * value,size_t value_max)994 format_struct_string (p11_buffer *buffer,
995                       enum uri_sep *sep,
996                       const char *name,
997                       const unsigned char *value,
998                       size_t value_max)
999 {
1000 	size_t len;
1001 
1002 	/* Not set */
1003 	if (!value[0])
1004 		return true;
1005 
1006 	len = p11_kit_space_strlen (value, value_max);
1007 	return format_encode_string (buffer, sep, name, value, len, false);
1008 }
1009 
1010 static bool
format_attribute_string(p11_buffer * buffer,enum uri_sep * sep,const char * name,CK_ATTRIBUTE_PTR attr,bool force)1011 format_attribute_string (p11_buffer *buffer,
1012                          enum uri_sep *sep,
1013                          const char *name,
1014                          CK_ATTRIBUTE_PTR attr,
1015                          bool force)
1016 {
1017 	/* Not set */;
1018 	if (attr == NULL)
1019 		return true;
1020 
1021 	return format_encode_string (buffer, sep, name,
1022 	                             attr->pValue, attr->ulValueLen,
1023 	                             force);
1024 }
1025 
1026 static bool
format_attribute_class(p11_buffer * buffer,enum uri_sep * sep,const char * name,CK_ATTRIBUTE_PTR attr)1027 format_attribute_class (p11_buffer *buffer,
1028                         enum uri_sep *sep,
1029                         const char *name,
1030                         CK_ATTRIBUTE_PTR attr)
1031 {
1032 	CK_OBJECT_CLASS klass;
1033 	const char *value;
1034 
1035 	/* Not set */;
1036 	if (attr == NULL)
1037 		return true;
1038 
1039 	klass = *((CK_OBJECT_CLASS*)attr->pValue);
1040 	switch (klass) {
1041 	case CKO_DATA:
1042 		value = "data";
1043 		break;
1044 	case CKO_SECRET_KEY:
1045 		value = "secret-key";
1046 		break;
1047 	case CKO_CERTIFICATE:
1048 		value = "cert";
1049 		break;
1050 	case CKO_PUBLIC_KEY:
1051 		value = "public";
1052 		break;
1053 	case CKO_PRIVATE_KEY:
1054 		value = "private";
1055 		break;
1056 	default:
1057 		return true;
1058 	}
1059 
1060 	return format_raw_string (buffer, sep, name, value);
1061 }
1062 
1063 static bool
format_struct_version(p11_buffer * buffer,enum uri_sep * sep,const char * name,CK_VERSION_PTR version)1064 format_struct_version (p11_buffer *buffer,
1065                        enum uri_sep *sep,
1066                        const char *name,
1067                        CK_VERSION_PTR version)
1068 {
1069 	char buf[64];
1070 
1071 	/* Not set */
1072 	if (version->major == (CK_BYTE)-1 && version->minor == (CK_BYTE)-1)
1073 		return true;
1074 
1075 	snprintf (buf, sizeof (buf), "%d.%d",
1076 	          (int)version->major, (int)version->minor);
1077 	return format_raw_string (buffer, sep, name, buf);
1078 }
1079 
1080 static bool
format_ulong(p11_buffer * buffer,enum uri_sep * sep,const char * name,CK_ULONG value)1081 format_ulong (p11_buffer *buffer,
1082 	      enum uri_sep *sep,
1083 	      const char *name,
1084 	      CK_ULONG value)
1085 {
1086 	char buf[64];
1087 
1088 	/* Not set */
1089 	if (value == (CK_ULONG)-1)
1090 		return true;
1091 
1092 	snprintf (buf, sizeof (buf), "%lu", value);
1093 	return format_raw_string (buffer, sep, name, buf);
1094 }
1095 
1096 /**
1097  * p11_kit_uri_format:
1098  * @uri: The URI.
1099  * @uri_type: The type of URI that should be produced.
1100  * @string: Location to store a newly allocated string.
1101  *
1102  * Format a PKCS\#11 URI into a string.
1103  *
1104  * Fields which are zeroed out will not be included in the resulting string.
1105  * Attributes which are not present will also not be included.
1106  *
1107  * The uri_type of URI specified limits the different parts of the resulting
1108  * URI. To format a URI containing all possible information use
1109  * %P11_KIT_URI_FOR_ANY
1110  *
1111  * It's up to the caller to guarantee that the attributes set in @uri are
1112  * those appropriate for inclusion in a URI, specifically:
1113  * <literal>CKA_ID</literal>, <literal>CKA_LABEL</literal>
1114  * and <literal>CKA_CLASS</literal>. The class must be one of
1115  * <literal>CKO_DATA</literal>, <literal>CKO_SECRET_KEY</literal>,
1116  * <literal>CKO_CERTIFICATE</literal>, <literal>CKO_PUBLIC_KEY</literal>,
1117  * <literal>CKO_PRIVATE_KEY</literal>.
1118  *
1119  * The resulting string should be freed with free().
1120  *
1121  * Returns: %P11_KIT_URI_OK if the URI was formatted successfully,
1122  *          %P11_KIT_URI_UNEXPECTED if the data in @uri is invalid for a URI.
1123  */
1124 int
p11_kit_uri_format(P11KitUri * uri,P11KitUriType uri_type,char ** string)1125 p11_kit_uri_format (P11KitUri *uri, P11KitUriType uri_type, char **string)
1126 {
1127 	p11_buffer buffer;
1128 	enum uri_sep sep = sep_path;
1129 	size_t i;
1130 
1131 	return_val_if_fail (uri != NULL, P11_KIT_URI_UNEXPECTED);
1132 	return_val_if_fail (string != NULL, P11_KIT_URI_UNEXPECTED);
1133 
1134 	if (!p11_buffer_init_null (&buffer, 64))
1135 		return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1136 
1137 	p11_buffer_add (&buffer, P11_KIT_URI_SCHEME, P11_KIT_URI_SCHEME_LEN);
1138 	p11_buffer_add (&buffer, ":", 1);
1139 
1140 	if ((uri_type & P11_KIT_URI_FOR_MODULE) == P11_KIT_URI_FOR_MODULE) {
1141 		if (!format_struct_string (&buffer, &sep, "library-description",
1142 		                           uri->module.libraryDescription,
1143 		                           sizeof (uri->module.libraryDescription)) ||
1144 		    !format_struct_string (&buffer, &sep, "library-manufacturer",
1145 		                           uri->module.manufacturerID,
1146 		                           sizeof (uri->module.manufacturerID))) {
1147 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1148 		}
1149 	}
1150 
1151 	if ((uri_type & P11_KIT_URI_FOR_MODULE_WITH_VERSION) == P11_KIT_URI_FOR_MODULE_WITH_VERSION) {
1152 		if (!format_struct_version (&buffer, &sep, "library-version",
1153 		                            &uri->module.libraryVersion)) {
1154 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1155 		}
1156 	}
1157 
1158 	if ((uri_type & P11_KIT_URI_FOR_SLOT) == P11_KIT_URI_FOR_SLOT) {
1159 		if (!format_struct_string (&buffer, &sep, "slot-description",
1160 		                           uri->slot.slotDescription,
1161 		                           sizeof (uri->slot.slotDescription)) ||
1162 		    !format_struct_string (&buffer, &sep, "slot-manufacturer",
1163 		                           uri->slot.manufacturerID,
1164 		                           sizeof (uri->slot.manufacturerID)) ||
1165 		    !format_ulong (&buffer, &sep, "slot-id",
1166 				   uri->slot_id)) {
1167 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1168 		}
1169 	}
1170 
1171 	if ((uri_type & P11_KIT_URI_FOR_TOKEN) == P11_KIT_URI_FOR_TOKEN) {
1172 		if (!format_struct_string (&buffer, &sep, "model",
1173 		                           uri->token.model,
1174 		                           sizeof (uri->token.model)) ||
1175 		    !format_struct_string (&buffer, &sep, "manufacturer",
1176 		                           uri->token.manufacturerID,
1177 		                           sizeof (uri->token.manufacturerID)) ||
1178 		    !format_struct_string (&buffer, &sep, "serial",
1179 		                           uri->token.serialNumber,
1180 		                           sizeof (uri->token.serialNumber)) ||
1181 		    !format_struct_string (&buffer, &sep, "token",
1182 		                           uri->token.label,
1183 		                           sizeof (uri->token.label))) {
1184 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1185 		}
1186 	}
1187 
1188 	if ((uri_type & P11_KIT_URI_FOR_OBJECT) == P11_KIT_URI_FOR_OBJECT) {
1189 		if (!format_attribute_string (&buffer, &sep, "id",
1190 		                              p11_kit_uri_get_attribute (uri, CKA_ID),
1191 		                              true) ||
1192 		    !format_attribute_string (&buffer, &sep, "object",
1193 		                              p11_kit_uri_get_attribute (uri, CKA_LABEL),
1194 		                              false)) {
1195 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1196 		}
1197 
1198 		if (!format_attribute_class (&buffer, &sep, "type",
1199 		                             p11_kit_uri_get_attribute (uri, CKA_CLASS))) {
1200 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1201 		}
1202 	}
1203 
1204 	sep = sep_query;
1205 
1206 	if (uri->pin_source) {
1207 		if (!format_encode_string (&buffer, &sep, "pin-source",
1208 		                           (const unsigned char*)uri->pin_source,
1209 		                           strlen (uri->pin_source), 0)) {
1210 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1211 		}
1212 	}
1213 
1214 	if (uri->pin_value) {
1215 		if (!format_encode_string (&buffer, &sep, "pin-value",
1216 		                           (const unsigned char*)uri->pin_value,
1217 		                           strlen (uri->pin_value), 0)) {
1218 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1219 		}
1220 	}
1221 
1222 	if (uri->module_name) {
1223 		if (!format_encode_string (&buffer, &sep, "module-name",
1224 		                           (const unsigned char*)uri->module_name,
1225 		                           strlen (uri->module_name), 0)) {
1226 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1227 		}
1228 	}
1229 
1230 	if (uri->module_path) {
1231 		if (!format_encode_string (&buffer, &sep, "module-path",
1232 		                           (const unsigned char*)uri->module_path,
1233 		                           strlen (uri->module_path), 0)) {
1234 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1235 		}
1236 	}
1237 
1238 	for (i = 0; i < uri->qattrs->num; i++) {
1239 		Attribute *attr = uri->qattrs->elem[i];
1240 		if (!format_encode_string (&buffer, &sep, attr->name,
1241 					   (const unsigned char *) attr->value,
1242 					   strlen (attr->value), 0)) {
1243 			return_val_if_reached (P11_KIT_URI_UNEXPECTED);
1244 		}
1245 	}
1246 
1247 	return_val_if_fail (p11_buffer_ok (&buffer), P11_KIT_URI_UNEXPECTED);
1248 	*string = p11_buffer_steal (&buffer, NULL);
1249 	return P11_KIT_URI_OK;
1250 }
1251 
1252 static bool
str_range_equal(const char * input,const char * start,const char * end)1253 str_range_equal (const char *input, const char *start, const char *end)
1254 {
1255 	return strlen (input) == end - start &&
1256 		memcmp (input, start, end - start) == 0;
1257 }
1258 
1259 static int
parse_string_attribute(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1260 parse_string_attribute (const char *name_start, const char *name_end,
1261 			const char *start, const char *end,
1262 			P11KitUri *uri)
1263 {
1264 	unsigned char *value;
1265 	CK_ATTRIBUTE_TYPE type;
1266 	size_t length;
1267 
1268 	assert (name_start <= name_end);
1269 	assert (start <= end);
1270 
1271 	if (str_range_equal ("id", name_start, name_end))
1272 		type = CKA_ID;
1273 	else if (str_range_equal ("object", name_start, name_end))
1274 		type = CKA_LABEL;
1275 	else
1276 		return 0;
1277 
1278 	value = p11_url_decode (start, end, P11_URL_WHITESPACE, &length);
1279 	if (value == NULL)
1280 		return P11_KIT_URI_BAD_ENCODING;
1281 
1282 	uri->attrs = p11_attrs_take (uri->attrs, type, value, length);
1283 	return 1;
1284 }
1285 
1286 static int
parse_class_attribute(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1287 parse_class_attribute (const char *name_start, const char *name_end,
1288 		       const char *start, const char *end,
1289 		       P11KitUri *uri)
1290 {
1291 	CK_OBJECT_CLASS klass = 0;
1292 	CK_ATTRIBUTE attr;
1293 
1294 	assert (name_start <= name_end);
1295 	assert (start <= end);
1296 
1297 	if (!str_range_equal ("objecttype", name_start, name_end) &&
1298 	    !str_range_equal ("object-type", name_start, name_end) &&
1299 	    !str_range_equal ("type", name_start, name_end))
1300 		return 0;
1301 
1302 	if (str_range_equal ("cert", start, end))
1303 		klass = CKO_CERTIFICATE;
1304 	else if (str_range_equal ("public", start, end))
1305 		klass = CKO_PUBLIC_KEY;
1306 	else if (str_range_equal ("private", start, end))
1307 		klass = CKO_PRIVATE_KEY;
1308 	else if (str_range_equal ("secretkey", start, end))
1309 		klass = CKO_SECRET_KEY;
1310 	else if (str_range_equal ("secret-key", start, end))
1311 		klass = CKO_SECRET_KEY;
1312 	else if (str_range_equal ("data", start, end))
1313 		klass = CKO_DATA;
1314 	else {
1315 		uri->unrecognized = true;
1316 		return 1;
1317 	}
1318 
1319 	attr.pValue = &klass;
1320 	attr.ulValueLen = sizeof (klass);
1321 	attr.type = CKA_CLASS;
1322 
1323 	uri->attrs = p11_attrs_build (uri->attrs, &attr, NULL);
1324 	return 1;
1325 }
1326 
1327 static int
parse_struct_info(unsigned char * where,size_t length,const char * start,const char * end,P11KitUri * uri)1328 parse_struct_info (unsigned char *where, size_t length, const char *start,
1329                    const char *end, P11KitUri *uri)
1330 {
1331 	unsigned char *value;
1332 	size_t value_length;
1333 
1334 	assert (start <= end);
1335 
1336 	value = p11_url_decode (start, end, P11_URL_WHITESPACE, &value_length);
1337 	if (value == NULL)
1338 		return P11_KIT_URI_BAD_ENCODING;
1339 
1340 	/* Too long, shouldn't match anything */
1341 	if (value_length > length) {
1342 		free (value);
1343 		uri->unrecognized = true;
1344 		return 1;
1345 	}
1346 
1347 	memset (where, ' ', length);
1348 	memcpy (where, value, value_length);
1349 
1350 	free (value);
1351 	return 1;
1352 }
1353 
1354 static int
parse_token_info(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1355 parse_token_info (const char *name_start, const char *name_end,
1356 		  const char *start, const char *end,
1357 		  P11KitUri *uri)
1358 {
1359 	unsigned char *where;
1360 	size_t length;
1361 
1362 	assert (name_start <= name_end);
1363 	assert (start <= end);
1364 
1365 	if (str_range_equal ("model", name_start, name_end)) {
1366 		where = uri->token.model;
1367 		length = sizeof (uri->token.model);
1368 	} else if (str_range_equal ("manufacturer", name_start, name_end)) {
1369 		where = uri->token.manufacturerID;
1370 		length = sizeof (uri->token.manufacturerID);
1371 	} else if (str_range_equal ("serial", name_start, name_end)) {
1372 		where = uri->token.serialNumber;
1373 		length = sizeof (uri->token.serialNumber);
1374 	} else if (str_range_equal ("token", name_start, name_end)) {
1375 		where = uri->token.label;
1376 		length = sizeof (uri->token.label);
1377 	} else {
1378 		return 0;
1379 	}
1380 
1381 	return parse_struct_info (where, length, start, end, uri);
1382 }
1383 
1384 static long
atoin(const char * start,const char * end)1385 atoin (const char *start, const char *end)
1386 {
1387 	long ret = 0;
1388 	while (start != end) {
1389 		if (*start < '0' || *start > '9')
1390 			return -1;
1391 		ret *= 10;
1392 		ret += (*start - '0');
1393 		++start;
1394 	}
1395 	return ret;
1396 }
1397 
1398 static int
parse_struct_version(const char * start,const char * end,CK_VERSION_PTR version)1399 parse_struct_version (const char *start, const char *end, CK_VERSION_PTR version)
1400 {
1401 	const char *dot;
1402 	int val;
1403 
1404 	assert (start <= end);
1405 
1406 	dot = memchr (start, '.', end - start);
1407 	if (!dot)
1408 		dot = end;
1409 
1410 	if (dot == start)
1411 		return P11_KIT_URI_BAD_VERSION;
1412 	val = atoin (start, dot);
1413 	if (val < 0 || val >= 255)
1414 		return P11_KIT_URI_BAD_VERSION;
1415 	version->major = (CK_BYTE)val;
1416 	version->minor = 0;
1417 
1418 	if (dot != end) {
1419 		if (dot + 1 == end)
1420 			return P11_KIT_URI_BAD_VERSION;
1421 		val = atoin (dot + 1, end);
1422 		if (val < 0 || val >= 255)
1423 			return P11_KIT_URI_BAD_VERSION;
1424 		version->minor = (CK_BYTE)val;
1425 	}
1426 
1427 	return 1;
1428 }
1429 
1430 static int
parse_slot_info(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1431 parse_slot_info (const char *name_start, const char *name_end,
1432                  const char *start, const char *end,
1433                  P11KitUri *uri)
1434 {
1435 	unsigned char *where;
1436 	size_t length;
1437 
1438 	assert (name_start <= name_end);
1439 	assert (start <= end);
1440 
1441 	if (str_range_equal ("slot-description", name_start, name_end)) {
1442 		where = uri->slot.slotDescription;
1443 		length = sizeof (uri->slot.slotDescription);
1444 	} else if (str_range_equal ("slot-manufacturer", name_start, name_end)) {
1445 		where = uri->slot.manufacturerID;
1446 		length = sizeof (uri->slot.manufacturerID);
1447 	} else {
1448 		return 0;
1449 	}
1450 
1451 	return parse_struct_info (where, length, start, end, uri);
1452 }
1453 
1454 static int
parse_slot_id(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1455 parse_slot_id (const char *name_start, const char *name_end,
1456 	       const char *start, const char *end,
1457 	       P11KitUri *uri)
1458 {
1459 	assert (name_start <= name_end);
1460 	assert (start <= end);
1461 
1462 	if (str_range_equal ("slot-id", name_start, name_end)) {
1463 		long val;
1464 		val = atoin (start, end);
1465 		if (val < 0)
1466 			return P11_KIT_URI_BAD_SYNTAX;
1467 		uri->slot_id = (CK_SLOT_ID)val;
1468 		return 1;
1469 	}
1470 	return 0;
1471 }
1472 
1473 static int
parse_module_version_info(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1474 parse_module_version_info (const char *name_start, const char *name_end,
1475 			   const char *start, const char *end,
1476 			   P11KitUri *uri)
1477 {
1478 	assert (name_start <= name_end);
1479 	assert (start <= end);
1480 
1481 	if (str_range_equal ("library-version", name_start, name_end))
1482 		return parse_struct_version (start, end,
1483 		                             &uri->module.libraryVersion);
1484 
1485 	return 0;
1486 }
1487 
1488 static int
parse_module_info(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1489 parse_module_info (const char *name_start, const char *name_end,
1490 		   const char *start, const char *end,
1491 		   P11KitUri *uri)
1492 {
1493 	unsigned char *where;
1494 	size_t length;
1495 
1496 	assert (name_start <= name_end);
1497 	assert (start <= end);
1498 
1499 	if (str_range_equal ("library-description", name_start, name_end)) {
1500 		where = uri->module.libraryDescription;
1501 		length = sizeof (uri->module.libraryDescription);
1502 	} else if (str_range_equal ("library-manufacturer", name_start, name_end)) {
1503 		where = uri->module.manufacturerID;
1504 		length = sizeof (uri->module.manufacturerID);
1505 	} else {
1506 		return 0;
1507 	}
1508 
1509 	return parse_struct_info (where, length, start, end, uri);
1510 }
1511 
1512 static int
parse_pin_query(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1513 parse_pin_query (const char *name_start, const char *name_end,
1514 		 const char *start, const char *end,
1515 		 P11KitUri *uri)
1516 {
1517 	unsigned char *value;
1518 
1519 	assert (name_start <= name_end);
1520 	assert (start <= end);
1521 
1522 	if (str_range_equal ("pinfile", name_start, name_end) ||
1523 	    str_range_equal ("pin-source", name_start, name_end)) {
1524 		value = p11_url_decode (start, end, P11_URL_WHITESPACE, NULL);
1525 		if (value == NULL)
1526 			return P11_KIT_URI_BAD_ENCODING;
1527 		free (uri->pin_source);
1528 		uri->pin_source = (char*)value;
1529 		return 1;
1530 	} else if (str_range_equal ("pin-value", name_start, name_end)) {
1531 		value = p11_url_decode (start, end, P11_URL_WHITESPACE, NULL);
1532 		if (value == NULL)
1533 			return P11_KIT_URI_BAD_ENCODING;
1534 		free (uri->pin_value);
1535 		uri->pin_value = (char*)value;
1536 		return 1;
1537 	}
1538 
1539 	return 0;
1540 }
1541 
1542 static int
parse_module_query(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1543 parse_module_query (const char *name_start, const char *name_end,
1544 		    const char *start, const char *end,
1545 		    P11KitUri *uri)
1546 {
1547 	unsigned char *value;
1548 
1549 	assert (name_start <= name_end);
1550 	assert (start <= end);
1551 
1552 	if (str_range_equal ("module-name", name_start, name_end)) {
1553 		value = p11_url_decode (start, end, P11_URL_WHITESPACE, NULL);
1554 		if (value == NULL)
1555 			return P11_KIT_URI_BAD_ENCODING;
1556 		free (uri->module_name);
1557 		uri->module_name = (char*)value;
1558 		return 1;
1559 	} else if (str_range_equal ("module-path", name_start, name_end)) {
1560 		value = p11_url_decode (start, end, P11_URL_WHITESPACE, NULL);
1561 		if (value == NULL)
1562 			return P11_KIT_URI_BAD_ENCODING;
1563 		free (uri->module_path);
1564 		uri->module_path = (char*)value;
1565 		return 1;
1566 	}
1567 
1568 	return 0;
1569 }
1570 
1571 static int
parse_vendor_query(const char * name_start,const char * name_end,const char * start,const char * end,P11KitUri * uri)1572 parse_vendor_query (const char *name_start, const char *name_end,
1573 		    const char *start, const char *end,
1574 		    P11KitUri *uri)
1575 {
1576 	char *name;
1577 	unsigned char *value;
1578 
1579 	assert (name_start <= name_end);
1580 	assert (start <= end);
1581 
1582 	name = malloc (name_end - name_start + 1);
1583 	if (name == NULL)
1584 		return P11_KIT_URI_BAD_ENCODING;
1585 	memcpy (name, name_start, name_end - name_start);
1586 	name[name_end - name_start] = '\0';
1587 
1588 	/* Limit the characters in NAME, according to the specification.  */
1589 	if (strspn (name, "abcdefghijklmnopqrstuvwxyz0123456789-_") !=
1590 	    name_end - name_start) {
1591 		free (name);
1592 		return P11_KIT_URI_UNEXPECTED;
1593 	}
1594 
1595 	value = p11_url_decode (start, end, P11_URL_WHITESPACE, NULL);
1596 	if (value == NULL) {
1597 		free (name);
1598 		return P11_KIT_URI_BAD_ENCODING;
1599 	}
1600 
1601 	if (!insert_attribute (uri->qattrs, name, (char *)value)) {
1602 		free (name);
1603 		free (value);
1604 		return P11_KIT_URI_UNEXPECTED;
1605 	}
1606 
1607 	return 0;
1608 }
1609 
1610 /**
1611  * p11_kit_uri_parse:
1612  * @string: The string to parse
1613  * @uri_type: The type of URI that is expected
1614  * @uri: The blank URI to parse the values into
1615  *
1616  * Parse a PKCS\#11 URI string.
1617  *
1618  * PKCS\#11 URIs can represent tokens, objects or modules. The uri_type argument
1619  * allows the caller to specify what type of URI is expected and the sorts of
1620  * things the URI should match. %P11_KIT_URI_FOR_ANY can be used to parse a URI
1621  * for any context. It's then up to the caller to make sense of the way that
1622  * it is used.
1623  *
1624  * If the PKCS\#11 URI contains unrecognized URI parts or parts not applicable
1625  * to the specified context, then the unrecognized flag will be set. This will
1626  * prevent the URI from matching using the various match functions.
1627  *
1628  * Returns: %P11_KIT_URI_OK if the URI was parsed successfully.
1629  *     %P11_KIT_URI_BAD_SCHEME if this was not a PKCS\#11 URI.
1630  *     %P11_KIT_URI_BAD_SYNTAX if the URI syntax was bad.
1631  *     %P11_KIT_URI_BAD_VERSION if a version number was bad.
1632  *     %P11_KIT_URI_BAD_ENCODING if the URI encoding was invalid.
1633  */
1634 int
p11_kit_uri_parse(const char * string,P11KitUriType uri_type,P11KitUri * uri)1635 p11_kit_uri_parse (const char *string, P11KitUriType uri_type,
1636                    P11KitUri *uri)
1637 {
1638 	const char *spos, *epos;
1639 	int ret;
1640 	size_t length, i;
1641 	char *allocated = NULL;
1642 
1643 	assert (string);
1644 	assert (uri);
1645 
1646 	/* If STRING contains any whitespace, create a copy of the
1647 	 * string and strip it out */
1648 	length = strcspn (string, P11_URL_WHITESPACE);
1649 	if (strspn (string + length, P11_URL_WHITESPACE) > 0) {
1650 		allocated = strip_whitespace (string);
1651 		return_val_if_fail (allocated != NULL, P11_KIT_URI_UNEXPECTED);
1652 		string = allocated;
1653 	}
1654 
1655 	epos = strchr (string, ':');
1656 	if (epos == NULL) {
1657 		free (allocated);
1658 		return P11_KIT_URI_BAD_SCHEME;
1659 	}
1660 	if (epos - string != P11_KIT_URI_SCHEME_LEN) {
1661 		free (allocated);
1662 		return P11_KIT_URI_BAD_SCHEME;
1663 	}
1664 	for (i = 0; i < P11_KIT_URI_SCHEME_LEN; i++)
1665 		if (p11_ascii_tolower (string[i]) != P11_KIT_URI_SCHEME[i])
1666 			break;
1667 	if (i != P11_KIT_URI_SCHEME_LEN) {
1668 		free (allocated);
1669 		return P11_KIT_URI_BAD_SCHEME;
1670 	}
1671 
1672 	string = epos + 1;
1673 
1674 	/* Clear everything out */
1675 	memset (&uri->module, 0, sizeof (uri->module));
1676 	memset (&uri->token, 0, sizeof (uri->token));
1677 	p11_attrs_free (uri->attrs);
1678 	uri->attrs = NULL;
1679 	uri->module.libraryVersion.major = (CK_BYTE)-1;
1680 	uri->module.libraryVersion.minor = (CK_BYTE)-1;
1681 	uri->unrecognized = 0;
1682 	uri->slot_id = (CK_SLOT_ID)-1;
1683 	free (uri->pin_source);
1684 	uri->pin_source = NULL;
1685 	free (uri->pin_value);
1686 	uri->pin_value = NULL;
1687 	free (uri->module_name);
1688 	uri->module_name = NULL;
1689 	free (uri->module_path);
1690 	uri->module_path = NULL;
1691 	p11_array_clear (uri->qattrs);
1692 
1693 	/* Parse the path. */
1694 	for (;;) {
1695 		spos = string + strcspn (string, ";?");
1696 		if (spos == string)
1697 			break;
1698 
1699 		epos = strchr (string, '=');
1700 		if (epos == NULL || epos == string || epos >= spos) {
1701 			free (allocated);
1702 			return P11_KIT_URI_BAD_SYNTAX;
1703 		}
1704 
1705 		ret = 0;
1706 		if ((uri_type & P11_KIT_URI_FOR_OBJECT) == P11_KIT_URI_FOR_OBJECT)
1707 			ret = parse_string_attribute (string, epos, epos + 1, spos, uri);
1708 		if (ret == 0 && (uri_type & P11_KIT_URI_FOR_OBJECT) == P11_KIT_URI_FOR_OBJECT)
1709 			ret = parse_class_attribute (string, epos, epos + 1, spos, uri);
1710 		if (ret == 0 && (uri_type & P11_KIT_URI_FOR_TOKEN) == P11_KIT_URI_FOR_TOKEN)
1711 			ret = parse_token_info (string, epos, epos + 1, spos, uri);
1712 		if (ret == 0 && (uri_type & P11_KIT_URI_FOR_SLOT) == P11_KIT_URI_FOR_SLOT)
1713 			ret = parse_slot_info (string, epos, epos + 1, spos, uri);
1714 		if (ret == 0 && (uri_type & P11_KIT_URI_FOR_SLOT) == P11_KIT_URI_FOR_SLOT)
1715 			ret = parse_slot_id (string, epos, epos + 1, spos, uri);
1716 		if (ret == 0 && (uri_type & P11_KIT_URI_FOR_MODULE) == P11_KIT_URI_FOR_MODULE)
1717 			ret = parse_module_info (string, epos, epos + 1, spos, uri);
1718 		if (ret == 0 && (uri_type & P11_KIT_URI_FOR_MODULE_WITH_VERSION) == P11_KIT_URI_FOR_MODULE_WITH_VERSION)
1719 			ret = parse_module_version_info (string, epos, epos + 1, spos, uri);
1720 		/* Accept 'pin-source' and 'pin-value' in path
1721 		 * attributes for backward compatibility.  */
1722 		if (ret == 0)
1723 			ret = parse_pin_query (string, epos, epos + 1, spos, uri);
1724 
1725 		if (ret < 0) {
1726 			free (allocated);
1727 			return ret;
1728 		}
1729 		if (ret == 0)
1730 			uri->unrecognized = true;
1731 
1732 		string = spos;
1733 		if (*spos == '\0')
1734 			break;
1735 		if (*spos == '?')
1736 			break;
1737 		string++;
1738 	}
1739 
1740 	/* Parse the query. */
1741 	for (;;) {
1742 		if (*string == '\0')
1743 			break;
1744 		string++;
1745 		spos = strchr (string, '&');
1746 		if (spos == NULL) {
1747 			spos = string + strlen (string);
1748 			assert (*spos == '\0');
1749 			if (spos == string)
1750 				break;
1751 		}
1752 
1753 		epos = strchr (string, '=');
1754 		if (epos == NULL || spos == string || epos == string || epos >= spos) {
1755 			free (allocated);
1756 			return P11_KIT_URI_BAD_SYNTAX;
1757 		}
1758 
1759 		ret = parse_pin_query (string, epos, epos + 1, spos, uri);
1760 		if (ret == 0)
1761 			ret = parse_module_query (string, epos, epos + 1, spos, uri);
1762 		if (ret == 0)
1763 			ret = parse_vendor_query (string, epos, epos + 1, spos, uri);
1764 		if (ret < 0) {
1765 			free (allocated);
1766 			return ret;
1767 		}
1768 
1769 		string = spos;
1770 	}
1771 
1772 	free (allocated);
1773 	return P11_KIT_URI_OK;
1774 }
1775 
1776 /**
1777  * p11_kit_uri_free:
1778  * @uri: The URI
1779  *
1780  * Free a PKCS\#11 URI.
1781  */
1782 void
p11_kit_uri_free(P11KitUri * uri)1783 p11_kit_uri_free (P11KitUri *uri)
1784 {
1785 	if (!uri)
1786 		return;
1787 
1788 	p11_attrs_free (uri->attrs);
1789 	free (uri->pin_source);
1790 	free (uri->pin_value);
1791 	free (uri->module_name);
1792 	free (uri->module_path);
1793 	p11_array_free (uri->qattrs);
1794 	free (uri);
1795 }
1796 
1797 /**
1798  * p11_kit_uri_message:
1799  * @code: The error code
1800  *
1801  * Lookup a message for the uri error code. These codes are the P11_KIT_URI_XXX
1802  * error codes that can be returned from p11_kit_uri_parse() or
1803  * p11_kit_uri_format(). As a special case %NULL, will be returned for
1804  * %P11_KIT_URI_OK.
1805  *
1806  * Returns: The message for the error code. This string is owned by the p11-kit
1807  *      library.
1808  */
1809 const char*
p11_kit_uri_message(int code)1810 p11_kit_uri_message (int code)
1811 {
1812 	switch (code) {
1813 	case P11_KIT_URI_OK:
1814 		return NULL;
1815 	case P11_KIT_URI_UNEXPECTED:
1816 		return "Unexpected or internal system error";
1817 	case P11_KIT_URI_BAD_SCHEME:
1818 		return "URI scheme must be 'pkcs11:'";
1819 	case P11_KIT_URI_BAD_ENCODING:
1820 		return "URI encoding invalid or corrupted";
1821 	case P11_KIT_URI_BAD_SYNTAX:
1822 		return "URI syntax is invalid";
1823 	case P11_KIT_URI_BAD_VERSION:
1824 		return "URI version component is invalid";
1825 	case P11_KIT_URI_NOT_FOUND:
1826 		return "The URI component was not found";
1827 	default:
1828 		p11_debug ("unknown error code: %d", code);
1829 		return "Unknown error";
1830 	}
1831 }
1832