1/* Copyright (c) 1998-2003,2005-2006,2008 Apple Inc. 2 * 3 * signerAndSubjTp.c 4 * 5 * Create two certs - a root, and a subject cert signed by the root. Includes 6 * extension construction. Verify certs every which way, including various expected 7 * failures. This version uses CSSM_TP_SubmitCredRequest to create the certs. 8 * 9 */ 10 11#include <utilLib/common.h> 12#include <utilLib/cspwrap.h> 13#include <security_cdsa_utils/cuFileIo.h> 14#include <clAppUtils/clutils.h> 15#include <stdlib.h> 16#include <stdio.h> 17#include <string.h> 18#include <Security/cssm.h> 19#include <Security/x509defs.h> 20#include <Security/oidsattr.h> 21#include <Security/oidscert.h> 22#include <Security/oidsalg.h> 23#include <Security/certextensions.h> 24#include <Security/cssmapple.h> 25#include <string.h> 26 27#define SUBJ_KEY_LABEL "subjectKey" 28#define ROOT_KEY_LABEL "rootKey" 29/* default key and signature algorithm */ 30#define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA 31#define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA 32#define KEY_ALG_DEFAULT CSSM_ALGID_RSA 33 34/* for write certs/keys option */ 35#define ROOT_CERT_FILE_NAME "ssRootCert.cer" 36#define SUBJ_CERT_FILE_NAME "ssSubjCert.cer" 37#define ROOT_KEY_FILE_NAME "ssRootKey.der" 38#define SUBJ_KEY_FILE_NAME "ssSubjKey.der" 39 40/* public key in ref form, TP supports this as of 1/30/02 */ 41#define PUB_KEY_IS_REF CSSM_TRUE 42 43#define SERIAL_DEFAULT 0x12345678 44 45static void usage(char **argv) 46{ 47 printf("Usage: %s [options]\n", argv[0]); 48 printf("Options:\n"); 49 printf(" w[rite certs and keys]\n"); 50 printf(" a=alg where alg is s(RSA/SHA1), m(RSA/MD5), f(FEE/MD5), F(FEE/SHA1),\n"); 51 printf(" 2(RSA/SHA224), 6(RSA/SHA256), 3(RSA/SHA384) 5=RSA/SHA512,\n"); 52 printf(" e(ECDSA), E(ANSI/ECDSA), 7(ECDSA/SHA256), 8(ECDSA/SHA384), 9(ECDSA/SHA512)\n"); 53 printf(" k=keySizeInBits\n"); 54 printf(" c=commonName (for SSL compatible subject name)\n"); 55 printf(" P (loop and pause for malloc debug)\n"); 56 printf("Extension options:\n"); 57 printf(" t=authorityKeyName -- AuthorityKeyID, generalNames, DNSName plus s/n variant\n"); 58 printf(" s -- SubjectKey, data = aabbccddeeff\n"); 59 printf(" e=emailAddress -- subjectAltName, RFC822Name variant\n"); 60 printf(" i=issuerAltName -- DNSName variant\n"); 61 printf(" r=crlDistributionPoint -- dpn, URI variant\n"); 62 printf(" u=authorityInfoAccess -- OCSP, DNSName variant\n"); 63 printf(" p=certPolicyString -- CertPolicies, id_cps variant\n"); 64 printf(" n=netscapeCertType -- NetscapeCertType, specify an integer\n"); 65 printf(" N=serialNumber -- in decimal, default is 0x%x\n", SERIAL_DEFAULT); 66 exit(1); 67} 68 69/* 70 * RDN components for root, subject 71 */ 72static CSSM_APPLE_TP_NAME_OID rootRdn[] = 73{ 74 { "Apple Computer", &CSSMOID_OrganizationName }, 75 { "The Big Cheesy Debug Root", &CSSMOID_CommonName } 76}; 77#define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID)) 78 79static CSSM_APPLE_TP_NAME_OID subjRdn[] = 80{ 81 /* note extra space for normalize test */ 82 { "Apple Computer", &CSSMOID_OrganizationName }, 83 /* this can get overridden by cmd line */ 84 { "Doug Mitchell", &CSSMOID_CommonName } 85}; 86#define NUM_SUBJ_NAMES (sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID)) 87 88static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2); 89static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand, 90 CSSM_CSP_HANDLE cspHand, 91 CSSM_DATA_PTR cert, 92 CSSM_DATA_PTR signerCert, 93 CSSM_KEY_PTR key, 94 CSSM_ALGORITHMS sigAlg, 95 CSSM_RETURN expectResult, 96 const char *opString); 97 98/* 99 * Cook up trivial CE_GeneralName, one component of specified NameType. 100 */ 101static void makeGeneralName( 102 CE_GeneralName *genName, /* locally declared, persistent */ 103 char *str, 104 CE_GeneralNameType nameType) /* GNT_RFC822Name, etc. */ 105{ 106 genName->nameType = nameType; 107 genName->berEncoded = CSSM_FALSE; 108 genName->name.Data = (uint8 *)str; 109 genName->name.Length = strlen(str); 110} 111 112/* 113 * Cook up a trivial CE_GeneralNames, one component of specified NameType. 114 */ 115static void makeGeneralNames( 116 CE_GeneralNames *genNames, /* pointer from CE_DataAndType */ 117 CE_GeneralName *genName, /* locally declared, persistent */ 118 char *str, 119 CE_GeneralNameType nameType) /* GNT_RFC822Name, etc. */ 120{ 121 genNames->numNames = 1; 122 genNames->generalName = genName; 123 makeGeneralName(genName, str, nameType); 124} 125 126int main(int argc, char **argv) 127{ 128 CSSM_CL_HANDLE clHand; // CL handle 129 CSSM_CSP_HANDLE cspHand; // CSP handle 130 CSSM_TP_HANDLE tpHand; // TP handle 131 CSSM_DATA signedRootCert; // from CSSM_CL_CertSign 132 CSSM_DATA signedSubjCert; // from CSSM_CL_CertSign 133 CSSM_KEY subjPubKey; // subject's RSA public key blob 134 CSSM_KEY subjPrivKey; // subject's RSA private key - ref format 135 CSSM_KEY rootPubKey; // root's RSA public key blob 136 CSSM_KEY rootPrivKey; // root's RSA private key - ref format 137 CSSM_RETURN crtn; 138 CSSM_KEY_PTR extractRootKey; // from CSSM_CL_CertGetKeyInfo() 139 CSSM_KEY_PTR extractSubjKey; // ditto 140 unsigned badByte; 141 int arg; 142 unsigned errorCount = 0; 143 CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest 144 CSSM_APPLE_TP_CERT_REQUEST certReq; 145 CSSM_TP_REQUEST_SET reqSet; 146 sint32 estTime; 147 CSSM_BOOL confirmRequired; 148 CSSM_TP_RESULT_SET_PTR rootResultSet; 149 CSSM_TP_RESULT_SET_PTR subjResultSet; 150 CSSM_ENCODED_CERT *rootEncCert; 151 CSSM_ENCODED_CERT *subjEncCert; 152 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext; 153 CSSM_FIELD policyId; 154 155 /* extension support */ 156 CE_GeneralName sanGenName; /* subjectAltName */ 157 CE_GeneralName ianGenName; /* issuerAltName */ 158 CE_DistributionPointName distPointName; 159 CE_GeneralName crlGenName; 160 CE_GeneralNames crlGenNames; 161 CE_CRLDistributionPoint cdp; 162 CE_AccessDescription accessDescr; 163 CE_GeneralNames authKeyIdGenNames; 164 CE_GeneralName authKeyIdGenName; 165 uint8 authKeyIdSerial[4] = {0x22, 0x33, 0x44, 0x55 }; 166 uint8 subjKeyIdData[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; 167 CE_PolicyQualifierInfo polQualInfo; 168 CE_PolicyInformation polInfo; 169 170 /* user-spec'd variables */ 171 CSSM_BOOL writeBlobs = CSSM_FALSE; 172 CSSM_ALGORITHMS keyAlg = KEY_ALG_DEFAULT; 173 CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT; 174 CSSM_OID sigOid = SIG_OID_DEFAULT; 175 uint32 keySizeInBits = CSP_KEY_SIZE_DEFAULT; 176 char *subjectEmail = NULL; // for S/MIME subjectAltName 177 char *issuerAltName = NULL; 178 char *crlDistPoint = NULL; 179 char *authorityInfoAccess = NULL; 180 char *authKeyIdName = NULL; 181 bool subjectKeyId = false; 182 char *certPoliciesStr = NULL; 183 bool netscapeTypeSpec = false; 184 uint16 netscapeType = 0; 185 uint32 serialNumber = SERIAL_DEFAULT; 186 bool loopPause = false; 187 188 /* 189 * Extensions. Subject at least one (KeyUsage). 190 * Root has KeyUsage and BasicConstraints. 191 */ 192 CE_DataAndType exts[8]; 193 CE_DataAndType *extp = &exts[0]; 194 195 for(arg=1; arg<argc; arg++) { 196 switch(argv[arg][0]) { 197 case 'w': 198 writeBlobs = CSSM_TRUE; 199 break; 200 case 'a': 201 if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) { 202 usage(argv); 203 } 204 switch(argv[arg][2]) { 205 case 's': 206 keyAlg = CSSM_ALGID_RSA; 207 sigAlg = CSSM_ALGID_SHA1WithRSA; 208 sigOid = CSSMOID_SHA1WithRSA; 209 break; 210 case 'm': 211 keyAlg = CSSM_ALGID_RSA; 212 sigAlg = CSSM_ALGID_MD5WithRSA; 213 sigOid = CSSMOID_MD5WithRSA; 214 break; 215 case '2': 216 keyAlg = CSSM_ALGID_RSA; 217 sigAlg = CSSM_ALGID_SHA224WithRSA; 218 sigOid = CSSMOID_SHA224WithRSA; 219 break; 220 case '6': 221 keyAlg = CSSM_ALGID_RSA; 222 sigAlg = CSSM_ALGID_SHA256WithRSA; 223 sigOid = CSSMOID_SHA256WithRSA; 224 break; 225 case '3': 226 keyAlg = CSSM_ALGID_RSA; 227 sigAlg = CSSM_ALGID_SHA384WithRSA; 228 sigOid = CSSMOID_SHA384WithRSA; 229 break; 230 case '5': 231 keyAlg = CSSM_ALGID_RSA; 232 sigAlg = CSSM_ALGID_SHA512WithRSA; 233 sigOid = CSSMOID_SHA512WithRSA; 234 break; 235 case 'f': 236 keyAlg = CSSM_ALGID_FEE; 237 sigAlg = CSSM_ALGID_FEE_MD5; 238 sigOid = CSSMOID_APPLE_FEE_MD5; 239 break; 240 case 'F': 241 keyAlg = CSSM_ALGID_FEE; 242 sigAlg = CSSM_ALGID_FEE_SHA1; 243 sigOid = CSSMOID_APPLE_FEE_SHA1; 244 break; 245 case 'e': 246 keyAlg = CSSM_ALGID_FEE; 247 sigAlg = CSSM_ALGID_SHA1WithECDSA; 248 sigOid = CSSMOID_APPLE_ECDSA; 249 break; 250 case 'E': 251 keyAlg = CSSM_ALGID_ECDSA; 252 sigAlg = CSSM_ALGID_SHA1WithECDSA; 253 sigOid = CSSMOID_ECDSA_WithSHA1; 254 break; 255 case '7': 256 keyAlg = CSSM_ALGID_ECDSA; 257 sigAlg = CSSM_ALGID_SHA256WithECDSA; 258 sigOid = CSSMOID_ECDSA_WithSHA256; 259 break; 260 case '8': 261 keyAlg = CSSM_ALGID_ECDSA; 262 sigAlg = CSSM_ALGID_SHA384WithECDSA; 263 sigOid = CSSMOID_ECDSA_WithSHA384; 264 break; 265 case '9': 266 keyAlg = CSSM_ALGID_ECDSA; 267 sigAlg = CSSM_ALGID_SHA512WithECDSA; 268 sigOid = CSSMOID_ECDSA_WithSHA512; 269 break; 270 default: 271 usage(argv); 272 } 273 break; 274 case 'k': 275 keySizeInBits = atoi(&argv[arg][2]); 276 break; 277 case 'e': 278 subjectEmail = &argv[arg][2]; 279 break; 280 case 'i': 281 issuerAltName = &argv[arg][2]; 282 break; 283 case 'r': 284 crlDistPoint = &argv[arg][2]; 285 break; 286 case 'u': 287 authorityInfoAccess = &argv[arg][2]; 288 break; 289 case 't': 290 authKeyIdName = &argv[arg][2]; 291 break; 292 case 's': 293 subjectKeyId = true; 294 break; 295 case 'p': 296 certPoliciesStr = &argv[arg][2]; 297 break; 298 case 'n': 299 netscapeTypeSpec = true; 300 netscapeType = atoi(&argv[arg][2]); 301 break; 302 case 'c': 303 subjRdn[NUM_SUBJ_NAMES-1].string = &argv[arg][2]; 304 break; 305 case 'N': 306 serialNumber = atoi(&argv[arg][2]); 307 break; 308 case 'P': 309 loopPause = true; 310 break; 311 default: 312 usage(argv); 313 } 314 } 315 316 /* connect to CL, TP, and CSP */ 317 clHand = clStartup(); 318 if(clHand == 0) { 319 return 0; 320 } 321 tpHand = tpStartup(); 322 if(tpHand == 0) { 323 return 0; 324 } 325 cspHand = cspStartup(); 326 if(cspHand == 0) { 327 return 0; 328 } 329 330 /* subsequent errors to abort: to detach */ 331 332 /* cook up an RSA key pair for the subject */ 333 crtn = cspGenKeyPair(cspHand, 334 keyAlg, 335 SUBJ_KEY_LABEL, 336 strlen(SUBJ_KEY_LABEL), 337 keySizeInBits, 338 &subjPubKey, 339 #if PUB_KEY_IS_REF 340 CSSM_TRUE, 341 #else 342 CSSM_FALSE, // pubIsRef 343 #endif 344 CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT, 345 CSSM_KEYBLOB_RAW_FORMAT_NONE, 346 &subjPrivKey, 347 writeBlobs ? CSSM_FALSE : CSSM_TRUE, // privIsRef 348 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_DECRYPT, 349 CSSM_KEYBLOB_RAW_FORMAT_NONE, 350 CSSM_FALSE); 351 if(crtn) { 352 errorCount++; 353 goto abort; 354 } 355 356 /* and the root */ 357 crtn = cspGenKeyPair(cspHand, 358 keyAlg, 359 ROOT_KEY_LABEL, 360 strlen(ROOT_KEY_LABEL), 361 keySizeInBits, 362 &rootPubKey, 363 CSSM_FALSE, // pubIsRef - should work both ways, but not yet 364 CSSM_KEYUSE_VERIFY, 365 CSSM_KEYBLOB_RAW_FORMAT_NONE, 366 &rootPrivKey, 367 writeBlobs ? CSSM_FALSE : CSSM_TRUE, // privIsRef 368 CSSM_KEYUSE_SIGN, 369 CSSM_KEYBLOB_RAW_FORMAT_NONE, 370 CSSM_FALSE); 371 if(crtn) { 372 errorCount++; 373 goto abort; 374 } 375 376 if(compareKeyData(&rootPubKey, &subjPubKey)) { 377 printf("**WARNING: Identical root and subj keys!\n"); 378 } 379 380 if(writeBlobs) { 381 writeFile(ROOT_KEY_FILE_NAME, rootPrivKey.KeyData.Data, 382 rootPrivKey.KeyData.Length); 383 printf("...wrote %lu bytes to %s\n", rootPrivKey.KeyData.Length, 384 ROOT_KEY_FILE_NAME); 385 writeFile(SUBJ_KEY_FILE_NAME, subjPrivKey.KeyData.Data, 386 subjPrivKey.KeyData.Length); 387 printf("...wrote %lu bytes to %s\n", subjPrivKey.KeyData.Length, 388 SUBJ_KEY_FILE_NAME); 389 } 390 391 if(loopPause) { 392 fpurge(stdin); 393 printf("pausing before root CSSM_TP_SubmitCredRequest; CR to continue:"); 394 getchar(); 395 } 396loopTop: 397 398 /* A KeyUsage extension for both certs */ 399 exts[0].type = DT_KeyUsage; 400 exts[0].critical = CSSM_FALSE; 401 exts[0].extension.keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign; 402 403 /* root - BasicConstraints extensions */ 404 exts[1].type = DT_BasicConstraints; 405 exts[1].critical = CSSM_TRUE; 406 exts[1].extension.basicConstraints.cA = CSSM_TRUE; 407 exts[1].extension.basicConstraints.pathLenConstraintPresent = CSSM_TRUE; 408 exts[1].extension.basicConstraints.pathLenConstraint = 2; 409 410 /* certReq for root */ 411 memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST)); 412 certReq.cspHand = cspHand; 413 certReq.clHand = clHand; 414 certReq.serialNumber = serialNumber; 415 certReq.numSubjectNames = NUM_ROOT_NAMES; 416 certReq.subjectNames = rootRdn; 417 certReq.numIssuerNames = 0; 418 certReq.issuerNames = NULL; 419 certReq.certPublicKey = &rootPubKey; 420 certReq.issuerPrivateKey = &rootPrivKey; 421 certReq.signatureAlg = sigAlg; 422 certReq.signatureOid = sigOid; 423 certReq.notBefore = 0; // now 424 certReq.notAfter = 10000; // seconds from now 425 certReq.numExtensions = 2; 426 certReq.extensions = exts; 427 428 reqSet.NumberOfRequests = 1; 429 reqSet.Requests = &certReq; 430 431 /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */ 432 memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT)); 433 memset(&policyId, 0, sizeof(CSSM_FIELD)); 434 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; 435 CallerAuthContext.Policy.NumberOfPolicyIds = 1; 436 CallerAuthContext.Policy.PolicyIds = &policyId; 437 438 /* generate root cert */ 439 printf("Creating root cert...\n"); 440 crtn = CSSM_TP_SubmitCredRequest(tpHand, 441 NULL, // PreferredAuthority 442 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, 443 &reqSet, 444 &CallerAuthContext, 445 &estTime, 446 &refId); 447 if(crtn) { 448 printError("CSSM_TP_SubmitCredRequest", crtn); 449 errorCount++; 450 goto abort; 451 } 452 crtn = CSSM_TP_RetrieveCredResult(tpHand, 453 &refId, 454 NULL, // CallerAuthCredentials 455 &estTime, 456 &confirmRequired, 457 &rootResultSet); 458 if(crtn) { 459 printError("CSSM_TP_RetrieveCredResult", crtn); 460 errorCount++; 461 goto abort; 462 } 463 CSSM_FREE(refId.Data); 464 if(rootResultSet == NULL) { 465 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n"); 466 errorCount++; 467 goto abort; 468 } 469 rootEncCert = (CSSM_ENCODED_CERT *)rootResultSet->Results; 470 signedRootCert = rootEncCert->CertBlob; 471 if(writeBlobs) { 472 writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, signedRootCert.Length); 473 printf("...wrote %lu bytes to %s\n", signedRootCert.Length, 474 ROOT_CERT_FILE_NAME); 475 } 476 477 if(loopPause) { 478 fpurge(stdin); 479 printf("pausing before subject CSSM_TP_SubmitCredRequest; CR to continue:"); 480 getchar(); 481 } 482 483 /* now a subject cert signed by the root cert */ 484 printf("Creating subject cert...\n"); 485 certReq.serialNumber = serialNumber + 1; 486 certReq.numSubjectNames = NUM_SUBJ_NAMES; 487 certReq.subjectNames = subjRdn; 488 certReq.numIssuerNames = NUM_ROOT_NAMES; 489 certReq.issuerNames = rootRdn; 490 certReq.certPublicKey = &subjPubKey; 491 certReq.issuerPrivateKey = &rootPrivKey; 492 certReq.numExtensions = 1; 493 certReq.extensions = exts; 494 495 /* subject cert extensions - at least KeyUsage, maybe more */ 496 exts[0].type = DT_KeyUsage; 497 exts[0].critical = CSSM_FALSE; 498 exts[0].extension.keyUsage = 499 CE_KU_DigitalSignature | CE_KU_DataEncipherment | CE_KU_KeyAgreement; 500 extp = &exts[1]; 501 502 if(subjectEmail) { 503 /* subjectAltName extension */ 504 makeGeneralNames(&extp->extension.subjectAltName, &sanGenName, 505 subjectEmail, GNT_RFC822Name); 506 extp->type = DT_SubjectAltName; 507 extp->critical = CSSM_FALSE; 508 certReq.numExtensions++; 509 extp++; 510 } 511 512 if(authKeyIdName) { 513 /* AuthorityKeyID extension */ 514 makeGeneralNames(&authKeyIdGenNames, &authKeyIdGenName, 515 authKeyIdName, GNT_DNSName); 516 CE_AuthorityKeyID *akid = &extp->extension.authorityKeyID; 517 memset(akid, 0, sizeof(*akid)); 518 akid->generalNamesPresent = CSSM_TRUE; 519 akid->generalNames = &authKeyIdGenNames; 520 akid->serialNumberPresent = CSSM_TRUE; 521 akid->serialNumber.Data = authKeyIdSerial; 522 akid->serialNumber.Length = sizeof(authKeyIdSerial); 523 524 extp->type = DT_AuthorityKeyID; 525 extp->critical = CSSM_FALSE; 526 certReq.numExtensions++; 527 extp++; 528 } 529 530 if(subjectKeyId) { 531 /* SubjectKeyID extension */ 532 CSSM_DATA *skid = &extp->extension.subjectKeyID; 533 skid->Data = subjKeyIdData; 534 skid->Length = sizeof(subjKeyIdData); 535 536 extp->type = DT_SubjectKeyID; 537 extp->critical = CSSM_FALSE; 538 certReq.numExtensions++; 539 extp++; 540 } 541 542 if(issuerAltName) { 543 /* issuerAltName extension */ 544 makeGeneralNames(&extp->extension.issuerAltName, &ianGenName, 545 issuerAltName, GNT_DNSName); 546 extp->type = DT_IssuerAltName; 547 extp->critical = CSSM_FALSE; 548 certReq.numExtensions++; 549 extp++; 550 } 551 552 if(crlDistPoint) { 553 /* CRLDistributionPoints extension */ 554 memset(&distPointName, 0, sizeof(distPointName)); 555 makeGeneralNames(&crlGenNames, &crlGenName, 556 crlDistPoint, GNT_URI); 557 distPointName.nameType = CE_CDNT_FullName; 558 distPointName.dpn.fullName = &crlGenNames; 559 560 cdp.distPointName = &distPointName; 561 cdp.reasonsPresent = CSSM_FALSE; 562 cdp.reasons = 0; 563 cdp.crlIssuer = NULL; 564 565 CE_CRLDistPointsSyntax *dps = &extp->extension.crlDistPoints; 566 dps->numDistPoints = 1; 567 dps->distPoints = &cdp; 568 extp->type = DT_CrlDistributionPoints; 569 extp->critical = CSSM_FALSE; 570 571 certReq.numExtensions++; 572 extp++; 573 } 574 575 if(authorityInfoAccess) { 576 /* AuthorityInfoAccess extension */ 577 CE_AuthorityInfoAccess *cad = &extp->extension.authorityInfoAccess; 578 cad->numAccessDescriptions = 1; 579 cad->accessDescriptions = &accessDescr; 580 makeGeneralName(&accessDescr.accessLocation, authorityInfoAccess, 581 GNT_DNSName); 582 accessDescr.accessMethod = CSSMOID_AD_OCSP; 583 extp->type = DT_AuthorityInfoAccess; 584 extp->critical = CSSM_FALSE; 585 certReq.numExtensions++; 586 extp++; 587 } 588 589 if(certPoliciesStr) { 590 /* Cert Policies extension */ 591 CE_CertPolicies *cp = &extp->extension.certPolicies; 592 cp->numPolicies = 1; 593 cp->policies = &polInfo; 594 /* just make this policy OID up */ 595 polInfo.certPolicyId = CSSMOID_APPLE_TP_PKINIT_CLIENT; 596 polInfo.numPolicyQualifiers = 1; 597 polInfo.policyQualifiers = &polQualInfo; 598 polQualInfo.policyQualifierId = CSSMOID_QT_CPS; 599 polQualInfo.qualifier.Data = (uint8 *)certPoliciesStr; 600 polQualInfo.qualifier.Length = strlen(certPoliciesStr); 601 602 extp->type = DT_CertPolicies; 603 extp->critical = CSSM_FALSE; 604 certReq.numExtensions++; 605 extp++; 606 } 607 608 if(netscapeTypeSpec) { 609 /* NetscapeCertType extension */ 610 extp->extension.netscapeCertType = netscapeType; 611 extp->type = DT_NetscapeCertType; 612 extp->critical = CSSM_FALSE; 613 certReq.numExtensions++; 614 extp++; 615 } 616 617 crtn = CSSM_TP_SubmitCredRequest(tpHand, 618 NULL, // PreferredAuthority 619 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, 620 &reqSet, 621 &CallerAuthContext, 622 &estTime, 623 &refId); 624 if(crtn) { 625 printError("CSSM_TP_SubmitCredRequest (2)", crtn); 626 errorCount++; 627 goto abort; 628 } 629 crtn = CSSM_TP_RetrieveCredResult(tpHand, 630 &refId, 631 NULL, // CallerAuthCredentials 632 &estTime, 633 &confirmRequired, 634 &subjResultSet); 635 if(crtn) { 636 printError("CSSM_TP_RetrieveCredResult (2)", crtn); 637 errorCount++; 638 goto abort; 639 } 640 CSSM_FREE(refId.Data); 641 if(subjResultSet == NULL) { 642 printf("***CSSM_TP_RetrieveCredResult (2) returned NULL result set.\n"); 643 errorCount++; 644 goto abort; 645 } 646 subjEncCert = (CSSM_ENCODED_CERT *)subjResultSet->Results; 647 signedSubjCert = subjEncCert->CertBlob; 648 649 if(writeBlobs) { 650 writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, signedSubjCert.Length); 651 printf("...wrote %lu bytes to %s\n", signedSubjCert.Length, 652 SUBJ_CERT_FILE_NAME); 653 } 654 655 /* 656 * Extract public keys from the two certs, verify. 657 */ 658 crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedSubjCert, &extractSubjKey); 659 if(crtn) { 660 printError("CSSM_CL_CertGetKeyInfo", crtn); 661 } 662 else { 663 /* compare key data - header is different. 664 * Known header differences: 665 * -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for 666 * this field 667 * -- Format. rootPubKey : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE) 668 * extractRootKey : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1) 669 * -- KeyAttr. rootPubKey : 0x20 (CSSM_KEYATTR_EXTRACTABLE) 670 * extractRootKey : 0x0 671 */ 672 if(!compareKeyData(extractSubjKey, &subjPubKey)) { 673 printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n"); 674 } 675 if(extractSubjKey->KeyHeader.LogicalKeySizeInBits != 676 subjPubKey.KeyHeader.LogicalKeySizeInBits) { 677 printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n", 678 (unsigned)extractSubjKey->KeyHeader.LogicalKeySizeInBits, 679 (unsigned)subjPubKey.KeyHeader.LogicalKeySizeInBits); 680 } 681 } 682 crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedRootCert, &extractRootKey); 683 if(crtn) { 684 printError("CSSM_CL_CertGetKeyInfo", crtn); 685 } 686 else { 687 if(!compareKeyData(extractRootKey, &rootPubKey)) { 688 printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n"); 689 } 690 } 691 692 /* 693 * Verify: 694 */ 695 printf("Verifying certificates...\n"); 696 697 /* 698 * Verify root cert by root pub key, should succeed. 699 */ 700 if(verifyCert(clHand, 701 cspHand, 702 &signedRootCert, 703 NULL, 704 &rootPubKey, 705 sigAlg, 706 CSSM_OK, 707 "Verify(root by root key)")) { 708 errorCount++; 709 /* continue */ 710 } 711 712 /* 713 * Verify root cert by root cert, should succeed. 714 */ 715 if(verifyCert(clHand, 716 cspHand, 717 &signedRootCert, 718 &signedRootCert, 719 NULL, 720 CSSM_ALGID_NONE, // sigAlg not used here 721 CSSM_OK, 722 "Verify(root by root cert)")) { 723 errorCount++; 724 /* continue */ 725 } 726 727 728 /* 729 * Verify subject cert by root pub key, should succeed. 730 */ 731 if(verifyCert(clHand, 732 cspHand, 733 &signedSubjCert, 734 NULL, 735 &rootPubKey, 736 sigAlg, 737 CSSM_OK, 738 "Verify(subj by root key)")) { 739 errorCount++; 740 /* continue */ 741 } 742 743 /* 744 * Verify subject cert by root cert, should succeed. 745 */ 746 if(verifyCert(clHand, 747 cspHand, 748 &signedSubjCert, 749 &signedRootCert, 750 NULL, 751 CSSM_ALGID_NONE, // sigAlg not used here 752 CSSM_OK, 753 "Verify(subj by root cert)")) { 754 errorCount++; 755 /* continue */ 756 } 757 758 /* 759 * Verify subject cert by root cert AND key, should succeed. 760 */ 761 if(verifyCert(clHand, 762 cspHand, 763 &signedSubjCert, 764 &signedRootCert, 765 &rootPubKey, 766 sigAlg, 767 CSSM_OK, 768 "Verify(subj by root cert and key)")) { 769 errorCount++; 770 /* continue */ 771 } 772 773 /* 774 * Verify subject cert by extracted root pub key, should succeed. 775 */ 776 if(verifyCert(clHand, 777 cspHand, 778 &signedSubjCert, 779 NULL, 780 extractRootKey, 781 sigAlg, 782 CSSM_OK, 783 "Verify(subj by extracted root key)")) { 784 errorCount++; 785 /* continue */ 786 } 787 788 /* 789 * Verify subject cert by subject pub key, should fail. 790 */ 791 if(verifyCert(clHand, 792 cspHand, 793 &signedSubjCert, 794 NULL, 795 &subjPubKey, 796 sigAlg, 797 CSSMERR_CL_VERIFICATION_FAILURE, 798 "Verify(subj by subj key)")) { 799 errorCount++; 800 /* continue */ 801 } 802 803 /* 804 * Verify subject cert by subject cert, should fail. 805 */ 806 if(verifyCert(clHand, 807 cspHand, 808 &signedSubjCert, 809 &signedSubjCert, 810 NULL, 811 CSSM_ALGID_NONE, // sigAlg not used here 812 CSSMERR_CL_VERIFICATION_FAILURE, 813 "Verify(subj by subj cert)")) { 814 errorCount++; 815 /* continue */ 816 } 817 818 /* 819 * Verify erroneous subject cert by root pub key, should fail. 820 */ 821 badByte = genRand(1, signedSubjCert.Length - 1); 822 signedSubjCert.Data[badByte] ^= 0x55; 823 if(verifyCert(clHand, 824 cspHand, 825 &signedSubjCert, 826 NULL, 827 &rootPubKey, 828 sigAlg, 829 CSSMERR_CL_VERIFICATION_FAILURE, 830 "Verify(bad subj by root key)")) { 831 errorCount++; 832 /* continue */ 833 } 834 835 836 /* free/delete certs and keys */ 837 CSSM_FREE(signedSubjCert.Data); 838 CSSM_FREE(signedRootCert.Data); 839 CSSM_FREE(rootEncCert); 840 CSSM_FREE(subjEncCert); 841 CSSM_FREE(rootResultSet); 842 CSSM_FREE(subjResultSet); 843 844 /* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with 845 * a bogus GUID. This may be a problem with the Apple CSP... 846 * 847 cspFreeKey(cspHand, extractRootKey); 848 cspFreeKey(cspHand, extractSubjKey); 849 * 850 * do it this way instead...*/ 851 CSSM_FREE(extractRootKey->KeyData.Data); 852 CSSM_FREE(extractSubjKey->KeyData.Data); 853 854 /* need to do this regardless...*/ 855 CSSM_FREE(extractRootKey); 856 CSSM_FREE(extractSubjKey); 857 858 if(loopPause) { 859 fpurge(stdin); 860 printf("pausing at end of loop; CR to continue:"); 861 getchar(); 862 goto loopTop; 863 } 864 865abort: 866 cspFreeKey(cspHand, &rootPubKey); 867 cspFreeKey(cspHand, &subjPubKey); 868 869 if(cspHand != 0) { 870 CSSM_ModuleDetach(cspHand); 871 } 872 if(clHand != 0) { 873 CSSM_ModuleDetach(clHand); 874 } 875 if(tpHand != 0) { 876 CSSM_ModuleDetach(tpHand); 877 } 878 879 if(errorCount) { 880 printf("Signer/Subject test failed with %d errors\n", errorCount); 881 } 882 else { 883 printf("Signer/Subject test succeeded\n"); 884 } 885 return 0; 886} 887 888 889/* compare KeyData for two keys. */ 890static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2) 891{ 892 if(key1->KeyData.Length != key2->KeyData.Length) { 893 return CSSM_FALSE; 894 } 895 if(memcmp(key1->KeyData.Data, 896 key2->KeyData.Data, 897 key1->KeyData.Length)) { 898 return CSSM_FALSE; 899 } 900 return CSSM_TRUE; 901} 902 903/* verify a cert using specified key and/or signerCert */ 904static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand, 905 CSSM_CSP_HANDLE cspHand, 906 CSSM_DATA_PTR cert, 907 CSSM_DATA_PTR signerCert, // optional 908 CSSM_KEY_PTR key, // ditto, to work spec one, other, or both 909 CSSM_ALGORITHMS sigAlg, // CSSM_ALGID_SHA1WithRSA, etc. 910 CSSM_RETURN expectResult, 911 const char *opString) 912{ 913 CSSM_RETURN crtn; 914 CSSM_CC_HANDLE signContext = CSSM_INVALID_HANDLE; 915 916 if(key) { 917 crtn = CSSM_CSP_CreateSignatureContext(cspHand, 918 sigAlg, 919 NULL, // AccessCred 920 key, 921 &signContext); 922 if(crtn) { 923 printf("Failure during %s\n", opString); 924 printError("CSSM_CSP_CreateSignatureContext", crtn); 925 return crtn; 926 } 927 } 928 crtn = CSSM_CL_CertVerify(clHand, 929 signContext, 930 cert, // CertToBeVerified 931 signerCert, // SignerCert 932 NULL, // VerifyScope 933 0); // ScopeSize 934 935 /* Hack to accomodate ECDSA returning CSSMERR_CSP_INVALID_SIGNATURE - a more detailed */ 936 if(crtn != expectResult) { 937 printf("Failure during %s\n", opString); 938 if(crtn == CSSM_OK) { 939 printf("Unexpected CSSM_CL_CertVerify success\n"); 940 } 941 else if(expectResult == CSSM_OK) { 942 printError("CSSM_CL_CertVerify", crtn); 943 } 944 else { 945 printError("CSSM_CL_CertVerify: expected", expectResult); 946 printError("CSSM_CL_CertVerify: got ", crtn); 947 } 948 return CSSMERR_CL_VERIFICATION_FAILURE; 949 } 950 if(signContext != CSSM_INVALID_HANDLE) { 951 crtn = CSSM_DeleteContext(signContext); 952 if(crtn) { 953 printf("Failure during %s\n", opString); 954 printError("CSSM_DeleteContext", crtn); 955 return crtn; 956 } 957 } 958 return CSSM_OK; 959} 960