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