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