1/* 2 * Copyright (c) 2002-2003 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please 7 * obtain a copy of the License at http://www.apple.com/publicsource and 8 * read it before using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 15 * Please see the License for the specific language governing rights and 16 * limitations under the License. 17 */ 18 19/* 20 File: CertTool.cpp 21 22 Description: certificate manipulation tool 23 24 Author: dmitch 25*/ 26 27#include <Security/Security.h> 28#include <Security/certextensions.h> 29#include <Security/cssmapple.h> 30#include <Security/oidsattr.h> 31#include <Security/oidscert.h> 32#include <Security/oidsalg.h> 33#include <Security/SecIdentityPriv.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <strings.h> 37#include <ctype.h> 38#include <sys/param.h> 39#include <unistd.h> 40#include <security_cdsa_utils/cuCdsaUtils.h> 41#include <security_cdsa_utils/cuDbUtils.h> 42#include <security_cdsa_utils/cuPrintCert.h> 43#include <security_cdsa_utils/cuFileIo.h> 44#include <security_cdsa_utils/cuPem.h> 45#include <security_utilities/alloc.h> 46#include <security_cdsa_client/aclclient.h> 47#include <security_utilities/devrandom.h> 48#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 49#include "CertUI.h" 50#include <CoreFoundation/CoreFoundation.h> 51 52#define KC_DB_PATH "Library/Keychains" /* relative to home */ 53#define SYSTEM_KDC "com.apple.kerberos.kdc" 54 55/* 56 * defaults for undocumented 'Z' option 57 */ 58#define ZDEF_KEY_LABEL "testCert" 59#define ZDEF_KEY_ALG CSSM_ALGID_RSA 60#define ZDEF_KEY_SIZE 512 61#define ZDEF_KEY_USAGE (kKeyUseSigning | kKeyUseEncrypting) 62#define ZDEF_SIG_ALG CSSM_ALGID_SHA256WithRSA 63#define ZDEF_SIG_OID CSSMOID_SHA256WithRSA 64#define ZDEF_COMMON_NAME "localhost" 65#define ZDEF_ORG_NAME "Apple Computer - DEBUG ONLY" 66#define ZDEF_COUNTRY "US" 67#define ZDEF_STATE "Washington" 68#define ZDEF_CHALLENGE "someChallenge" 69 70/* 71 * Key and cert parameters for creating system identity 72 */ 73#define SI_DEF_KEY_LABEL "System Identity" 74#define SI_DEF_KEY_ALG CSSM_ALGID_RSA 75#define SI_DEF_KEY_SIZE (1024 * 2) 76#define SI_DEF_KEY_USAGE (kKeyUseSigning | kKeyUseEncrypting) 77#define SI_DEF_SIG_ALG CSSM_ALGID_SHA256WithRSA 78#define SI_DEF_SIG_OID CSSMOID_SHA256WithRSA 79/* common name = domain */ 80#define SI_DEF_ORG_NAME "System Identity" 81/* org unit = hostname */ 82#define SI_DEF_VALIDITY (60 * 60 * 24 * 365 * 20) /* 20 years */ 83 84/* 85 * Default validity 86 */ 87#define DEFAULT_CERT_VALIDITY (60 * 60 * 24 * 30) /* 30 days */ 88 89/* 90 * Validity period environment variable 91 * <rdar://problem/16760570> Update certtool to support validate period via an environment variable 92 */ 93#define VALIDITY_DAYS_ENVIRONMENT_VARIABLE "CERTTOOL_EXPIRATION_DAYS" 94 95 CSSM_BOOL verbose = CSSM_FALSE; 96 97static void usage(char **argv) 98{ 99 printf("usage:\n"); 100 printf(" Create a keypair and cert: %s c [options]\n", argv[0]); 101 printf(" Create a CSR: %s r outFileName [options]\n", 102 argv[0]); 103 printf(" Verify a CSR: %s v infileName [options]\n", argv[0]); 104 printf(" Create a system Identity: %s C domainName [options]\n", argv[0]); 105 printf(" Import a certificate: %s i inFileName [options]\n", argv[0]); 106 printf(" Display a certificate: %s d inFileName [options]\n", argv[0]); 107 printf(" Import a CRL: %s I inFileName [options]\n", argv[0]); 108 printf(" Display a CRL: %s D inFileName [options]\n", argv[0]); 109 printf(" Display certs and CRLs in keychain: %s y [options]\n", argv[0]); 110 printf("Options:\n"); 111 printf(" k=keychainName\n"); 112 printf(" c (create the keychain)\n"); 113 printf(" p=passphrase (specify passphrase at keychain creation)\n"); 114 printf(" o=outFileName (create cert command only)\n"); 115 printf(" v (verbose)\n"); 116 printf(" d (infile/outfile in DER format; default is PEM)\n"); 117 printf(" r=privateKeyFileName (optional; for Import Certificate only)\n"); 118 printf(" f=[18fo] (private key format = PKCS1/PKCS8/FIPS186; default is PKCS1\n" 119 " (openssl) for RSA, openssl for DSA, PKCS8 for Diffie-Hellman,\n" 120 " OpenSSL for ECDSA\n"); 121 printf(" x=[asSm] (Extended Key Usage: a=Any; s=SSL Client; S=SSL Server; m=SMIME)\n"); 122 printf(" a (create key with default ACL)\n"); 123 printf(" u (create key with ACL limiting access to current UID)\n"); 124 printf(" P (Don't create system identity if one already exists for specified domain)\n"); 125 printf(" h(elp)\n"); 126 exit(1); 127} 128 129static void printError(const char *errDescription,const char *errLocation,OSStatus crtn) 130{ 131 // Show error in text form. If verbose, show location and decimal and hex error values 132 int len=64+(errLocation?strlen(errLocation):0); 133 if (verbose) 134 { 135 char *buf=(char *)malloc(len); 136 if (errDescription) 137 fprintf(stderr,"%s : ",errDescription); 138 // sprintf(buf," %s : %d [0x%x] : ", errLocation,(int)crtn,(unsigned int)crtn); 139 // cuPrintError(buf, crtn); 140 cuPrintError(errLocation, crtn); 141 free(buf); 142 } 143 else 144 { 145 if (errDescription) 146 fprintf(stderr,"%s\n",errDescription); 147 else 148 if (errLocation) 149 fprintf(stderr,"%s\n",errLocation); 150 else 151 fprintf(stderr,"Error: %d [0x%x]\n",(int)crtn,(unsigned int)crtn); 152 } 153} 154 155void check_obsolete_keychain(const char *kcName) 156{ 157 if(!strcmp(kcName, "/System/Library/Keychains/X509Anchors")) { 158 fprintf(stderr, "***************************************************************\n"); 159 fprintf(stderr, " WARNING\n"); 160 fprintf(stderr, "\n"); 161 fprintf(stderr, "The keychain you are accessing, X509Anchors, is no longer\n"); 162 fprintf(stderr, "used by Mac OS X as the system root certificate store.\n"); 163 fprintf(stderr, "Please read the security man page for information on the \n"); 164 fprintf(stderr, "add-trusted-cert command. New system root certificates should\n"); 165 fprintf(stderr, "be added to the Admin Trust Settings domain and to the \n"); 166 fprintf(stderr, "System keychain in /Library/Keychains.\n"); 167 fprintf(stderr, "***************************************************************\n"); 168 } 169 else if(!strcmp(kcName, "/System/Library/Keychains/X509Certificates")) { 170 fprintf(stderr, "***************************************************************\n"); 171 fprintf(stderr, " WARNING\n"); 172 fprintf(stderr, "\n"); 173 fprintf(stderr, "The keychain you are accessing, X509Certificates, is no longer\n"); 174 fprintf(stderr, "used by Mac OS X as the system intermediate certificate\n"); 175 fprintf(stderr, "store. New system intermediate certificates should be added\n"); 176 fprintf(stderr, "to the System keychain in /Library/Keychains.\n"); 177 fprintf(stderr, "***************************************************************\n"); 178 } 179} 180 181// 182// Create a SecAccessRef with a custom form. 183// Both the owner and the ACL set allow free access to the specified, 184// UID, but nothing to anyone else. 185// 186static OSStatus makeUidAccess(uid_t uid, SecAccessRef *rtnAccess) 187{ 188 // make the "uid/gid" ACL subject 189 // this is a CSSM_LIST_ELEMENT chain 190 CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = { 191 CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, // selector version 192 CSSM_ACL_MATCH_UID, // set mask: match uids (only) 193 uid, // uid to match 194 0 // gid (not matched here) 195 }; 196 CSSM_LIST_ELEMENT subject2 = { NULL, 0 }; 197 subject2.Element.Word.Data = (UInt8 *)&selector; 198 subject2.Element.Word.Length = sizeof(selector); 199 CSSM_LIST_ELEMENT subject1 = { 200 &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID 201 }; 202 203 204 // rights granted (replace with individual list if desired) 205 CSSM_ACL_AUTHORIZATION_TAG rights[] = { 206 CSSM_ACL_AUTHORIZATION_ANY // everything 207 }; 208 // owner component (right to change ACL) 209 CSSM_ACL_OWNER_PROTOTYPE owner = { 210 // TypedSubject 211 { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, 212 // Delegate 213 false 214 }; 215 // ACL entries (any number, just one here) 216 CSSM_ACL_ENTRY_INFO acls[] = { 217 { 218 // prototype 219 { 220 // TypedSubject 221 { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, 222 false, // Delegate 223 // rights for this entry 224 { sizeof(rights) / sizeof(rights[0]), rights }, 225 // rest is defaulted 226 } 227 } 228 }; 229 230 return SecAccessCreateFromOwnerAndACL(&owner, 231 sizeof(acls) / sizeof(acls[0]), acls, rtnAccess); 232} 233 234static OSStatus setKeyPrintName( 235 SecKeyRef keyRef, 236 const char *keyName) 237{ 238 UInt32 tag = kSecKeyPrintName; 239 SecKeychainAttributeInfo attrInfo; 240 attrInfo.count = 1; 241 attrInfo.tag = &tag; 242 attrInfo.format = NULL; 243 SecKeychainAttributeList *copiedAttrs = NULL; 244 245 OSStatus ortn = SecKeychainItemCopyAttributesAndData( 246 (SecKeychainItemRef)keyRef, 247 &attrInfo, 248 NULL, // itemClass 249 &copiedAttrs, 250 NULL, // length - don't need the data 251 NULL); // outData 252 if(ortn) { 253 printError("***Error creating key pair", 254 "SecKeychainItemCopyAttributesAndData", ortn); 255 return ortn; 256 } 257 258 SecKeychainAttributeList newAttrList; 259 newAttrList.count = 1; 260 SecKeychainAttribute newAttr; 261 newAttrList.attr = &newAttr; 262 newAttr.tag = copiedAttrs->attr->tag; 263 newAttr.length = strlen(keyName); 264 newAttr.data = (void*)keyName; 265 ortn = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)keyRef, 266 &newAttrList, 0, NULL); 267 if(ortn) { 268 printError("***Error creating key pair", 269 "SecKeychainItemModifyAttributesAndData", ortn); 270 } 271 SecKeychainItemFreeAttributesAndData(copiedAttrs, NULL); 272 return ortn; 273} 274 275/* 276 * Generate a key pair using SecKeyCreatePair. 277 */ 278static OSStatus generateSecKeyPair( 279 SecKeychainRef kcRef, 280 CSSM_ALGORITHMS keyAlg, // e.g., CSSM_ALGID_RSA 281 uint32 keySizeInBits, 282 CU_KeyUsage keyUsage, // CUK_Signing, etc. 283 CSSM_BOOL aclForUid, // ACL for current UID 284 CSSM_BOOL verbose, 285 const char *keyLabel, // optional 286 CSSM_KEY_PTR *pubKeyPtr, // RETURNED, owned by Sec layer 287 CSSM_KEY_PTR *privKeyPtr, // RETURNED, owned by Sec layer 288 SecKeyRef *pubSecKey, // caller must release 289 SecKeyRef *privSecKey) // caller must release 290{ 291 OSStatus ortn; 292 CSSM_KEYUSE pubKeyUse = 0; 293 CSSM_KEYUSE privKeyUse = 0; 294 SecAccessRef secAccess = NULL; 295 296 if(aclForUid) { 297 ortn = makeUidAccess(geteuid(), &secAccess); 298 if(ortn) { 299 printError("***Error creating key pair", 300 "SecAccessCreateFromOwnerAndACL", ortn); 301 return ortn; 302 } 303 } 304 if(keyUsage & kKeyUseSigning) { 305 pubKeyUse |= CSSM_KEYUSE_VERIFY; 306 privKeyUse |= CSSM_KEYUSE_SIGN; 307 } 308 if(keyUsage & kKeyUseEncrypting) { 309 pubKeyUse |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP); 310 privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP); 311 } 312 if(keyUsage & kKeyUseDerive) { 313 pubKeyUse |= CSSM_KEYUSE_DERIVE; 314 privKeyUse |= CSSM_KEYUSE_DERIVE; 315 } 316 ortn = SecKeyCreatePair(kcRef, 317 keyAlg, keySizeInBits, 318 0, // contextHandle 319 pubKeyUse, 320 CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE | 321 CSSM_KEYATTR_RETURN_REF, 322 privKeyUse, 323 CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | 324 CSSM_KEYATTR_PERMANENT |CSSM_KEYATTR_EXTRACTABLE, 325 secAccess, 326 pubSecKey, 327 privSecKey); 328 if(secAccess) { 329 CFRelease(secAccess); 330 } 331 if(ortn) { 332 printError("***Error creating key pair", 333 "SecKeyCreatePair", ortn); 334 cuPrintError("", ortn); 335 return ortn; 336 } 337 if(keyLabel != NULL) { 338 ortn = setKeyPrintName(*pubSecKey, keyLabel); 339 if(ortn) { 340 return ortn; 341 } 342 ortn = setKeyPrintName(*privSecKey, keyLabel); 343 if(ortn) { 344 return ortn; 345 } 346 } 347 348 /* extract CSSM keys for caller */ 349 ortn = SecKeyGetCSSMKey(*pubSecKey, const_cast<const CSSM_KEY **>(pubKeyPtr)); 350 if(ortn) { 351 printError("***Error extracting public key", 352 "SecKeyGetCSSMKey", ortn); 353 cuPrintError("", ortn); 354 } 355 else ortn = SecKeyGetCSSMKey(*privSecKey, const_cast<const CSSM_KEY **>(privKeyPtr)); 356 if(ortn) { 357 printError("***Error extracting private key", 358 "SecKeyGetCSSMKey", ortn); 359 cuPrintError("", ortn); 360 } 361 if(ortn) { 362 CFRelease(*pubSecKey); 363 *pubSecKey = NULL; 364 CFRelease(*privSecKey); 365 *privSecKey = NULL; 366 } 367 return ortn; 368} 369 370/* 371 * Find private key by label, modify its Label attr to be the 372 * hash of the associated public key. 373 */ 374static CSSM_RETURN setPubKeyHash( 375 CSSM_CSP_HANDLE cspHand, 376 CSSM_DL_DB_HANDLE dlDbHand, 377 const char *keyLabel) // look up by this 378{ 379 CSSM_QUERY query; 380 CSSM_SELECTION_PREDICATE predicate; 381 CSSM_DB_UNIQUE_RECORD_PTR record = NULL; 382 CSSM_RETURN crtn; 383 CSSM_DATA labelData; 384 CSSM_HANDLE resultHand; 385 386 labelData.Data = (uint8 *)keyLabel; 387 labelData.Length = strlen(keyLabel) + 1; // incl. NULL 388 query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; 389 query.Conjunctive = CSSM_DB_NONE; 390 query.NumSelectionPredicates = 1; 391 predicate.DbOperator = CSSM_DB_EQUAL; 392 393 predicate.Attribute.Info.AttributeNameFormat = 394 CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 395 predicate.Attribute.Info.Label.AttributeName = (char*) "Label"; 396 predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; 397 /* hope this cast is OK */ 398 predicate.Attribute.Value = &labelData; 399 query.SelectionPredicate = &predicate; 400 401 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful? 402 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful? 403 query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA; // FIXME - used? 404 405 /* build Record attribute with one attr */ 406 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; 407 CSSM_DB_ATTRIBUTE_DATA attr; 408 attr.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 409 attr.Info.Label.AttributeName = (char*) "Label"; 410 attr.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; 411 412 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; 413 recordAttrs.NumberOfAttributes = 1; 414 recordAttrs.AttributeData = &attr; 415 416 CSSM_DATA recordData = {0, NULL}; 417 crtn = CSSM_DL_DataGetFirst(dlDbHand, 418 &query, 419 &resultHand, 420 &recordAttrs, 421 &recordData, 422 &record); 423 /* abort only on success */ 424 if(crtn != CSSM_OK) { 425 printError("***setPubKeyHash: can't find private key","CSSM_DL_DataGetFirst",crtn); 426 return crtn; 427 } 428 429 CSSM_KEY_PTR keyToDigest = (CSSM_KEY_PTR)recordData.Data; 430 CSSM_DATA_PTR keyDigest = NULL; 431 CSSM_CC_HANDLE ccHand; 432 crtn = CSSM_CSP_CreatePassThroughContext(cspHand, 433 keyToDigest, 434 &ccHand); 435 if(crtn) { 436 printError("***Error calculating public key hash. Aborting.", 437 "CSSM_CSP_CreatePassThroughContext", crtn); 438 return crtn; 439 } 440 crtn = CSSM_CSP_PassThrough(ccHand, 441 CSSM_APPLECSP_KEYDIGEST, 442 NULL, 443 (void **)&keyDigest); 444 if(crtn) { 445 printError("***Error calculating public key hash. Aborting.", 446 "CSSM_CSP_PassThrough(PUBKEYHASH)", crtn); 447 return -1; 448 } 449 CSSM_FreeKey(cspHand, NULL, keyToDigest, CSSM_FALSE); 450 CSSM_DeleteContext(ccHand); 451 452 /* 453 * Replace Label attr data with hash. 454 * NOTE: the module which allocated this attribute data - a DL - 455 * was loaded and attached by the Sec layer, not by us. Thus 456 * we can't use the memory allocator functions *we* used when 457 * attaching to the CSPDL - we have to use the ones 458 * which the Sec layer registered with the DL. 459 */ 460 CSSM_API_MEMORY_FUNCS memFuncs; 461 crtn = CSSM_GetAPIMemoryFunctions(dlDbHand.DLHandle, &memFuncs); 462 if(crtn) { 463 printError("***Error ","CSSM_GetAPIMemoryFunctions(DLHandle)",crtn); 464 /* oh well, leak and continue */ 465 } 466 else { 467 memFuncs.free_func(attr.Value->Data, memFuncs.AllocRef); 468 memFuncs.free_func(attr.Value, memFuncs.AllocRef); 469 } 470 attr.Value = keyDigest; 471 472 /* modify key attributes */ 473 crtn = CSSM_DL_DataModify(dlDbHand, 474 CSSM_DL_DB_RECORD_PRIVATE_KEY, 475 record, 476 &recordAttrs, 477 NULL, // DataToBeModified 478 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); 479 if(crtn) { 480 printError("***Error setting public key hash. Aborting.", 481 "CSSM_DL_DataModify(PUBKEYHASH)", crtn); 482 return crtn; 483 } 484 crtn = CSSM_DL_DataAbortQuery(dlDbHand, resultHand); 485 if(crtn) { 486 printError("***Error while stopping query", 487 "CSSM_DL_DataAbortQuery", crtn); 488 /* let's keep going in this case */ 489 } 490 crtn = CSSM_DL_FreeUniqueRecord(dlDbHand, record); 491 if(crtn) { 492 printError("***Error while freeing record", 493 "CSSM_DL_FreeUniqueRecord", crtn); 494 /* let's keep going in this case */ 495 crtn = CSSM_OK; 496 } 497 498 /* free resources */ 499 cuAppFree(keyDigest->Data, NULL); 500 return CSSM_OK; 501} 502 503/* 504 * Generate a key pair using the CSPDL. 505 */ 506static OSStatus generateKeyPair( 507 CSSM_CSP_HANDLE cspHand, 508 CSSM_DL_DB_HANDLE dlDbHand, 509 CSSM_ALGORITHMS keyAlg, // e.g., CSSM_ALGID_RSA 510 uint32 keySizeInBits, 511 const char *keyLabel, // C string 512 CU_KeyUsage keyUsage, // CUK_Signing, etc. 513 CSSM_BOOL verbose, 514 CSSM_KEY_PTR *pubKeyPtr, // mallocd, created, RETURNED 515 CSSM_KEY_PTR *privKeyPtr) // mallocd, created, RETURNED 516{ 517 CSSM_KEY_PTR pubKey = reinterpret_cast<CSSM_KEY_PTR>( 518 APP_MALLOC(sizeof(CSSM_KEY))); 519 CSSM_KEY_PTR privKey = reinterpret_cast<CSSM_KEY_PTR>( 520 APP_MALLOC(sizeof(CSSM_KEY))); 521 if((pubKey == NULL) || (privKey == NULL)) { 522 return memFullErr; 523 } 524 525 CSSM_RETURN crtn; 526 CSSM_KEYUSE pubKeyUse = 0; 527 CSSM_KEYUSE privKeyUse = 0; 528 529 if(keyUsage & kKeyUseSigning) { 530 pubKeyUse |= CSSM_KEYUSE_VERIFY; 531 privKeyUse |= CSSM_KEYUSE_SIGN; 532 } 533 if(keyUsage & kKeyUseEncrypting) { 534 pubKeyUse |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP); 535 privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP); 536 } 537 if(keyUsage & kKeyUseDerive) { 538 pubKeyUse |= CSSM_KEYUSE_DERIVE; 539 privKeyUse |= CSSM_KEYUSE_DERIVE; 540 } 541 542 crtn = cuCspGenKeyPair(cspHand, 543 &dlDbHand, 544 keyAlg, 545 keyLabel, 546 strlen(keyLabel) + 1, 547 keySizeInBits, 548 pubKey, 549 pubKeyUse, 550 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF, 551 privKey, 552 privKeyUse, 553 CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | 554 CSSM_KEYATTR_EXTRACTABLE); 555 if(crtn) { 556 APP_FREE(pubKey); 557 APP_FREE(privKey); 558 return paramErr; 559 } 560 if(verbose) { 561 printf("...%u bit key pair generated.\n", 562 (unsigned)keySizeInBits); 563 } 564 565 /* bind private key to cert by public key hash */ 566 crtn = setPubKeyHash(cspHand, 567 dlDbHand, 568 keyLabel); 569 if(crtn) { 570 printError("***Error setting public key hash. Continuing at peril.", 571 "setPubKeyHash", crtn); 572 } 573 574 *pubKeyPtr = pubKey; 575 *privKeyPtr = privKey; 576 return noErr; 577} 578 579static OSStatus verifyCsr( 580 CSSM_CL_HANDLE clHand, 581 const char *fileName, 582 CSSM_BOOL pemFormat) 583{ 584 unsigned char *csr = NULL; 585 unsigned csrLen; 586 CSSM_DATA csrData; 587 unsigned char *der = NULL; 588 unsigned derLen = 0; 589 590 if(readFile(fileName, &csr, &csrLen)) { 591 printf("***Error reading CSR from file %s. Aborting.\n", 592 fileName); 593 return ioErr; 594 } 595 if(pemFormat) { 596 int rtn = pemDecode(csr, csrLen, &der, &derLen); 597 if(rtn) { 598 printf("***%s: Bad PEM formatting. Aborting.\n", fileName); 599 return ioErr; 600 } 601 csrData.Data = der; 602 csrData.Length = derLen; 603 } 604 else { 605 csrData.Data = csr; 606 csrData.Length = csrLen; 607 } 608 609 CSSM_RETURN crtn = CSSM_CL_PassThrough(clHand, 610 0, // CCHandle 611 CSSM_APPLEX509CL_VERIFY_CSR, 612 &csrData, 613 NULL); 614 if(crtn) { 615 printError("***Error verifying CSR","Verify CSR",crtn); 616 } 617 else { 618 printf("...CSR verified successfully.\n"); 619 } 620 if(der) { 621 free(der); 622 } 623 if(csr) { 624 free(csr); 625 } 626 return crtn; 627} 628 629typedef enum { 630 CC_Cert, 631 CC_CRL 632} CertOrCrl; 633 634static OSStatus displayCertCRL( 635 const char *fileName, 636 CSSM_BOOL pemFormat, 637 CertOrCrl certOrCrl, 638 CSSM_BOOL verbose) 639{ 640 unsigned char *rawData = NULL; 641 unsigned rawDataSize; 642 unsigned char *derData = NULL; 643 unsigned derDataSize; 644 int rtn; 645 646 rtn = readFile(fileName, &rawData, &rawDataSize); 647 if(rtn) { 648 printf("Error reading %s; aborting.\n", fileName); 649 return ioErr; 650 } 651 if(pemFormat && isPem(rawData, rawDataSize)) { 652 /* 653 * Here we cut the user some slack. See if the thing is actually 654 * PEM encoded and assume DER-encoded if it's not. 655 */ 656 rtn = pemDecode(rawData, rawDataSize, &derData, &derDataSize); 657 if(rtn) { 658 printf("***%s: Bad PEM formatting. Aborting.\n", fileName); 659 return ioErr; 660 } 661 rawData = derData; 662 rawDataSize = derDataSize; 663 } 664 if(certOrCrl == CC_Cert) { 665 printCert(rawData, rawDataSize, verbose); 666 } 667 else { 668 printCrl(rawData, rawDataSize, verbose); 669 } 670 if(derData != NULL) { 671 free(derData); 672 } 673 return noErr; 674} 675 676static CSSM_RETURN importPrivateKey( 677 CSSM_DL_DB_HANDLE dlDbHand, 678 CSSM_CSP_HANDLE cspHand, 679 const char *privKeyFileName, 680 CSSM_ALGORITHMS keyAlg, 681 CSSM_BOOL pemFormat, // of the file 682 CSSM_KEYBLOB_FORMAT keyFormat) // of the key blob itself, NONE means use 683 // default 684{ 685 unsigned char *derKey = NULL; 686 unsigned derKeyLen; 687 unsigned char *pemKey = NULL; 688 unsigned pemKeyLen; 689 CSSM_KEY wrappedKey; 690 CSSM_KEY unwrappedKey; 691 CSSM_ACCESS_CREDENTIALS creds; 692 CSSM_CC_HANDLE ccHand = 0; 693 CSSM_RETURN crtn; 694 CSSM_DATA labelData; 695 CSSM_KEYHEADER_PTR hdr = &wrappedKey.KeyHeader; 696 CSSM_DATA descData = {0, NULL}; 697 CSSM_CSP_HANDLE rawCspHand = 0; 698 const char *privKeyLabel = NULL; 699 700 /* 701 * Validate specified format for clarity 702 */ 703 switch(keyAlg) { 704 case CSSM_ALGID_RSA: 705 switch(keyFormat) { 706 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 707 keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; // default 708 break; 709 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: 710 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: 711 break; 712 default: 713 printf("***RSA Private key must be in PKCS1 or PKCS8 format\n"); 714 return CSSMERR_CSSM_INTERNAL_ERROR; 715 } 716 privKeyLabel = "Imported RSA key"; 717 break; 718 case CSSM_ALGID_DSA: 719 switch(keyFormat) { 720 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 721 keyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; // default 722 break; 723 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: 724 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: 725 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: 726 break; 727 default: 728 printf("***DSA Private key must be in openssl, FIPS186, " 729 "or PKCS8 format\n"); 730 return CSSMERR_CSSM_INTERNAL_ERROR; 731 } 732 privKeyLabel = "Imported DSA key"; 733 break; 734 case CSSM_ALGID_DH: 735 switch(keyFormat) { 736 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 737 keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; // default 738 break; 739 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: 740 break; 741 default: 742 printf("***Diffie-Hellman Private key must be in PKCS8 format.\n"); 743 return CSSMERR_CSSM_INTERNAL_ERROR; 744 } 745 privKeyLabel = "Imported Diffie-Hellman key"; 746 break; 747 case CSSM_ALGID_ECDSA: 748 switch(keyFormat) { 749 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 750 keyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; // default 751 break; 752 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: 753 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: 754 break; 755 default: 756 printf("***ECDSA Private key must be in PKCS8 or OpenSSLformat.\n"); 757 return CSSMERR_CSSM_INTERNAL_ERROR; 758 } 759 privKeyLabel = "Imported ECDSA key"; 760 break; 761 } 762 if(readFile(privKeyFileName, &pemKey, &pemKeyLen)) { 763 printf("***Error reading private key from file %s. Aborting.\n", 764 privKeyFileName); 765 return CSSMERR_CSSM_INTERNAL_ERROR; 766 } 767 /* subsequent errors to done: */ 768 if(pemFormat) { 769 int rtn = pemDecode(pemKey, pemKeyLen, &derKey, &derKeyLen); 770 if(rtn) { 771 printf("***%s: Bad PEM formatting. Aborting.\n", privKeyFileName); 772 crtn = CSSMERR_CSP_INVALID_KEY; 773 goto done; 774 } 775 } 776 else { 777 derKey = pemKey; 778 derKeyLen = pemKeyLen; 779 } 780 781 /* importing a raw key into the CSPDL involves a NULL unwrap */ 782 memset(&unwrappedKey, 0, sizeof(CSSM_KEY)); 783 memset(&wrappedKey, 0, sizeof(CSSM_KEY)); 784 785 /* set up the imported key to look like a CSSM_KEY */ 786 hdr->HeaderVersion = CSSM_KEYHEADER_VERSION; 787 hdr->BlobType = CSSM_KEYBLOB_RAW; 788 hdr->AlgorithmId = keyAlg; 789 hdr->KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; 790 hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE; 791 hdr->KeyUsage = CSSM_KEYUSE_ANY; 792 hdr->Format = keyFormat; 793 wrappedKey.KeyData.Data = derKey; 794 wrappedKey.KeyData.Length = derKeyLen; 795 796 /* get key size in bits from raw CSP */ 797 rawCspHand = cuCspStartup(CSSM_TRUE); 798 if(rawCspHand == 0) { 799 printf("***Error attaching to CSP. Aborting.\n"); 800 crtn = CSSMERR_CSSM_INTERNAL_ERROR; 801 goto done; 802 } 803 CSSM_KEY_SIZE keySize; 804 crtn = CSSM_QueryKeySizeInBits(rawCspHand, CSSM_INVALID_HANDLE, &wrappedKey, &keySize); 805 if(crtn) { 806 printError("***Error finding size of key","CSSM_QueryKeySizeInBits",crtn); 807 goto done; 808 } 809 hdr->LogicalKeySizeInBits = keySize.LogicalKeySizeInBits; 810 811 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); 812 crtn = CSSM_CSP_CreateSymmetricContext(cspHand, 813 CSSM_ALGID_NONE, // unwrapAlg 814 CSSM_ALGMODE_NONE, // unwrapMode 815 &creds, 816 NULL, // unwrappingKey 817 NULL, // initVector 818 CSSM_PADDING_NONE, // unwrapPad 819 0, // Params 820 &ccHand); 821 if(crtn) { 822 printError("***Error creating context","CSSM_CSP_CreateSymmetricContext",crtn); 823 goto done; 824 } 825 826 /* add DL/DB to context */ 827 CSSM_CONTEXT_ATTRIBUTE newAttr; 828 newAttr.AttributeType = CSSM_ATTRIBUTE_DL_DB_HANDLE; 829 newAttr.AttributeLength = sizeof(CSSM_DL_DB_HANDLE); 830 newAttr.Attribute.Data = (CSSM_DATA_PTR)&dlDbHand; 831 crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr); 832 if(crtn) { 833 printError("***Error updating context attributes","CSSM_UpdateContextAttributes",crtn); 834 goto done; 835 } 836 837 /* do the NULL unwrap */ 838 labelData.Data = (uint8 *)privKeyLabel; 839 labelData.Length = strlen(privKeyLabel) + 1; 840 crtn = CSSM_UnwrapKey(ccHand, 841 NULL, // PublicKey 842 &wrappedKey, 843 CSSM_KEYUSE_ANY, 844 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE | 845 CSSM_KEYATTR_EXTRACTABLE, 846 &labelData, 847 NULL, // CredAndAclEntry 848 &unwrappedKey, 849 &descData); // required 850 if(crtn != CSSM_OK) { 851 cuPrintError("CSSM_UnwrapKey", crtn); 852 goto done; 853 } 854 855 /* one more thing: bind this private key to its public key */ 856 crtn = setPubKeyHash(cspHand, dlDbHand, privKeyLabel); 857 858 /* We don't need the unwrapped key any more */ 859 CSSM_FreeKey(cspHand, 860 NULL, // access cred 861 &unwrappedKey, 862 CSSM_FALSE); // delete 863 864done: 865 if(ccHand) { 866 CSSM_DeleteContext(ccHand); 867 } 868 if(derKey) { 869 free(derKey); 870 } 871 if(pemFormat && pemKey) { 872 free(pemKey); 873 } 874 if(rawCspHand) { 875 CSSM_ModuleDetach(rawCspHand); 876 } 877 return crtn; 878} 879 880static OSStatus importCert( 881 SecKeychainRef kcRef, 882 CSSM_DL_DB_HANDLE dlDbHand, 883 CSSM_CSP_HANDLE cspHand, 884 CSSM_CL_HANDLE clHand, 885 const char *fileName, 886 const char *privKeyFileName, // optional for importing priv key 887 CSSM_BOOL pemFormat, // format of files 888 CSSM_KEYBLOB_FORMAT privKeyFormat) // optional format of priv key 889{ 890 unsigned char *cert = NULL; 891 unsigned certLen; 892 CSSM_DATA certData; 893 unsigned char *der = NULL; 894 unsigned derLen = 0; 895 896 if(readFile(fileName, &cert, &certLen)) { 897 printf("***Error reading certificate from file %s. Aborting.\n", 898 fileName); 899 return ioErr; 900 } 901 if(pemFormat) { 902 int rtn = pemDecode(cert, certLen, &der, &derLen); 903 if(rtn) { 904 printf("***%s: Bad PEM formatting. Aborting.\n", fileName); 905 return ioErr; 906 } 907 certData.Data = der; 908 certData.Length = derLen; 909 } 910 else { 911 certData.Data = cert; 912 certData.Length = certLen; 913 } 914 915 SecCertificateRef certRef; 916 OSStatus ortn = SecCertificateCreateFromData( 917 &certData, 918 CSSM_CERT_X_509v3, 919 CSSM_CERT_ENCODING_DER, 920 &certRef); 921 if(ortn) { 922 printError("***Error creating certificate","SecCertificateCreateFromData",ortn); 923 cuPrintError("", ortn); 924 return ortn; 925 } 926 ortn = SecCertificateAddToKeychain(certRef, kcRef); 927 if(ortn) { 928 printError("***Error adding certificate to keychain","SecCertificateAddToKeychain",ortn); 929 return ortn; 930 } 931 932 if(privKeyFileName) { 933 /* Importing private key requires algorithm, from cert */ 934 CSSM_RETURN crtn; 935 CSSM_KEY_PTR pubKey; 936 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey); 937 if(crtn) { 938 printError("***Error obtaining public key from cert. Aborting","CSSM_CL_CertGetKeyInfo",crtn); 939 return crtn; 940 } 941 crtn = importPrivateKey(dlDbHand, cspHand, privKeyFileName, 942 pubKey->KeyHeader.AlgorithmId, pemFormat, privKeyFormat); 943 if(crtn) { 944 printError("***Error importing private key. Aborting","importPrivateKey",crtn); 945 return crtn; 946 } 947 /* this was mallocd by the CL */ 948 cuAppFree(pubKey->KeyData.Data, NULL); 949 cuAppFree(pubKey, NULL); 950 } 951 printf("...certificate successfully imported.\n"); 952 if(der) { 953 free(der); 954 } 955 if(cert) { 956 free(cert); 957 } 958 return noErr; 959} 960 961static OSStatus importCRL( 962 CSSM_DL_DB_HANDLE dlDbHand, 963 CSSM_CL_HANDLE clHand, 964 const char *fileName, 965 CSSM_BOOL pemFormat) 966{ 967 unsigned char *crl = NULL; 968 unsigned crlLen; 969 CSSM_DATA crlData; 970 unsigned char *der = NULL; 971 unsigned derLen = 0; 972 973 if(readFile(fileName, &crl, &crlLen)) { 974 printf("***Error reading CRL from file %s. Aborting.\n", 975 fileName); 976 return ioErr; 977 } 978 if(pemFormat) { 979 int rtn = pemDecode(crl, crlLen, &der, &derLen); 980 if(rtn) { 981 printf("***%s: Bad PEM formatting. Aborting.\n", fileName); 982 return ioErr; 983 } 984 crlData.Data = der; 985 crlData.Length = derLen; 986 } 987 else { 988 crlData.Data = crl; 989 crlData.Length = crlLen; 990 } 991 CSSM_RETURN crtn = cuAddCrlToDb(dlDbHand, clHand, &crlData, NULL); 992 if(crtn) { 993 printError("***Error adding CRL to keychain. Aborting","cuAddCrlToDb",crtn); 994 } 995 else { 996 printf("...CRL successfully imported.\n"); 997 } 998 if(der) { 999 free(der); 1000 } 1001 if(crl) { 1002 free(crl); 1003 } 1004 return noErr; 1005} 1006 1007/* Get validity period */ 1008uint32 notValidAfter(int isSystemDomain) 1009{ 1010 char *validityEnv = NULL; 1011 uint32 validAfter = 0; 1012 int result = 0; 1013 1014 if (isSystemDomain) return SI_DEF_VALIDITY; 1015 1016 validityEnv = getenv(VALIDITY_DAYS_ENVIRONMENT_VARIABLE); 1017 1018 if (validityEnv != NULL) { 1019 result = sscanf(validityEnv, "%u", &validAfter); 1020 1021 /* could we actually parse it? */ 1022 if (result == 1) { 1023 /* check that it is between 30 days and 20 years */ 1024 if (validAfter < 30) validAfter = 30; 1025 if (validAfter > (365 * 20)) validAfter = (365 * 20); 1026 1027 /* convert to seconds, which is what we need to use */ 1028 validAfter *= (60 * 60 * 24); 1029 1030 return validAfter; 1031 } 1032 } 1033 1034 return DEFAULT_CERT_VALIDITY; 1035} 1036 1037 1038/* serial number is generated randomly */ 1039#define SERIAL_NUM_LENGTH 4 1040 1041static OSStatus createCertCsr( 1042 CSSM_BOOL createCsr, // true: CSR, false: Cert 1043 CSSM_TP_HANDLE tpHand, // eventually, a SecKeychainRef 1044 CSSM_CL_HANDLE clHand, 1045 CSSM_CSP_HANDLE cspHand, 1046 CSSM_KEY_PTR subjPubKey, 1047 CSSM_KEY_PTR signerPrivKey, 1048 CSSM_ALGORITHMS sigAlg, 1049 const CSSM_OID *sigOid, 1050 CU_KeyUsage keyUsage, // kKeyUseSigning, etc. 1051 /* 1052 * Issuer's RDN is obtained from the issuer cert, if present, or is 1053 * assumed to be the same as the subject name (i.e., we're creating 1054 * a self-signed root cert). 1055 */ 1056 const CSSM_DATA *issuerCert, 1057 const CSSM_OID *extendedKeyUse, // optional 1058 CSSM_BOOL useAllDefaults, // secret 'Z' option 1059 const char *systemDomain, // domain name for system identities 1060 CSSM_DATA_PTR certData) // cert or CSR: mallocd and RETURNED 1061{ 1062 CE_DataAndType exts[4]; 1063 CE_DataAndType *extp = exts; 1064 unsigned numExts; 1065 1066 CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest 1067 CSSM_APPLE_TP_CERT_REQUEST certReq; 1068 CSSM_TP_REQUEST_SET reqSet; 1069 sint32 estTime; 1070 CSSM_BOOL confirmRequired; 1071 CSSM_TP_RESULT_SET_PTR resultSet; 1072 CSSM_ENCODED_CERT *encCert; 1073 CSSM_APPLE_TP_NAME_OID subjectNames[MAX_NAMES]; 1074 uint32 numNames; 1075 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext; 1076 CSSM_FIELD policyId; 1077 unsigned char serialNum[SERIAL_NUM_LENGTH]; 1078 CSSM_BOOL isSystemKDC = CSSM_FALSE; 1079 1080 /* Note a lot of the CSSM_APPLE_TP_CERT_REQUEST fields are not 1081 * used for the createCsr option, but we'll fill in as much as is practical 1082 * for either case. 1083 */ 1084 if(issuerCert != NULL) { 1085 printf("createCertCsr: issuerCert not implemented\n"); 1086 return unimpErr; 1087 } 1088 1089 numExts = 0; 1090 1091 if (systemDomain != NULL && strncmp(SYSTEM_KDC, systemDomain, strlen(SYSTEM_KDC)) == 0) { 1092 isSystemKDC = CSSM_TRUE; 1093 } 1094 1095 char challengeBuf[400]; 1096 if(createCsr) { 1097 if(useAllDefaults) { 1098 strcpy(challengeBuf, ZDEF_CHALLENGE); 1099 } 1100 else { 1101 while(1) { 1102 getStringWithPrompt("Enter challenge string: ", 1103 challengeBuf, sizeof(challengeBuf)); 1104 if(challengeBuf[0] != '\0') { 1105 break; 1106 } 1107 } 1108 } 1109 certReq.challengeString = challengeBuf; 1110 } 1111 else { 1112 /* creating cert */ 1113 certReq.challengeString = NULL; 1114 1115 /* KeyUsage extension */ 1116 if(systemDomain) { 1117 extp->type = DT_KeyUsage; 1118 extp->critical = CSSM_FALSE; 1119 extp->extension.keyUsage = 0; 1120 if(keyUsage & kKeyUseSigning) { 1121 extp->extension.keyUsage |= 1122 (CE_KU_DigitalSignature); 1123 } 1124 if (isSystemKDC) { 1125 if(keyUsage & kKeyUseEncrypting) { 1126 extp->extension.keyUsage |= 1127 (CE_KU_KeyEncipherment); 1128 } 1129 } 1130 else { 1131 if(keyUsage & kKeyUseEncrypting) { 1132 extp->extension.keyUsage |= 1133 (CE_KU_KeyEncipherment | CE_KU_DataEncipherment); 1134 } 1135 if(keyUsage & kKeyUseDerive) { 1136 extp->extension.keyUsage |= CE_KU_KeyAgreement; 1137 } 1138 } 1139 extp++; 1140 numExts++; 1141 } 1142 1143 /* BasicConstraints */ 1144 if(!systemDomain) { 1145 extp->type = DT_BasicConstraints; 1146 extp->critical = CSSM_TRUE; 1147 extp->extension.basicConstraints.cA = CSSM_TRUE; 1148 extp->extension.basicConstraints.pathLenConstraintPresent = CSSM_FALSE; 1149 extp++; 1150 numExts++; 1151 } 1152 1153 /* Extended Key Usage, optional */ 1154 if (extendedKeyUse != NULL) { 1155 extp->type = DT_ExtendedKeyUsage; 1156 extp->critical = CSSM_FALSE; 1157 extp->extension.extendedKeyUsage.numPurposes = 1; 1158 extp->extension.extendedKeyUsage.purposes = const_cast<CSSM_OID_PTR>(extendedKeyUse); 1159 extp++; 1160 numExts++; 1161 } 1162 1163 if (isSystemKDC) { 1164 uint8_t oidData[] = {0x2B, 0x6, 0x1, 0x5, 0x2, 0x3, 0x5}; 1165 CSSM_OID oid = {sizeof(oidData), oidData}; 1166 extp->type = DT_ExtendedKeyUsage; 1167 extp->critical = CSSM_FALSE; 1168 extp->extension.extendedKeyUsage.numPurposes = 1; 1169 extp->extension.extendedKeyUsage.purposes = &oid; 1170 extp++; 1171 numExts++; 1172 } 1173 1174 1175 } 1176 1177 /* name array */ 1178 if(systemDomain) { 1179 subjectNames[0].string = systemDomain; 1180 subjectNames[0].oid = &CSSMOID_CommonName; 1181 subjectNames[1].string = SI_DEF_ORG_NAME; 1182 subjectNames[1].oid = &CSSMOID_OrganizationName; 1183 numNames = 2; 1184 } 1185 else if(useAllDefaults) { 1186 subjectNames[0].string = ZDEF_COMMON_NAME; 1187 subjectNames[0].oid = &CSSMOID_CommonName; 1188 subjectNames[1].string = ZDEF_ORG_NAME; 1189 subjectNames[1].oid = &CSSMOID_OrganizationName; 1190 subjectNames[2].string = ZDEF_COUNTRY; 1191 subjectNames[2].oid = &CSSMOID_CountryName; 1192 subjectNames[3].string = ZDEF_STATE; 1193 subjectNames[3].oid = &CSSMOID_StateProvinceName; 1194 numNames = 4; 1195 } 1196 else { 1197 getNameOids(subjectNames, &numNames); 1198 } 1199 1200 /* certReq */ 1201 certReq.cspHand = cspHand; 1202 certReq.clHand = clHand; 1203 certReq.numSubjectNames = numNames; 1204 certReq.subjectNames = subjectNames; 1205 1206 /* random serial number */ 1207 try { 1208 DevRandomGenerator drg; 1209 drg.random(serialNum, SERIAL_NUM_LENGTH); 1210 /* MS bit must be zero */ 1211 serialNum[0] &= 0x7f; 1212 certReq.serialNumber = ((uint32)(serialNum[0])) << 24 | 1213 ((uint32)(serialNum[1])) << 16 | 1214 ((uint32)(serialNum[2])) << 8 | 1215 ((uint32)(serialNum[3])); 1216 } 1217 catch(...) { 1218 certReq.serialNumber = 0x12345678; 1219 } 1220 1221 /* TBD - if we're passed in a signing cert, certReq.issuerNameX509 will 1222 * be obtained from that cert. For now we specify "self-signed" cert 1223 * by not providing an issuer name at all. */ 1224 certReq.numIssuerNames = 0; // root for now 1225 certReq.issuerNames = NULL; 1226 certReq.issuerNameX509 = NULL; 1227 certReq.certPublicKey = subjPubKey; 1228 certReq.issuerPrivateKey = signerPrivKey; 1229 certReq.signatureAlg = sigAlg; 1230 certReq.signatureOid = *sigOid; 1231 certReq.notBefore = 0; // TBD - from user 1232 certReq.notAfter = notValidAfter((systemDomain == NULL) ? 0 : 1); 1233 1234 certReq.numExtensions = numExts; 1235 certReq.extensions = exts; 1236 1237 reqSet.NumberOfRequests = 1; 1238 reqSet.Requests = &certReq; 1239 1240 /* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */ 1241 memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT)); 1242 memset(&policyId, 0, sizeof(CSSM_FIELD)); 1243 if(createCsr) { 1244 policyId.FieldOid = CSSMOID_APPLE_TP_CSR_GEN; 1245 } 1246 else { 1247 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; 1248 } 1249 CallerAuthContext.Policy.NumberOfPolicyIds = 1; 1250 CallerAuthContext.Policy.PolicyIds = &policyId; 1251 1252 CssmClient::AclFactory factory; 1253 CallerAuthContext.CallerCredentials = 1254 const_cast<Security::AccessCredentials *>(factory.promptCred()); 1255 1256 CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tpHand, 1257 NULL, // PreferredAuthority 1258 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, 1259 &reqSet, 1260 &CallerAuthContext, 1261 &estTime, 1262 &refId); 1263 1264 /* before proceeding, free resources allocated thus far */ 1265 if(!useAllDefaults && (systemDomain == NULL)) { 1266 freeNameOids(subjectNames, numNames); 1267 } 1268 1269 if(crtn) { 1270 printError("***Error submitting credential request","CSSM_TP_SubmitCredRequest",crtn); 1271 return crtn; 1272 } 1273 crtn = CSSM_TP_RetrieveCredResult(tpHand, 1274 &refId, 1275 NULL, // CallerAuthCredentials 1276 &estTime, 1277 &confirmRequired, 1278 &resultSet); 1279 if(crtn) { 1280 printError("***Error retreiving credential request","CSSM_TP_RetrieveCredResult",crtn); 1281 return crtn; 1282 } 1283 if(resultSet == NULL) { 1284 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n"); 1285 return ioErr; 1286 } 1287 encCert = (CSSM_ENCODED_CERT *)resultSet->Results; 1288 *certData = encCert->CertBlob; 1289 1290 /* free resources allocated by TP */ 1291 APP_FREE(refId.Data); 1292 APP_FREE(encCert); 1293 APP_FREE(resultSet); 1294 return noErr; 1295} 1296 1297/* dump all certs & CRLs in a DL/DB */ 1298static OSStatus dumpCrlsCerts( 1299 CSSM_DL_DB_HANDLE dlDbHand, 1300 CSSM_CL_HANDLE clHand, 1301 CSSM_BOOL verbose) 1302{ 1303 CSSM_RETURN crtn; 1304 unsigned numItems; 1305 1306 crtn = cuDumpCrlsCerts(dlDbHand, clHand, CSSM_TRUE, numItems, verbose); 1307 if(crtn && (crtn != CSSMERR_DL_INVALID_RECORDTYPE)) { 1308 /* invalid record type just means "this hasn't been set up 1309 * for certs yet". */ 1310 return noErr; 1311 } 1312 printf("...%u certificates found\n", numItems); 1313 crtn = cuDumpCrlsCerts(dlDbHand, clHand, CSSM_FALSE, numItems, verbose); 1314 if(crtn && (crtn != CSSMERR_DL_INVALID_RECORDTYPE)) { 1315 /* invalid record type just means "this hasn't been set up 1316 * for CRLs yet". */ 1317 return noErr; 1318 } 1319 printf("...%u CRLs found\n", numItems); 1320 return noErr; 1321} 1322 1323 1324typedef enum { 1325 CO_Nop, 1326 CO_CreateCert, 1327 CO_CreateCSR, 1328 CO_VerifyCSR, 1329 CO_ImportCert, 1330 CO_DisplayCert, 1331 CO_ImportCRL, 1332 CO_DisplayCRL, 1333 CO_DumpDb, // display certs & CRLs from a DB 1334 CO_SystemIdentity 1335} CertOp; 1336 1337int realmain (int argc, char **argv) 1338{ 1339 SecKeychainRef kcRef = nil; 1340 char kcPath[MAXPATHLEN + 1]; 1341 UInt32 kcPathLen = MAXPATHLEN + 1; 1342 CSSM_BOOL createKc = CSSM_FALSE; 1343 OSStatus ortn; 1344 CSSM_DL_DB_HANDLE dlDbHand = {0, 0}; 1345 CSSM_CSP_HANDLE cspHand = 0; 1346 CSSM_TP_HANDLE tpHand = 0; 1347 CSSM_CL_HANDLE clHand = 0; 1348 CSSM_KEY_PTR pubKey; 1349 CSSM_KEY_PTR privKey; 1350 int arg; 1351 char *argp; 1352 CSSM_ALGORITHMS keyAlg; 1353 CSSM_ALGORITHMS sigAlg; 1354 const CSSM_OID *sigOid; 1355 CSSM_DATA certData = {0, NULL}; 1356 CU_KeyUsage keyUsage = 0; 1357 bool isRoot; 1358 CSSM_DATA keyLabel; 1359 CSSM_BOOL createCsr = CSSM_FALSE; // else create cert 1360 int optArgs = 0; 1361 UInt32 pwdLen = 0; 1362 Boolean promptUser = true; 1363 char *allocdPassPhrase = NULL; 1364 OSStatus ourRtn = noErr; 1365 1366 /* command line arguments */ 1367 char *fileName = NULL; 1368 CSSM_BOOL pemFormat = CSSM_TRUE; 1369 CertOp op = CO_Nop; 1370 uint32 keySizeInBits; 1371 char *kcName = NULL; 1372 CSSM_BOOL useAllDefaults = CSSM_FALSE; // undoc'd cmd option 1373 char *passPhrase = NULL; 1374 const char *privKeyFileName = NULL; // optional openssl-style private key 1375 CSSM_KEYBLOB_FORMAT privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE; 1376 SecKeyRef pubSecKey = NULL; 1377 SecKeyRef privSecKey = NULL; 1378 CSSM_BOOL useSecKey = CSSM_FALSE; // w/default ACL 1379 const CSSM_OID *extKeyUse = NULL; 1380 CSSM_BOOL aclForUid = CSSM_FALSE; // ACL limited to current uid */ 1381 CSSM_BOOL avoidDupIdentity = CSSM_FALSE; 1382 const char *domainName = NULL; 1383 CFStringRef cfDomain = NULL; 1384 1385 if(argc < 2) { 1386 usage(argv); 1387 } 1388 switch(argv[1][0]) { 1389 case 'c': 1390 op = CO_CreateCert; 1391 optArgs = 2; 1392 break; 1393 case 'r': 1394 if(argc < 3) { 1395 usage(argv); 1396 } 1397 op = CO_CreateCSR; 1398 createCsr = CSSM_TRUE; 1399 fileName = argv[2]; 1400 optArgs = 3; 1401 break; 1402 1403 case 'C': 1404 if(argc < 3) { 1405 usage(argv); 1406 } 1407 op = CO_SystemIdentity; 1408 domainName = argv[2]; 1409 cfDomain = CFStringCreateWithCString(NULL, 1410 domainName, kCFStringEncodingASCII); 1411 optArgs = 3; 1412 /* custom ExtendedKeyUse for this type of cert */ 1413 extKeyUse = &CSSMOID_APPLE_EKU_SYSTEM_IDENTITY; 1414 /* *some* ACL - default, or per-uid (specified later) */ 1415 useSecKey = CSSM_TRUE; 1416 break; 1417 1418 case 'i': 1419 if(argc < 3) { 1420 usage(argv); 1421 } 1422 optArgs = 3; 1423 op = CO_ImportCert; 1424 fileName = argv[2]; 1425 break; 1426 case 'd': 1427 if(argc < 3) { 1428 usage(argv); 1429 } 1430 op = CO_DisplayCert; 1431 fileName = argv[2]; 1432 optArgs = 3; 1433 break; 1434 case 'I': 1435 if(argc < 3) { 1436 usage(argv); 1437 } 1438 optArgs = 3; 1439 op = CO_ImportCRL; 1440 fileName = argv[2]; 1441 break; 1442 case 'D': 1443 if(argc < 3) { 1444 usage(argv); 1445 } 1446 op = CO_DisplayCRL; 1447 fileName = argv[2]; 1448 optArgs = 3; 1449 break; 1450 case 'y': 1451 op = CO_DumpDb; 1452 optArgs = 2; 1453 break; 1454 default: 1455 usage(argv); 1456 } 1457 for(arg=optArgs; arg<argc; arg++) { 1458 argp = argv[arg]; 1459 switch(argp[0]) { 1460 case 'k': 1461 if(argp[1] != '=') { 1462 usage(argv); 1463 } 1464 kcName = &argp[2]; 1465 break; 1466 case 'v': 1467 verbose = CSSM_TRUE; 1468 break; 1469 case 'd': 1470 pemFormat = CSSM_FALSE; 1471 break; 1472 case 'c': 1473 createKc = CSSM_TRUE; 1474 break; 1475 case 'p': 1476 if(argp[1] != '=') { 1477 usage(argv); 1478 } 1479 passPhrase = &argp[2]; 1480 break; 1481 case 'o': 1482 if((op != CO_CreateCert) || (argp[1] != '=')){ 1483 usage(argv); 1484 } 1485 fileName = &argp[2]; 1486 break; 1487 case 'r': 1488 privKeyFileName = &argp[2]; 1489 break; 1490 case 'f': 1491 if(argp[1] != '=') { 1492 usage(argv); 1493 } 1494 switch(argp[2]) { 1495 case '1': 1496 privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; 1497 break; 1498 case '8': 1499 privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; 1500 break; 1501 case 'f': 1502 privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_FIPS186; 1503 break; 1504 case 'o': 1505 privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; 1506 break; 1507 default:usage(argv); 1508 } 1509 break; 1510 case 'x': 1511 if(argp[1] != '=') { 1512 usage(argv); 1513 } 1514 switch(argp[2]) { 1515 case 'a': 1516 extKeyUse = &CSSMOID_ExtendedKeyUsageAny; 1517 break; 1518 case 's': 1519 extKeyUse = &CSSMOID_ClientAuth; 1520 break; 1521 case 'S': 1522 extKeyUse = &CSSMOID_ServerAuth; 1523 break; 1524 case 'm': 1525 extKeyUse = &CSSMOID_EmailProtection; 1526 break; 1527 default: 1528 usage(argv); 1529 } 1530 break; 1531 case 'Z': 1532 /* undocumented "use all defaults quickly" option */ 1533 useAllDefaults = CSSM_TRUE; 1534 break; 1535 case 'a': 1536 /* default ACL */ 1537 useSecKey = CSSM_TRUE; 1538 break; 1539 case 'u': 1540 /* ACL for uid */ 1541 useSecKey = CSSM_TRUE; 1542 aclForUid = CSSM_TRUE; 1543 break; 1544 case 'P': 1545 avoidDupIdentity = CSSM_TRUE; 1546 break; 1547 default: 1548 usage(argv); 1549 } 1550 } 1551 if((passPhrase != NULL) && !createKc) { 1552 printf("***passphrase specification only allowed on keychain create. Aborting.\n"); 1553 exit(1); 1554 } 1555 1556 switch(op) { 1557 case CO_DisplayCert: 1558 /* ready to roll */ 1559 displayCertCRL(fileName, pemFormat, CC_Cert, verbose); 1560 return 0; 1561 case CO_DisplayCRL: 1562 displayCertCRL(fileName, pemFormat, CC_CRL, verbose); 1563 return 0; 1564 case CO_SystemIdentity: 1565 if(avoidDupIdentity) { 1566 /* 1567 * We're done if there already exists an identity for 1568 * the specified domain. 1569 */ 1570 CFStringRef actualDomain = NULL; 1571 SecIdentityRef idRef = NULL; 1572 bool done = false; 1573 1574 OSStatus ortn = SecIdentityCopySystemIdentity(cfDomain, 1575 &idRef, &actualDomain); 1576 if(ortn == noErr) { 1577 if((actualDomain != NULL) && CFEqual(actualDomain, cfDomain)) { 1578 printf("...System identity already exists for domain %s. Done.\n", 1579 domainName); 1580 done = true; 1581 } 1582 } 1583 if(actualDomain) { 1584 CFRelease(actualDomain); 1585 } 1586 if(idRef) { 1587 CFRelease(idRef); 1588 } 1589 if(done) { 1590 CFRelease(cfDomain); 1591 return 0; 1592 } 1593 } 1594 break; 1595 default: 1596 /* proceed */ 1597 break; 1598 } 1599 1600 clHand = cuClStartup(); 1601 if(clHand == 0) { 1602 printf("Error connecting to CL. Aborting.\n"); 1603 exit(1); 1604 } 1605 1606 /* that's all we need for verifying a CSR */ 1607 if(op == CO_VerifyCSR) { 1608 ourRtn = verifyCsr(clHand, fileName, pemFormat); 1609 goto abort; 1610 } 1611 1612 /* Cook up a keychain path */ 1613 if(op == CO_SystemIdentity) { 1614 /* this one's implied and hard coded */ 1615 const char *sysKcPath = kSystemKeychainDir kSystemKeychainName; 1616 strncpy(kcPath, sysKcPath, MAXPATHLEN); 1617 } 1618 else if(kcName) { 1619 if(kcName[0] == '/') { 1620 /* specific keychain not in Library/Keychains */ 1621 check_obsolete_keychain(kcName); 1622 strncpy(kcPath, kcName, MAXPATHLEN); 1623 } 1624 else { 1625 const char *userHome = getenv("HOME"); 1626 1627 if(userHome == NULL) { 1628 /* well, this is probably not going to work */ 1629 userHome = ""; 1630 } 1631 snprintf(kcPath, MAXPATHLEN, "%s/%s/%s", userHome, KC_DB_PATH, kcName); 1632 } 1633 } 1634 else { 1635 /* use default keychain */ 1636 ortn = SecKeychainCopyDefault(&kcRef); 1637 if(ortn) { 1638 printError("***Error retreiving default keychain","SecKeychainCopyDefault",ortn); 1639 exit(1); 1640 } 1641 ortn = SecKeychainGetPath(kcRef, &kcPathLen, kcPath); 1642 if(ortn) { 1643 printError("***Error retreiving default keychain path","SecKeychainGetPath",ortn); 1644 exit(1); 1645 } 1646 1647 /* 1648 * OK, we have a path, we have to release the first KC ref, 1649 * then get another one by opening it 1650 */ 1651 CFRelease(kcRef); 1652 } 1653 1654 if(passPhrase != NULL) { 1655 pwdLen = strlen(passPhrase); 1656 /* work around bug - incoming passphrase gets freed */ 1657 Security::Allocator &alloc = Security::Allocator::standard(); 1658 allocdPassPhrase = (char *)alloc.malloc(pwdLen); 1659 memmove(allocdPassPhrase, passPhrase, pwdLen); 1660 promptUser = false; 1661 } 1662 if(createKc) { 1663 ortn = SecKeychainCreate(kcPath, 1664 pwdLen, 1665 allocdPassPhrase, 1666 promptUser, 1667 nil, // initialAccess 1668 &kcRef); 1669 /* fixme - do we have to open it? */ 1670 if(ortn) { 1671 printError("***Error creating keychain","SecKeychainCreate",ortn); 1672 printf("***Path: %s\n", kcPath); 1673 exit(1); 1674 } 1675 } 1676 else { 1677 ortn = SecKeychainOpen(kcPath, &kcRef); 1678 if(ortn) { 1679 printError("***Error opening keychain. Aborting","SecKeychainOpen",ortn); 1680 printf("***Path: %s\n", kcPath); 1681 exit(1); 1682 } 1683 } 1684 1685 /* get associated DL/DB handle */ 1686 ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand); 1687 if(ortn) { 1688 printError("***Error getting keychain handle","SecKeychainGetDLDBHandle",ortn); 1689 exit(1); 1690 } 1691 1692 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand); 1693 if(ortn) { 1694 printError("***Error getting keychain CSP handle","SecKeychainGetCSPHandle",ortn); 1695 exit(1); 1696 } 1697 1698 switch(op) { 1699 case CO_ImportCert: 1700 ourRtn = importCert(kcRef, dlDbHand, cspHand, clHand, fileName, privKeyFileName, 1701 pemFormat, privKeyFormat); 1702 goto abort; 1703 case CO_ImportCRL: 1704 ourRtn = importCRL(dlDbHand, clHand, fileName, pemFormat); 1705 goto abort; 1706 case CO_DumpDb: 1707 ourRtn = dumpCrlsCerts(dlDbHand, clHand, verbose); 1708 goto abort; 1709 default: 1710 break; 1711 } 1712 1713 /* remaining ops need TP as well */ 1714 tpHand = cuTpStartup(); 1715 if(tpHand == 0) { 1716 printf("Error connecting to TP. Aborting.\n"); 1717 exit(1); 1718 } 1719 1720 /*** op = CO_CreateCert, CO_CreateCSR, CO_SystemIdentity ***/ 1721 1722 /* 1723 * TBD: eventually we want to present the option of using an existing 1724 * SecIdentityRef from the keychain as the signing cert/key. 1725 */ 1726 isRoot = true; 1727 1728 /* 1729 * Generate a key pair - via CDSA if no ACL is requested, else 1730 * SecKeyCreatePair(). 1731 */ 1732 char labelBuf[200]; 1733 if(op == CO_SystemIdentity) { 1734 strncpy(labelBuf, domainName, sizeof(labelBuf)); 1735 } 1736 else if(useAllDefaults) { 1737 /* the secret 'Z' option */ 1738 strcpy(labelBuf, ZDEF_KEY_LABEL); 1739 } 1740 else { 1741 while(1) { 1742 getStringWithPrompt("Enter key and certificate label: ", labelBuf, 1743 sizeof(labelBuf)); 1744 if(labelBuf[0] != '\0') { 1745 break; 1746 } 1747 } 1748 } 1749 keyLabel.Data = (uint8 *)labelBuf; 1750 keyLabel.Length = strlen(labelBuf); 1751 1752 /* get key algorithm and size */ 1753 if(op == CO_SystemIdentity) { 1754 keyAlg = SI_DEF_KEY_ALG; 1755 keySizeInBits = SI_DEF_KEY_SIZE; 1756 } 1757 else if(useAllDefaults) { 1758 keyAlg = ZDEF_KEY_ALG; 1759 keySizeInBits = ZDEF_KEY_SIZE; 1760 } 1761 else { 1762 getKeyParams(keyAlg, keySizeInBits); 1763 } 1764 1765 /* get usage for keys and certs */ 1766 if(op == CO_SystemIdentity) { 1767 keyUsage = SI_DEF_KEY_USAGE; 1768 } 1769 else if(useAllDefaults) { 1770 keyUsage = ZDEF_KEY_USAGE; 1771 } 1772 else { 1773 keyUsage = getKeyUsage(isRoot); 1774 } 1775 1776 printf("...Generating key pair...\n"); 1777 1778 if(useSecKey) { 1779 /* generate keys using SecKeyCreatePair */ 1780 ourRtn = generateSecKeyPair(kcRef, 1781 keyAlg, 1782 keySizeInBits, 1783 keyUsage, 1784 aclForUid, 1785 verbose, 1786 labelBuf, 1787 &pubKey, 1788 &privKey, 1789 &pubSecKey, 1790 &privSecKey); 1791 } 1792 else { 1793 /* generate keys using CSPDL */ 1794 ourRtn = generateKeyPair(cspHand, 1795 dlDbHand, 1796 keyAlg, 1797 keySizeInBits, 1798 labelBuf, 1799 keyUsage, 1800 verbose, 1801 &pubKey, 1802 &privKey); 1803 } 1804 if(ourRtn) { 1805 printError("Error generating keys; aborting","generateKeyPair",ourRtn); 1806 goto abort; 1807 } 1808 1809 /* get signing algorithm per the signing key */ 1810 if(op == CO_SystemIdentity) { 1811 sigAlg = SI_DEF_SIG_ALG; 1812 sigOid = &SI_DEF_SIG_OID; 1813 } 1814 else if(useAllDefaults) { 1815 sigAlg = ZDEF_SIG_ALG; 1816 sigOid = &ZDEF_SIG_OID; 1817 } 1818 else { 1819 ourRtn = getSigAlg(privKey, sigAlg, sigOid); 1820 if(ourRtn) { 1821 printError("Cannot sign with this private key. Aborting","getSigAlg",ourRtn); 1822 goto abort; 1823 } 1824 } 1825 1826 if(createCsr) { 1827 printf("...creating CSR...\n"); 1828 } 1829 else { 1830 printf("...creating certificate...\n"); 1831 } 1832 /* generate the cert */ 1833 ourRtn = createCertCsr(createCsr, 1834 tpHand, 1835 clHand, 1836 cspHand, 1837 pubKey, 1838 privKey, 1839 sigAlg, 1840 sigOid, 1841 keyUsage, 1842 NULL, // issuer cert 1843 extKeyUse, 1844 useAllDefaults, 1845 domainName, 1846 &certData); 1847 if(ourRtn) { 1848 goto abort; 1849 } 1850 if(verbose) { 1851 printCert(certData.Data, certData.Length, CSSM_FALSE); 1852 printCertShutdown(); 1853 } 1854 1855 if(fileName) { 1856 /* 1857 * Create CSR, or create cert with outFileName option. 1858 * Write results to a file 1859 */ 1860 unsigned char *pem = NULL; 1861 unsigned pemLen; 1862 int rtn; 1863 1864 if(pemFormat) { 1865 const char *headerStr; 1866 switch(op) { 1867 case CO_CreateCSR: 1868 headerStr = "CERTIFICATE REQUEST"; 1869 break; 1870 case CO_CreateCert: 1871 headerStr = "CERTIFICATE"; 1872 break; 1873 default: 1874 printf("***INTERNAL ERROR; aborting.\n"); 1875 exit(1); 1876 } 1877 rtn = pemEncode(certData.Data, certData.Length, &pem, &pemLen, headerStr); 1878 if(rtn) { 1879 /* very unlikely, I think malloc is the only failure */ 1880 printf("***Error PEM-encoding output. Aborting.\n"); 1881 goto abort; 1882 } 1883 rtn = writeFile(fileName, pem, pemLen); 1884 } 1885 else { 1886 rtn = writeFile(fileName, certData.Data, certData.Length); 1887 } 1888 if(rtn) { 1889 printf("***Error writing CSR to %s\n", fileName); 1890 ourRtn = ioErr; 1891 } 1892 else { 1893 printf("Wrote %u bytes of CSR to %s\n", (unsigned)certData.Length, 1894 fileName); 1895 } 1896 if(pem) { 1897 free(pem); 1898 } 1899 } 1900 if((op == CO_CreateCert) || (op == CO_SystemIdentity)) { 1901 /* store the cert in the same DL/DB as the key pair */ 1902 SecCertificateRef certRef = NULL; 1903 1904 OSStatus ortn = SecCertificateCreateFromData( 1905 &certData, 1906 CSSM_CERT_X_509v3, 1907 CSSM_CERT_ENCODING_DER, 1908 &certRef); 1909 if(ortn) { 1910 printError("***Error creating certificate", 1911 "SecCertificateCreateFromData", ortn); 1912 cuPrintError("", ortn); 1913 ourRtn = ortn; 1914 } 1915 else { 1916 ortn = SecCertificateAddToKeychain(certRef, kcRef); 1917 if(ortn) { 1918 printError("***Error adding certificate to keychain", 1919 "SecCertificateAddToKeychain", ortn); 1920 ourRtn = ortn; 1921 } 1922 } 1923 if(ourRtn == noErr) { 1924 printf("..cert stored in Keychain.\n"); 1925 if(op == CO_SystemIdentity) { 1926 /* 1927 * Get the SecIdentityRef assocaited with this cert and 1928 * register it 1929 */ 1930 SecIdentityRef idRef; 1931 ortn = SecIdentityCreateWithCertificate(kcRef, certRef, &idRef); 1932 if(ortn) { 1933 printError("Cannot register Identity", 1934 "SecIdentityCreateWithCertificate", ortn); 1935 } 1936 else { 1937 ortn = SecIdentitySetSystemIdentity(cfDomain, idRef); 1938 CFRelease(idRef); 1939 if(ortn) { 1940 printError("Cannot register Identity", 1941 "SecIdentitySetSystemIdentity", ortn); 1942 } 1943 else { 1944 printf("..identity registered for domain %s.\n", domainName); 1945 1946 } 1947 } 1948 CFRelease(cfDomain); 1949 } /* CO_SystemIdentity */ 1950 } /* cert store successful */ 1951 if(certRef) { 1952 CFRelease(certRef); 1953 } 1954 } /* generated/stored a cert */ 1955abort: 1956 /* CLEANUP */ 1957 if(pubSecKey != NULL) { 1958 CFRelease(pubSecKey); 1959 } 1960 if(privSecKey != NULL) { 1961 CFRelease(privSecKey); 1962 } 1963 return ourRtn; 1964} 1965 1966int main (int argc, char **argv) 1967{ 1968 try { 1969 return realmain (argc, argv); 1970 } 1971 catch (AbortException e) 1972 { 1973 putchar ('\n'); // prompt on the next line. 1974 return 1; 1975 } 1976} 1977 1978