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