1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "pkcs11.h"
6 #include "pkcs11uri.h"
7 #include "plarena.h"
8 #include "prprf.h"
9 #include "secport.h"
10
11 /* Character sets used in the ABNF rules in RFC7512. */
12 #define PK11URI_DIGIT "0123456789"
13 #define PK11URI_ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
14 #define PK11URI_HEXDIG PK11URI_DIGIT "abcdefABCDEF"
15 #define PK11URI_UNRESERVED PK11URI_ALPHA PK11URI_DIGIT "-._~"
16 #define PK11URI_RES_AVAIL ":[]@!$'()*+,="
17 #define PK11URI_PATH_RES_AVAIL PK11URI_RES_AVAIL "&"
18 #define PK11URI_QUERY_RES_AVAIL PK11URI_RES_AVAIL "/?|"
19 #define PK11URI_ATTR_NM_CHAR PK11URI_ALPHA PK11URI_DIGIT "-_"
20 #define PK11URI_PCHAR PK11URI_UNRESERVED PK11URI_PATH_RES_AVAIL
21 #define PK11URI_QCHAR PK11URI_UNRESERVED PK11URI_QUERY_RES_AVAIL
22
23 /* Path attributes defined in RFC7512. */
24 static const char *pattr_names[] = {
25 PK11URI_PATTR_TOKEN,
26 PK11URI_PATTR_MANUFACTURER,
27 PK11URI_PATTR_SERIAL,
28 PK11URI_PATTR_MODEL,
29 PK11URI_PATTR_LIBRARY_MANUFACTURER,
30 PK11URI_PATTR_LIBRARY_DESCRIPTION,
31 PK11URI_PATTR_LIBRARY_VERSION,
32 PK11URI_PATTR_OBJECT,
33 PK11URI_PATTR_TYPE,
34 PK11URI_PATTR_ID,
35 PK11URI_PATTR_SLOT_MANUFACTURER,
36 PK11URI_PATTR_SLOT_DESCRIPTION,
37 PK11URI_PATTR_SLOT_ID
38 };
39
40 /* Query attributes defined in RFC7512. */
41 static const char *qattr_names[] = {
42 PK11URI_QATTR_PIN_SOURCE,
43 PK11URI_QATTR_PIN_VALUE,
44 PK11URI_QATTR_MODULE_NAME,
45 PK11URI_QATTR_MODULE_PATH
46 };
47
48 struct PK11URIBufferStr {
49 PLArenaPool *arena;
50 char *data;
51 size_t size;
52 size_t allocated;
53 };
54 typedef struct PK11URIBufferStr PK11URIBuffer;
55
56 struct PK11URIAttributeListEntryStr {
57 char *name;
58 char *value;
59 };
60 typedef struct PK11URIAttributeListEntryStr PK11URIAttributeListEntry;
61
62 struct PK11URIAttributeListStr {
63 PLArenaPool *arena;
64 PK11URIAttributeListEntry *attrs;
65 size_t num_attrs;
66 };
67 typedef struct PK11URIAttributeListStr PK11URIAttributeList;
68
69 struct PK11URIStr {
70 PLArenaPool *arena;
71
72 PK11URIAttributeList pattrs;
73 PK11URIAttributeList vpattrs;
74
75 PK11URIAttributeList qattrs;
76 PK11URIAttributeList vqattrs;
77 };
78
79 #define PK11URI_ARENA_SIZE 1024
80
81 typedef int (*PK11URIAttributeCompareNameFunc)(const char *a, const char *b);
82
83 /* This belongs in secport.h */
84 #define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \
85 (type *)PORT_ArenaGrow((poolp), (oldptr), \
86 (oldnum) * sizeof(type), (newnum) * sizeof(type))
87 #define PORT_ReallocArray(oldptr, type, newnum) \
88 (type *)PORT_Realloc((oldptr), (newnum) * sizeof(type))
89
90 /* Functions for resizable buffer. */
91 static SECStatus
pk11uri_AppendBuffer(PK11URIBuffer * buffer,const unsigned char * data,size_t size)92 pk11uri_AppendBuffer(PK11URIBuffer *buffer, const unsigned char *data,
93 size_t size)
94 {
95 /* Check overflow. */
96 if (buffer->size + size < buffer->size)
97 return SECFailure;
98
99 if (buffer->size + size > buffer->allocated) {
100 size_t allocated = buffer->allocated * 2 + size;
101 if (allocated < buffer->allocated)
102 return SECFailure;
103 if (buffer->arena)
104 buffer->data = PORT_ArenaGrow(buffer->arena, buffer->data,
105 buffer->allocated, allocated);
106 else
107 buffer->data = PORT_Realloc(buffer->data, allocated);
108 if (buffer->data == NULL)
109 return SECFailure;
110 buffer->allocated = allocated;
111 }
112
113 memcpy(&buffer->data[buffer->size], data, size);
114 buffer->size += size;
115
116 return SECSuccess;
117 }
118
119 static void
pk11uri_InitBuffer(PK11URIBuffer * buffer,PLArenaPool * arena)120 pk11uri_InitBuffer(PK11URIBuffer *buffer, PLArenaPool *arena)
121 {
122 memset(buffer, 0, sizeof(PK11URIBuffer));
123 buffer->arena = arena;
124 }
125
126 static void
pk11uri_DestroyBuffer(PK11URIBuffer * buffer)127 pk11uri_DestroyBuffer(PK11URIBuffer *buffer)
128 {
129 if (buffer->arena == NULL) {
130 PORT_Free(buffer->data);
131 }
132 }
133
134 /* URI encoding functions. */
135 static char *
pk11uri_Escape(PLArenaPool * arena,const char * value,size_t length,const char * available)136 pk11uri_Escape(PLArenaPool *arena, const char *value, size_t length,
137 const char *available)
138 {
139 PK11URIBuffer buffer;
140 const char *p;
141 unsigned char buf[4];
142 char *result = NULL;
143 SECStatus ret;
144
145 pk11uri_InitBuffer(&buffer, arena);
146
147 for (p = value; p < value + length; p++) {
148 if (strchr(available, *p) == NULL) {
149 if (PR_snprintf((char *)buf, sizeof(buf), "%%%02X", *p) == (PRUint32)-1) {
150 goto fail;
151 }
152 ret = pk11uri_AppendBuffer(&buffer, buf, 3);
153 if (ret != SECSuccess) {
154 goto fail;
155 }
156 } else {
157 ret = pk11uri_AppendBuffer(&buffer, (const unsigned char *)p, 1);
158 if (ret != SECSuccess) {
159 goto fail;
160 }
161 }
162 }
163 buf[0] = '\0';
164 ret = pk11uri_AppendBuffer(&buffer, buf, 1);
165 if (ret != SECSuccess) {
166 goto fail;
167 }
168
169 /* Steal the memory allocated in buffer. */
170 result = buffer.data;
171 buffer.data = NULL;
172
173 fail:
174 pk11uri_DestroyBuffer(&buffer);
175
176 return result;
177 }
178
179 static char *
pk11uri_Unescape(PLArenaPool * arena,const char * value,size_t length)180 pk11uri_Unescape(PLArenaPool *arena, const char *value, size_t length)
181 {
182 PK11URIBuffer buffer;
183 const char *p;
184 unsigned char buf[1];
185 char *result = NULL;
186 SECStatus ret;
187
188 pk11uri_InitBuffer(&buffer, arena);
189
190 for (p = value; p < value + length; p++) {
191 if (*p == '%') {
192 int c;
193 size_t i;
194
195 p++;
196 for (c = 0, i = 0; i < 2; i++) {
197 int h = *(p + i);
198 if ('0' <= h && h <= '9') {
199 c = (c << 4) | (h - '0');
200 } else if ('a' <= h && h <= 'f') {
201 c = (c << 4) | (h - 'a' + 10);
202 } else if ('A' <= h && h <= 'F') {
203 c = (c << 4) | (h - 'A' + 10);
204 } else {
205 break;
206 }
207 }
208 if (i != 2) {
209 goto fail;
210 }
211 p++;
212 buf[0] = c;
213 } else {
214 buf[0] = *p;
215 }
216 ret = pk11uri_AppendBuffer(&buffer, buf, 1);
217 if (ret != SECSuccess) {
218 goto fail;
219 }
220 }
221 buf[0] = '\0';
222 ret = pk11uri_AppendBuffer(&buffer, buf, 1);
223 if (ret != SECSuccess) {
224 goto fail;
225 }
226
227 result = buffer.data;
228 buffer.data = NULL;
229
230 fail:
231 pk11uri_DestroyBuffer(&buffer);
232
233 return result;
234 }
235
236 /* Functions for manipulating attributes array. */
237
238 /* Compare two attribute names by the array index in attr_names. Both
239 * attribute names must be present in attr_names, otherwise it is a
240 * programming error. */
241 static int
pk11uri_CompareByPosition(const char * a,const char * b,const char ** attr_names,size_t num_attr_names)242 pk11uri_CompareByPosition(const char *a, const char *b,
243 const char **attr_names, size_t num_attr_names)
244 {
245 size_t i, j;
246
247 for (i = 0; i < num_attr_names; i++) {
248 if (strcmp(a, attr_names[i]) == 0) {
249 break;
250 }
251 }
252 PR_ASSERT(i < num_attr_names);
253
254 for (j = 0; j < num_attr_names; j++) {
255 if (strcmp(b, attr_names[j]) == 0) {
256 break;
257 }
258 }
259 PR_ASSERT(j < num_attr_names);
260
261 return i - j;
262 }
263
264 /* Those pk11uri_Compare{Path,Query}AttributeName functions are used
265 * to reorder attributes when inserting. */
266 static int
pk11uri_ComparePathAttributeName(const char * a,const char * b)267 pk11uri_ComparePathAttributeName(const char *a, const char *b)
268 {
269 return pk11uri_CompareByPosition(a, b, pattr_names, PR_ARRAY_SIZE(pattr_names));
270 }
271
272 static int
pk11uri_CompareQueryAttributeName(const char * a,const char * b)273 pk11uri_CompareQueryAttributeName(const char *a, const char *b)
274 {
275 return pk11uri_CompareByPosition(a, b, qattr_names, PR_ARRAY_SIZE(qattr_names));
276 }
277
278 static SECStatus
pk11uri_InsertToAttributeList(PK11URIAttributeList * attrs,char * name,char * value,PK11URIAttributeCompareNameFunc compare_name,PRBool allow_duplicate)279 pk11uri_InsertToAttributeList(PK11URIAttributeList *attrs,
280 char *name, char *value,
281 PK11URIAttributeCompareNameFunc compare_name,
282 PRBool allow_duplicate)
283 {
284 size_t i;
285
286 if (attrs->arena) {
287 attrs->attrs = PORT_ArenaGrowArray(attrs->arena, attrs->attrs,
288 PK11URIAttributeListEntry,
289 attrs->num_attrs,
290 attrs->num_attrs + 1);
291 } else {
292 attrs->attrs = PORT_ReallocArray(attrs->attrs,
293 PK11URIAttributeListEntry,
294 attrs->num_attrs + 1);
295 }
296 if (attrs->attrs == NULL) {
297 return SECFailure;
298 }
299
300 for (i = 0; i < attrs->num_attrs; i++) {
301 if (!allow_duplicate && strcmp(name, attrs->attrs[i].name) == 0) {
302 return SECFailure;
303 }
304 if (compare_name(name, attrs->attrs[i].name) < 0) {
305 memmove(&attrs->attrs[i + 1], &attrs->attrs[i],
306 sizeof(PK11URIAttributeListEntry) * (attrs->num_attrs - i));
307 break;
308 }
309 }
310
311 attrs->attrs[i].name = name;
312 attrs->attrs[i].value = value;
313
314 attrs->num_attrs++;
315
316 return SECSuccess;
317 }
318
319 static SECStatus
pk11uri_InsertToAttributeListEscaped(PK11URIAttributeList * attrs,const char * name,size_t name_size,const char * value,size_t value_size,PK11URIAttributeCompareNameFunc compare_name,PRBool allow_duplicate)320 pk11uri_InsertToAttributeListEscaped(PK11URIAttributeList *attrs,
321 const char *name, size_t name_size,
322 const char *value, size_t value_size,
323 PK11URIAttributeCompareNameFunc compare_name,
324 PRBool allow_duplicate)
325 {
326 char *name_copy = NULL, *value_copy = NULL;
327 SECStatus ret;
328
329 if (attrs->arena) {
330 name_copy = PORT_ArenaNewArray(attrs->arena, char, name_size + 1);
331 } else {
332 name_copy = PORT_Alloc(name_size + 1);
333 }
334 if (name_copy == NULL) {
335 goto fail;
336 }
337 memcpy(name_copy, name, name_size);
338 name_copy[name_size] = '\0';
339
340 value_copy = pk11uri_Unescape(attrs->arena, value, value_size);
341 if (value_copy == NULL) {
342 goto fail;
343 }
344
345 ret = pk11uri_InsertToAttributeList(attrs, name_copy, value_copy, compare_name,
346 allow_duplicate);
347 if (ret != SECSuccess) {
348 goto fail;
349 }
350
351 return ret;
352
353 fail:
354 if (attrs->arena == NULL) {
355 PORT_Free(name_copy);
356 PORT_Free(value_copy);
357 }
358
359 return SECFailure;
360 }
361
362 static void
pk11uri_InitAttributeList(PK11URIAttributeList * attrs,PLArenaPool * arena)363 pk11uri_InitAttributeList(PK11URIAttributeList *attrs, PLArenaPool *arena)
364 {
365 memset(attrs, 0, sizeof(PK11URIAttributeList));
366 attrs->arena = arena;
367 }
368
369 static void
pk11uri_DestroyAttributeList(PK11URIAttributeList * attrs)370 pk11uri_DestroyAttributeList(PK11URIAttributeList *attrs)
371 {
372 if (attrs->arena == NULL) {
373 size_t i;
374
375 for (i = 0; i < attrs->num_attrs; i++) {
376 PORT_Free(attrs->attrs[i].name);
377 PORT_Free(attrs->attrs[i].value);
378 }
379 PORT_Free(attrs->attrs);
380 }
381 }
382
383 static SECStatus
pk11uri_AppendAttributeListToBuffer(PK11URIBuffer * buffer,PK11URIAttributeList * attrs,int separator,const char * unescaped)384 pk11uri_AppendAttributeListToBuffer(PK11URIBuffer *buffer,
385 PK11URIAttributeList *attrs,
386 int separator,
387 const char *unescaped)
388 {
389 size_t i;
390 SECStatus ret;
391
392 for (i = 0; i < attrs->num_attrs; i++) {
393 unsigned char sep[1];
394 char *escaped;
395 PK11URIAttributeListEntry *attr = &attrs->attrs[i];
396
397 if (i > 0) {
398 sep[0] = separator;
399 ret = pk11uri_AppendBuffer(buffer, sep, 1);
400 if (ret != SECSuccess) {
401 return ret;
402 }
403 }
404
405 ret = pk11uri_AppendBuffer(buffer, (unsigned char *)attr->name,
406 strlen(attr->name));
407 if (ret != SECSuccess) {
408 return ret;
409 }
410
411 sep[0] = '=';
412 ret = pk11uri_AppendBuffer(buffer, sep, 1);
413 if (ret != SECSuccess) {
414 return ret;
415 }
416
417 escaped = pk11uri_Escape(buffer->arena, attr->value, strlen(attr->value),
418 unescaped);
419 if (escaped == NULL) {
420 return ret;
421 }
422 ret = pk11uri_AppendBuffer(buffer, (unsigned char *)escaped,
423 strlen(escaped));
424 if (buffer->arena == NULL) {
425 PORT_Free(escaped);
426 }
427 if (ret != SECSuccess) {
428 return ret;
429 }
430 }
431
432 return SECSuccess;
433 }
434
435 /* Creation of PK11URI object. */
436 static PK11URI *
pk11uri_AllocURI(void)437 pk11uri_AllocURI(void)
438 {
439 PLArenaPool *arena;
440 PK11URI *result;
441
442 arena = PORT_NewArena(PK11URI_ARENA_SIZE);
443 if (arena == NULL) {
444 return NULL;
445 }
446
447 result = PORT_ArenaZAlloc(arena, sizeof(PK11URI));
448 if (result == NULL) {
449 PORT_FreeArena(arena, PR_FALSE);
450 return NULL;
451 }
452
453 result->arena = arena;
454 pk11uri_InitAttributeList(&result->pattrs, arena);
455 pk11uri_InitAttributeList(&result->vpattrs, arena);
456 pk11uri_InitAttributeList(&result->qattrs, arena);
457 pk11uri_InitAttributeList(&result->vqattrs, arena);
458
459 return result;
460 }
461
462 static SECStatus
pk11uri_InsertAttributes(PK11URIAttributeList * dest_attrs,PK11URIAttributeList * dest_vattrs,const PK11URIAttribute * attrs,size_t num_attrs,const char ** attr_names,size_t num_attr_names,PK11URIAttributeCompareNameFunc compare_name,PRBool allow_duplicate,PRBool vendor_allow_duplicate)463 pk11uri_InsertAttributes(PK11URIAttributeList *dest_attrs,
464 PK11URIAttributeList *dest_vattrs,
465 const PK11URIAttribute *attrs,
466 size_t num_attrs,
467 const char **attr_names,
468 size_t num_attr_names,
469 PK11URIAttributeCompareNameFunc compare_name,
470 PRBool allow_duplicate,
471 PRBool vendor_allow_duplicate)
472 {
473 SECStatus ret;
474 size_t i;
475
476 for (i = 0; i < num_attrs; i++) {
477 char *name, *value;
478 const char *p;
479 size_t j;
480
481 p = attrs[i].name;
482
483 /* The attribute must not be empty. */
484 if (*p == '\0') {
485 return SECFailure;
486 }
487
488 /* Check that the name doesn't contain invalid character. */
489 for (; *p != '\0'; p++) {
490 if (strchr(PK11URI_ATTR_NM_CHAR, *p) == NULL) {
491 return SECFailure;
492 }
493 }
494
495 name = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].name);
496 if (name == NULL) {
497 return SECFailure;
498 }
499
500 value = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].value);
501 if (value == NULL) {
502 return SECFailure;
503 }
504
505 for (j = 0; j < num_attr_names; j++) {
506 if (strcmp(name, attr_names[j]) == 0) {
507 break;
508 }
509 }
510 if (j < num_attr_names) {
511 /* Named attribute. */
512 ret = pk11uri_InsertToAttributeList(dest_attrs,
513 name, value,
514 compare_name,
515 allow_duplicate);
516 if (ret != SECSuccess) {
517 return ret;
518 }
519 } else {
520 /* Vendor attribute. */
521 ret = pk11uri_InsertToAttributeList(dest_vattrs,
522 name, value,
523 strcmp,
524 vendor_allow_duplicate);
525 if (ret != SECSuccess) {
526 return ret;
527 }
528 }
529 }
530
531 return SECSuccess;
532 }
533
534 PK11URI *
PK11URI_CreateURI(const PK11URIAttribute * pattrs,size_t num_pattrs,const PK11URIAttribute * qattrs,size_t num_qattrs)535 PK11URI_CreateURI(const PK11URIAttribute *pattrs,
536 size_t num_pattrs,
537 const PK11URIAttribute *qattrs,
538 size_t num_qattrs)
539 {
540 PK11URI *result;
541 SECStatus ret;
542
543 result = pk11uri_AllocURI();
544
545 ret = pk11uri_InsertAttributes(&result->pattrs, &result->vpattrs,
546 pattrs, num_pattrs,
547 pattr_names, PR_ARRAY_SIZE(pattr_names),
548 pk11uri_ComparePathAttributeName,
549 PR_FALSE, PR_FALSE);
550 if (ret != SECSuccess) {
551 goto fail;
552 }
553
554 ret = pk11uri_InsertAttributes(&result->qattrs, &result->vqattrs,
555 qattrs, num_qattrs,
556 qattr_names, PR_ARRAY_SIZE(qattr_names),
557 pk11uri_CompareQueryAttributeName,
558 PR_FALSE, PR_TRUE);
559 if (ret != SECSuccess) {
560 goto fail;
561 }
562
563 return result;
564
565 fail:
566 PK11URI_DestroyURI(result);
567
568 return NULL;
569 }
570
571 /* Parsing. */
572 static SECStatus
pk11uri_ParseAttributes(const char ** string,const char * stop_chars,int separator,const char * accept_chars,const char ** attr_names,size_t num_attr_names,PK11URIAttributeList * attrs,PK11URIAttributeList * vattrs,PK11URIAttributeCompareNameFunc compare_name,PRBool allow_duplicate,PRBool vendor_allow_duplicate)573 pk11uri_ParseAttributes(const char **string,
574 const char *stop_chars,
575 int separator,
576 const char *accept_chars,
577 const char **attr_names, size_t num_attr_names,
578 PK11URIAttributeList *attrs,
579 PK11URIAttributeList *vattrs,
580 PK11URIAttributeCompareNameFunc compare_name,
581 PRBool allow_duplicate,
582 PRBool vendor_allow_duplicate)
583 {
584 const char *p = *string;
585
586 for (; *p != '\0'; p++) {
587 const char *name_start, *name_end, *value_start, *value_end;
588 size_t name_length, value_length, i;
589 SECStatus ret;
590
591 if (strchr(stop_chars, *p) != NULL) {
592 break;
593 }
594 for (name_start = p; *p != '=' && *p != '\0'; p++) {
595 if (strchr(PK11URI_ATTR_NM_CHAR, *p) != NULL)
596 continue;
597
598 return SECFailure;
599 }
600 if (*p == '\0') {
601 return SECFailure;
602 }
603 name_end = p++;
604
605 /* The attribute name must not be empty. */
606 if (name_end == name_start) {
607 return SECFailure;
608 }
609
610 for (value_start = p; *p != separator && *p != '\0'; p++) {
611 if (strchr(stop_chars, *p) != NULL) {
612 break;
613 }
614 if (strchr(accept_chars, *p) != NULL) {
615 continue;
616 }
617 if (*p == '%') {
618 const char ch2 = *++p;
619 if (strchr(PK11URI_HEXDIG, ch2) != NULL) {
620 const char ch3 = *++p;
621 if (strchr(PK11URI_HEXDIG, ch3) != NULL)
622 continue;
623 }
624 }
625
626 return SECFailure;
627 }
628 value_end = p;
629
630 name_length = name_end - name_start;
631 value_length = value_end - value_start;
632
633 for (i = 0; i < num_attr_names; i++) {
634 if (name_length == strlen(attr_names[i]) &&
635 memcmp(name_start, attr_names[i], name_length) == 0) {
636 break;
637 }
638 }
639 if (i < num_attr_names) {
640 /* Named attribute. */
641 ret = pk11uri_InsertToAttributeListEscaped(attrs,
642 name_start, name_length,
643 value_start, value_length,
644 compare_name,
645 allow_duplicate);
646 if (ret != SECSuccess) {
647 return ret;
648 }
649 } else {
650 /* Vendor attribute. */
651 ret = pk11uri_InsertToAttributeListEscaped(vattrs,
652 name_start, name_length,
653 value_start, value_length,
654 strcmp,
655 vendor_allow_duplicate);
656 if (ret != SECSuccess) {
657 return ret;
658 }
659 }
660
661 if (*p == '?' || *p == '\0') {
662 break;
663 }
664 }
665
666 *string = p;
667 return SECSuccess;
668 }
669
670 PK11URI *
PK11URI_ParseURI(const char * string)671 PK11URI_ParseURI(const char *string)
672 {
673 PK11URI *result;
674 const char *p = string;
675 SECStatus ret;
676
677 if (PORT_Strncasecmp("pkcs11:", p, 7) != 0) {
678 return NULL;
679 }
680 p += 7;
681
682 result = pk11uri_AllocURI();
683 if (result == NULL) {
684 return NULL;
685 }
686
687 /* Parse the path component and its attributes. */
688 ret = pk11uri_ParseAttributes(&p, "?", ';', PK11URI_PCHAR,
689 pattr_names, PR_ARRAY_SIZE(pattr_names),
690 &result->pattrs, &result->vpattrs,
691 pk11uri_ComparePathAttributeName,
692 PR_FALSE, PR_FALSE);
693 if (ret != SECSuccess) {
694 goto fail;
695 }
696
697 /* Parse the query component and its attributes. */
698 if (*p == '?') {
699 p++;
700 ret = pk11uri_ParseAttributes(&p, "", '&', PK11URI_QCHAR,
701 qattr_names, PR_ARRAY_SIZE(qattr_names),
702 &result->qattrs, &result->vqattrs,
703 pk11uri_CompareQueryAttributeName,
704 PR_FALSE, PR_TRUE);
705 if (ret != SECSuccess) {
706 goto fail;
707 }
708 }
709
710 return result;
711
712 fail:
713 PK11URI_DestroyURI(result);
714
715 return NULL;
716 }
717
718 /* Formatting. */
719 char *
PK11URI_FormatURI(PLArenaPool * arena,PK11URI * uri)720 PK11URI_FormatURI(PLArenaPool *arena, PK11URI *uri)
721 {
722 PK11URIBuffer buffer;
723 SECStatus ret;
724 char *result = NULL;
725
726 pk11uri_InitBuffer(&buffer, arena);
727
728 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"pkcs11:", 7);
729 if (ret != SECSuccess)
730 goto fail;
731
732 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->pattrs, ';', PK11URI_PCHAR);
733 if (ret != SECSuccess) {
734 goto fail;
735 }
736
737 if (uri->pattrs.num_attrs > 0 && uri->vpattrs.num_attrs > 0) {
738 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)";", 1);
739 if (ret != SECSuccess) {
740 goto fail;
741 }
742 }
743
744 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vpattrs, ';',
745 PK11URI_PCHAR);
746 if (ret != SECSuccess) {
747 goto fail;
748 }
749
750 if (uri->qattrs.num_attrs > 0 || uri->vqattrs.num_attrs > 0) {
751 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"?", 1);
752 if (ret != SECSuccess) {
753 goto fail;
754 }
755 }
756
757 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->qattrs, '&', PK11URI_QCHAR);
758 if (ret != SECSuccess) {
759 goto fail;
760 }
761
762 if (uri->qattrs.num_attrs > 0 && uri->vqattrs.num_attrs > 0) {
763 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"&", 1);
764 if (ret != SECSuccess) {
765 goto fail;
766 }
767 }
768
769 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vqattrs, '&',
770 PK11URI_QCHAR);
771 if (ret != SECSuccess) {
772 goto fail;
773 }
774
775 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"\0", 1);
776 if (ret != SECSuccess) {
777 goto fail;
778 }
779
780 result = buffer.data;
781 buffer.data = NULL;
782
783 fail:
784 pk11uri_DestroyBuffer(&buffer);
785
786 return result;
787 }
788
789 /* Deallocating. */
790 void
PK11URI_DestroyURI(PK11URI * uri)791 PK11URI_DestroyURI(PK11URI *uri)
792 {
793 pk11uri_DestroyAttributeList(&uri->pattrs);
794 pk11uri_DestroyAttributeList(&uri->vpattrs);
795 pk11uri_DestroyAttributeList(&uri->qattrs);
796 pk11uri_DestroyAttributeList(&uri->vqattrs);
797 PORT_FreeArena(uri->arena, PR_FALSE);
798 }
799
800 /* Accessors. */
801 static const char *
pk11uri_GetAttribute(PK11URIAttributeList * attrs,PK11URIAttributeList * vattrs,const char * name)802 pk11uri_GetAttribute(PK11URIAttributeList *attrs,
803 PK11URIAttributeList *vattrs,
804 const char *name)
805 {
806 size_t i;
807
808 for (i = 0; i < attrs->num_attrs; i++) {
809 if (strcmp(name, attrs->attrs[i].name) == 0) {
810 return attrs->attrs[i].value;
811 }
812 }
813
814 for (i = 0; i < vattrs->num_attrs; i++) {
815 if (strcmp(name, vattrs->attrs[i].name) == 0) {
816 return vattrs->attrs[i].value;
817 }
818 }
819
820 return NULL;
821 }
822
823 const char *
PK11URI_GetPathAttribute(PK11URI * uri,const char * name)824 PK11URI_GetPathAttribute(PK11URI *uri, const char *name)
825 {
826 return pk11uri_GetAttribute(&uri->pattrs, &uri->vpattrs, name);
827 }
828
829 const char *
PK11URI_GetQueryAttribute(PK11URI * uri,const char * name)830 PK11URI_GetQueryAttribute(PK11URI *uri, const char *name)
831 {
832 return pk11uri_GetAttribute(&uri->qattrs, &uri->vqattrs, name);
833 }
834