Coverage Report

Created: 2025-06-24 06:49

/src/nss/lib/certdb/genname.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 "plarena.h"
6
#include "seccomon.h"
7
#include "secitem.h"
8
#include "secoidt.h"
9
#include "secasn1.h"
10
#include "secder.h"
11
#include "certt.h"
12
#include "cert.h"
13
#include "certi.h"
14
#include "xconst.h"
15
#include "secerr.h"
16
#include "secoid.h"
17
#include "prprf.h"
18
#include "genname.h"
19
20
SEC_ASN1_MKSUB(SEC_AnyTemplate)
21
SEC_ASN1_MKSUB(SEC_IntegerTemplate)
22
SEC_ASN1_MKSUB(SEC_IA5StringTemplate)
23
SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
24
SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
25
26
static const SEC_ASN1Template CERTNameConstraintTemplate[] = {
27
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraint) },
28
    { SEC_ASN1_ANY, offsetof(CERTNameConstraint, DERName) },
29
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
30
      offsetof(CERTNameConstraint, min), SEC_ASN1_SUB(SEC_IntegerTemplate) },
31
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
32
      offsetof(CERTNameConstraint, max), SEC_ASN1_SUB(SEC_IntegerTemplate) },
33
    { 0 }
34
};
35
36
const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = {
37
    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
38
};
39
40
static const SEC_ASN1Template CERTNameConstraintsTemplate[] = {
41
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraints) },
42
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
43
      offsetof(CERTNameConstraints, DERPermited),
44
      CERT_NameConstraintSubtreeSubTemplate },
45
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
46
      offsetof(CERTNameConstraints, DERExcluded),
47
      CERT_NameConstraintSubtreeSubTemplate },
48
    { 0 }
49
};
50
51
static const SEC_ASN1Template CERTOthNameTemplate[] = {
52
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OtherName) },
53
    { SEC_ASN1_OBJECT_ID, offsetof(OtherName, oid) },
54
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
55
          SEC_ASN1_XTRN | 0,
56
      offsetof(OtherName, name), SEC_ASN1_SUB(SEC_AnyTemplate) },
57
    { 0 }
58
};
59
60
static const SEC_ASN1Template CERTOtherNameTemplate[] = {
61
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0,
62
      offsetof(CERTGeneralName, name.OthName), CERTOthNameTemplate,
63
      sizeof(CERTGeneralName) }
64
};
65
66
static const SEC_ASN1Template CERT_RFC822NameTemplate[] = {
67
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
68
      offsetof(CERTGeneralName, name.other),
69
      SEC_ASN1_SUB(SEC_IA5StringTemplate), sizeof(CERTGeneralName) }
70
};
71
72
static const SEC_ASN1Template CERT_DNSNameTemplate[] = {
73
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
74
      offsetof(CERTGeneralName, name.other),
75
      SEC_ASN1_SUB(SEC_IA5StringTemplate), sizeof(CERTGeneralName) }
76
};
77
78
static const SEC_ASN1Template CERT_X400AddressTemplate[] = {
79
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 3,
80
      offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
81
      sizeof(CERTGeneralName) }
82
};
83
84
static const SEC_ASN1Template CERT_DirectoryNameTemplate[] = {
85
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
86
          SEC_ASN1_XTRN | 4,
87
      offsetof(CERTGeneralName, derDirectoryName),
88
      SEC_ASN1_SUB(SEC_AnyTemplate), sizeof(CERTGeneralName) }
89
};
90
91
static const SEC_ASN1Template CERT_EDIPartyNameTemplate[] = {
92
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 5,
93
      offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
94
      sizeof(CERTGeneralName) }
95
};
96
97
static const SEC_ASN1Template CERT_URITemplate[] = {
98
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 6,
99
      offsetof(CERTGeneralName, name.other),
100
      SEC_ASN1_SUB(SEC_IA5StringTemplate), sizeof(CERTGeneralName) }
101
};
102
103
static const SEC_ASN1Template CERT_IPAddressTemplate[] = {
104
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 7,
105
      offsetof(CERTGeneralName, name.other),
106
      SEC_ASN1_SUB(SEC_OctetStringTemplate), sizeof(CERTGeneralName) }
107
};
108
109
static const SEC_ASN1Template CERT_RegisteredIDTemplate[] = {
110
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 8,
111
      offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_ObjectIDTemplate),
112
      sizeof(CERTGeneralName) }
113
};
114
115
const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
116
    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
117
};
118
119
static struct {
120
    CERTGeneralNameType type;
121
    char *name;
122
} typesArray[] = { { certOtherName, "other" },
123
                   { certRFC822Name, "email" },
124
                   { certRFC822Name, "rfc822" },
125
                   { certDNSName, "dns" },
126
                   { certX400Address, "x400" },
127
                   { certX400Address, "x400addr" },
128
                   { certDirectoryName, "directory" },
129
                   { certDirectoryName, "dn" },
130
                   { certEDIPartyName, "edi" },
131
                   { certEDIPartyName, "ediparty" },
132
                   { certURI, "uri" },
133
                   { certIPAddress, "ip" },
134
                   { certIPAddress, "ipaddr" },
135
                   { certRegisterID, "registerid" } };
136
137
CERTGeneralNameType
138
CERT_GetGeneralNameTypeFromString(const char *string)
139
0
{
140
0
    int types_count = sizeof(typesArray) / sizeof(typesArray[0]);
141
0
    int i;
142
143
0
    for (i = 0; i < types_count; i++) {
144
0
        if (PORT_Strcasecmp(string, typesArray[i].name) == 0) {
145
0
            return typesArray[i].type;
146
0
        }
147
0
    }
148
0
    return 0;
149
0
}
150
151
CERTGeneralName *
152
CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type)
153
28.0k
{
154
28.0k
    CERTGeneralName *name = arena ? PORT_ArenaZNew(arena, CERTGeneralName)
155
28.0k
                                  : PORT_ZNew(CERTGeneralName);
156
28.0k
    if (name) {
157
28.0k
        name->type = type;
158
28.0k
        name->l.prev = name->l.next = &name->l;
159
28.0k
    }
160
28.0k
    return name;
161
28.0k
}
162
163
/* Copy content of one General Name to another.
164
** Caller has allocated destination general name.
165
** This function does not change the destinate's GeneralName's list linkage.
166
*/
167
SECStatus
168
cert_CopyOneGeneralName(PLArenaPool *arena, CERTGeneralName *dest,
169
                        CERTGeneralName *src)
170
0
{
171
0
    SECStatus rv;
172
0
    void *mark = NULL;
173
174
0
    PORT_Assert(dest != NULL);
175
0
    dest->type = src->type;
176
177
0
    mark = PORT_ArenaMark(arena);
178
179
0
    switch (src->type) {
180
0
        case certDirectoryName:
181
0
            rv = SECITEM_CopyItem(arena, &dest->derDirectoryName,
182
0
                                  &src->derDirectoryName);
183
0
            if (rv == SECSuccess)
184
0
                rv = CERT_CopyName(arena, &dest->name.directoryName,
185
0
                                   &src->name.directoryName);
186
0
            break;
187
188
0
        case certOtherName:
189
0
            rv = SECITEM_CopyItem(arena, &dest->name.OthName.name,
190
0
                                  &src->name.OthName.name);
191
0
            if (rv == SECSuccess)
192
0
                rv = SECITEM_CopyItem(arena, &dest->name.OthName.oid,
193
0
                                      &src->name.OthName.oid);
194
0
            break;
195
196
0
        default:
197
0
            rv = SECITEM_CopyItem(arena, &dest->name.other, &src->name.other);
198
0
            break;
199
0
    }
200
0
    if (rv != SECSuccess) {
201
0
        PORT_ArenaRelease(arena, mark);
202
0
    } else {
203
0
        PORT_ArenaUnmark(arena, mark);
204
0
    }
205
0
    return rv;
206
0
}
207
208
void
209
CERT_DestroyGeneralNameList(CERTGeneralNameList *list)
210
0
{
211
0
    PZLock *lock;
212
213
0
    if (list != NULL) {
214
0
        lock = list->lock;
215
0
        PZ_Lock(lock);
216
0
        if (--list->refCount <= 0 && list->arena != NULL) {
217
0
            PORT_FreeArena(list->arena, PR_FALSE);
218
0
            PZ_Unlock(lock);
219
0
            PZ_DestroyLock(lock);
220
0
        } else {
221
0
            PZ_Unlock(lock);
222
0
        }
223
0
    }
224
0
    return;
225
0
}
226
227
CERTGeneralNameList *
228
CERT_CreateGeneralNameList(CERTGeneralName *name)
229
0
{
230
0
    PLArenaPool *arena;
231
0
    CERTGeneralNameList *list = NULL;
232
233
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
234
0
    if (arena == NULL) {
235
0
        goto done;
236
0
    }
237
0
    list = PORT_ArenaZNew(arena, CERTGeneralNameList);
238
0
    if (!list)
239
0
        goto loser;
240
0
    if (name != NULL) {
241
0
        SECStatus rv;
242
0
        list->name = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
243
0
        if (!list->name)
244
0
            goto loser;
245
0
        rv = CERT_CopyGeneralName(arena, list->name, name);
246
0
        if (rv != SECSuccess)
247
0
            goto loser;
248
0
    }
249
0
    list->lock = PZ_NewLock(nssILockList);
250
0
    if (!list->lock)
251
0
        goto loser;
252
0
    list->arena = arena;
253
0
    list->refCount = 1;
254
0
done:
255
0
    return list;
256
257
0
loser:
258
0
    PORT_FreeArena(arena, PR_FALSE);
259
0
    return NULL;
260
0
}
261
262
CERTGeneralName *
263
CERT_GetNextGeneralName(CERTGeneralName *current)
264
30.0k
{
265
30.0k
    PRCList *next;
266
267
30.0k
    next = current->l.next;
268
30.0k
    return (CERTGeneralName *)(((char *)next) - offsetof(CERTGeneralName, l));
269
30.0k
}
270
271
CERTGeneralName *
272
CERT_GetPrevGeneralName(CERTGeneralName *current)
273
0
{
274
0
    PRCList *prev;
275
0
    prev = current->l.prev;
276
0
    return (CERTGeneralName *)(((char *)prev) - offsetof(CERTGeneralName, l));
277
0
}
278
279
CERTNameConstraint *
280
CERT_GetNextNameConstraint(CERTNameConstraint *current)
281
0
{
282
0
    PRCList *next;
283
284
0
    next = current->l.next;
285
0
    return (CERTNameConstraint *)(((char *)next) -
286
0
                                  offsetof(CERTNameConstraint, l));
287
0
}
288
289
CERTNameConstraint *
290
CERT_GetPrevNameConstraint(CERTNameConstraint *current)
291
0
{
292
0
    PRCList *prev;
293
0
    prev = current->l.prev;
294
0
    return (CERTNameConstraint *)(((char *)prev) -
295
0
                                  offsetof(CERTNameConstraint, l));
296
0
}
297
298
SECItem *
299
CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest,
300
                       PLArenaPool *arena)
301
0
{
302
303
0
    const SEC_ASN1Template *template;
304
305
0
    PORT_Assert(arena);
306
0
    if (arena == NULL || !genName) {
307
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
308
0
        return NULL;
309
0
    }
310
    /* TODO: mark arena */
311
0
    if (dest == NULL) {
312
0
        dest = PORT_ArenaZNew(arena, SECItem);
313
0
        if (!dest)
314
0
            goto loser;
315
0
    }
316
0
    if (genName->type == certDirectoryName) {
317
0
        if (genName->derDirectoryName.data == NULL) {
318
            /* The field hasn't been encoded yet. */
319
0
            SECItem *pre_dest = SEC_ASN1EncodeItem(
320
0
                arena, &(genName->derDirectoryName),
321
0
                &(genName->name.directoryName), CERT_NameTemplate);
322
0
            if (!pre_dest)
323
0
                goto loser;
324
0
        }
325
0
        if (genName->derDirectoryName.data == NULL) {
326
0
            goto loser;
327
0
        }
328
0
    }
329
0
    switch (genName->type) {
330
0
        case certURI:
331
0
            template = CERT_URITemplate;
332
0
            break;
333
0
        case certRFC822Name:
334
0
            template = CERT_RFC822NameTemplate;
335
0
            break;
336
0
        case certDNSName:
337
0
            template = CERT_DNSNameTemplate;
338
0
            break;
339
0
        case certIPAddress:
340
0
            template = CERT_IPAddressTemplate;
341
0
            break;
342
0
        case certOtherName:
343
0
            template = CERTOtherNameTemplate;
344
0
            break;
345
0
        case certRegisterID:
346
0
            template = CERT_RegisteredIDTemplate;
347
0
            break;
348
        /* for this type, we expect the value is already encoded */
349
0
        case certEDIPartyName:
350
0
            template = CERT_EDIPartyNameTemplate;
351
0
            break;
352
        /* for this type, we expect the value is already encoded */
353
0
        case certX400Address:
354
0
            template = CERT_X400AddressTemplate;
355
0
            break;
356
0
        case certDirectoryName:
357
0
            template = CERT_DirectoryNameTemplate;
358
0
            break;
359
0
        default:
360
0
            PORT_Assert(0);
361
0
            goto loser;
362
0
    }
363
0
    dest = SEC_ASN1EncodeItem(arena, dest, genName, template);
364
0
    if (!dest) {
365
0
        goto loser;
366
0
    }
367
    /* TODO: unmark arena */
368
0
    return dest;
369
0
loser:
370
    /* TODO: release arena back to mark */
371
0
    return NULL;
372
0
}
373
374
SECItem **
375
cert_EncodeGeneralNames(PLArenaPool *arena, CERTGeneralName *names)
376
0
{
377
0
    CERTGeneralName *current_name;
378
0
    SECItem **items = NULL;
379
0
    int count = 1;
380
0
    int i;
381
0
    PRCList *head;
382
383
0
    if (!names) {
384
0
        return NULL;
385
0
    }
386
387
0
    PORT_Assert(arena);
388
    /* TODO: mark arena */
389
0
    current_name = names;
390
0
    head = &(names->l);
391
0
    while (current_name->l.next != head) {
392
0
        current_name = CERT_GetNextGeneralName(current_name);
393
0
        ++count;
394
0
    }
395
0
    current_name = CERT_GetNextGeneralName(current_name);
396
0
    items = PORT_ArenaNewArray(arena, SECItem *, count + 1);
397
0
    if (items == NULL) {
398
0
        goto loser;
399
0
    }
400
0
    for (i = 0; i < count; i++) {
401
0
        items[i] = CERT_EncodeGeneralName(current_name, (SECItem *)NULL, arena);
402
0
        if (items[i] == NULL) {
403
0
            goto loser;
404
0
        }
405
0
        current_name = CERT_GetNextGeneralName(current_name);
406
0
    }
407
0
    items[i] = NULL;
408
    /* TODO: unmark arena */
409
0
    return items;
410
0
loser:
411
    /* TODO: release arena to mark */
412
0
    return NULL;
413
0
}
414
415
CERTGeneralName *
416
CERT_DecodeGeneralName(PLArenaPool *reqArena, SECItem *encodedName,
417
                       CERTGeneralName *genName)
418
20.7k
{
419
20.7k
    const SEC_ASN1Template *template;
420
20.7k
    CERTGeneralNameType genNameType;
421
20.7k
    SECStatus rv = SECSuccess;
422
20.7k
    SECItem *newEncodedName;
423
424
20.7k
    if (!reqArena) {
425
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
426
0
        return NULL;
427
0
    }
428
    /* make a copy for decoding so the data decoded with QuickDER doesn't
429
       point to temporary memory */
430
20.7k
    newEncodedName = SECITEM_ArenaDupItem(reqArena, encodedName);
431
20.7k
    if (!newEncodedName) {
432
0
        return NULL;
433
0
    }
434
    /* TODO: mark arena */
435
20.7k
    genNameType = (CERTGeneralNameType)((*(newEncodedName->data) & 0x0f) + 1);
436
20.7k
    if (genName == NULL) {
437
20.7k
        genName = CERT_NewGeneralName(reqArena, genNameType);
438
20.7k
        if (!genName)
439
0
            goto loser;
440
20.7k
    } else {
441
0
        genName->type = genNameType;
442
0
        genName->l.prev = genName->l.next = &genName->l;
443
0
    }
444
445
20.7k
    switch (genNameType) {
446
972
        case certURI:
447
972
            template = CERT_URITemplate;
448
972
            break;
449
1.70k
        case certRFC822Name:
450
1.70k
            template = CERT_RFC822NameTemplate;
451
1.70k
            break;
452
14.0k
        case certDNSName:
453
14.0k
            template = CERT_DNSNameTemplate;
454
14.0k
            break;
455
2.18k
        case certIPAddress:
456
2.18k
            template = CERT_IPAddressTemplate;
457
2.18k
            break;
458
480
        case certOtherName:
459
480
            template = CERTOtherNameTemplate;
460
480
            break;
461
515
        case certRegisterID:
462
515
            template = CERT_RegisteredIDTemplate;
463
515
            break;
464
41
        case certEDIPartyName:
465
41
            template = CERT_EDIPartyNameTemplate;
466
41
            break;
467
102
        case certX400Address:
468
102
            template = CERT_X400AddressTemplate;
469
102
            break;
470
594
        case certDirectoryName:
471
594
            template = CERT_DirectoryNameTemplate;
472
594
            break;
473
114
        default:
474
114
            goto loser;
475
20.7k
    }
476
20.6k
    rv = SEC_QuickDERDecodeItem(reqArena, genName, template, newEncodedName);
477
20.6k
    if (rv != SECSuccess)
478
527
        goto loser;
479
20.1k
    if (genNameType == certDirectoryName) {
480
543
        rv = SEC_QuickDERDecodeItem(reqArena, &(genName->name.directoryName),
481
543
                                    CERT_NameTemplate,
482
543
                                    &(genName->derDirectoryName));
483
543
        if (rv != SECSuccess)
484
275
            goto loser;
485
543
    }
486
487
    /* TODO: unmark arena */
488
19.8k
    return genName;
489
916
loser:
490
    /* TODO: release arena to mark */
491
916
    return NULL;
492
20.1k
}
493
494
CERTGeneralName *
495
cert_DecodeGeneralNames(PLArenaPool *arena, SECItem **encodedGenName)
496
5.55k
{
497
5.55k
    PRCList *head = NULL;
498
5.55k
    PRCList *tail = NULL;
499
5.55k
    CERTGeneralName *currentName = NULL;
500
501
5.55k
    PORT_Assert(arena);
502
5.55k
    if (!encodedGenName || !arena) {
503
2.80k
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
504
2.80k
        return NULL;
505
2.80k
    }
506
    /* TODO: mark arena */
507
22.6k
    while (*encodedGenName != NULL) {
508
20.7k
        currentName = CERT_DecodeGeneralName(arena, *encodedGenName, NULL);
509
20.7k
        if (currentName == NULL)
510
916
            break;
511
19.8k
        if (head == NULL) {
512
2.08k
            head = &(currentName->l);
513
2.08k
            tail = head;
514
2.08k
        }
515
19.8k
        currentName->l.next = head;
516
19.8k
        currentName->l.prev = tail;
517
19.8k
        tail = head->prev = tail->next = &(currentName->l);
518
19.8k
        encodedGenName++;
519
19.8k
    }
520
2.74k
    if (currentName) {
521
        /* TODO: unmark arena */
522
1.82k
        return CERT_GetNextGeneralName(currentName);
523
1.82k
    }
524
    /* TODO: release arena to mark */
525
916
    return NULL;
526
2.74k
}
527
528
void
529
CERT_DestroyGeneralName(CERTGeneralName *name)
530
0
{
531
0
    cert_DestroyGeneralNames(name);
532
0
}
533
534
SECStatus
535
cert_DestroyGeneralNames(CERTGeneralName *name)
536
0
{
537
0
    CERTGeneralName *first;
538
0
    CERTGeneralName *next = NULL;
539
540
0
    first = name;
541
0
    do {
542
0
        next = CERT_GetNextGeneralName(name);
543
0
        PORT_Free(name);
544
0
        name = next;
545
0
    } while (name != first);
546
0
    return SECSuccess;
547
0
}
548
549
static SECItem *
550
cert_EncodeNameConstraint(CERTNameConstraint *constraint, SECItem *dest,
551
                          PLArenaPool *arena)
552
0
{
553
0
    PORT_Assert(arena);
554
0
    if (dest == NULL) {
555
0
        dest = PORT_ArenaZNew(arena, SECItem);
556
0
        if (dest == NULL) {
557
0
            return NULL;
558
0
        }
559
0
    }
560
0
    CERT_EncodeGeneralName(&(constraint->name), &(constraint->DERName), arena);
561
562
0
    dest =
563
0
        SEC_ASN1EncodeItem(arena, dest, constraint, CERTNameConstraintTemplate);
564
0
    return dest;
565
0
}
566
567
SECStatus
568
cert_EncodeNameConstraintSubTree(CERTNameConstraint *constraints,
569
                                 PLArenaPool *arena, SECItem ***dest,
570
                                 PRBool permited)
571
0
{
572
0
    CERTNameConstraint *current_constraint = constraints;
573
0
    SECItem **items = NULL;
574
0
    int count = 0;
575
0
    int i;
576
0
    PRCList *head;
577
578
0
    PORT_Assert(arena);
579
    /* TODO: mark arena */
580
0
    if (constraints != NULL) {
581
0
        count = 1;
582
0
    }
583
0
    head = &constraints->l;
584
0
    while (current_constraint->l.next != head) {
585
0
        current_constraint = CERT_GetNextNameConstraint(current_constraint);
586
0
        ++count;
587
0
    }
588
0
    current_constraint = CERT_GetNextNameConstraint(current_constraint);
589
0
    items = PORT_ArenaZNewArray(arena, SECItem *, count + 1);
590
0
    if (items == NULL) {
591
0
        goto loser;
592
0
    }
593
0
    for (i = 0; i < count; i++) {
594
0
        items[i] = cert_EncodeNameConstraint(current_constraint,
595
0
                                             (SECItem *)NULL, arena);
596
0
        if (items[i] == NULL) {
597
0
            goto loser;
598
0
        }
599
0
        current_constraint = CERT_GetNextNameConstraint(current_constraint);
600
0
    }
601
0
    *dest = items;
602
0
    if (*dest == NULL) {
603
0
        goto loser;
604
0
    }
605
    /* TODO: unmark arena */
606
0
    return SECSuccess;
607
0
loser:
608
    /* TODO: release arena to mark */
609
0
    return SECFailure;
610
0
}
611
612
SECStatus
613
cert_EncodeNameConstraints(CERTNameConstraints *constraints, PLArenaPool *arena,
614
                           SECItem *dest)
615
0
{
616
0
    SECStatus rv = SECSuccess;
617
618
0
    PORT_Assert(arena);
619
    /* TODO: mark arena */
620
0
    if (constraints->permited != NULL) {
621
0
        rv = cert_EncodeNameConstraintSubTree(
622
0
            constraints->permited, arena, &constraints->DERPermited, PR_TRUE);
623
0
        if (rv == SECFailure) {
624
0
            goto loser;
625
0
        }
626
0
    }
627
0
    if (constraints->excluded != NULL) {
628
0
        rv = cert_EncodeNameConstraintSubTree(
629
0
            constraints->excluded, arena, &constraints->DERExcluded, PR_FALSE);
630
0
        if (rv == SECFailure) {
631
0
            goto loser;
632
0
        }
633
0
    }
634
0
    dest = SEC_ASN1EncodeItem(arena, dest, constraints,
635
0
                              CERTNameConstraintsTemplate);
636
0
    if (dest == NULL) {
637
0
        goto loser;
638
0
    }
639
    /* TODO: unmark arena */
640
0
    return SECSuccess;
641
0
loser:
642
    /* TODO: release arena to mark */
643
0
    return SECFailure;
644
0
}
645
646
CERTNameConstraint *
647
cert_DecodeNameConstraint(PLArenaPool *reqArena, SECItem *encodedConstraint)
648
0
{
649
0
    CERTNameConstraint *constraint;
650
0
    SECStatus rv = SECSuccess;
651
0
    CERTGeneralName *temp;
652
0
    SECItem *newEncodedConstraint;
653
654
0
    if (!reqArena) {
655
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
656
0
        return NULL;
657
0
    }
658
0
    newEncodedConstraint = SECITEM_ArenaDupItem(reqArena, encodedConstraint);
659
0
    if (!newEncodedConstraint) {
660
0
        return NULL;
661
0
    }
662
    /* TODO: mark arena */
663
0
    constraint = PORT_ArenaZNew(reqArena, CERTNameConstraint);
664
0
    if (!constraint)
665
0
        goto loser;
666
0
    rv = SEC_QuickDERDecodeItem(
667
0
        reqArena, constraint, CERTNameConstraintTemplate, newEncodedConstraint);
668
0
    if (rv != SECSuccess) {
669
0
        goto loser;
670
0
    }
671
0
    temp = CERT_DecodeGeneralName(reqArena, &(constraint->DERName),
672
0
                                  &(constraint->name));
673
0
    if (temp != &(constraint->name)) {
674
0
        goto loser;
675
0
    }
676
677
    /* ### sjlee: since the name constraint contains only one
678
     *            CERTGeneralName, the list within CERTGeneralName shouldn't
679
     *            point anywhere else.  Otherwise, bad things will happen.
680
     */
681
0
    constraint->name.l.prev = constraint->name.l.next = &(constraint->name.l);
682
    /* TODO: unmark arena */
683
0
    return constraint;
684
0
loser:
685
    /* TODO: release arena back to mark */
686
0
    return NULL;
687
0
}
688
689
static CERTNameConstraint *
690
cert_DecodeNameConstraintSubTree(PLArenaPool *arena, SECItem **subTree,
691
                                 PRBool permited)
692
0
{
693
0
    CERTNameConstraint *current = NULL;
694
0
    CERTNameConstraint *first = NULL;
695
0
    CERTNameConstraint *last = NULL;
696
0
    int i = 0;
697
698
0
    PORT_Assert(arena);
699
    /* TODO: mark arena */
700
0
    while (subTree[i] != NULL) {
701
0
        current = cert_DecodeNameConstraint(arena, subTree[i]);
702
0
        if (current == NULL) {
703
0
            goto loser;
704
0
        }
705
0
        if (first == NULL) {
706
0
            first = current;
707
0
        } else {
708
0
            current->l.prev = &(last->l);
709
0
            last->l.next = &(current->l);
710
0
        }
711
0
        last = current;
712
0
        i++;
713
0
    }
714
0
    if (first && last) {
715
0
        first->l.prev = &(last->l);
716
0
        last->l.next = &(first->l);
717
0
    }
718
    /* TODO: unmark arena */
719
0
    return first;
720
0
loser:
721
    /* TODO: release arena back to mark */
722
0
    return NULL;
723
0
}
724
725
CERTNameConstraints *
726
cert_DecodeNameConstraints(PLArenaPool *reqArena,
727
                           const SECItem *encodedConstraints)
728
16
{
729
16
    CERTNameConstraints *constraints;
730
16
    SECStatus rv;
731
16
    SECItem *newEncodedConstraints;
732
733
16
    if (!reqArena) {
734
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
735
0
        return NULL;
736
0
    }
737
16
    PORT_Assert(encodedConstraints);
738
16
    newEncodedConstraints = SECITEM_ArenaDupItem(reqArena, encodedConstraints);
739
740
    /* TODO: mark arena */
741
16
    constraints = PORT_ArenaZNew(reqArena, CERTNameConstraints);
742
16
    if (constraints == NULL) {
743
0
        goto loser;
744
0
    }
745
16
    rv = SEC_QuickDERDecodeItem(reqArena, constraints,
746
16
                                CERTNameConstraintsTemplate,
747
16
                                newEncodedConstraints);
748
16
    if (rv != SECSuccess) {
749
16
        goto loser;
750
16
    }
751
0
    if (constraints->DERPermited != NULL &&
752
0
        constraints->DERPermited[0] != NULL) {
753
0
        constraints->permited = cert_DecodeNameConstraintSubTree(
754
0
            reqArena, constraints->DERPermited, PR_TRUE);
755
0
        if (constraints->permited == NULL) {
756
0
            goto loser;
757
0
        }
758
0
    }
759
0
    if (constraints->DERExcluded != NULL &&
760
0
        constraints->DERExcluded[0] != NULL) {
761
0
        constraints->excluded = cert_DecodeNameConstraintSubTree(
762
0
            reqArena, constraints->DERExcluded, PR_FALSE);
763
0
        if (constraints->excluded == NULL) {
764
0
            goto loser;
765
0
        }
766
0
    }
767
    /* TODO: unmark arena */
768
0
    return constraints;
769
16
loser:
770
    /* TODO: release arena back to mark */
771
16
    return NULL;
772
0
}
773
774
/* Copy a chain of one or more general names to a destination chain.
775
** Caller has allocated at least the first destination GeneralName struct.
776
** Both source and destination chains are circular doubly-linked lists.
777
** The first source struct is copied to the first destination struct.
778
** If the source chain has more than one member, and the destination chain
779
** has only one member, then this function allocates new structs for all but
780
** the first copy from the arena and links them into the destination list.
781
** If the destination struct is part of a list with more than one member,
782
** then this function traverses both the source and destination lists,
783
** copying each source struct to the corresponding dest struct.
784
** In that case, the destination list MUST contain at least as many
785
** structs as the source list or some dest entries will be overwritten.
786
*/
787
SECStatus
788
CERT_CopyGeneralName(PLArenaPool *arena, CERTGeneralName *dest,
789
                     CERTGeneralName *src)
790
0
{
791
0
    SECStatus rv;
792
0
    CERTGeneralName *destHead = dest;
793
0
    CERTGeneralName *srcHead = src;
794
795
0
    PORT_Assert(dest != NULL);
796
0
    if (!dest) {
797
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
798
0
        return SECFailure;
799
0
    }
800
    /* TODO: mark arena */
801
0
    do {
802
0
        rv = cert_CopyOneGeneralName(arena, dest, src);
803
0
        if (rv != SECSuccess)
804
0
            goto loser;
805
0
        src = CERT_GetNextGeneralName(src);
806
        /* if there is only one general name, we shouldn't do this */
807
0
        if (src != srcHead) {
808
0
            if (dest->l.next == &destHead->l) {
809
0
                CERTGeneralName *temp;
810
0
                temp = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
811
0
                if (!temp)
812
0
                    goto loser;
813
0
                temp->l.next = &destHead->l;
814
0
                temp->l.prev = &dest->l;
815
0
                destHead->l.prev = &temp->l;
816
0
                dest->l.next = &temp->l;
817
0
                dest = temp;
818
0
            } else {
819
0
                dest = CERT_GetNextGeneralName(dest);
820
0
            }
821
0
        }
822
0
    } while (src != srcHead && rv == SECSuccess);
823
    /* TODO: unmark arena */
824
0
    return rv;
825
0
loser:
826
    /* TODO: release back to mark */
827
0
    return SECFailure;
828
0
}
829
830
CERTGeneralNameList *
831
CERT_DupGeneralNameList(CERTGeneralNameList *list)
832
0
{
833
0
    if (list != NULL) {
834
0
        PZ_Lock(list->lock);
835
0
        list->refCount++;
836
0
        PZ_Unlock(list->lock);
837
0
    }
838
0
    return list;
839
0
}
840
841
/* Allocate space and copy CERTNameConstraint from src to dest */
842
CERTNameConstraint *
843
CERT_CopyNameConstraint(PLArenaPool *arena, CERTNameConstraint *dest,
844
                        CERTNameConstraint *src)
845
0
{
846
0
    SECStatus rv;
847
848
    /* TODO: mark arena */
849
0
    if (dest == NULL) {
850
0
        dest = PORT_ArenaZNew(arena, CERTNameConstraint);
851
0
        if (!dest)
852
0
            goto loser;
853
        /* mark that it is not linked */
854
0
        dest->name.l.prev = dest->name.l.next = &(dest->name.l);
855
0
    }
856
0
    rv = CERT_CopyGeneralName(arena, &dest->name, &src->name);
857
0
    if (rv != SECSuccess) {
858
0
        goto loser;
859
0
    }
860
0
    rv = SECITEM_CopyItem(arena, &dest->DERName, &src->DERName);
861
0
    if (rv != SECSuccess) {
862
0
        goto loser;
863
0
    }
864
0
    rv = SECITEM_CopyItem(arena, &dest->min, &src->min);
865
0
    if (rv != SECSuccess) {
866
0
        goto loser;
867
0
    }
868
0
    rv = SECITEM_CopyItem(arena, &dest->max, &src->max);
869
0
    if (rv != SECSuccess) {
870
0
        goto loser;
871
0
    }
872
0
    dest->l.prev = dest->l.next = &dest->l;
873
    /* TODO: unmark arena */
874
0
    return dest;
875
0
loser:
876
    /* TODO: release arena to mark */
877
0
    return NULL;
878
0
}
879
880
CERTGeneralName *
881
cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2)
882
13.7k
{
883
13.7k
    PRCList *begin1;
884
13.7k
    PRCList *begin2;
885
13.7k
    PRCList *end1;
886
13.7k
    PRCList *end2;
887
888
13.7k
    if (list1 == NULL) {
889
6.56k
        return list2;
890
7.22k
    } else if (list2 == NULL) {
891
6.21k
        return list1;
892
6.21k
    } else {
893
1.01k
        begin1 = &list1->l;
894
1.01k
        begin2 = &list2->l;
895
1.01k
        end1 = list1->l.prev;
896
1.01k
        end2 = list2->l.prev;
897
1.01k
        end1->next = begin2;
898
1.01k
        end2->next = begin1;
899
1.01k
        begin1->prev = end2;
900
1.01k
        begin2->prev = end1;
901
1.01k
        return list1;
902
1.01k
    }
903
13.7k
}
904
905
CERTNameConstraint *
906
cert_CombineConstraintsLists(CERTNameConstraint *list1,
907
                             CERTNameConstraint *list2)
908
0
{
909
0
    PRCList *begin1;
910
0
    PRCList *begin2;
911
0
    PRCList *end1;
912
0
    PRCList *end2;
913
914
0
    if (list1 == NULL) {
915
0
        return list2;
916
0
    } else if (list2 == NULL) {
917
0
        return list1;
918
0
    } else {
919
0
        begin1 = &list1->l;
920
0
        begin2 = &list2->l;
921
0
        end1 = list1->l.prev;
922
0
        end2 = list2->l.prev;
923
0
        end1->next = begin2;
924
0
        end2->next = begin1;
925
0
        begin1->prev = end2;
926
0
        begin2->prev = end1;
927
0
        return list1;
928
0
    }
929
0
}
930
931
/* Add a CERTNameConstraint to the CERTNameConstraint list */
932
CERTNameConstraint *
933
CERT_AddNameConstraint(CERTNameConstraint *list, CERTNameConstraint *constraint)
934
0
{
935
0
    PORT_Assert(constraint != NULL);
936
0
    constraint->l.next = constraint->l.prev = &constraint->l;
937
0
    list = cert_CombineConstraintsLists(list, constraint);
938
0
    return list;
939
0
}
940
941
SECStatus
942
CERT_GetNameConstraintByType(CERTNameConstraint *constraints,
943
                             CERTGeneralNameType type,
944
                             CERTNameConstraint **returnList,
945
                             PLArenaPool *arena)
946
0
{
947
0
    CERTNameConstraint *current = NULL;
948
0
    void *mark = NULL;
949
950
0
    *returnList = NULL;
951
0
    if (!constraints)
952
0
        return SECSuccess;
953
954
0
    mark = PORT_ArenaMark(arena);
955
956
0
    current = constraints;
957
0
    do {
958
0
        PORT_Assert(current->name.type);
959
0
        if (current->name.type == type) {
960
0
            CERTNameConstraint *temp;
961
0
            temp = CERT_CopyNameConstraint(arena, NULL, current);
962
0
            if (temp == NULL)
963
0
                goto loser;
964
0
            *returnList = CERT_AddNameConstraint(*returnList, temp);
965
0
        }
966
0
        current = CERT_GetNextNameConstraint(current);
967
0
    } while (current != constraints);
968
0
    PORT_ArenaUnmark(arena, mark);
969
0
    return SECSuccess;
970
971
0
loser:
972
0
    PORT_ArenaRelease(arena, mark);
973
0
    return SECFailure;
974
0
}
975
976
void *
977
CERT_GetGeneralNameByType(CERTGeneralName *genNames, CERTGeneralNameType type,
978
                          PRBool derFormat)
979
111
{
980
111
    CERTGeneralName *current;
981
982
111
    if (!genNames)
983
0
        return NULL;
984
111
    current = genNames;
985
986
153
    do {
987
153
        if (current->type == type) {
988
79
            switch (type) {
989
0
                case certDNSName:
990
0
                case certEDIPartyName:
991
0
                case certIPAddress:
992
0
                case certRegisterID:
993
0
                case certRFC822Name:
994
0
                case certX400Address:
995
0
                case certURI:
996
0
                    return (void *)&current->name.other; /* SECItem * */
997
998
0
                case certOtherName:
999
0
                    return (void *)&current->name.OthName; /* OthName * */
1000
1001
79
                case certDirectoryName:
1002
79
                    return derFormat
1003
79
                               ? (void *)&current
1004
79
                                     ->derDirectoryName /* SECItem * */
1005
79
                               : (void *)&current->name
1006
0
                                     .directoryName; /* CERTName * */
1007
79
            }
1008
0
            PORT_Assert(0);
1009
0
            return NULL;
1010
79
        }
1011
74
        current = CERT_GetNextGeneralName(current);
1012
74
    } while (current != genNames);
1013
32
    return NULL;
1014
111
}
1015
1016
int
1017
CERT_GetNamesLength(CERTGeneralName *names)
1018
6.39k
{
1019
6.39k
    int length = 0;
1020
6.39k
    CERTGeneralName *first;
1021
1022
6.39k
    first = names;
1023
6.39k
    if (names != NULL) {
1024
10.3k
        do {
1025
10.3k
            length++;
1026
10.3k
            names = CERT_GetNextGeneralName(names);
1027
10.3k
        } while (names != first);
1028
6.39k
    }
1029
6.39k
    return length;
1030
6.39k
}
1031
1032
/* Creates new GeneralNames for any email addresses found in the
1033
** input DN, and links them onto the list for the DN.
1034
*/
1035
SECStatus
1036
cert_ExtractDNEmailAddrs(CERTGeneralName *name, PLArenaPool *arena)
1037
6.44k
{
1038
6.44k
    CERTGeneralName *nameList = NULL;
1039
6.44k
    const CERTRDN **nRDNs = (const CERTRDN **)(name->name.directoryName.rdns);
1040
6.44k
    SECStatus rv = SECSuccess;
1041
1042
6.44k
    PORT_Assert(name->type == certDirectoryName);
1043
6.44k
    if (name->type != certDirectoryName) {
1044
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1045
0
        return SECFailure;
1046
0
    }
1047
    /* TODO: mark arena */
1048
20.9k
    while (nRDNs && *nRDNs) { /* loop over RDNs */
1049
14.5k
        const CERTRDN *nRDN = *nRDNs++;
1050
14.5k
        CERTAVA **nAVAs = nRDN->avas;
1051
28.7k
        while (nAVAs && *nAVAs) { /* loop over AVAs */
1052
14.2k
            int tag;
1053
14.2k
            CERTAVA *nAVA = *nAVAs++;
1054
14.2k
            tag = CERT_GetAVATag(nAVA);
1055
14.2k
            if (tag == SEC_OID_PKCS9_EMAIL_ADDRESS ||
1056
14.2k
                tag == SEC_OID_RFC1274_MAIL) { /* email AVA */
1057
248
                CERTGeneralName *newName = NULL;
1058
248
                SECItem *avaValue = CERT_DecodeAVAValue(&nAVA->value);
1059
248
                if (!avaValue)
1060
56
                    goto loser;
1061
192
                rv = SECFailure;
1062
192
                newName = CERT_NewGeneralName(arena, certRFC822Name);
1063
192
                if (newName) {
1064
192
                    rv =
1065
192
                        SECITEM_CopyItem(arena, &newName->name.other, avaValue);
1066
192
                }
1067
192
                SECITEM_FreeItem(avaValue, PR_TRUE);
1068
192
                if (rv != SECSuccess)
1069
0
                    goto loser;
1070
192
                nameList = cert_CombineNamesLists(nameList, newName);
1071
192
            } /* handle one email AVA */
1072
14.2k
        }     /* loop over AVAs */
1073
14.5k
    }         /* loop over RDNs */
1074
    /* combine new names with old one. */
1075
6.39k
    (void)cert_CombineNamesLists(name, nameList);
1076
    /* TODO: unmark arena */
1077
6.39k
    return SECSuccess;
1078
1079
56
loser:
1080
    /* TODO: release arena back to mark */
1081
56
    return SECFailure;
1082
6.44k
}
1083
1084
/* Extract all names except Subject Common Name from a cert
1085
** in preparation for a name constraints test.
1086
*/
1087
CERTGeneralName *
1088
CERT_GetCertificateNames(CERTCertificate *cert, PLArenaPool *arena)
1089
0
{
1090
0
    return CERT_GetConstrainedCertificateNames(cert, arena, PR_FALSE);
1091
0
}
1092
1093
/* This function is called by CERT_VerifyCertChain to extract all
1094
** names from a cert in preparation for a name constraints test.
1095
*/
1096
CERTGeneralName *
1097
CERT_GetConstrainedCertificateNames(const CERTCertificate *cert,
1098
                                    PLArenaPool *arena,
1099
                                    PRBool includeSubjectCommonName)
1100
6.44k
{
1101
6.44k
    CERTGeneralName *DN;
1102
6.44k
    CERTGeneralName *SAN;
1103
6.44k
    PRUint32 numDNSNames = 0;
1104
6.44k
    SECStatus rv;
1105
1106
6.44k
    if (!arena) {
1107
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1108
0
        return NULL;
1109
0
    }
1110
    /* TODO: mark arena */
1111
6.44k
    DN = CERT_NewGeneralName(arena, certDirectoryName);
1112
6.44k
    if (DN == NULL) {
1113
0
        goto loser;
1114
0
    }
1115
6.44k
    rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject);
1116
6.44k
    if (rv != SECSuccess) {
1117
0
        goto loser;
1118
0
    }
1119
6.44k
    rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject);
1120
6.44k
    if (rv != SECSuccess) {
1121
0
        goto loser;
1122
0
    }
1123
    /* Extract email addresses from DN, construct CERTGeneralName structs
1124
    ** for them, add them to the name list
1125
    */
1126
6.44k
    rv = cert_ExtractDNEmailAddrs(DN, arena);
1127
6.44k
    if (rv != SECSuccess)
1128
56
        goto loser;
1129
1130
    /* Now extract any GeneralNames from the subject name names extension. */
1131
6.39k
    SAN = cert_GetSubjectAltNameList(cert, arena);
1132
6.39k
    if (SAN) {
1133
221
        numDNSNames = cert_CountDNSPatterns(SAN);
1134
221
        DN = cert_CombineNamesLists(DN, SAN);
1135
221
    }
1136
6.39k
    if (!numDNSNames && includeSubjectCommonName) {
1137
803
        char *cn = CERT_GetCommonName(&cert->subject);
1138
803
        if (cn) {
1139
597
            CERTGeneralName *CN = CERT_NewGeneralName(arena, certDNSName);
1140
597
            if (CN) {
1141
597
                SECItem cnItem = { siBuffer, NULL, 0 };
1142
597
                cnItem.data = (unsigned char *)cn;
1143
597
                cnItem.len = strlen(cn);
1144
597
                rv = SECITEM_CopyItem(arena, &CN->name.other, &cnItem);
1145
597
                if (rv == SECSuccess) {
1146
597
                    DN = cert_CombineNamesLists(DN, CN);
1147
597
                }
1148
597
            }
1149
597
            PORT_Free(cn);
1150
597
        }
1151
803
    }
1152
6.39k
    if (rv == SECSuccess) {
1153
        /* TODO: unmark arena */
1154
6.39k
        return DN;
1155
6.39k
    }
1156
56
loser:
1157
    /* TODO: release arena to mark */
1158
56
    return NULL;
1159
6.39k
}
1160
1161
/* Returns SECSuccess if name matches constraint per RFC 3280 rules for
1162
** URI name constraints.  SECFailure otherwise.
1163
** If the constraint begins with a dot, it is a domain name, otherwise
1164
** It is a host name.  Examples:
1165
**  Constraint            Name             Result
1166
** ------------      ---------------      --------
1167
**  foo.bar.com          foo.bar.com      matches
1168
**  foo.bar.com          FoO.bAr.CoM      matches
1169
**  foo.bar.com      www.foo.bar.com      no match
1170
**  foo.bar.com        nofoo.bar.com      no match
1171
** .foo.bar.com      www.foo.bar.com      matches
1172
** .foo.bar.com        nofoo.bar.com      no match
1173
** .foo.bar.com          foo.bar.com      no match
1174
** .foo.bar.com     www..foo.bar.com      no match
1175
*/
1176
static SECStatus
1177
compareURIN2C(const SECItem *name, const SECItem *constraint)
1178
0
{
1179
0
    int offset;
1180
    /* The spec is silent on intepreting zero-length constraints.
1181
    ** We interpret them as matching no URI names.
1182
    */
1183
0
    if (!constraint->len)
1184
0
        return SECFailure;
1185
0
    if (constraint->data[0] != '.') {
1186
        /* constraint is a host name. */
1187
0
        if (name->len != constraint->len ||
1188
0
            PL_strncasecmp((char *)name->data, (char *)constraint->data,
1189
0
                           constraint->len))
1190
0
            return SECFailure;
1191
0
        return SECSuccess;
1192
0
    }
1193
    /* constraint is a domain name. */
1194
0
    if (name->len < constraint->len)
1195
0
        return SECFailure;
1196
0
    offset = name->len - constraint->len;
1197
0
    if (PL_strncasecmp((char *)(name->data + offset), (char *)constraint->data,
1198
0
                       constraint->len))
1199
0
        return SECFailure;
1200
0
    if (!offset ||
1201
0
        (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
1202
0
        return SECSuccess;
1203
0
    return SECFailure;
1204
0
}
1205
1206
/* for DNSname constraints, RFC 3280 says, (section 4.2.1.11, page 38)
1207
**
1208
** DNS name restrictions are expressed as foo.bar.com.  Any DNS name
1209
** that can be constructed by simply adding to the left hand side of the
1210
** name satisfies the name constraint.  For example, www.foo.bar.com
1211
** would satisfy the constraint but foo1.bar.com would not.
1212
**
1213
** But NIST's PKITS test suite requires that the constraint be treated
1214
** as a domain name, and requires that any name added to the left hand
1215
** side end in a dot ".".  Sensible, but not strictly following the RFC.
1216
**
1217
**  Constraint            Name            RFC 3280  NIST PKITS
1218
** ------------      ---------------      --------  ----------
1219
**  foo.bar.com          foo.bar.com      matches    matches
1220
**  foo.bar.com          FoO.bAr.CoM      matches    matches
1221
**  foo.bar.com      www.foo.bar.com      matches    matches
1222
**  foo.bar.com        nofoo.bar.com      MATCHES    NO MATCH
1223
** .foo.bar.com      www.foo.bar.com      matches    matches? disallowed?
1224
** .foo.bar.com          foo.bar.com      no match   no match
1225
** .foo.bar.com     www..foo.bar.com      matches    probably not
1226
**
1227
** We will try to conform to NIST's PKITS tests, and the unstated
1228
** rules they imply.
1229
*/
1230
static SECStatus
1231
compareDNSN2C(const SECItem *name, const SECItem *constraint)
1232
0
{
1233
0
    int offset;
1234
    /* The spec is silent on intepreting zero-length constraints.
1235
    ** We interpret them as matching all DNSnames.
1236
    */
1237
0
    if (!constraint->len)
1238
0
        return SECSuccess;
1239
0
    if (name->len < constraint->len)
1240
0
        return SECFailure;
1241
0
    offset = name->len - constraint->len;
1242
0
    if (PL_strncasecmp((char *)(name->data + offset), (char *)constraint->data,
1243
0
                       constraint->len))
1244
0
        return SECFailure;
1245
0
    if (!offset ||
1246
0
        (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
1247
0
        return SECSuccess;
1248
0
    return SECFailure;
1249
0
}
1250
1251
/* Returns SECSuccess if name matches constraint per RFC 3280 rules for
1252
** internet email addresses.  SECFailure otherwise.
1253
** If constraint contains a '@' then the two strings much match exactly.
1254
** Else if constraint starts with a '.'. then it must match the right-most
1255
** substring of the name,
1256
** else constraint string must match entire name after the name's '@'.
1257
** Empty constraint string matches all names. All comparisons case insensitive.
1258
*/
1259
static SECStatus
1260
compareRFC822N2C(const SECItem *name, const SECItem *constraint)
1261
0
{
1262
0
    int offset;
1263
0
    if (!constraint->len)
1264
0
        return SECSuccess;
1265
0
    if (name->len < constraint->len)
1266
0
        return SECFailure;
1267
0
    if (constraint->len == 1 && constraint->data[0] == '.')
1268
0
        return SECSuccess;
1269
0
    for (offset = constraint->len - 1; offset >= 0; --offset) {
1270
0
        if (constraint->data[offset] == '@') {
1271
0
            return (name->len == constraint->len &&
1272
0
                    !PL_strncasecmp((char *)name->data,
1273
0
                                    (char *)constraint->data, constraint->len))
1274
0
                       ? SECSuccess
1275
0
                       : SECFailure;
1276
0
        }
1277
0
    }
1278
0
    offset = name->len - constraint->len;
1279
0
    if (PL_strncasecmp((char *)(name->data + offset), (char *)constraint->data,
1280
0
                       constraint->len))
1281
0
        return SECFailure;
1282
0
    if (constraint->data[0] == '.')
1283
0
        return SECSuccess;
1284
0
    if (offset > 0 && name->data[offset - 1] == '@')
1285
0
        return SECSuccess;
1286
0
    return SECFailure;
1287
0
}
1288
1289
/* name contains either a 4 byte IPv4 address or a 16 byte IPv6 address.
1290
** constraint contains an address of the same length, and a subnet mask
1291
** of the same length.  Compare name's address to the constraint's
1292
** address, subject to the mask.
1293
** Return SECSuccess if they match, SECFailure if they don't.
1294
*/
1295
static SECStatus
1296
compareIPaddrN2C(const SECItem *name, const SECItem *constraint)
1297
0
{
1298
0
    int i;
1299
0
    if (name->len == 4 && constraint->len == 8) { /* ipv4 addr */
1300
0
        for (i = 0; i < 4; i++) {
1301
0
            if ((name->data[i] ^ constraint->data[i]) & constraint->data[i + 4])
1302
0
                goto loser;
1303
0
        }
1304
0
        return SECSuccess;
1305
0
    }
1306
0
    if (name->len == 16 && constraint->len == 32) { /* ipv6 addr */
1307
0
        for (i = 0; i < 16; i++) {
1308
0
            if ((name->data[i] ^ constraint->data[i]) &
1309
0
                constraint->data[i + 16])
1310
0
                goto loser;
1311
0
        }
1312
0
        return SECSuccess;
1313
0
    }
1314
0
loser:
1315
0
    return SECFailure;
1316
0
}
1317
1318
/* start with a SECItem that points to a URI.  Parse it lookingg for
1319
** a hostname.  Modify item->data and item->len to define the hostname,
1320
** but do not modify and data at item->data.
1321
** If anything goes wrong, the contents of *item are undefined.
1322
*/
1323
static SECStatus
1324
parseUriHostname(SECItem *item)
1325
0
{
1326
0
    int i;
1327
0
    PRBool found = PR_FALSE;
1328
0
    for (i = 0; (unsigned)(i + 2) < item->len; ++i) {
1329
0
        if (item->data[i] == ':' && item->data[i + 1] == '/' &&
1330
0
            item->data[i + 2] == '/') {
1331
0
            i += 3;
1332
0
            item->data += i;
1333
0
            item->len -= i;
1334
0
            found = PR_TRUE;
1335
0
            break;
1336
0
        }
1337
0
    }
1338
0
    if (!found)
1339
0
        return SECFailure;
1340
    /* now look for a '/', which is an upper bound in the end of the name */
1341
0
    for (i = 0; (unsigned)i < item->len; ++i) {
1342
0
        if (item->data[i] == '/') {
1343
0
            item->len = i;
1344
0
            break;
1345
0
        }
1346
0
    }
1347
    /* now look for a ':', which marks the end of the name */
1348
0
    for (i = item->len; --i >= 0;) {
1349
0
        if (item->data[i] == ':') {
1350
0
            item->len = i;
1351
0
            break;
1352
0
        }
1353
0
    }
1354
    /* now look for an '@', which marks the beginning of the hostname */
1355
0
    for (i = 0; (unsigned)i < item->len; ++i) {
1356
0
        if (item->data[i] == '@') {
1357
0
            ++i;
1358
0
            item->data += i;
1359
0
            item->len -= i;
1360
0
            break;
1361
0
        }
1362
0
    }
1363
0
    return item->len ? SECSuccess : SECFailure;
1364
0
}
1365
1366
/* This function takes one name, and a list of constraints.
1367
** It searches the constraints looking for a match.
1368
** It returns SECSuccess if the name satisfies the constraints, i.e.,
1369
** if excluded, then the name does not match any constraint,
1370
** if permitted, then the name matches at least one constraint.
1371
** It returns SECFailure if the name fails to satisfy the constraints,
1372
** or if some code fails (e.g. out of memory, or invalid constraint)
1373
*/
1374
SECStatus
1375
cert_CompareNameWithConstraints(const CERTGeneralName *name,
1376
                                const CERTNameConstraint *constraints,
1377
                                PRBool excluded)
1378
0
{
1379
0
    SECStatus rv = SECSuccess;
1380
0
    SECStatus matched = SECFailure;
1381
0
    const CERTNameConstraint *current;
1382
1383
0
    PORT_Assert(constraints); /* caller should not call with NULL */
1384
0
    if (!constraints) {
1385
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1386
0
        return SECFailure;
1387
0
    }
1388
1389
0
    current = constraints;
1390
0
    do {
1391
0
        rv = SECSuccess;
1392
0
        matched = SECFailure;
1393
0
        PORT_Assert(name->type == current->name.type);
1394
0
        switch (name->type) {
1395
1396
0
            case certDNSName:
1397
0
                matched =
1398
0
                    compareDNSN2C(&name->name.other, &current->name.name.other);
1399
0
                break;
1400
1401
0
            case certRFC822Name:
1402
0
                matched = compareRFC822N2C(&name->name.other,
1403
0
                                           &current->name.name.other);
1404
0
                break;
1405
1406
0
            case certURI: {
1407
                /* make a modifiable copy of the URI SECItem. */
1408
0
                SECItem uri = name->name.other;
1409
                /* find the hostname in the URI */
1410
0
                rv = parseUriHostname(&uri);
1411
0
                if (rv == SECSuccess) {
1412
                    /* does our hostname meet the constraint? */
1413
0
                    matched = compareURIN2C(&uri, &current->name.name.other);
1414
0
                }
1415
0
            } break;
1416
1417
0
            case certDirectoryName:
1418
                /* Determine if the constraint directory name is a "prefix"
1419
                ** for the directory name being tested.
1420
                */
1421
0
                {
1422
                    /* status defaults to SECEqual, so that a constraint with
1423
                    ** no AVAs will be a wildcard, matching all directory names.
1424
                    */
1425
0
                    SECComparison status = SECEqual;
1426
0
                    const CERTRDN **cRDNs =
1427
0
                        (const CERTRDN **)current->name.name.directoryName.rdns;
1428
0
                    const CERTRDN **nRDNs =
1429
0
                        (const CERTRDN **)name->name.directoryName.rdns;
1430
0
                    while (cRDNs && *cRDNs && nRDNs && *nRDNs) {
1431
                        /* loop over name RDNs and constraint RDNs in lock step
1432
                         */
1433
0
                        const CERTRDN *cRDN = *cRDNs++;
1434
0
                        const CERTRDN *nRDN = *nRDNs++;
1435
0
                        CERTAVA **cAVAs = cRDN->avas;
1436
0
                        while (cAVAs &&
1437
0
                               *cAVAs) { /* loop over constraint AVAs */
1438
0
                            CERTAVA *cAVA = *cAVAs++;
1439
0
                            CERTAVA **nAVAs = nRDN->avas;
1440
0
                            while (nAVAs && *nAVAs) { /* loop over name AVAs */
1441
0
                                CERTAVA *nAVA = *nAVAs++;
1442
0
                                status = CERT_CompareAVA(cAVA, nAVA);
1443
0
                                if (status == SECEqual)
1444
0
                                    break;
1445
0
                            } /* loop over name AVAs */
1446
0
                            if (status != SECEqual)
1447
0
                                break;
1448
0
                        } /* loop over constraint AVAs */
1449
0
                        if (status != SECEqual)
1450
0
                            break;
1451
0
                    } /* loop over name RDNs and constraint RDNs */
1452
0
                    matched = (status == SECEqual) ? SECSuccess : SECFailure;
1453
0
                    break;
1454
0
                }
1455
1456
0
            case certIPAddress: /* type 8 */
1457
0
                matched = compareIPaddrN2C(&name->name.other,
1458
0
                                           &current->name.name.other);
1459
0
                break;
1460
1461
            /* NSS does not know how to compare these "Other" type names with
1462
            ** their respective constraints.  But it does know how to tell
1463
            ** if the constraint applies to the type of name (by comparing
1464
            ** the constraint OID to the name OID).  NSS makes no use of "Other"
1465
            ** type names at all, so NSS errs on the side of leniency for these
1466
            ** types, provided that their OIDs match.  So, when an "Other"
1467
            ** name constraint appears in an excluded subtree, it never causes
1468
            ** a name to fail.  When an "Other" name constraint appears in a
1469
            ** permitted subtree, AND the constraint's OID matches the name's
1470
            ** OID, then name is treated as if it matches the constraint.
1471
            */
1472
0
            case certOtherName: /* type 1 */
1473
0
                matched =
1474
0
                    (!excluded && name->type == current->name.type &&
1475
0
                     SECITEM_ItemsAreEqual(&name->name.OthName.oid,
1476
0
                                           &current->name.name.OthName.oid))
1477
0
                        ? SECSuccess
1478
0
                        : SECFailure;
1479
0
                break;
1480
1481
            /* NSS does not know how to compare these types of names with their
1482
            ** respective constraints.  But NSS makes no use of these types of
1483
            ** names at all, so it errs on the side of leniency for these types.
1484
            ** Constraints for these types of names never cause the name to
1485
            ** fail the constraints test.  NSS behaves as if the name matched
1486
            ** for permitted constraints, and did not match for excluded ones.
1487
            */
1488
0
            case certX400Address:  /* type 4 */
1489
0
            case certEDIPartyName: /* type 6 */
1490
0
            case certRegisterID:   /* type 9 */
1491
0
                matched = excluded ? SECFailure : SECSuccess;
1492
0
                break;
1493
1494
0
            default: /* non-standard types are not supported */
1495
0
                rv = SECFailure;
1496
0
                break;
1497
0
        }
1498
0
        if (matched == SECSuccess || rv != SECSuccess)
1499
0
            break;
1500
0
        current = CERT_GetNextNameConstraint((CERTNameConstraint *)current);
1501
0
    } while (current != constraints);
1502
0
    if (rv == SECSuccess) {
1503
0
        if (matched == SECSuccess)
1504
0
            rv = excluded ? SECFailure : SECSuccess;
1505
0
        else
1506
0
            rv = excluded ? SECSuccess : SECFailure;
1507
0
        return rv;
1508
0
    }
1509
1510
0
    return SECFailure;
1511
0
}
1512
1513
/* Add and link a CERTGeneralName to a CERTNameConstraint list. Most
1514
** likely the CERTNameConstraint passed in is either the permitted
1515
** list or the excluded list of a CERTNameConstraints.
1516
*/
1517
SECStatus
1518
CERT_AddNameConstraintByGeneralName(PLArenaPool *arena,
1519
                                    CERTNameConstraint **constraints,
1520
                                    CERTGeneralName *name)
1521
0
{
1522
0
    SECStatus rv;
1523
0
    CERTNameConstraint *current = NULL;
1524
0
    CERTNameConstraint *first = *constraints;
1525
0
    void *mark = NULL;
1526
1527
0
    mark = PORT_ArenaMark(arena);
1528
1529
0
    current = PORT_ArenaZNew(arena, CERTNameConstraint);
1530
0
    if (current == NULL) {
1531
0
        rv = SECFailure;
1532
0
        goto done;
1533
0
    }
1534
1535
0
    rv = cert_CopyOneGeneralName(arena, &current->name, name);
1536
0
    if (rv != SECSuccess) {
1537
0
        goto done;
1538
0
    }
1539
1540
0
    current->name.l.prev = current->name.l.next = &(current->name.l);
1541
1542
0
    if (first == NULL) {
1543
0
        *constraints = current;
1544
0
        PR_INIT_CLIST(&current->l);
1545
0
    } else {
1546
0
        PR_INSERT_BEFORE(&current->l, &first->l);
1547
0
    }
1548
1549
0
done:
1550
0
    if (rv == SECFailure) {
1551
0
        PORT_ArenaRelease(arena, mark);
1552
0
    } else {
1553
0
        PORT_ArenaUnmark(arena, mark);
1554
0
    }
1555
0
    return rv;
1556
0
}
1557
1558
/*
1559
 * Here we define a list of name constraints to be imposed on
1560
 * certain certificates, most importantly root certificates.
1561
 *
1562
 * Each entry in the name constraints list is constructed with this
1563
 * macro.  An entry contains two SECItems, which have names in
1564
 * specific forms to make the macro work:
1565
 *
1566
 *  * ${CA}_SUBJECT_DN - The subject DN for which the constraints
1567
 *                       should be applied
1568
 *  * ${CA}_NAME_CONSTRAINTS - The name constraints extension
1569
 *
1570
 * Entities subject to name constraints are identified by subject name
1571
 * so that we can cover all certificates for that entity, including, e.g.,
1572
 * cross-certificates.  We use subject rather than public key because
1573
 * calling methods often have easy access to that field (vs., say, a key ID),
1574
 * and in practice, subject names and public keys are usually in one-to-one
1575
 * correspondence anyway.
1576
 *
1577
 */
1578
1579
#define STRING_TO_SECITEM(str)                          \
1580
    {                                                   \
1581
        siBuffer, (unsigned char *)str, sizeof(str) - 1 \
1582
    }
1583
1584
#define NAME_CONSTRAINTS_ENTRY(CA)                   \
1585
    {                                                \
1586
        STRING_TO_SECITEM(CA##_SUBJECT_DN)           \
1587
        ,                                            \
1588
            STRING_TO_SECITEM(CA##_NAME_CONSTRAINTS) \
1589
    }
1590
1591
/* clang-format off */
1592
1593
/* Agence Nationale de la Securite des Systemes d'Information (ANSSI) */
1594
1595
#define ANSSI_SUBJECT_DN                                                       \
1596
    "\x30\x81\x85"                                                             \
1597
    "\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02" "FR"       /* C */          \
1598
    "\x31\x0F\x30\x0D\x06\x03\x55\x04\x08\x13\x06" "France"   /* ST */         \
1599
    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05" "Paris"    /* L */          \
1600
    "\x31\x10\x30\x0E\x06\x03\x55\x04\x0A\x13\x07" "PM/SGDN"  /* O */          \
1601
    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13\x05" "DCSSI"    /* OU */         \
1602
    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x03\x13\x05" "IGC/A"    /* CN */         \
1603
    "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01"             \
1604
    "\x16\x14" "igca@sgdn.pm.gouv.fr" /* emailAddress */                       \
1605
1606
#define ANSSI_NAME_CONSTRAINTS                                                 \
1607
    "\x30\x5D\xA0\x5B"                                                         \
1608
    "\x30\x05\x82\x03" ".fr"                                                   \
1609
    "\x30\x05\x82\x03" ".gp"                                                   \
1610
    "\x30\x05\x82\x03" ".gf"                                                   \
1611
    "\x30\x05\x82\x03" ".mq"                                                   \
1612
    "\x30\x05\x82\x03" ".re"                                                   \
1613
    "\x30\x05\x82\x03" ".yt"                                                   \
1614
    "\x30\x05\x82\x03" ".pm"                                                   \
1615
    "\x30\x05\x82\x03" ".bl"                                                   \
1616
    "\x30\x05\x82\x03" ".mf"                                                   \
1617
    "\x30\x05\x82\x03" ".wf"                                                   \
1618
    "\x30\x05\x82\x03" ".pf"                                                   \
1619
    "\x30\x05\x82\x03" ".nc"                                                   \
1620
    "\x30\x05\x82\x03" ".tf"
1621
1622
/* TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 */
1623
1624
#define TUBITAK1_SUBJECT_DN                                                    \
1625
    "\x30\x81\xd2"                                                             \
1626
    "\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02"                             \
1627
    /* C */ "TR"                                                               \
1628
    "\x31\x18\x30\x16\x06\x03\x55\x04\x07\x13\x0f"                             \
1629
    /* L */ "Gebze - Kocaeli"                                                  \
1630
    "\x31\x42\x30\x40\x06\x03\x55\x04\x0a\x13\x39"                             \
1631
    /* O */ "Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK"        \
1632
    "\x31\x2d\x30\x2b\x06\x03\x55\x04\x0b\x13\x24"                             \
1633
    /* OU */ "Kamu Sertifikasyon Merkezi - Kamu SM"                            \
1634
    "\x31\x36\x30\x34\x06\x03\x55\x04\x03\x13\x2d"                             \
1635
    /* CN */ "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1"
1636
1637
#define TUBITAK1_NAME_CONSTRAINTS                                              \
1638
    "\x30\x09\xa0\x07"                                                         \
1639
    "\x30\x05\x82\x03" ".tr"
1640
1641
/* clang-format on */
1642
1643
static const SECItem builtInNameConstraints[][2] = {
1644
    NAME_CONSTRAINTS_ENTRY(ANSSI),
1645
    NAME_CONSTRAINTS_ENTRY(TUBITAK1)
1646
};
1647
1648
SECStatus
1649
CERT_GetImposedNameConstraints(const SECItem *derSubject, SECItem *extensions)
1650
413
{
1651
413
    size_t i;
1652
1653
413
    if (!extensions) {
1654
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1655
0
        return SECFailure;
1656
0
    }
1657
1658
1.23k
    for (i = 0; i < PR_ARRAY_SIZE(builtInNameConstraints); ++i) {
1659
826
        if (SECITEM_ItemsAreEqual(derSubject, &builtInNameConstraints[i][0])) {
1660
0
            return SECITEM_CopyItem(NULL, extensions,
1661
0
                                    &builtInNameConstraints[i][1]);
1662
0
        }
1663
826
    }
1664
1665
413
    PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
1666
413
    return SECFailure;
1667
413
}
1668
1669
/*
1670
 * Extract the name constraints extension from the CA cert.
1671
 * If the certificate contains no name constraints extension, but
1672
 * CERT_GetImposedNameConstraints returns a name constraints extension
1673
 * for the subject of the certificate, then that extension will be returned.
1674
 */
1675
SECStatus
1676
CERT_FindNameConstraintsExten(PLArenaPool *arena, CERTCertificate *cert,
1677
                              CERTNameConstraints **constraints)
1678
429
{
1679
429
    SECStatus rv = SECSuccess;
1680
429
    SECItem constraintsExtension;
1681
429
    void *mark = NULL;
1682
1683
429
    *constraints = NULL;
1684
1685
429
    rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS,
1686
429
                                &constraintsExtension);
1687
429
    if (rv != SECSuccess) {
1688
413
        if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
1689
0
            return rv;
1690
0
        }
1691
413
        rv = CERT_GetImposedNameConstraints(&cert->derSubject,
1692
413
                                            &constraintsExtension);
1693
413
        if (rv != SECSuccess) {
1694
413
            if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
1695
413
                return SECSuccess;
1696
413
            }
1697
0
            return rv;
1698
413
        }
1699
413
    }
1700
1701
16
    mark = PORT_ArenaMark(arena);
1702
1703
16
    *constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
1704
16
    if (*constraints == NULL) { /* decode failed */
1705
16
        rv = SECFailure;
1706
16
    }
1707
16
    PORT_Free(constraintsExtension.data);
1708
1709
16
    if (rv == SECFailure) {
1710
16
        PORT_ArenaRelease(arena, mark);
1711
16
    } else {
1712
0
        PORT_ArenaUnmark(arena, mark);
1713
0
    }
1714
1715
16
    return rv;
1716
429
}
1717
1718
/* Verify name against all the constraints relevant to that type of
1719
** the name.
1720
*/
1721
SECStatus
1722
CERT_CheckNameSpace(PLArenaPool *arena, const CERTNameConstraints *constraints,
1723
                    const CERTGeneralName *currentName)
1724
0
{
1725
0
    CERTNameConstraint *matchingConstraints;
1726
0
    SECStatus rv = SECSuccess;
1727
1728
0
    if (constraints->excluded != NULL) {
1729
0
        rv = CERT_GetNameConstraintByType(constraints->excluded,
1730
0
                                          currentName->type,
1731
0
                                          &matchingConstraints, arena);
1732
0
        if (rv == SECSuccess && matchingConstraints != NULL) {
1733
0
            rv = cert_CompareNameWithConstraints(currentName,
1734
0
                                                 matchingConstraints, PR_TRUE);
1735
0
        }
1736
0
        if (rv != SECSuccess) {
1737
0
            return (rv);
1738
0
        }
1739
0
    }
1740
1741
0
    if (constraints->permited != NULL) {
1742
0
        rv = CERT_GetNameConstraintByType(constraints->permited,
1743
0
                                          currentName->type,
1744
0
                                          &matchingConstraints, arena);
1745
0
        if (rv == SECSuccess && matchingConstraints != NULL) {
1746
0
            rv = cert_CompareNameWithConstraints(currentName,
1747
0
                                                 matchingConstraints, PR_FALSE);
1748
0
        }
1749
0
        if (rv != SECSuccess) {
1750
0
            return (rv);
1751
0
        }
1752
0
    }
1753
1754
0
    return (SECSuccess);
1755
0
}
1756
1757
/* Extract the name constraints extension from the CA cert.
1758
** Test each and every name in namesList against all the constraints
1759
** relevant to that type of name.
1760
** Returns NULL in pBadCert for success, if all names are acceptable.
1761
** If some name is not acceptable, returns a pointer to the cert that
1762
** contained that name.
1763
*/
1764
SECStatus
1765
CERT_CompareNameSpace(CERTCertificate *cert, CERTGeneralName *namesList,
1766
                      CERTCertificate **certsList, PLArenaPool *reqArena,
1767
                      CERTCertificate **pBadCert)
1768
429
{
1769
429
    SECStatus rv = SECSuccess;
1770
429
    CERTNameConstraints *constraints;
1771
429
    CERTGeneralName *currentName;
1772
429
    int count = 0;
1773
429
    CERTCertificate *badCert = NULL;
1774
1775
    /* If no names to check, then no names can be bad. */
1776
429
    if (!namesList)
1777
0
        goto done;
1778
429
    rv = CERT_FindNameConstraintsExten(reqArena, cert, &constraints);
1779
429
    if (rv != SECSuccess) {
1780
16
        count = -1;
1781
16
        goto done;
1782
16
    }
1783
1784
413
    currentName = namesList;
1785
528
    do {
1786
528
        if (constraints) {
1787
0
            rv = CERT_CheckNameSpace(reqArena, constraints, currentName);
1788
0
            if (rv != SECSuccess) {
1789
0
                break;
1790
0
            }
1791
0
        }
1792
528
        currentName = CERT_GetNextGeneralName(currentName);
1793
528
        count++;
1794
528
    } while (currentName != namesList);
1795
1796
429
done:
1797
429
    if (rv != SECSuccess) {
1798
16
        badCert = (count >= 0) ? certsList[count] : cert;
1799
16
    }
1800
429
    if (pBadCert)
1801
429
        *pBadCert = badCert;
1802
1803
429
    return rv;
1804
413
}
1805
1806
#if 0
1807
/* not exported from shared libs, not used.  Turn on if we ever need it. */
1808
SECStatus
1809
CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b)
1810
{
1811
    CERTGeneralName *currentA;
1812
    CERTGeneralName *currentB;
1813
    PRBool found;
1814
1815
    currentA = a;
1816
    currentB = b;
1817
    if (a != NULL) {
1818
  do {
1819
      if (currentB == NULL) {
1820
    return SECFailure;
1821
      }
1822
      currentB = CERT_GetNextGeneralName(currentB);
1823
      currentA = CERT_GetNextGeneralName(currentA);
1824
  } while (currentA != a);
1825
    }
1826
    if (currentB != b) {
1827
  return SECFailure;
1828
    }
1829
    currentA = a;
1830
    do {
1831
  currentB = b;
1832
  found = PR_FALSE;
1833
  do {
1834
      if (currentB->type == currentA->type) {
1835
    switch (currentB->type) {
1836
      case certDNSName:
1837
      case certEDIPartyName:
1838
      case certIPAddress:
1839
      case certRegisterID:
1840
      case certRFC822Name:
1841
      case certX400Address:
1842
      case certURI:
1843
        if (SECITEM_CompareItem(&currentA->name.other,
1844
              &currentB->name.other)
1845
      == SECEqual) {
1846
      found = PR_TRUE;
1847
        }
1848
        break;
1849
      case certOtherName:
1850
        if (SECITEM_CompareItem(&currentA->name.OthName.oid,
1851
              &currentB->name.OthName.oid)
1852
      == SECEqual &&
1853
      SECITEM_CompareItem(&currentA->name.OthName.name,
1854
              &currentB->name.OthName.name)
1855
      == SECEqual) {
1856
      found = PR_TRUE;
1857
        }
1858
        break;
1859
      case certDirectoryName:
1860
        if (CERT_CompareName(&currentA->name.directoryName,
1861
           &currentB->name.directoryName)
1862
      == SECEqual) {
1863
      found = PR_TRUE;
1864
        }
1865
    }
1866
1867
      }
1868
      currentB = CERT_GetNextGeneralName(currentB);
1869
  } while (currentB != b && found != PR_TRUE);
1870
  if (found != PR_TRUE) {
1871
      return SECFailure;
1872
  }
1873
  currentA = CERT_GetNextGeneralName(currentA);
1874
    } while (currentA != a);
1875
    return SECSuccess;
1876
}
1877
1878
SECStatus
1879
CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b)
1880
{
1881
    SECStatus rv;
1882
1883
    if (a == b) {
1884
  return SECSuccess;
1885
    }
1886
    if (a != NULL && b != NULL) {
1887
  PZ_Lock(a->lock);
1888
  PZ_Lock(b->lock);
1889
  rv = CERT_CompareGeneralName(a->name, b->name);
1890
  PZ_Unlock(a->lock);
1891
  PZ_Unlock(b->lock);
1892
    } else {
1893
  rv = SECFailure;
1894
    }
1895
    return rv;
1896
}
1897
#endif
1898
1899
#if 0
1900
/* This function is not exported from NSS shared libraries, and is not
1901
** used inside of NSS.
1902
** XXX it doesn't check for failed allocations. :-(
1903
*/
1904
void *
1905
CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
1906
          CERTGeneralNameType type,
1907
          PLArenaPool *arena)
1908
{
1909
    CERTName *name = NULL;
1910
    SECItem *item = NULL;
1911
    OtherName *other = NULL;
1912
    OtherName *tmpOther = NULL;
1913
    void *data;
1914
1915
    PZ_Lock(list->lock);
1916
    data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE);
1917
    if (data != NULL) {
1918
  switch (type) {
1919
    case certDNSName:
1920
    case certEDIPartyName:
1921
    case certIPAddress:
1922
    case certRegisterID:
1923
    case certRFC822Name:
1924
    case certX400Address:
1925
    case certURI:
1926
      if (arena != NULL) {
1927
    item = PORT_ArenaNew(arena, SECItem);
1928
    if (item != NULL) {
1929
XXX       SECITEM_CopyItem(arena, item, (SECItem *) data);
1930
    }
1931
      } else {
1932
    item = SECITEM_DupItem((SECItem *) data);
1933
      }
1934
      PZ_Unlock(list->lock);
1935
      return item;
1936
    case certOtherName:
1937
      other = (OtherName *) data;
1938
      if (arena != NULL) {
1939
    tmpOther = PORT_ArenaNew(arena, OtherName);
1940
      } else {
1941
    tmpOther = PORT_New(OtherName);
1942
      }
1943
      if (tmpOther != NULL) {
1944
XXX   SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
1945
XXX   SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
1946
      }
1947
      PZ_Unlock(list->lock);
1948
      return tmpOther;
1949
    case certDirectoryName:
1950
      if (arena) {
1951
    name = PORT_ArenaZNew(list->arena, CERTName);
1952
    if (name) {
1953
XXX       CERT_CopyName(arena, name, (CERTName *) data);
1954
    }
1955
      }
1956
      PZ_Unlock(list->lock);
1957
      return name;
1958
  }
1959
    }
1960
    PZ_Unlock(list->lock);
1961
    return NULL;
1962
}
1963
#endif
1964
1965
#if 0
1966
/* This function is not exported from NSS shared libraries, and is not
1967
** used inside of NSS.
1968
** XXX it should NOT be a void function, since it does allocations
1969
** that can fail.
1970
*/
1971
void
1972
CERT_AddGeneralNameToList(CERTGeneralNameList *list,
1973
        CERTGeneralNameType type,
1974
        void *data, SECItem *oid)
1975
{
1976
    CERTGeneralName *name;
1977
1978
    if (list != NULL && data != NULL) {
1979
  PZ_Lock(list->lock);
1980
  name = CERT_NewGeneralName(list->arena, type);
1981
  if (!name)
1982
      goto done;
1983
  switch (type) {
1984
    case certDNSName:
1985
    case certEDIPartyName:
1986
    case certIPAddress:
1987
    case certRegisterID:
1988
    case certRFC822Name:
1989
    case certX400Address:
1990
    case certURI:
1991
XXX     SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
1992
      break;
1993
    case certOtherName:
1994
XXX     SECITEM_CopyItem(list->arena, &name->name.OthName.name,
1995
           (SECItem *) data);
1996
XXX     SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
1997
           oid);
1998
      break;
1999
    case certDirectoryName:
2000
XXX     CERT_CopyName(list->arena, &name->name.directoryName,
2001
        (CERTName *) data);
2002
      break;
2003
  }
2004
  list->name = cert_CombineNamesLists(list->name, name);
2005
  list->len++;
2006
done:
2007
  PZ_Unlock(list->lock);
2008
    }
2009
    return;
2010
}
2011
#endif