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

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

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

Powered by Google App Engine
This is Rietveld 408576698