secname.c (18937B)
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 "cert.h" 6 #include "secoid.h" 7 #include "secder.h" /* XXX remove this when remove the DERTemplates */ 8 #include "secasn1.h" 9 #include "secitem.h" 10 #include <stdarg.h> 11 #include "secerr.h" 12 #include "certi.h" 13 14 static const SEC_ASN1Template cert_AVATemplate[] = { 15 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAVA) }, 16 { SEC_ASN1_OBJECT_ID, offsetof(CERTAVA, type) }, 17 { SEC_ASN1_ANY, offsetof(CERTAVA, value) }, 18 { 0 } 19 }; 20 21 const SEC_ASN1Template CERT_RDNTemplate[] = { 22 { SEC_ASN1_SET_OF, offsetof(CERTRDN, avas), cert_AVATemplate, 23 sizeof(CERTRDN) } 24 }; 25 26 static int 27 CountArray(void **array) 28 { 29 int count = 0; 30 if (array) { 31 while (*array++) { 32 count++; 33 } 34 } 35 return count; 36 } 37 38 static void ** 39 AddToArray(PLArenaPool *arena, void **array, void *element) 40 { 41 unsigned count; 42 void **ap; 43 44 /* Count up number of slots already in use in the array */ 45 count = 0; 46 ap = array; 47 if (ap) { 48 while (*ap++) { 49 count++; 50 } 51 } 52 53 if (array) { 54 array = 55 (void **)PORT_ArenaGrow(arena, array, (count + 1) * sizeof(void *), 56 (count + 2) * sizeof(void *)); 57 } else { 58 array = (void **)PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *)); 59 } 60 if (array) { 61 array[count] = element; 62 array[count + 1] = 0; 63 } 64 return array; 65 } 66 67 SECOidTag 68 CERT_GetAVATag(CERTAVA *ava) 69 { 70 SECOidData *oid; 71 if (!ava->type.data) 72 return (SECOidTag)-1; 73 74 oid = SECOID_FindOID(&ava->type); 75 76 if (oid) { 77 return (oid->offset); 78 } 79 return (SECOidTag)-1; 80 } 81 82 static SECStatus 83 SetupAVAType(PLArenaPool *arena, SECOidTag type, SECItem *it, unsigned *maxLenp) 84 { 85 unsigned char *oid; 86 unsigned oidLen; 87 unsigned char *cp; 88 int maxLen; 89 SECOidData *oidrec; 90 91 oidrec = SECOID_FindOIDByTag(type); 92 if (oidrec == NULL) 93 return SECFailure; 94 95 oid = oidrec->oid.data; 96 oidLen = oidrec->oid.len; 97 98 maxLen = cert_AVAOidTagToMaxLen(type); 99 if (maxLen < 0) { 100 PORT_SetError(SEC_ERROR_INVALID_ARGS); 101 return SECFailure; 102 } 103 104 it->data = cp = (unsigned char *)PORT_ArenaAlloc(arena, oidLen); 105 if (cp == NULL) { 106 return SECFailure; 107 } 108 it->len = oidLen; 109 PORT_Memcpy(cp, oid, oidLen); 110 *maxLenp = (unsigned)maxLen; 111 return SECSuccess; 112 } 113 114 static SECStatus 115 SetupAVAValue(PLArenaPool *arena, int valueType, const SECItem *in, 116 SECItem *out, unsigned maxLen) 117 { 118 PRUint8 *value, *cp, *ucs4Val; 119 unsigned valueLen, valueLenLen, total; 120 unsigned ucs4Len = 0, ucs4MaxLen; 121 122 value = in->data; 123 valueLen = in->len; 124 switch (valueType) { 125 case SEC_ASN1_PRINTABLE_STRING: 126 case SEC_ASN1_IA5_STRING: 127 case SEC_ASN1_T61_STRING: 128 case SEC_ASN1_UTF8_STRING: /* no conversion required */ 129 break; 130 case SEC_ASN1_UNIVERSAL_STRING: 131 ucs4MaxLen = valueLen * 6; 132 ucs4Val = (PRUint8 *)PORT_ArenaZAlloc(arena, ucs4MaxLen); 133 if (!ucs4Val || 134 !PORT_UCS4_UTF8Conversion(PR_TRUE, value, valueLen, ucs4Val, 135 ucs4MaxLen, &ucs4Len)) { 136 PORT_SetError(SEC_ERROR_INVALID_ARGS); 137 return SECFailure; 138 } 139 value = ucs4Val; 140 valueLen = ucs4Len; 141 maxLen *= 4; 142 break; 143 default: 144 PORT_SetError(SEC_ERROR_INVALID_ARGS); 145 return SECFailure; 146 } 147 148 if (valueLen > maxLen) { 149 PORT_SetError(SEC_ERROR_INVALID_ARGS); 150 return SECFailure; 151 } 152 153 valueLenLen = DER_LengthLength(valueLen); 154 total = 1 + valueLenLen + valueLen; 155 cp = (PRUint8 *)PORT_ArenaAlloc(arena, total); 156 if (!cp) { 157 return SECFailure; 158 } 159 out->data = cp; 160 out->len = total; 161 cp = (PRUint8 *)DER_StoreHeader(cp, valueType, valueLen); 162 PORT_Memcpy(cp, value, valueLen); 163 return SECSuccess; 164 } 165 166 CERTAVA * 167 CERT_CreateAVAFromRaw(PLArenaPool *pool, const SECItem *OID, 168 const SECItem *value) 169 { 170 CERTAVA *ava; 171 int rv; 172 173 ava = PORT_ArenaZNew(pool, CERTAVA); 174 if (ava) { 175 rv = SECITEM_CopyItem(pool, &ava->type, OID); 176 if (rv) 177 return NULL; 178 179 rv = SECITEM_CopyItem(pool, &ava->value, value); 180 if (rv) 181 return NULL; 182 } 183 return ava; 184 } 185 186 CERTAVA * 187 CERT_CreateAVAFromSECItem(PLArenaPool *arena, SECOidTag kind, int valueType, 188 SECItem *value) 189 { 190 CERTAVA *ava; 191 int rv; 192 unsigned maxLen; 193 194 ava = (CERTAVA *)PORT_ArenaZAlloc(arena, sizeof(CERTAVA)); 195 if (ava) { 196 rv = SetupAVAType(arena, kind, &ava->type, &maxLen); 197 if (rv) { 198 /* Illegal AVA type */ 199 return NULL; 200 } 201 rv = SetupAVAValue(arena, valueType, value, &ava->value, maxLen); 202 if (rv) { 203 /* Illegal value type */ 204 return NULL; 205 } 206 } 207 return ava; 208 } 209 210 CERTAVA * 211 CERT_CreateAVA(PLArenaPool *arena, SECOidTag kind, int valueType, char *value) 212 { 213 SECItem item = { siBuffer, NULL, 0 }; 214 215 item.data = (PRUint8 *)value; 216 item.len = PORT_Strlen(value); 217 218 return CERT_CreateAVAFromSECItem(arena, kind, valueType, &item); 219 } 220 221 CERTAVA * 222 CERT_CopyAVA(PLArenaPool *arena, CERTAVA *from) 223 { 224 CERTAVA *ava; 225 int rv; 226 227 ava = (CERTAVA *)PORT_ArenaZAlloc(arena, sizeof(CERTAVA)); 228 if (ava) { 229 rv = SECITEM_CopyItem(arena, &ava->type, &from->type); 230 if (rv) 231 goto loser; 232 rv = SECITEM_CopyItem(arena, &ava->value, &from->value); 233 if (rv) 234 goto loser; 235 } 236 return ava; 237 238 loser: 239 return 0; 240 } 241 242 CERTRDN * 243 CERT_CreateRDN(PLArenaPool *arena, CERTAVA *ava0, ...) 244 { 245 CERTAVA *ava; 246 CERTRDN *rdn; 247 va_list ap; 248 unsigned count; 249 CERTAVA **avap; 250 251 rdn = (CERTRDN *)PORT_ArenaAlloc(arena, sizeof(CERTRDN)); 252 if (rdn) { 253 /* Count number of avas going into the rdn */ 254 count = 0; 255 if (ava0) { 256 count++; 257 va_start(ap, ava0); 258 while (va_arg(ap, CERTAVA *) != 0) { 259 count++; 260 } 261 va_end(ap); 262 } 263 264 /* Now fill in the pointers */ 265 rdn->avas = avap = 266 (CERTAVA **)PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTAVA *)); 267 if (!avap) { 268 return 0; 269 } 270 if (ava0) { 271 *avap++ = ava0; 272 va_start(ap, ava0); 273 while ((ava = va_arg(ap, CERTAVA *)) != 0) { 274 *avap++ = ava; 275 } 276 va_end(ap); 277 } 278 *avap++ = 0; 279 } 280 return rdn; 281 } 282 283 SECStatus 284 CERT_AddAVA(PLArenaPool *arena, CERTRDN *rdn, CERTAVA *ava) 285 { 286 rdn->avas = (CERTAVA **)AddToArray(arena, (void **)rdn->avas, ava); 287 return rdn->avas ? SECSuccess : SECFailure; 288 } 289 290 SECStatus 291 CERT_CopyRDN(PLArenaPool *arena, CERTRDN *to, CERTRDN *from) 292 { 293 CERTAVA **avas, *fava, *tava; 294 SECStatus rv = SECSuccess; 295 296 /* Copy each ava from from */ 297 avas = from->avas; 298 if (avas) { 299 if (avas[0] == NULL) { 300 rv = CERT_AddAVA(arena, to, NULL); 301 return rv; 302 } 303 while ((fava = *avas++) != 0) { 304 tava = CERT_CopyAVA(arena, fava); 305 if (!tava) { 306 rv = SECFailure; 307 break; 308 } 309 rv = CERT_AddAVA(arena, to, tava); 310 if (rv != SECSuccess) 311 break; 312 } 313 } 314 return rv; 315 } 316 317 /************************************************************************/ 318 319 const SEC_ASN1Template CERT_NameTemplate[] = { 320 { SEC_ASN1_SEQUENCE_OF, offsetof(CERTName, rdns), CERT_RDNTemplate, 321 sizeof(CERTName) } 322 }; 323 324 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_NameTemplate) 325 326 CERTName * 327 CERT_CreateName(CERTRDN *rdn0, ...) 328 { 329 CERTRDN *rdn; 330 CERTName *name; 331 va_list ap; 332 unsigned count; 333 CERTRDN **rdnp; 334 PLArenaPool *arena; 335 336 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 337 if (!arena) { 338 return (0); 339 } 340 341 name = (CERTName *)PORT_ArenaAlloc(arena, sizeof(CERTName)); 342 if (name) { 343 name->arena = arena; 344 345 /* Count number of RDNs going into the Name */ 346 if (!rdn0) { 347 count = 0; 348 } else { 349 count = 1; 350 va_start(ap, rdn0); 351 while (va_arg(ap, CERTRDN *) != 0) { 352 count++; 353 } 354 va_end(ap); 355 } 356 357 /* Allocate space (including space for terminal null ptr) */ 358 name->rdns = rdnp = 359 (CERTRDN **)PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTRDN *)); 360 if (!name->rdns) { 361 goto loser; 362 } 363 364 /* Now fill in the pointers */ 365 if (count > 0) { 366 *rdnp++ = rdn0; 367 va_start(ap, rdn0); 368 while ((rdn = va_arg(ap, CERTRDN *)) != 0) { 369 *rdnp++ = rdn; 370 } 371 va_end(ap); 372 } 373 374 /* null terminate the list */ 375 *rdnp++ = 0; 376 } 377 return name; 378 379 loser: 380 PORT_FreeArena(arena, PR_FALSE); 381 return (0); 382 } 383 384 void 385 CERT_DestroyName(CERTName *name) 386 { 387 if (name) { 388 PLArenaPool *arena = name->arena; 389 name->rdns = NULL; 390 name->arena = NULL; 391 if (arena) 392 PORT_FreeArena(arena, PR_FALSE); 393 } 394 } 395 396 SECStatus 397 CERT_AddRDN(CERTName *name, CERTRDN *rdn) 398 { 399 name->rdns = (CERTRDN **)AddToArray(name->arena, (void **)name->rdns, rdn); 400 return name->rdns ? SECSuccess : SECFailure; 401 } 402 403 SECStatus 404 CERT_CopyName(PLArenaPool *arena, CERTName *to, const CERTName *from) 405 { 406 CERTRDN **rdns, *frdn, *trdn; 407 SECStatus rv = SECSuccess; 408 409 if (!to || !from) { 410 PORT_SetError(SEC_ERROR_INVALID_ARGS); 411 return SECFailure; 412 } 413 414 CERT_DestroyName(to); 415 to->arena = arena; 416 417 /* Copy each rdn from from */ 418 rdns = from->rdns; 419 if (rdns) { 420 if (rdns[0] == NULL) { 421 rv = CERT_AddRDN(to, NULL); 422 return rv; 423 } 424 while ((frdn = *rdns++) != NULL) { 425 trdn = CERT_CreateRDN(arena, NULL); 426 if (!trdn) { 427 rv = SECFailure; 428 break; 429 } 430 rv = CERT_CopyRDN(arena, trdn, frdn); 431 if (rv != SECSuccess) 432 break; 433 rv = CERT_AddRDN(to, trdn); 434 if (rv != SECSuccess) 435 break; 436 } 437 } 438 return rv; 439 } 440 441 /************************************************************************/ 442 443 static void 444 canonicalize(SECItem *foo) 445 { 446 int ch, lastch, len, src, dest; 447 448 /* strip trailing whitespace. */ 449 len = foo->len; 450 while (len > 0 && ((ch = foo->data[len - 1]) == ' ' || ch == '\t' || 451 ch == '\r' || ch == '\n')) { 452 len--; 453 } 454 455 src = 0; 456 /* strip leading whitespace. */ 457 while (src < len && ((ch = foo->data[src]) == ' ' || ch == '\t' || 458 ch == '\r' || ch == '\n')) { 459 src++; 460 } 461 dest = 0; 462 lastch = ' '; 463 while (src < len) { 464 ch = foo->data[src++]; 465 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') { 466 ch = ' '; 467 if (ch == lastch) 468 continue; 469 } else if (ch >= 'A' && ch <= 'Z') { 470 ch |= 0x20; /* downshift */ 471 } 472 foo->data[dest++] = lastch = ch; 473 } 474 foo->len = dest; 475 } 476 477 /* SECItems a and b contain DER-encoded printable strings. */ 478 SECComparison 479 CERT_CompareDERPrintableStrings(const SECItem *a, const SECItem *b) 480 { 481 SECComparison rv = SECLessThan; 482 SECItem *aVal = CERT_DecodeAVAValue(a); 483 SECItem *bVal = CERT_DecodeAVAValue(b); 484 485 if (aVal && aVal->len && aVal->data && bVal && bVal->len && bVal->data) { 486 canonicalize(aVal); 487 canonicalize(bVal); 488 rv = SECITEM_CompareItem(aVal, bVal); 489 } 490 SECITEM_FreeItem(aVal, PR_TRUE); 491 SECITEM_FreeItem(bVal, PR_TRUE); 492 return rv; 493 } 494 495 SECComparison 496 CERT_CompareAVA(const CERTAVA *a, const CERTAVA *b) 497 { 498 SECComparison rv; 499 500 rv = SECITEM_CompareItem(&a->type, &b->type); 501 if (SECEqual != rv) 502 return rv; /* Attribute types don't match. */ 503 /* Let's be optimistic. Maybe the values will just compare equal. */ 504 rv = SECITEM_CompareItem(&a->value, &b->value); 505 if (SECEqual == rv) 506 return rv; /* values compared exactly. */ 507 if (a->value.len && a->value.data && b->value.len && b->value.data) { 508 /* Here, the values did not match. 509 ** If the values had different encodings, convert them to the same 510 ** encoding and compare that way. 511 */ 512 if (a->value.data[0] != b->value.data[0]) { 513 /* encodings differ. Convert both to UTF-8 and compare. */ 514 SECItem *aVal = CERT_DecodeAVAValue(&a->value); 515 SECItem *bVal = CERT_DecodeAVAValue(&b->value); 516 if (aVal && aVal->len && aVal->data && bVal && bVal->len && 517 bVal->data) { 518 rv = SECITEM_CompareItem(aVal, bVal); 519 } 520 SECITEM_FreeItem(aVal, PR_TRUE); 521 SECITEM_FreeItem(bVal, PR_TRUE); 522 } else if (a->value.data[0] == 0x13) { /* both are printable strings. */ 523 /* printable strings */ 524 rv = CERT_CompareDERPrintableStrings(&a->value, &b->value); 525 } 526 } 527 return rv; 528 } 529 530 SECComparison 531 CERT_CompareRDN(const CERTRDN *a, const CERTRDN *b) 532 { 533 CERTAVA **aavas, *aava; 534 CERTAVA **bavas, *bava; 535 int ac, bc; 536 SECComparison rv = SECEqual; 537 538 aavas = a->avas; 539 bavas = b->avas; 540 541 /* 542 ** Make sure array of ava's are the same length. If not, then we are 543 ** not equal 544 */ 545 ac = CountArray((void **)aavas); 546 bc = CountArray((void **)bavas); 547 if (ac < bc) 548 return SECLessThan; 549 if (ac > bc) 550 return SECGreaterThan; 551 552 while (NULL != (aava = *aavas++)) { 553 for (bavas = b->avas; NULL != (bava = *bavas++);) { 554 rv = SECITEM_CompareItem(&aava->type, &bava->type); 555 if (SECEqual == rv) { 556 rv = CERT_CompareAVA(aava, bava); 557 if (SECEqual != rv) 558 return rv; 559 break; 560 } 561 } 562 if (!bava) /* didn't find a match */ 563 return SECGreaterThan; 564 } 565 return rv; 566 } 567 568 SECComparison 569 CERT_CompareName(const CERTName *a, const CERTName *b) 570 { 571 CERTRDN **ardns; 572 CERTRDN **brdns; 573 int ac, bc; 574 SECComparison rv = SECEqual; 575 576 ardns = a->rdns; 577 brdns = b->rdns; 578 579 /* 580 ** Make sure array of rdn's are the same length. If not, then we are 581 ** not equal 582 */ 583 ac = CountArray((void **)ardns); 584 bc = CountArray((void **)brdns); 585 if (ac < bc) 586 return SECLessThan; 587 if (ac > bc) 588 return SECGreaterThan; 589 590 while (rv == SECEqual && *ardns) { 591 rv = CERT_CompareRDN(*ardns++, *brdns++); 592 } 593 return rv; 594 } 595 596 /* Moved from certhtml.c */ 597 SECItem * 598 CERT_DecodeAVAValue(const SECItem *derAVAValue) 599 { 600 SECItem *retItem; 601 const SEC_ASN1Template *theTemplate = NULL; 602 enum { conv_none, 603 conv_ucs4, 604 conv_ucs2, 605 conv_iso88591 } convert = conv_none; 606 SECItem avaValue = { siBuffer, 0 }; 607 PORTCheapArenaPool tmpArena; 608 609 if (!derAVAValue || !derAVAValue->len || !derAVAValue->data) { 610 PORT_SetError(SEC_ERROR_INVALID_ARGS); 611 return NULL; 612 } 613 614 switch (derAVAValue->data[0]) { 615 case SEC_ASN1_UNIVERSAL_STRING: 616 convert = conv_ucs4; 617 theTemplate = SEC_ASN1_GET(SEC_UniversalStringTemplate); 618 break; 619 case SEC_ASN1_IA5_STRING: 620 theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate); 621 break; 622 case SEC_ASN1_PRINTABLE_STRING: 623 theTemplate = SEC_ASN1_GET(SEC_PrintableStringTemplate); 624 break; 625 case SEC_ASN1_T61_STRING: 626 /* 627 * Per common practice, we're not decoding actual T.61, but instead 628 * treating T61-labeled strings as containing ISO-8859-1. 629 */ 630 convert = conv_iso88591; 631 theTemplate = SEC_ASN1_GET(SEC_T61StringTemplate); 632 break; 633 case SEC_ASN1_BMP_STRING: 634 convert = conv_ucs2; 635 theTemplate = SEC_ASN1_GET(SEC_BMPStringTemplate); 636 break; 637 case SEC_ASN1_UTF8_STRING: 638 /* No conversion needed ! */ 639 theTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate); 640 break; 641 default: 642 PORT_SetError(SEC_ERROR_INVALID_AVA); 643 return NULL; 644 } 645 646 PORT_Memset(&avaValue, 0, sizeof(SECItem)); 647 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); 648 if (SEC_QuickDERDecodeItem(&tmpArena.arena, &avaValue, theTemplate, 649 derAVAValue) != SECSuccess) { 650 PORT_DestroyCheapArena(&tmpArena); 651 return NULL; 652 } 653 654 if (convert != conv_none) { 655 unsigned int utf8ValLen = avaValue.len * 3; 656 unsigned char *utf8Val = 657 (unsigned char *)PORT_ArenaZAlloc(&tmpArena.arena, utf8ValLen); 658 659 switch (convert) { 660 case conv_ucs4: 661 if (avaValue.len % 4 != 0 || 662 !PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data, 663 avaValue.len, utf8Val, utf8ValLen, 664 &utf8ValLen)) { 665 PORT_DestroyCheapArena(&tmpArena); 666 PORT_SetError(SEC_ERROR_INVALID_AVA); 667 return NULL; 668 } 669 break; 670 case conv_ucs2: 671 if (avaValue.len % 2 != 0 || 672 !PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data, 673 avaValue.len, utf8Val, utf8ValLen, 674 &utf8ValLen)) { 675 PORT_DestroyCheapArena(&tmpArena); 676 PORT_SetError(SEC_ERROR_INVALID_AVA); 677 return NULL; 678 } 679 break; 680 case conv_iso88591: 681 if (!PORT_ISO88591_UTF8Conversion(avaValue.data, avaValue.len, 682 utf8Val, utf8ValLen, 683 &utf8ValLen)) { 684 PORT_DestroyCheapArena(&tmpArena); 685 PORT_SetError(SEC_ERROR_INVALID_AVA); 686 return NULL; 687 } 688 break; 689 case conv_none: 690 PORT_Assert(0); /* not reached */ 691 break; 692 } 693 694 avaValue.data = utf8Val; 695 avaValue.len = utf8ValLen; 696 } 697 698 retItem = SECITEM_DupItem(&avaValue); 699 PORT_DestroyCheapArena(&tmpArena); 700 return retItem; 701 }