security/nss/lib/certdb/genname.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial