Coverage Report

Created: 2024-11-21 07:03

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