comparison nss/lib/certdb/genname.c @ 0:1e5118fa0cb1

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