| 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 |