Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/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
#define PK11URI_DIGIT "0123456789"
13
0
#define PK11URI_ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
14
#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
#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
    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
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
    (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
92
pk11uri_AppendBuffer(PK11URIBuffer *buffer, const unsigned char *data,
93
                     size_t size)
94
0
{
95
0
    /* Check overflow. */
96
0
    if (buffer->size + size < buffer->size)
97
0
        return SECFailure;
98
0
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
0
113
0
    memcpy(&buffer->data[buffer->size], data, size);
114
0
    buffer->size += size;
115
0
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 char *value, size_t length,
137
               const char *available)
138
0
{
139
0
    PK11URIBuffer buffer;
140
0
    const char *p;
141
0
    unsigned char buf[4];
142
0
    char *result = NULL;
143
0
    SECStatus ret;
144
0
145
0
    pk11uri_InitBuffer(&buffer, arena);
146
0
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, (const unsigned char *)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
0
169
0
    /* Steal the memory allocated in buffer. */
170
0
    result = buffer.data;
171
0
    buffer.data = NULL;
172
0
173
0
fail:
174
0
    pk11uri_DestroyBuffer(&buffer);
175
0
176
0
    return result;
177
0
}
178
179
static 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
    char *result = NULL;
186
0
    SECStatus ret;
187
0
188
0
    pk11uri_InitBuffer(&buffer, arena);
189
0
190
0
    for (p = value; p < value + length; p++) {
191
0
        if (*p == '%') {
192
0
            int c;
193
0
            size_t i;
194
0
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
    buf[0] = '\0';
222
0
    ret = pk11uri_AppendBuffer(&buffer, buf, 1);
223
0
    if (ret != SECSuccess) {
224
0
        goto fail;
225
0
    }
226
0
227
0
    result = buffer.data;
228
0
    buffer.data = NULL;
229
0
230
0
fail:
231
0
    pk11uri_DestroyBuffer(&buffer);
232
0
233
0
    return result;
234
0
}
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
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
267
pk11uri_ComparePathAttributeName(const char *a, const char *b)
268
0
{
269
0
    return pk11uri_CompareByPosition(a, b, pattr_names, PR_ARRAY_SIZE(pattr_names));
270
0
}
271
272
static int
273
pk11uri_CompareQueryAttributeName(const char *a, const char *b)
274
0
{
275
0
    return pk11uri_CompareByPosition(a, b, qattr_names, PR_ARRAY_SIZE(qattr_names));
276
0
}
277
278
static SECStatus
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
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
0
{
326
0
    char *name_copy = NULL, *value_copy = NULL;
327
0
    SECStatus ret;
328
0
329
0
    if (attrs->arena) {
330
0
        name_copy = PORT_ArenaNewArray(attrs->arena, char, name_size + 1);
331
0
    } else {
332
0
        name_copy = PORT_Alloc(name_size + 1);
333
0
    }
334
0
    if (name_copy == NULL) {
335
0
        goto fail;
336
0
    }
337
0
    memcpy(name_copy, name, name_size);
338
0
    name_copy[name_size] = '\0';
339
0
340
0
    value_copy = pk11uri_Unescape(attrs->arena, value, value_size);
341
0
    if (value_copy == NULL) {
342
0
        goto fail;
343
0
    }
344
0
345
0
    ret = pk11uri_InsertToAttributeList(attrs, name_copy, value_copy, compare_name,
346
0
                                        allow_duplicate);
347
0
    if (ret != SECSuccess) {
348
0
        goto fail;
349
0
    }
350
0
351
0
    return ret;
352
0
353
0
fail:
354
0
    if (attrs->arena == NULL) {
355
0
        PORT_Free(name_copy);
356
0
        PORT_Free(value_copy);
357
0
    }
358
0
359
0
    return SECFailure;
360
0
}
361
362
static void
363
pk11uri_InitAttributeList(PK11URIAttributeList *attrs, PLArenaPool *arena)
364
0
{
365
0
    memset(attrs, 0, sizeof(PK11URIAttributeList));
366
0
    attrs->arena = arena;
367
0
}
368
369
static void
370
pk11uri_DestroyAttributeList(PK11URIAttributeList *attrs)
371
0
{
372
0
    if (attrs->arena == NULL) {
373
0
        size_t i;
374
0
375
0
        for (i = 0; i < attrs->num_attrs; i++) {
376
0
            PORT_Free(attrs->attrs[i].name);
377
0
            PORT_Free(attrs->attrs[i].value);
378
0
        }
379
0
        PORT_Free(attrs->attrs);
380
0
    }
381
0
}
382
383
static SECStatus
384
pk11uri_AppendAttributeListToBuffer(PK11URIBuffer *buffer,
385
                                    PK11URIAttributeList *attrs,
386
                                    int separator,
387
                                    const char *unescaped)
388
0
{
389
0
    size_t i;
390
0
    SECStatus ret;
391
0
392
0
    for (i = 0; i < attrs->num_attrs; i++) {
393
0
        unsigned char sep[1];
394
0
        char *escaped;
395
0
        PK11URIAttributeListEntry *attr = &attrs->attrs[i];
396
0
397
0
        if (i > 0) {
398
0
            sep[0] = separator;
399
0
            ret = pk11uri_AppendBuffer(buffer, sep, 1);
400
0
            if (ret != SECSuccess) {
401
0
                return ret;
402
0
            }
403
0
        }
404
0
405
0
        ret = pk11uri_AppendBuffer(buffer, (unsigned char *)attr->name,
406
0
                                   strlen(attr->name));
407
0
        if (ret != SECSuccess) {
408
0
            return ret;
409
0
        }
410
0
411
0
        sep[0] = '=';
412
0
        ret = pk11uri_AppendBuffer(buffer, sep, 1);
413
0
        if (ret != SECSuccess) {
414
0
            return ret;
415
0
        }
416
0
417
0
        escaped = pk11uri_Escape(buffer->arena, attr->value, strlen(attr->value),
418
0
                                 unescaped);
419
0
        if (escaped == NULL) {
420
0
            return ret;
421
0
        }
422
0
        ret = pk11uri_AppendBuffer(buffer, (unsigned char *)escaped,
423
0
                                   strlen(escaped));
424
0
        if (buffer->arena == NULL) {
425
0
            PORT_Free(escaped);
426
0
        }
427
0
        if (ret != SECSuccess) {
428
0
            return ret;
429
0
        }
430
0
    }
431
0
432
0
    return SECSuccess;
433
0
}
434
435
/* Creation of PK11URI object. */
436
static PK11URI *
437
pk11uri_AllocURI(void)
438
0
{
439
0
    PLArenaPool *arena;
440
0
    PK11URI *result;
441
0
442
0
    arena = PORT_NewArena(PK11URI_ARENA_SIZE);
443
0
    if (arena == NULL) {
444
0
        return NULL;
445
0
    }
446
0
447
0
    result = PORT_ArenaZAlloc(arena, sizeof(PK11URI));
448
0
    if (result == NULL) {
449
0
        PORT_FreeArena(arena, PR_FALSE);
450
0
        return NULL;
451
0
    }
452
0
453
0
    result->arena = arena;
454
0
    pk11uri_InitAttributeList(&result->pattrs, arena);
455
0
    pk11uri_InitAttributeList(&result->vpattrs, arena);
456
0
    pk11uri_InitAttributeList(&result->qattrs, arena);
457
0
    pk11uri_InitAttributeList(&result->vqattrs, arena);
458
0
459
0
    return result;
460
0
}
461
462
static SECStatus
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
0
{
473
0
    SECStatus ret;
474
0
    size_t i;
475
0
476
0
    for (i = 0; i < num_attrs; i++) {
477
0
        char *name, *value;
478
0
        const char *p;
479
0
        size_t j;
480
0
481
0
        p = attrs[i].name;
482
0
483
0
        /* The attribute must not be empty. */
484
0
        if (*p == '\0') {
485
0
            return SECFailure;
486
0
        }
487
0
488
0
        /* Check that the name doesn't contain invalid character. */
489
0
        for (; *p != '\0'; p++) {
490
0
            if (strchr(PK11URI_ATTR_NM_CHAR, *p) == NULL) {
491
0
                return SECFailure;
492
0
            }
493
0
        }
494
0
495
0
        name = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].name);
496
0
        if (name == NULL) {
497
0
            return SECFailure;
498
0
        }
499
0
500
0
        value = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].value);
501
0
        if (value == NULL) {
502
0
            return SECFailure;
503
0
        }
504
0
505
0
        for (j = 0; j < num_attr_names; j++) {
506
0
            if (strcmp(name, attr_names[j]) == 0) {
507
0
                break;
508
0
            }
509
0
        }
510
0
        if (j < num_attr_names) {
511
0
            /* Named attribute. */
512
0
            ret = pk11uri_InsertToAttributeList(dest_attrs,
513
0
                                                name, value,
514
0
                                                compare_name,
515
0
                                                allow_duplicate);
516
0
            if (ret != SECSuccess) {
517
0
                return ret;
518
0
            }
519
0
        } else {
520
0
            /* Vendor attribute. */
521
0
            ret = pk11uri_InsertToAttributeList(dest_vattrs,
522
0
                                                name, value,
523
0
                                                strcmp,
524
0
                                                vendor_allow_duplicate);
525
0
            if (ret != SECSuccess) {
526
0
                return ret;
527
0
            }
528
0
        }
529
0
    }
530
0
531
0
    return SECSuccess;
532
0
}
533
534
PK11URI *
535
PK11URI_CreateURI(const PK11URIAttribute *pattrs,
536
                  size_t num_pattrs,
537
                  const PK11URIAttribute *qattrs,
538
                  size_t num_qattrs)
539
0
{
540
0
    PK11URI *result;
541
0
    SECStatus ret;
542
0
543
0
    result = pk11uri_AllocURI();
544
0
545
0
    ret = pk11uri_InsertAttributes(&result->pattrs, &result->vpattrs,
546
0
                                   pattrs, num_pattrs,
547
0
                                   pattr_names, PR_ARRAY_SIZE(pattr_names),
548
0
                                   pk11uri_ComparePathAttributeName,
549
0
                                   PR_FALSE, PR_FALSE);
550
0
    if (ret != SECSuccess) {
551
0
        goto fail;
552
0
    }
553
0
554
0
    ret = pk11uri_InsertAttributes(&result->qattrs, &result->vqattrs,
555
0
                                   qattrs, num_qattrs,
556
0
                                   qattr_names, PR_ARRAY_SIZE(qattr_names),
557
0
                                   pk11uri_CompareQueryAttributeName,
558
0
                                   PR_FALSE, PR_TRUE);
559
0
    if (ret != SECSuccess) {
560
0
        goto fail;
561
0
    }
562
0
563
0
    return result;
564
0
565
0
fail:
566
0
    PK11URI_DestroyURI(result);
567
0
568
0
    return NULL;
569
0
}
570
571
/* Parsing. */
572
static SECStatus
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
0
{
584
0
    const char *p = *string;
585
0
586
0
    for (; *p != '\0'; p++) {
587
0
        const char *name_start, *name_end, *value_start, *value_end;
588
0
        size_t name_length, value_length, i;
589
0
        SECStatus ret;
590
0
591
0
        if (strchr(stop_chars, *p) != NULL) {
592
0
            break;
593
0
        }
594
0
        for (name_start = p; *p != '=' && *p != '\0'; p++) {
595
0
            if (strchr(PK11URI_ATTR_NM_CHAR, *p) != NULL)
596
0
                continue;
597
0
598
0
            return SECFailure;
599
0
        }
600
0
        if (*p == '\0') {
601
0
            return SECFailure;
602
0
        }
603
0
        name_end = p++;
604
0
605
0
        /* The attribute name must not be empty. */
606
0
        if (name_end == name_start) {
607
0
            return SECFailure;
608
0
        }
609
0
610
0
        for (value_start = p; *p != separator && *p != '\0'; p++) {
611
0
            if (strchr(stop_chars, *p) != NULL) {
612
0
                break;
613
0
            }
614
0
            if (strchr(accept_chars, *p) != NULL) {
615
0
                continue;
616
0
            }
617
0
            if (*p == '%') {
618
0
                const char ch2 = *++p;
619
0
                if (strchr(PK11URI_HEXDIG, ch2) != NULL) {
620
0
                    const char ch3 = *++p;
621
0
                    if (strchr(PK11URI_HEXDIG, ch3) != NULL)
622
0
                        continue;
623
0
                }
624
0
            }
625
0
626
0
            return SECFailure;
627
0
        }
628
0
        value_end = p;
629
0
630
0
        name_length = name_end - name_start;
631
0
        value_length = value_end - value_start;
632
0
633
0
        for (i = 0; i < num_attr_names; i++) {
634
0
            if (name_length == strlen(attr_names[i]) &&
635
0
                memcmp(name_start, attr_names[i], name_length) == 0) {
636
0
                break;
637
0
            }
638
0
        }
639
0
        if (i < num_attr_names) {
640
0
            /* Named attribute. */
641
0
            ret = pk11uri_InsertToAttributeListEscaped(attrs,
642
0
                                                       name_start, name_length,
643
0
                                                       value_start, value_length,
644
0
                                                       compare_name,
645
0
                                                       allow_duplicate);
646
0
            if (ret != SECSuccess) {
647
0
                return ret;
648
0
            }
649
0
        } else {
650
0
            /* Vendor attribute. */
651
0
            ret = pk11uri_InsertToAttributeListEscaped(vattrs,
652
0
                                                       name_start, name_length,
653
0
                                                       value_start, value_length,
654
0
                                                       strcmp,
655
0
                                                       vendor_allow_duplicate);
656
0
            if (ret != SECSuccess) {
657
0
                return ret;
658
0
            }
659
0
        }
660
0
661
0
        if (*p == '?' || *p == '\0') {
662
0
            break;
663
0
        }
664
0
    }
665
0
666
0
    *string = p;
667
0
    return SECSuccess;
668
0
}
669
670
PK11URI *
671
PK11URI_ParseURI(const char *string)
672
0
{
673
0
    PK11URI *result;
674
0
    const char *p = string;
675
0
    SECStatus ret;
676
0
677
0
    if (PORT_Strncasecmp("pkcs11:", p, 7) != 0) {
678
0
        return NULL;
679
0
    }
680
0
    p += 7;
681
0
682
0
    result = pk11uri_AllocURI();
683
0
    if (result == NULL) {
684
0
        return NULL;
685
0
    }
686
0
687
0
    /* Parse the path component and its attributes. */
688
0
    ret = pk11uri_ParseAttributes(&p, "?", ';', PK11URI_PCHAR,
689
0
                                  pattr_names, PR_ARRAY_SIZE(pattr_names),
690
0
                                  &result->pattrs, &result->vpattrs,
691
0
                                  pk11uri_ComparePathAttributeName,
692
0
                                  PR_FALSE, PR_FALSE);
693
0
    if (ret != SECSuccess) {
694
0
        goto fail;
695
0
    }
696
0
697
0
    /* Parse the query component and its attributes. */
698
0
    if (*p == '?') {
699
0
        p++;
700
0
        ret = pk11uri_ParseAttributes(&p, "", '&', PK11URI_QCHAR,
701
0
                                      qattr_names, PR_ARRAY_SIZE(qattr_names),
702
0
                                      &result->qattrs, &result->vqattrs,
703
0
                                      pk11uri_CompareQueryAttributeName,
704
0
                                      PR_FALSE, PR_TRUE);
705
0
        if (ret != SECSuccess) {
706
0
            goto fail;
707
0
        }
708
0
    }
709
0
710
0
    return result;
711
0
712
0
fail:
713
0
    PK11URI_DestroyURI(result);
714
0
715
0
    return NULL;
716
0
}
717
718
/* Formatting. */
719
char *
720
PK11URI_FormatURI(PLArenaPool *arena, PK11URI *uri)
721
0
{
722
0
    PK11URIBuffer buffer;
723
0
    SECStatus ret;
724
0
    char *result = NULL;
725
0
726
0
    pk11uri_InitBuffer(&buffer, arena);
727
0
728
0
    ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"pkcs11:", 7);
729
0
    if (ret != SECSuccess)
730
0
        goto fail;
731
0
732
0
    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->pattrs, ';', PK11URI_PCHAR);
733
0
    if (ret != SECSuccess) {
734
0
        goto fail;
735
0
    }
736
0
737
0
    if (uri->pattrs.num_attrs > 0 && uri->vpattrs.num_attrs > 0) {
738
0
        ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)";", 1);
739
0
        if (ret != SECSuccess) {
740
0
            goto fail;
741
0
        }
742
0
    }
743
0
744
0
    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vpattrs, ';',
745
0
                                              PK11URI_PCHAR);
746
0
    if (ret != SECSuccess) {
747
0
        goto fail;
748
0
    }
749
0
750
0
    if (uri->qattrs.num_attrs > 0 || uri->vqattrs.num_attrs > 0) {
751
0
        ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"?", 1);
752
0
        if (ret != SECSuccess) {
753
0
            goto fail;
754
0
        }
755
0
    }
756
0
757
0
    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->qattrs, '&', PK11URI_QCHAR);
758
0
    if (ret != SECSuccess) {
759
0
        goto fail;
760
0
    }
761
0
762
0
    if (uri->qattrs.num_attrs > 0 && uri->vqattrs.num_attrs > 0) {
763
0
        ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"&", 1);
764
0
        if (ret != SECSuccess) {
765
0
            goto fail;
766
0
        }
767
0
    }
768
0
769
0
    ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vqattrs, '&',
770
0
                                              PK11URI_QCHAR);
771
0
    if (ret != SECSuccess) {
772
0
        goto fail;
773
0
    }
774
0
775
0
    ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"\0", 1);
776
0
    if (ret != SECSuccess) {
777
0
        goto fail;
778
0
    }
779
0
780
0
    result = buffer.data;
781
0
    buffer.data = NULL;
782
0
783
0
fail:
784
0
    pk11uri_DestroyBuffer(&buffer);
785
0
786
0
    return result;
787
0
}
788
789
/* Deallocating. */
790
void
791
PK11URI_DestroyURI(PK11URI *uri)
792
0
{
793
0
    pk11uri_DestroyAttributeList(&uri->pattrs);
794
0
    pk11uri_DestroyAttributeList(&uri->vpattrs);
795
0
    pk11uri_DestroyAttributeList(&uri->qattrs);
796
0
    pk11uri_DestroyAttributeList(&uri->vqattrs);
797
0
    PORT_FreeArena(uri->arena, PR_FALSE);
798
0
}
799
800
/* Accessors. */
801
static const char *
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 *
824
PK11URI_GetPathAttribute(PK11URI *uri, const char *name)
825
0
{
826
0
    return pk11uri_GetAttribute(&uri->pattrs, &uri->vpattrs, name);
827
0
}
828
829
const char *
830
PK11URI_GetQueryAttribute(PK11URI *uri, const char *name)
831
0
{
832
0
    return pk11uri_GetAttribute(&uri->qattrs, &uri->vqattrs, name);
833
0
}