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