1/* 2 * extenTest - verify encoding and decoding of extensions. 3 */ 4 5#include <security_cdsa_utils/cuFileIo.h> 6#include <clAppUtils/CertBuilderApp.h> 7#include <utilLib/common.h> 8#include <utilLib/cspwrap.h> 9#include <clAppUtils/clutils.h> 10#include <security_cdsa_utils/cuPrintCert.h> 11#include <security_cdsa_utils/cuOidParser.h> 12#include <stdlib.h> 13#include <stdio.h> 14#include <string.h> 15#include <time.h> 16#include <Security/cssm.h> 17#include <Security/x509defs.h> 18#include <Security/oidsattr.h> 19#include <Security/oidscert.h> 20#include <Security/certextensions.h> 21 22#define KEY_ALG CSSM_ALGID_RSA 23#define SIG_ALG CSSM_ALGID_SHA1WithRSA 24#define KEY_SIZE_BITS CSP_RSA_KEY_SIZE_DEFAULT 25#define SUBJ_KEY_LABEL "subjectKey" 26 27#define LOOPS_DEF 10 28 29static void usage(char **argv) 30{ 31 printf("Usage: %s [options]\n", argv[0]); 32 printf("Options:\n"); 33 printf(" e=extenSpec (default = all)\n"); 34 printf(" k keyUsage\n"); 35 printf(" b basicConstraints\n"); 36 printf(" x extendedKeyUsage\n"); 37 printf(" s subjectKeyId\n"); 38 printf(" a authorityKeyId\n"); 39 printf(" t SubjectAltName\n"); 40 printf(" i IssuerAltName\n"); 41 printf(" c certPolicies\n"); 42 printf(" n netscapeCertType\n"); 43 printf(" p CRLDistributionPoints\n"); 44 printf(" A AuthorityInfoAccess\n"); 45 printf(" S SubjectInfoAccess\n"); 46 printf(" q QualifiedCertStatements\n"); 47 printf(" w(rite blobs)\n"); 48 printf(" f=fileName (default is extension-specific file name)\n"); 49 printf(" d(isplay certs)\n"); 50 printf(" l=loops (default = %d)\n", LOOPS_DEF); 51 printf(" p(ause on each loop)\n"); 52 printf(" P(ause on each cert)\n"); 53 exit(1); 54} 55 56/* dummy RDN - subject and issuer - we aren't testing this */ 57CB_NameOid dummyRdn[] = 58{ 59 { "Apple Computer", &CSSMOID_OrganizationName }, 60 { "Doug Mitchell", &CSSMOID_CommonName } 61}; 62#define NUM_DUMMY_NAMES (sizeof(dummyRdn) / sizeof(CB_NameOid)) 63 64/* 65 * Static components we reuse for each encode/decode. 66 */ 67static CSSM_X509_NAME *dummyName; 68static CSSM_X509_TIME *notBefore; // UTC-style "not before" time 69static CSSM_X509_TIME *notAfter; // UTC-style "not after" time 70static CSSM_KEY subjPrivKey; 71static CSSM_KEY subjPubKey; 72 73static CSSM_BOOL randBool() 74{ 75 unsigned r = genRand(1, 0x10000000); 76 return (r & 0x1) ? CSSM_TRUE : CSSM_FALSE; 77} 78 79/* Fill a CSSM_DATA with random data. Its referent is allocd with malloc. */ 80static void randData( 81 CSSM_DATA_PTR data, 82 uint8 maxLen) 83{ 84 data->Data = (uint8 *)malloc(maxLen); 85 simpleGenData(data, 1, maxLen); 86} 87 88/* 89 * Various compare tests 90 */ 91int compBool( 92 CSSM_BOOL pre, 93 CSSM_BOOL post, 94 const char *desc) 95{ 96 if(pre == post) { 97 return 0; 98 } 99 printf("***Boolean miscompare on %s\n", desc); 100 /* in case a CSSM_TRUE isn't exactly right... */ 101 switch(post) { 102 case CSSM_FALSE: 103 case CSSM_TRUE: 104 break; 105 default: 106 printf("*** post value is %d expected %d\n", 107 (int)post, (int)pre); 108 break; 109 } 110 return 1; 111} 112 113static int compCssmData( 114 CSSM_DATA &d1, 115 CSSM_DATA &d2, 116 const char *desc) 117{ 118 if(appCompareCssmData(&d1, &d2)) { 119 return 0; 120 } 121 printf("CSSM_DATA miscompare on %s\n", desc); 122 return 1; 123} 124 125#pragma mark ----- individual extension tests ----- 126 127#pragma mark --- CE_KeyUsage --- 128static void kuCreate(void *arg) 129{ 130 CE_KeyUsage *ku = (CE_KeyUsage *)arg; 131 132 /* set two random valid bits */ 133 *ku = 0; 134 *ku |= 1 << genRand(7, 15); 135 *ku |= 1 << genRand(7, 15); 136} 137 138static unsigned kuCompare(const void *pre, const void *post) 139{ 140 const CE_KeyUsage *kuPre = (CE_KeyUsage *)pre; 141 const CE_KeyUsage *kuPost = (CE_KeyUsage *)post; 142 if(*kuPre != *kuPost) { 143 printf("***Miscompare in CE_KeyUsage\n"); 144 return 1; 145 } 146 return 0; 147} 148 149#pragma mark --- CE_BasicConstraints --- 150static void bcCreate(void *arg) 151{ 152 CE_BasicConstraints *bc = (CE_BasicConstraints *)arg; 153 bc->cA = randBool(); 154 bc->pathLenConstraintPresent = randBool(); 155 if(bc->pathLenConstraintPresent) { 156 bc->pathLenConstraint = genRand(1,10); 157 } 158} 159 160static unsigned bcCompare(const void *pre, const void *post) 161{ 162 const CE_BasicConstraints *bcpre = (CE_BasicConstraints *)pre; 163 const CE_BasicConstraints *bcpost = (CE_BasicConstraints *)post; 164 unsigned rtn = 0; 165 166 rtn += compBool(bcpre->cA, bcpost->cA, "BasicConstraints.cA"); 167 rtn += compBool(bcpre->pathLenConstraintPresent, 168 bcpost->pathLenConstraintPresent, 169 "BasicConstraints.pathLenConstraintPresent"); 170 if(bcpre->pathLenConstraint != bcpost->pathLenConstraint) { 171 printf("BasicConstraints.pathLenConstraint mismatch\n"); 172 rtn++; 173 } 174 return rtn; 175} 176 177#pragma mark --- CE_SubjectKeyID --- 178static void skidCreate(void *arg) 179{ 180 CSSM_DATA_PTR skid = (CSSM_DATA_PTR)arg; 181 randData(skid, 16); 182} 183 184static unsigned skidCompare(const void *pre, const void *post) 185{ 186 CSSM_DATA_PTR spre = (CSSM_DATA_PTR)pre; 187 CSSM_DATA_PTR spost = (CSSM_DATA_PTR)post; 188 return compCssmData(*spre, *spost, "SubjectKeyID"); 189} 190 191static void skidFree(void *arg) 192{ 193 CSSM_DATA_PTR skid = (CSSM_DATA_PTR)arg; 194 free(skid->Data); 195} 196 197#pragma mark --- CE_NetscapeCertType --- 198static void nctCreate(void *arg) 199{ 200 CE_NetscapeCertType *nct = (CE_NetscapeCertType *)arg; 201 202 /* set two random valid bits */ 203 *nct = 0; 204 *nct |= 1 << genRand(8, 15); 205 *nct |= 1 << genRand(8, 15); 206} 207 208static unsigned nctCompare(const void *pre, const void *post) 209{ 210 const CE_NetscapeCertType *nPre = (CE_NetscapeCertType *)pre; 211 const CE_NetscapeCertType *nPost = (CE_NetscapeCertType *)post; 212 if(*nPre != *nPost) { 213 printf("***Miscompare in CE_NetscapeCertType\n"); 214 return 1; 215 } 216 return 0; 217} 218 219#pragma mark --- CE_ExtendedKeyUsage --- 220 221/* a static array of meaningless OIDs, use 1.. NUM_SKU_OIDS */ 222CSSM_OID ekuOids[] = { 223 CSSMOID_CrlNumber, 224 CSSMOID_CrlReason, 225 CSSMOID_HoldInstructionCode, 226 CSSMOID_InvalidityDate 227}; 228#define NUM_SKU_OIDS 4 229 230static void ekuCreate(void *arg) 231{ 232 CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)arg; 233 eku->numPurposes = genRand(1, NUM_SKU_OIDS); 234 eku->purposes = ekuOids; 235} 236 237static unsigned ekuCompare(const void *pre, const void *post) 238{ 239 CE_ExtendedKeyUsage *ekupre = (CE_ExtendedKeyUsage *)pre; 240 CE_ExtendedKeyUsage *ekupost = (CE_ExtendedKeyUsage *)post; 241 242 if(ekupre->numPurposes != ekupost->numPurposes) { 243 printf("CE_ExtendedKeyUsage.numPurposes miscompare\n"); 244 return 1; 245 } 246 unsigned rtn = 0; 247 for(unsigned dex=0; dex<ekupre->numPurposes; dex++) { 248 rtn += compCssmData(ekupre->purposes[dex], 249 ekupost->purposes[dex], "CE_ExtendedKeyUsage.purposes"); 250 } 251 return rtn; 252} 253 254 255#pragma mark --- general purpose X509 name generator --- 256 257/* Attr/Value pairs, pick one of NUM_ATTR_STRINGS */ 258static char *attrStrings[] = { 259 (char *)"thisName", 260 (char *)"anotherName", 261 (char *)"someOtherName" 262}; 263#define NUM_ATTR_STRINGS 3 264 265/* A/V type, pick one of NUM_ATTR_TYPES */ 266static CSSM_OID attrTypes[] = { 267 CSSMOID_Surname, 268 CSSMOID_CountryName, 269 CSSMOID_OrganizationName, 270 CSSMOID_Description 271}; 272#define NUM_ATTR_TYPES 4 273 274/* A/V tag, pick one of NUM_ATTR_TAGS */ 275static char attrTags[] = { 276 BER_TAG_PRINTABLE_STRING, 277 BER_TAG_IA5_STRING, 278 BER_TAG_T61_STRING 279}; 280#define NUM_ATTR_TAGS 3 281 282static void rdnCreate( 283 CSSM_X509_RDN_PTR rdn) 284{ 285 unsigned numPairs = genRand(1,4); 286 rdn->numberOfPairs = numPairs; 287 unsigned len = numPairs * sizeof(CSSM_X509_TYPE_VALUE_PAIR); 288 rdn->AttributeTypeAndValue = 289 (CSSM_X509_TYPE_VALUE_PAIR_PTR)malloc(len); 290 memset(rdn->AttributeTypeAndValue, 0, len); 291 292 for(unsigned atvDex=0; atvDex<numPairs; atvDex++) { 293 CSSM_X509_TYPE_VALUE_PAIR &pair = 294 rdn->AttributeTypeAndValue[atvDex]; 295 unsigned die = genRand(1, NUM_ATTR_TYPES); 296 pair.type = attrTypes[die - 1]; 297 die = genRand(1, NUM_ATTR_STRINGS); 298 char *str = attrStrings[die - 1]; 299 pair.value.Data = (uint8 *)str; 300 pair.value.Length = strlen(str); 301 die = genRand(1, NUM_ATTR_TAGS); 302 pair.valueType = attrTags[die - 1]; 303 } 304} 305 306static unsigned rdnCompare( 307 CSSM_X509_RDN_PTR rdn1, 308 CSSM_X509_RDN_PTR rdn2) 309{ 310 if(rdn1->numberOfPairs != rdn2->numberOfPairs) { 311 printf("***Mismatch in numberOfPairs\n"); 312 return 1; 313 } 314 unsigned rtn = 0; 315 for(unsigned atvDex=0; atvDex<rdn1->numberOfPairs; atvDex++) { 316 CSSM_X509_TYPE_VALUE_PAIR &p1 = 317 rdn1->AttributeTypeAndValue[atvDex]; 318 CSSM_X509_TYPE_VALUE_PAIR &p2 = 319 rdn2->AttributeTypeAndValue[atvDex]; 320 if(p1.valueType != p2.valueType) { 321 printf("***valueType miscompare\n"); 322 rtn++; 323 } 324 if(compCssmData(p1.type, p2.type, "ATV.type")) { 325 rtn++; 326 } 327 if(compCssmData(p1.value, p2.value, "ATV.value")) { 328 rtn++; 329 } 330 } 331 return rtn; 332} 333 334static void rdnFree( 335 CSSM_X509_RDN_PTR rdn) 336{ 337 free(rdn->AttributeTypeAndValue); 338} 339 340static void x509NameCreate( 341 CSSM_X509_NAME_PTR x509Name) 342{ 343 memset(x509Name, 0, sizeof(*x509Name)); 344 unsigned numRdns = genRand(1,4); 345 x509Name->numberOfRDNs = numRdns; 346 unsigned len = numRdns * sizeof(CSSM_X509_RDN); 347 x509Name->RelativeDistinguishedName = (CSSM_X509_RDN_PTR)malloc(len); 348 memset(x509Name->RelativeDistinguishedName, 0, len); 349 350 for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) { 351 CSSM_X509_RDN &rdn = x509Name->RelativeDistinguishedName[rdnDex]; 352 rdnCreate(&rdn); 353 } 354} 355 356static unsigned x509NameCompare( 357 const CSSM_X509_NAME_PTR n1, 358 const CSSM_X509_NAME_PTR n2) 359{ 360 if(n1->numberOfRDNs != n2->numberOfRDNs) { 361 printf("***Mismatch in numberOfRDNs\n"); 362 return 1; 363 } 364 unsigned rtn = 0; 365 for(unsigned rdnDex=0; rdnDex<n1->numberOfRDNs; rdnDex++) { 366 CSSM_X509_RDN &rdn1 = n1->RelativeDistinguishedName[rdnDex]; 367 CSSM_X509_RDN &rdn2 = n2->RelativeDistinguishedName[rdnDex]; 368 rtn += rdnCompare(&rdn1, &rdn2); 369 } 370 return rtn; 371} 372 373static void x509NameFree( 374 CSSM_X509_NAME_PTR n) 375{ 376 for(unsigned rdnDex=0; rdnDex<n->numberOfRDNs; rdnDex++) { 377 CSSM_X509_RDN &rdn = n->RelativeDistinguishedName[rdnDex]; 378 rdnFree(&rdn); 379 } 380 free(n->RelativeDistinguishedName); 381} 382 383#pragma mark --- general purpose GeneralNames generator --- 384 385#define SOME_URL_1 "http://foo.bar.com" 386#define SOME_URL_2 "http://bar.foo.com" 387#define SOME_DNS_1 "Some DNS" 388#define SOME_DNS_2 "Another DNS" 389unsigned char someIpAdr_1[] = {208, 161, 124, 209 }; 390unsigned char someIpAdr_2[] = {10, 0, 61, 5}; 391 392static void genNameCreate(CE_GeneralName *name) 393{ 394 unsigned type = genRand(1, 5); 395 const char *src; 396 unsigned char *usrc; 397 switch(type) { 398 case 1: 399 name->nameType = GNT_URI; 400 name->berEncoded = CSSM_FALSE; 401 src = randBool() ? SOME_URL_1 : SOME_URL_2; 402 appCopyData(src, strlen(src), &name->name); 403 break; 404 405 case 2: 406 name->nameType = GNT_RegisteredID; 407 name->berEncoded = CSSM_FALSE; 408 appCopyData(CSSMOID_SubjectDirectoryAttributes.Data, 409 CSSMOID_SubjectDirectoryAttributes.Length, 410 &name->name); 411 break; 412 413 case 3: 414 name->nameType = GNT_DNSName; 415 name->berEncoded = CSSM_FALSE; 416 src = randBool() ? SOME_DNS_1 : SOME_DNS_2; 417 appCopyData(src, strlen(src), &name->name); 418 break; 419 420 case 4: 421 name->nameType = GNT_IPAddress; 422 name->berEncoded = CSSM_FALSE; 423 usrc = randBool() ? someIpAdr_1 : someIpAdr_2; 424 appCopyData(usrc, 4, &name->name); 425 break; 426 427 case 5: 428 { 429 /* X509_NAME, the hard one */ 430 name->nameType = GNT_DirectoryName; 431 name->berEncoded = CSSM_FALSE; 432 appSetupCssmData(&name->name, sizeof(CSSM_X509_NAME)); 433 x509NameCreate((CSSM_X509_NAME_PTR)name->name.Data); 434 } 435 } 436} 437 438static void genNamesCreate(void *arg) 439{ 440 CE_GeneralNames *names = (CE_GeneralNames *)arg; 441 names->numNames = genRand(1, 3); 442 // one at a time 443 //names->numNames = 1; 444 names->generalName = (CE_GeneralName *)malloc(names->numNames * 445 sizeof(CE_GeneralName)); 446 memset(names->generalName, 0, names->numNames * sizeof(CE_GeneralName)); 447 448 for(unsigned i=0; i<names->numNames; i++) { 449 CE_GeneralName *name = &names->generalName[i]; 450 genNameCreate(name); 451 } 452} 453 454static unsigned genNameCompare( 455 CE_GeneralName *npre, 456 CE_GeneralName *npost) 457{ 458 unsigned rtn = 0; 459 if(npre->nameType != npost->nameType) { 460 printf("***CE_GeneralName.nameType miscompare\n"); 461 rtn++; 462 } 463 if(compBool(npre->berEncoded, npost->berEncoded, 464 "CE_GeneralName.berEncoded")) { 465 rtn++; 466 } 467 468 /* nameType-specific compare */ 469 switch(npre->nameType) { 470 case GNT_RFC822Name: 471 rtn += compCssmData(npre->name, npost->name, 472 "CE_GeneralName.RFC822Name"); 473 break; 474 case GNT_DNSName: 475 rtn += compCssmData(npre->name, npost->name, 476 "CE_GeneralName.DNSName"); 477 break; 478 case GNT_URI: 479 rtn += compCssmData(npre->name, npost->name, 480 "CE_GeneralName.URI"); 481 break; 482 case GNT_IPAddress: 483 rtn += compCssmData(npre->name, npost->name, 484 "CE_GeneralName.RFIPAddressC822Name"); 485 break; 486 case GNT_RegisteredID: 487 rtn += compCssmData(npre->name, npost->name, 488 "CE_GeneralName.RegisteredID"); 489 break; 490 case GNT_DirectoryName: 491 rtn += x509NameCompare((CSSM_X509_NAME_PTR)npre->name.Data, 492 (CSSM_X509_NAME_PTR)npost->name.Data); 493 break; 494 default: 495 printf("****BRRZAP! genNamesCompare needs work\n"); 496 rtn++; 497 } 498 return rtn; 499} 500 501static unsigned genNamesCompare(const void *pre, const void *post) 502{ 503 const CE_GeneralNames *gnPre = (CE_GeneralNames *)pre; 504 const CE_GeneralNames *gnPost = (CE_GeneralNames *)post; 505 unsigned rtn = 0; 506 507 if((gnPre == NULL) || (gnPost == NULL)) { 508 printf("***Bad GenNames pointer\n"); 509 return 1; 510 } 511 if(gnPre->numNames != gnPost->numNames) { 512 printf("***CE_GeneralNames.numNames miscompare\n"); 513 return 1; 514 } 515 for(unsigned dex=0; dex<gnPre->numNames; dex++) { 516 CE_GeneralName *npre = &gnPre->generalName[dex]; 517 CE_GeneralName *npost = &gnPost->generalName[dex]; 518 rtn += genNameCompare(npre, npost); 519 } 520 return rtn; 521} 522 523 524static void genNameFree(CE_GeneralName *n) 525{ 526 switch(n->nameType) { 527 case GNT_DirectoryName: 528 x509NameFree((CSSM_X509_NAME_PTR)n->name.Data); 529 CSSM_FREE(n->name.Data); 530 break; 531 default: 532 CSSM_FREE(n->name.Data); 533 break; 534 } 535} 536 537 538static void genNamesFree(void *arg) 539{ 540 const CE_GeneralNames *gn = (CE_GeneralNames *)arg; 541 for(unsigned dex=0; dex<gn->numNames; dex++) { 542 CE_GeneralName *n = (CE_GeneralName *)&gn->generalName[dex]; 543 genNameFree(n); 544 } 545 free(gn->generalName); 546} 547 548#pragma mark --- CE_CRLDistPointsSyntax --- 549static void cdpCreate(void *arg) 550{ 551 CE_CRLDistPointsSyntax *cdp = (CE_CRLDistPointsSyntax *)arg; 552 //cdp->numDistPoints = genRand(1,3); 553 // one at a time 554 cdp->numDistPoints = 1; 555 unsigned len = sizeof(CE_CRLDistributionPoint) * cdp->numDistPoints; 556 cdp->distPoints = (CE_CRLDistributionPoint *)malloc(len); 557 memset(cdp->distPoints, 0, len); 558 559 for(unsigned dex=0; dex<cdp->numDistPoints; dex++) { 560 CE_CRLDistributionPoint *pt = &cdp->distPoints[dex]; 561 562 /* all fields optional */ 563 if(randBool()) { 564 CE_DistributionPointName *dpn = pt->distPointName = 565 (CE_DistributionPointName *)malloc( 566 sizeof(CE_DistributionPointName)); 567 memset(dpn, 0, sizeof(CE_DistributionPointName)); 568 569 /* CE_DistributionPointName has two flavors */ 570 if(randBool()) { 571 dpn->nameType = CE_CDNT_FullName; 572 dpn->dpn.fullName = (CE_GeneralNames *)malloc( 573 sizeof(CE_GeneralNames)); 574 memset(dpn->dpn.fullName, 0, sizeof(CE_GeneralNames)); 575 genNamesCreate(dpn->dpn.fullName); 576 } 577 else { 578 dpn->nameType = CE_CDNT_NameRelativeToCrlIssuer; 579 dpn->dpn.rdn = (CSSM_X509_RDN_PTR)malloc( 580 sizeof(CSSM_X509_RDN)); 581 memset(dpn->dpn.rdn, 0, sizeof(CSSM_X509_RDN)); 582 rdnCreate(dpn->dpn.rdn); 583 } 584 } /* creating CE_DistributionPointName */ 585 586 pt->reasonsPresent = randBool(); 587 if(pt->reasonsPresent) { 588 CE_CrlDistReasonFlags *cdr = &pt->reasons; 589 /* set two random valid bits */ 590 *cdr = 0; 591 *cdr |= 1 << genRand(0,7); 592 *cdr |= 1 << genRand(0,7); 593 } 594 595 /* make sure at least one present */ 596 if((!pt->distPointName && !pt->reasonsPresent) || randBool()) { 597 pt->crlIssuer = (CE_GeneralNames *)malloc(sizeof(CE_GeneralNames)); 598 memset(pt->crlIssuer, 0, sizeof(CE_GeneralNames)); 599 genNamesCreate(pt->crlIssuer); 600 } 601 } 602} 603 604static unsigned cdpCompare(const void *pre, const void *post) 605{ 606 CE_CRLDistPointsSyntax *cpre = (CE_CRLDistPointsSyntax *)pre; 607 CE_CRLDistPointsSyntax *cpost = (CE_CRLDistPointsSyntax *)post; 608 609 if(cpre->numDistPoints != cpost->numDistPoints) { 610 printf("***CE_CRLDistPointsSyntax.numDistPoints miscompare\n"); 611 return 1; 612 } 613 unsigned rtn = 0; 614 for(unsigned dex=0; dex<cpre->numDistPoints; dex++) { 615 CE_CRLDistributionPoint *ptpre = &cpre->distPoints[dex]; 616 CE_CRLDistributionPoint *ptpost = &cpost->distPoints[dex]; 617 618 if(ptpre->distPointName) { 619 if(ptpost->distPointName == NULL) { 620 printf("***NULL distPointName post decode\n"); 621 rtn++; 622 goto checkReason; 623 } 624 CE_DistributionPointName *dpnpre = ptpre->distPointName; 625 CE_DistributionPointName *dpnpost = ptpost->distPointName; 626 if(dpnpre->nameType != dpnpost->nameType) { 627 printf("***CE_DistributionPointName.nameType miscompare\n"); 628 rtn++; 629 goto checkReason; 630 } 631 if(dpnpre->nameType == CE_CDNT_FullName) { 632 rtn += genNamesCompare(dpnpre->dpn.fullName, dpnpost->dpn.fullName); 633 } 634 else { 635 rtn += rdnCompare(dpnpre->dpn.rdn, dpnpost->dpn.rdn); 636 } 637 638 } 639 else if(ptpost->distPointName != NULL) { 640 printf("***NON NULL distPointName post decode\n"); 641 rtn++; 642 } 643 644 checkReason: 645 if(ptpre->reasons != ptpost->reasons) { 646 printf("***CE_CRLDistributionPoint.reasons miscompare\n"); 647 rtn++; 648 } 649 650 if(ptpre->crlIssuer) { 651 if(ptpost->crlIssuer == NULL) { 652 printf("***NULL crlIssuer post decode\n"); 653 rtn++; 654 continue; 655 } 656 CE_GeneralNames *gnpre = ptpre->crlIssuer; 657 CE_GeneralNames *gnpost = ptpost->crlIssuer; 658 rtn += genNamesCompare(gnpre, gnpost); 659 } 660 else if(ptpost->crlIssuer != NULL) { 661 printf("***NON NULL crlIssuer post decode\n"); 662 rtn++; 663 } 664 } 665 return rtn; 666} 667 668static void cdpFree(void *arg) 669{ 670 CE_CRLDistPointsSyntax *cdp = (CE_CRLDistPointsSyntax *)arg; 671 for(unsigned dex=0; dex<cdp->numDistPoints; dex++) { 672 CE_CRLDistributionPoint *pt = &cdp->distPoints[dex]; 673 if(pt->distPointName) { 674 CE_DistributionPointName *dpn = pt->distPointName; 675 if(dpn->nameType == CE_CDNT_FullName) { 676 genNamesFree(dpn->dpn.fullName); 677 free(dpn->dpn.fullName); 678 } 679 else { 680 rdnFree(dpn->dpn.rdn); 681 free(dpn->dpn.rdn); 682 } 683 free(dpn); 684 } 685 686 if(pt->crlIssuer) { 687 genNamesFree(pt->crlIssuer); 688 free(pt->crlIssuer); 689 } 690 } 691 free(cdp->distPoints); 692} 693 694#pragma mark --- CE_AuthorityKeyID --- 695static void authKeyIdCreate(void *arg) 696{ 697 CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)arg; 698 699 /* all three fields optional */ 700 701 akid->keyIdentifierPresent = randBool(); 702 if(akid->keyIdentifierPresent) { 703 randData(&akid->keyIdentifier, 16); 704 } 705 706 akid->generalNamesPresent = randBool(); 707 if(akid->generalNamesPresent) { 708 akid->generalNames = 709 (CE_GeneralNames *)malloc(sizeof(CE_GeneralNames)); 710 memset(akid->generalNames, 0, sizeof(CE_GeneralNames)); 711 genNamesCreate(akid->generalNames); 712 } 713 714 if(!akid->keyIdentifierPresent & !akid->generalNamesPresent) { 715 /* force at least one to be present */ 716 akid->serialNumberPresent = CSSM_TRUE; 717 } 718 else { 719 akid->serialNumberPresent = randBool(); 720 } 721 if(akid->serialNumberPresent) { 722 randData(&akid->serialNumber, 16); 723 } 724 725} 726 727static unsigned authKeyIdCompare(const void *pre, const void *post) 728{ 729 CE_AuthorityKeyID *akpre = (CE_AuthorityKeyID *)pre; 730 CE_AuthorityKeyID *akpost = (CE_AuthorityKeyID *)post; 731 unsigned rtn = 0; 732 733 if(compBool(akpre->keyIdentifierPresent, akpost->keyIdentifierPresent, 734 "CE_AuthorityKeyID.keyIdentifierPresent")) { 735 rtn++; 736 } 737 else if(akpre->keyIdentifierPresent) { 738 rtn += compCssmData(akpre->keyIdentifier, 739 akpost->keyIdentifier, "CE_AuthorityKeyID.keyIdentifier"); 740 } 741 742 if(compBool(akpre->generalNamesPresent, akpost->generalNamesPresent, 743 "CE_AuthorityKeyID.generalNamesPresent")) { 744 rtn++; 745 } 746 else if(akpre->generalNamesPresent) { 747 rtn += genNamesCompare(akpre->generalNames, 748 akpost->generalNames); 749 } 750 751 if(compBool(akpre->serialNumberPresent, akpost->serialNumberPresent, 752 "CE_AuthorityKeyID.serialNumberPresent")) { 753 rtn++; 754 } 755 else if(akpre->serialNumberPresent) { 756 rtn += compCssmData(akpre->serialNumber, 757 akpost->serialNumber, "CE_AuthorityKeyID.serialNumber"); 758 } 759 return rtn; 760} 761 762static void authKeyIdFree(void *arg) 763{ 764 CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)arg; 765 766 if(akid->keyIdentifier.Data) { 767 free(akid->keyIdentifier.Data); 768 } 769 if(akid->generalNames) { 770 genNamesFree(akid->generalNames); // genNamesCreate mallocd 771 free(akid->generalNames); // we mallocd 772 } 773 if(akid->serialNumber.Data) { 774 free(akid->serialNumber.Data); 775 } 776} 777 778#pragma mark --- CE_CertPolicies --- 779 780/* random OIDs, pick 1..NUM_CP_OIDS */ 781static CSSM_OID cpOids[] = 782{ 783 CSSMOID_EmailAddress, 784 CSSMOID_UnstructuredName, 785 CSSMOID_ContentType, 786 CSSMOID_MessageDigest 787}; 788#define NUM_CP_OIDS 4 789 790/* CPS strings, pick one of NUM_CPS_STR */ 791static char *someCPSs[] = 792{ 793 (char *)"http://www.apple.com", 794 (char *)"https://cdnow.com", 795 (char *)"ftp:backwards.com" 796}; 797#define NUM_CPS_STR 3 798 799/* make these looks like real sequences */ 800static uint8 someUnotice[] = {0x30, 0x03, BER_TAG_BOOLEAN, 1, 0xff}; 801static uint8 someOtherData[] = {0x30, 0x02, BER_TAG_NULL, 0}; 802 803static void cpCreate(void *arg) 804{ 805 CE_CertPolicies *cp = (CE_CertPolicies *)arg; 806 cp->numPolicies = genRand(1,3); 807 //cp->numPolicies = 1; 808 unsigned len = sizeof(CE_PolicyInformation) * cp->numPolicies; 809 cp->policies = (CE_PolicyInformation *)malloc(len); 810 memset(cp->policies, 0, len); 811 812 for(unsigned polDex=0; polDex<cp->numPolicies; polDex++) { 813 CE_PolicyInformation *pi = &cp->policies[polDex]; 814 unsigned die = genRand(1, NUM_CP_OIDS); 815 pi->certPolicyId = cpOids[die - 1]; 816 unsigned numQual = genRand(1,3); 817 pi->numPolicyQualifiers = numQual; 818 len = sizeof(CE_PolicyQualifierInfo) * numQual; 819 pi->policyQualifiers = (CE_PolicyQualifierInfo *) 820 malloc(len); 821 memset(pi->policyQualifiers, 0, len); 822 for(unsigned cpiDex=0; cpiDex<numQual; cpiDex++) { 823 CE_PolicyQualifierInfo *qi = 824 &pi->policyQualifiers[cpiDex]; 825 if(randBool()) { 826 qi->policyQualifierId = CSSMOID_QT_CPS; 827 die = genRand(1, NUM_CPS_STR); 828 qi->qualifier.Data = (uint8 *)someCPSs[die - 1]; 829 qi->qualifier.Length = strlen((char *)qi->qualifier.Data); 830 } 831 else { 832 qi->policyQualifierId = CSSMOID_QT_UNOTICE; 833 if(randBool()) { 834 qi->qualifier.Data = someUnotice; 835 qi->qualifier.Length = 5; 836 } 837 else { 838 qi->qualifier.Data = someOtherData; 839 qi->qualifier.Length = 4; 840 } 841 } 842 } 843 } 844} 845 846static unsigned cpCompare(const void *pre, const void *post) 847{ 848 CE_CertPolicies *cppre = (CE_CertPolicies *)pre; 849 CE_CertPolicies *cppost = (CE_CertPolicies *)post; 850 851 if(cppre->numPolicies != cppost->numPolicies) { 852 printf("CE_CertPolicies.numPolicies mismatch\n"); 853 return 1; 854 } 855 unsigned rtn = 0; 856 for(unsigned polDex=0; polDex<cppre->numPolicies; polDex++) { 857 CE_PolicyInformation *pipre = &cppre->policies[polDex]; 858 CE_PolicyInformation *pipost = &cppost->policies[polDex]; 859 rtn += compCssmData(pipre->certPolicyId, pipost->certPolicyId, 860 "CE_PolicyInformation.certPolicyId"); 861 if(pipre->numPolicyQualifiers != pipost->numPolicyQualifiers) { 862 printf("CE_PolicyInformation.CE_PolicyInformation mismatch\n"); 863 rtn++; 864 continue; 865 } 866 867 for(unsigned qiDex=0; qiDex<pipre->numPolicyQualifiers; qiDex++) { 868 CE_PolicyQualifierInfo *qipre = &pipre->policyQualifiers[qiDex]; 869 CE_PolicyQualifierInfo *qipost = &pipost->policyQualifiers[qiDex]; 870 rtn += compCssmData(qipre->policyQualifierId, 871 qipost->policyQualifierId, 872 "CE_PolicyQualifierInfo.policyQualifierId"); 873 rtn += compCssmData(qipre->qualifier, 874 qipost->qualifier, 875 "CE_PolicyQualifierInfo.qualifier"); 876 } 877 } 878 return rtn; 879} 880 881static void cpFree(void *arg) 882{ 883 CE_CertPolicies *cp = (CE_CertPolicies *)arg; 884 for(unsigned polDex=0; polDex<cp->numPolicies; polDex++) { 885 CE_PolicyInformation *pi = &cp->policies[polDex]; 886 free(pi->policyQualifiers); 887 } 888 free(cp->policies); 889} 890 891#pragma mark --- CE_AuthorityInfoAccess --- 892 893/* random OIDs, pick 1..NUM_AI_OIDS */ 894static CSSM_OID aiOids[] = 895{ 896 CSSMOID_AD_OCSP, 897 CSSMOID_AD_CA_ISSUERS, 898 CSSMOID_AD_TIME_STAMPING, 899 CSSMOID_AD_CA_REPOSITORY 900}; 901#define NUM_AI_OIDS 4 902 903static void aiaCreate(void *arg) 904{ 905 CE_AuthorityInfoAccess *aia = (CE_AuthorityInfoAccess *)arg; 906 aia->numAccessDescriptions = genRand(1,3); 907 unsigned len = aia->numAccessDescriptions * sizeof(CE_AccessDescription); 908 aia->accessDescriptions = (CE_AccessDescription *)malloc(len); 909 memset(aia->accessDescriptions, 0, len); 910 911 for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) { 912 CE_AccessDescription *ad = &aia->accessDescriptions[dex]; 913 int die = genRand(1, NUM_AI_OIDS); 914 ad->accessMethod = aiOids[die - 1]; 915 genNameCreate(&ad->accessLocation); 916 } 917} 918 919static unsigned aiaCompare(const void *pre, const void *post) 920{ 921 CE_AuthorityInfoAccess *apre = (CE_AuthorityInfoAccess *)pre; 922 CE_AuthorityInfoAccess *apost = (CE_AuthorityInfoAccess *)post; 923 unsigned rtn = 0; 924 925 if(apre->numAccessDescriptions != apost->numAccessDescriptions) { 926 printf("***CE_AuthorityInfoAccess.numAccessDescriptions miscompare\n"); 927 return 1; 928 } 929 for(unsigned dex=0; dex<apre->numAccessDescriptions; dex++) { 930 CE_AccessDescription *adPre = &apre->accessDescriptions[dex]; 931 CE_AccessDescription *adPost = &apost->accessDescriptions[dex]; 932 if(compCssmData(adPre->accessMethod, adPost->accessMethod, 933 "CE_AccessDescription.accessMethod")) { 934 rtn++; 935 } 936 rtn += genNameCompare(&adPre->accessLocation, &adPost->accessLocation); 937 } 938 return rtn; 939} 940 941static void aiaFree(void *arg) 942{ 943 CE_AuthorityInfoAccess *aia = (CE_AuthorityInfoAccess *)arg; 944 for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) { 945 CE_AccessDescription *ad = &aia->accessDescriptions[dex]; 946 genNameFree(&ad->accessLocation); 947 } 948 free(aia->accessDescriptions); 949} 950 951#pragma mark --- CE_QC_Statements --- 952 953/* a static array of CE_QC_Statement.statementId */ 954static const CSSM_OID qcsOids[] = { 955 CSSMOID_OID_QCS_SYNTAX_V1, 956 CSSMOID_OID_QCS_SYNTAX_V2, 957 CSSMOID_ETSI_QCS_QC_COMPLIANCE, 958}; 959#define NUM_QCS_OIDS 3 960#define WHICH_QCS_V2 1 961 962static void qcsCreate(void *arg) 963{ 964 CE_QC_Statements *qcss = (CE_QC_Statements *)arg; 965 //unsigned numQcs = genRand(1,3); 966 unsigned numQcs = 1; 967 qcss->numQCStatements = numQcs; 968 qcss->qcStatements = (CE_QC_Statement *)malloc(numQcs * sizeof(CE_QC_Statement)); 969 memset(qcss->qcStatements, 0, numQcs * sizeof(CE_QC_Statement)); 970 971 for(unsigned dex=0; dex<numQcs; dex++) { 972 CE_QC_Statement *qcs = &qcss->qcStatements[dex]; 973 unsigned whichOid = genRand(0, NUM_QCS_OIDS-1); 974 qcs->statementId = qcsOids[whichOid]; 975 976 /* three legal combos of (semanticsInfo, otherInfo), constrained by whichOid */ 977 unsigned coin = genRand(1, 2); 978 switch(coin) { 979 case 1: 980 /* nothing */ 981 break; 982 case 2: 983 { 984 /* 985 * CSSMOID_OID_QCS_SYNTAX_V2 --> semanticsInfo 986 * other --> otherInfo 987 */ 988 if(whichOid == WHICH_QCS_V2) { 989 CE_SemanticsInformation *si = (CE_SemanticsInformation *)malloc( 990 sizeof(CE_SemanticsInformation)); 991 qcs->semanticsInfo = si; 992 memset(si, 0, sizeof(CE_SemanticsInformation)); 993 994 /* flip a coin; heads --> semanticsIdentifier */ 995 coin = genRand(1, 2); 996 if(coin == 2) { 997 si->semanticsIdentifier = (CSSM_OID *)malloc(sizeof(CSSM_OID)); 998 *si->semanticsIdentifier = qcsOids[0]; 999 } 1000 1001 /* flip a coin; heads --> nameRegistrationAuthorities */ 1002 /* also gen this one if semanticsInfo is empty */ 1003 coin = genRand(1, 2); 1004 if((coin == 2) || (si->semanticsIdentifier == NULL)) { 1005 si->nameRegistrationAuthorities = (CE_NameRegistrationAuthorities *) 1006 malloc(sizeof(CE_NameRegistrationAuthorities)); 1007 genNamesCreate(si->nameRegistrationAuthorities); 1008 } 1009 } 1010 else { 1011 /* ASN_ANY - just take an encoded NULL */ 1012 CSSM_DATA *otherInfo = (CSSM_DATA *)malloc(sizeof(CSSM_DATA)); 1013 otherInfo->Data = (uint8 *)malloc(2); 1014 otherInfo->Data[0] = 5; 1015 otherInfo->Data[1] = 0; 1016 otherInfo->Length = 2; 1017 qcs->otherInfo = otherInfo; 1018 } 1019 break; 1020 } 1021 } 1022 } 1023} 1024 1025static unsigned qcsCompare(const void *pre, const void *post) 1026{ 1027 CE_QC_Statements *qpre = (CE_QC_Statements *)pre; 1028 CE_QC_Statements *qpost = (CE_QC_Statements *)post; 1029 uint32 numQcs = qpre->numQCStatements; 1030 if(numQcs != qpost->numQCStatements) { 1031 printf("***numQCStatements miscompare\n"); 1032 return 1; 1033 } 1034 1035 unsigned rtn = 0; 1036 for(unsigned dex=0; dex<numQcs; dex++) { 1037 CE_QC_Statement *qcsPre = &qpre->qcStatements[dex]; 1038 CE_QC_Statement *qcsPost = &qpost->qcStatements[dex]; 1039 if(compCssmData(qcsPre->statementId, qcsPost->statementId, 1040 "CE_QC_Statement.statementId")) { 1041 rtn++; 1042 } 1043 if(qcsPre->semanticsInfo) { 1044 if(qcsPost->semanticsInfo == NULL) { 1045 printf("***semanticsInfo in pre but not in post\n"); 1046 rtn++; 1047 } 1048 else { 1049 CE_SemanticsInformation *siPre = qcsPre->semanticsInfo; 1050 CE_SemanticsInformation *siPost = qcsPost->semanticsInfo; 1051 if((siPre->semanticsIdentifier == NULL) != (siPost->semanticsIdentifier == NULL)) { 1052 printf("***mismatch in presence of semanticsIdentifier\n"); 1053 rtn++; 1054 } 1055 else if(siPre->semanticsIdentifier) { 1056 if(compCssmData(*siPre->semanticsIdentifier, *siPost->semanticsIdentifier, 1057 "CE_SemanticsInformation.semanticsIdentifier")) { 1058 rtn++; 1059 } 1060 } 1061 if((siPre->nameRegistrationAuthorities == NULL) != 1062 (siPost->nameRegistrationAuthorities == NULL)) { 1063 printf("***mismatch in presence of nameRegistrationAuthorities\n"); 1064 rtn++; 1065 } 1066 else if(siPre->nameRegistrationAuthorities) { 1067 rtn += genNamesCompare(siPre->nameRegistrationAuthorities, 1068 siPost->nameRegistrationAuthorities); 1069 } 1070 } 1071 } 1072 else if(qcsPost->semanticsInfo != NULL) { 1073 printf("***semanticsInfo in post but not in pre\n"); 1074 rtn++; 1075 } 1076 if(qcsPre->otherInfo) { 1077 if(qcsPost->otherInfo == NULL) { 1078 printf("***otherInfo in pre but not in post\n"); 1079 rtn++; 1080 } 1081 else { 1082 if(compCssmData(*qcsPre->otherInfo, *qcsPre->otherInfo, 1083 "CE_QC_Statement.otherInfo")) { 1084 rtn++; 1085 } 1086 } 1087 } 1088 else if(qcsPost->otherInfo != NULL) { 1089 printf("***otherInfo in post but not in pre\n"); 1090 rtn++; 1091 } 1092 } 1093 return rtn; 1094} 1095 1096static void qcsFree(void *arg) 1097{ 1098 CE_QC_Statements *qcss = (CE_QC_Statements *)arg; 1099 uint32 numQcs = qcss->numQCStatements; 1100 for(unsigned dex=0; dex<numQcs; dex++) { 1101 CE_QC_Statement *qcs = &qcss->qcStatements[dex]; 1102 if(qcs->semanticsInfo) { 1103 CE_SemanticsInformation *si = qcs->semanticsInfo; 1104 if(si->semanticsIdentifier) { 1105 free(si->semanticsIdentifier); 1106 } 1107 if(si->nameRegistrationAuthorities) { 1108 genNamesFree(si->nameRegistrationAuthorities); 1109 free(si->nameRegistrationAuthorities); 1110 } 1111 free(qcs->semanticsInfo); 1112 } 1113 if(qcs->otherInfo) { 1114 free(qcs->otherInfo->Data); 1115 free(qcs->otherInfo); 1116 } 1117 } 1118 free(qcss->qcStatements); 1119} 1120 1121#pragma mark --- test definitions --- 1122 1123/* 1124 * Define one extension test. 1125 */ 1126 1127/* 1128 * Cook up this extension with random, reasonable values. 1129 * Incoming pointer refers to extension-specific C struct, mallocd 1130 * and zeroed by main test routine. 1131 */ 1132typedef void (*extenCreateFcn)(void *arg); 1133 1134/* 1135 * Compare two instances of this extension. Return number of 1136 * compare errors. 1137 */ 1138typedef unsigned (*extenCompareFcn)( 1139 const void *preEncode, 1140 const void *postEncode); 1141 1142/* 1143 * Free struct components mallocd in extenCreateFcn. Do not free 1144 * the outer struct. 1145 */ 1146typedef void (*extenFreeFcn)(void *arg); 1147 1148typedef struct { 1149 /* three extension-specific functions */ 1150 extenCreateFcn createFcn; 1151 extenCompareFcn compareFcn; 1152 extenFreeFcn freeFcn; 1153 1154 /* size of C struct passed to all three functions */ 1155 unsigned extenSize; 1156 1157 /* the OID for this extension */ 1158 CSSM_OID extenOid; 1159 1160 /* description for error logging and blob writing */ 1161 const char *extenDescr; 1162 1163 /* command-line letter for this one */ 1164 char extenLetter; 1165 1166} ExtenTest; 1167 1168/* empty freeFcn means no extension-specific resources to free */ 1169#define NO_FREE NULL 1170 1171static ExtenTest extenTests[] = { 1172 { kuCreate, kuCompare, NO_FREE, 1173 sizeof(CE_KeyUsage), CSSMOID_KeyUsage, 1174 "KeyUsage", 'k' }, 1175 { bcCreate, bcCompare, NO_FREE, 1176 sizeof(CE_BasicConstraints), CSSMOID_BasicConstraints, 1177 "BasicConstraints", 'b' }, 1178 { ekuCreate, ekuCompare, NO_FREE, 1179 sizeof(CE_ExtendedKeyUsage), CSSMOID_ExtendedKeyUsage, 1180 "ExtendedKeyUsage", 'x' }, 1181 { skidCreate, skidCompare, skidFree, 1182 sizeof(CSSM_DATA), CSSMOID_SubjectKeyIdentifier, 1183 "SubjectKeyID", 's' }, 1184 { authKeyIdCreate, authKeyIdCompare, authKeyIdFree, 1185 sizeof(CE_AuthorityKeyID), CSSMOID_AuthorityKeyIdentifier, 1186 "AuthorityKeyID", 'a' }, 1187 { genNamesCreate, genNamesCompare, genNamesFree, 1188 sizeof(CE_GeneralNames), CSSMOID_SubjectAltName, 1189 "SubjectAltName", 't' }, 1190 { genNamesCreate, genNamesCompare, genNamesFree, 1191 sizeof(CE_GeneralNames), CSSMOID_IssuerAltName, 1192 "IssuerAltName", 'i' }, 1193 { nctCreate, nctCompare, NO_FREE, 1194 sizeof(CE_NetscapeCertType), CSSMOID_NetscapeCertType, 1195 "NetscapeCertType", 'n' }, 1196 { cdpCreate, cdpCompare, cdpFree, 1197 sizeof(CE_CRLDistPointsSyntax), CSSMOID_CrlDistributionPoints, 1198 "CRLDistPoints", 'p' }, 1199 { cpCreate, cpCompare, cpFree, 1200 sizeof(CE_CertPolicies), CSSMOID_CertificatePolicies, 1201 "CertPolicies", 'c' }, 1202 { aiaCreate, aiaCompare, aiaFree, 1203 sizeof(CE_AuthorityInfoAccess), CSSMOID_AuthorityInfoAccess, 1204 "AuthorityInfoAccess", 'A' }, 1205 { aiaCreate, aiaCompare, aiaFree, 1206 sizeof(CE_AuthorityInfoAccess), CSSMOID_SubjectInfoAccess, 1207 "SubjectInfoAccess", 'S' }, 1208 { qcsCreate, qcsCompare, qcsFree, 1209 sizeof(CE_QC_Statements), CSSMOID_QC_Statements, 1210 "QualifiedCertStatements", 'q' }, 1211}; 1212 1213#define NUM_EXTEN_TESTS (sizeof(extenTests) / sizeof(ExtenTest)) 1214 1215static void printExten( 1216 CSSM_X509_EXTENSION &extn, 1217 bool preEncode, 1218 OidParser &parser) 1219{ 1220 CSSM_FIELD field; 1221 field.FieldOid = extn.extnId; 1222 field.FieldValue.Data = (uint8 *)&extn; 1223 field.FieldValue.Length = sizeof(CSSM_X509_EXTENSION); 1224 printf("=== %s:\n", preEncode ? "PRE-ENCODE" : "POST-DECODE" ); 1225 printCertField(field, parser, CSSM_TRUE); 1226} 1227 1228static int doTest( 1229 CSSM_CL_HANDLE clHand, 1230 CSSM_CSP_HANDLE cspHand, 1231 ExtenTest &extenTest, 1232 bool writeBlobs, 1233 const char *constFileName, // all blobs to this file if non-NULL 1234 bool displayExtens, 1235 OidParser &parser) 1236{ 1237 /* 1238 * 1. Cook up a random and reasonable instance of the C struct 1239 * associated with this extension. 1240 */ 1241 void *preEncode = CSSM_MALLOC(extenTest.extenSize); 1242 memset(preEncode, 0, extenTest.extenSize); 1243 extenTest.createFcn(preEncode); 1244 1245 /* 1246 * Cook up the associated CSSM_X509_EXTENSION. 1247 */ 1248 CSSM_X509_EXTENSION extnPre; 1249 1250 extnPre.extnId = extenTest.extenOid; 1251 extnPre.critical = randBool(); 1252 extnPre.format = CSSM_X509_DATAFORMAT_PARSED; 1253 extnPre.value.parsedValue = preEncode; 1254 extnPre.BERvalue.Data = NULL; 1255 extnPre.BERvalue.Length = 0; 1256 1257 /* encode the extension in a TBSCert */ 1258 CSSM_DATA_PTR rawCert = CB_MakeCertTemplate(clHand, 1259 0x12345678, // serial number 1260 dummyName, 1261 dummyName, 1262 notBefore, 1263 notAfter, 1264 &subjPubKey, 1265 SIG_ALG, 1266 NULL, // subjUniqueId 1267 NULL, // issuerUniqueId 1268 &extnPre, // extensions 1269 1); // numExtensions 1270 if(rawCert == NULL) { 1271 printf("Error generating template; aborting.\n"); 1272 /* show what we tried to encode */ 1273 printExten(extnPre, true, parser); 1274 return 1; 1275 } 1276 1277 /* sign the cert */ 1278 CSSM_DATA signedCert = {0, NULL}; 1279 CSSM_CC_HANDLE sigHand; 1280 CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand, 1281 SIG_ALG, 1282 NULL, // no passphrase for now 1283 &subjPrivKey, 1284 &sigHand); 1285 if(crtn) { 1286 printError("CreateSignatureContext", crtn); 1287 return 1; 1288 } 1289 1290 crtn = CSSM_CL_CertSign(clHand, 1291 sigHand, 1292 rawCert, // CertToBeSigned 1293 NULL, // SignScope per spec 1294 0, // ScopeSize per spec 1295 &signedCert); 1296 if(crtn) { 1297 printError("CSSM_CL_CertSign", crtn); 1298 /* show what we tried to encode */ 1299 printExten(extnPre, true, parser); 1300 return 1; 1301 } 1302 CSSM_DeleteContext(sigHand); 1303 1304 if(writeBlobs) { 1305 char fileName[200]; 1306 if(constFileName) { 1307 strcpy(fileName, constFileName); 1308 } 1309 else { 1310 sprintf(fileName, "%scert.der", extenTest.extenDescr); 1311 } 1312 writeFile(fileName, signedCert.Data, signedCert.Length); 1313 printf("...wrote %lu bytes to %s\n", signedCert.Length, fileName); 1314 } 1315 1316 /* snag the same extension from the encoded cert */ 1317 CSSM_DATA_PTR postField; 1318 CSSM_HANDLE resultHand; 1319 uint32 numFields; 1320 1321 crtn = CSSM_CL_CertGetFirstFieldValue(clHand, 1322 &signedCert, 1323 &extenTest.extenOid, 1324 &resultHand, 1325 &numFields, 1326 &postField); 1327 if(crtn) { 1328 printf("****Extension field not found on decode for %s\n", 1329 extenTest.extenDescr); 1330 printError("CSSM_CL_CertGetFirstFieldValue", crtn); 1331 1332 /* show what we tried to encode and decode */ 1333 printExten(extnPre, true, parser); 1334 return 1; 1335 } 1336 1337 if(numFields != 1) { 1338 printf("****GetFirstFieldValue: expect 1 value, got %u\n", 1339 (unsigned)numFields); 1340 return 1; 1341 } 1342 CSSM_CL_CertAbortQuery(clHand, resultHand); 1343 1344 /* verify the fields we generated */ 1345 CSSM_X509_EXTENSION *extnPost = (CSSM_X509_EXTENSION *)postField->Data; 1346 if((extnPost == NULL) || 1347 (postField->Length != sizeof(CSSM_X509_EXTENSION))) { 1348 printf("***Malformed CSSM_X509_EXTENSION (1) after decode\n"); 1349 return 1; 1350 } 1351 int rtn = 0; 1352 rtn += compBool(extnPre.critical, extnPost->critical, 1353 "CSSM_X509_EXTENSION.critical"); 1354 rtn += compCssmData(extnPre.extnId, extnPost->extnId, 1355 "CSSM_X509_EXTENSION.extnId"); 1356 1357 if(extnPost->format != CSSM_X509_DATAFORMAT_PARSED) { 1358 printf("***Expected CSSM_X509_DATAFORMAT_PARSED (%x(x), got %x(x)\n", 1359 CSSM_X509_DATAFORMAT_PARSED, extnPost->format); 1360 } 1361 if(extnPost->value.parsedValue == NULL) { 1362 printf("***no parsedValue pointer!\n"); 1363 return 1; 1364 } 1365 1366 /* down to extension-specific compare */ 1367 rtn += extenTest.compareFcn(preEncode, extnPost->value.parsedValue); 1368 1369 if(rtn) { 1370 /* print preencode only on error */ 1371 printExten(extnPre, true, parser); 1372 } 1373 if(displayExtens || rtn) { 1374 printExten(*extnPost, false, parser); 1375 } 1376 1377 /* free the allocated data */ 1378 if(extenTest.freeFcn) { 1379 extenTest.freeFcn(preEncode); 1380 } 1381 CSSM_CL_FreeFieldValue(clHand, &extenTest.extenOid, postField); 1382 CSSM_FREE(rawCert->Data); 1383 CSSM_FREE(rawCert); 1384 CSSM_FREE(signedCert.Data); 1385 CSSM_FREE(preEncode); 1386 return rtn; 1387} 1388 1389static void doPause(bool pause) 1390{ 1391 if(!pause) { 1392 return; 1393 } 1394 fpurge(stdin); 1395 printf("CR to continue "); 1396 getchar(); 1397} 1398 1399int main(int argc, char **argv) 1400{ 1401 CSSM_CL_HANDLE clHand; 1402 CSSM_CSP_HANDLE cspHand; 1403 CSSM_RETURN crtn; 1404 int arg; 1405 int rtn; 1406 OidParser parser; 1407 char *argp; 1408 unsigned i; 1409 1410 /* user-specificied params */ 1411 unsigned minExtenNum = 0; 1412 unsigned maxExtenNum = NUM_EXTEN_TESTS-1; 1413 bool writeBlobs = false; 1414 bool displayExtens = false; 1415 bool quiet = false; 1416 unsigned loops = LOOPS_DEF; 1417 bool pauseLoop = false; 1418 bool pauseCert = false; 1419 const char *constFileName = NULL; 1420 1421 for(arg=1; arg<argc; arg++) { 1422 argp = argv[arg]; 1423 switch(argp[0]) { 1424 case 'w': 1425 writeBlobs = true; 1426 break; 1427 case 'd': 1428 displayExtens = true; 1429 break; 1430 case 'q': 1431 quiet = true; 1432 break; 1433 case 'p': 1434 pauseLoop = true; 1435 break; 1436 case 'P': 1437 pauseCert = true; 1438 break; 1439 case 'l': 1440 loops = atoi(&argp[2]); 1441 break; 1442 case 'f': 1443 constFileName = &argp[2]; 1444 break; 1445 case 'e': 1446 if(argp[1] != '=') { 1447 usage(argv); 1448 } 1449 /* scan thru test array looking for epecified extension */ 1450 for(i=0; i<NUM_EXTEN_TESTS; i++) { 1451 if(extenTests[i].extenLetter == argp[2]) { 1452 minExtenNum = maxExtenNum = i; 1453 break; 1454 } 1455 } 1456 if(i == NUM_EXTEN_TESTS) { 1457 usage(argv); 1458 } 1459 break; 1460 default: 1461 usage(argv); 1462 } 1463 } 1464 1465 1466 /* common setup */ 1467 clHand = clStartup(); 1468 if(clHand == 0) { 1469 return 0; 1470 } 1471 cspHand = cspStartup(); 1472 if(cspHand == 0) { 1473 return 0; 1474 } 1475 1476 printf("Starting extenTest; args: "); 1477 for(i=1; i<(unsigned)argc; i++) { 1478 printf("%s ", argv[i]); 1479 } 1480 printf("\n"); 1481 1482 /* one common key pair - we're definitely not testing this */ 1483 crtn = cspGenKeyPair(cspHand, 1484 KEY_ALG, 1485 SUBJ_KEY_LABEL, 1486 strlen(SUBJ_KEY_LABEL), 1487 KEY_SIZE_BITS, 1488 &subjPubKey, 1489 CSSM_FALSE, // pubIsRef - should work both ways, but not yet 1490 CSSM_KEYUSE_VERIFY, 1491 CSSM_KEYBLOB_RAW_FORMAT_NONE, 1492 &subjPrivKey, 1493 CSSM_TRUE, // privIsRef - doesn't matter 1494 CSSM_KEYUSE_SIGN, 1495 CSSM_KEYBLOB_RAW_FORMAT_NONE, 1496 CSSM_FALSE); 1497 if(crtn) { 1498 exit(1); 1499 } 1500 1501 /* common issuer/subject - not testing this */ 1502 dummyName = CB_BuildX509Name(dummyRdn, NUM_DUMMY_NAMES); 1503 if(dummyName == NULL) { 1504 printf("CB_BuildX509Name failure"); 1505 exit(1); 1506 } 1507 1508 /* not before/after in generalized time format */ 1509 notBefore = CB_BuildX509Time(0); 1510 notAfter = CB_BuildX509Time(10000); 1511 1512 for(unsigned loop=0; loop<loops; loop++) { 1513 if(!quiet) { 1514 printf("...loop %u\n", loop); 1515 } 1516 for(unsigned extenDex=minExtenNum; extenDex<=maxExtenNum; extenDex++) { 1517 rtn = doTest(clHand, cspHand, extenTests[extenDex], 1518 writeBlobs, constFileName, displayExtens, parser); 1519 if(rtn) { 1520 break; 1521 } 1522 doPause(pauseCert); 1523 } 1524 if(rtn) { 1525 break; 1526 } 1527 doPause(pauseLoop); 1528 } 1529 1530 if(rtn) { 1531 printf("***%s FAILED\n", argv[0]); 1532 } 1533 else if(!quiet) { 1534 printf("...%s passed\n", argv[0]); 1535 } 1536 1537 1538 /* cleanup */ 1539 CB_FreeX509Name(dummyName); 1540 CB_FreeX509Time(notBefore); 1541 CB_FreeX509Time(notAfter); 1542 CSSM_ModuleDetach(cspHand); 1543 CSSM_ModuleDetach(clHand); 1544 return 0; 1545} 1546 1547