Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(218)

Side by Side Diff: nss/lib/certdb/genname.c

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

Powered by Google App Engine
This is Rietveld 408576698