1/* 2 * cmstool.cpp - manipulate CMS messages, CMSEncoder/CMSDecoder version 3 */ 4 5#include <Security/Security.h> 6#include <security_cdsa_utils/cuFileIo.h> 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#include <unistd.h> 11#include <utilLib/common.h> 12#include <security_cdsa_utils/cuFileIo.h> 13#include <security_cdsa_utils/cuPrintCert.h> 14#include <clAppUtils/identPicker.h> 15#include <clAppUtils/sslAppUtils.h> 16#include <security_cdsa_utils/cuOidParser.h> 17#include <CoreFoundation/CoreFoundation.h> 18#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 19 20#include <Security/SecTrustPriv.h> /* SecTrustGetCssmResultCode */ 21#include <Security/SecIdentityPriv.h> /* SecIdentityCreateWithCertificate */ 22#include <Security/CMSEncoder.h> 23#include <Security/CMSDecoder.h> 24#include <Security/CMSPrivate.h> 25 26#include <Security/SecCertificate.h> 27#include <Security/oidsattr.h> 28 29#define CFRELEASE(cfr) if(cfr != NULL) { CFRelease(cfr); } 30 31static SecKeychainRef keychain_open(const char *name); 32 33static void usage(char **argv) 34{ 35 printf("Usage: %s cmd [option ...]\n", argv[0]); 36 printf("cmd values:\n"); 37 printf(" sign -- create signedData\n"); 38 printf(" envel -- create envelopedData\n"); 39 printf(" signEnv -- create nested EnvelopedData(signedData(data))\n"); 40 printf(" certs -- create certs-only CMS msg\n"); 41 printf(" parse -- parse a CMS message file\n"); 42 printf("Input/output options:\n"); 43 printf(" -i infile\n"); 44 printf(" -o outfile\n"); 45 printf(" -D detachedContent -- detached content (parse only)\n"); 46 printf(" -d detached -- infile contains detached content (sign only)\n"); 47 printf(" -f certFileBase -- dump all certs to certFileBase\n"); 48 printf("Signer and recipient options:\n"); 49 printf(" -k keychain -- Keychain to search for certs\n"); 50 printf(" -p -- Use identity picker\n"); 51 printf(" -r recipient -- add recipient (via email address) of enveloped data\n"); 52 printf(" -R recipCertFile -- add recipient (via cert from file) of enveloped data\n"); 53 printf(" -S signerEmail -- add signer email address\n"); 54 printf(" -C cert -- add (general) signedData cert\n"); 55 printf("Misc. options:\n"); 56 printf(" -e eContentType -- a(uthData)|r(keyData)\n"); 57 printf(" -m -- multi updates; default is one-shot\n"); 58 printf(" -1 (one) -- custom encoder/decoder\n"); 59 printf(" -2 -- fetch SecCmsMessageRef\n"); 60 printf(" -c -- parse signer certs\n"); 61 printf(" -a [ceEt] -- Signed Attributes: c=SmimeCaps,\n"); 62 printf(" e=EncrPrefs, E=MSEncrPrefs, t=signingTime\n"); 63 printf(" -A anchorFile -- Verify certs using specified anchor cert\n"); 64 printf(" -M -- Do SecTrustEvaluate manually\n"); 65 printf(" -t certChainMode -- none|signer|chain|chainWithRoot; default is chain\n"); 66 printf(" -l -- loop & pause for malloc debug\n"); 67 printf(" -q -- quiet\n"); 68 printf(" -Z -- silent, no output at all except for errors\n"); 69 printf("Verification options:\n"); 70 printf(" -v sign|encr|signEnv -- verify message is signed/encrypted/both\n"); 71 printf(" -s numSigners -- verify msg has specified number of signers\n"); 72 printf(" -E eContentType -- verify a(authData)|r(keyData)|d(data)\n"); 73 printf(" -N numCerts -- verify number of certs\n"); 74 exit(1); 75} 76 77/* high level op */ 78typedef enum { 79 CTO_Sign, 80 CTO_Envelop, 81 CTO_SignEnvelop, 82 CTO_CertsOnly, 83 CTO_Parse 84} CT_Op; 85 86/* to verify */ 87typedef enum { 88 CTV_None, 89 CTV_Sign, 90 CTV_Envelop, 91 CTV_SignEnvelop 92} CT_Vfy; 93 94/* additional OIDS to specify as eContentType */ 95#define OID_PKINIT 0x2B, 6, 1, 5, 2, 3 96#define OID_PKINIT_LEN 6 97 98static const uint8 OID_PKINIT_AUTH_DATA[] = {OID_PKINIT, 1}; 99static const uint8 OID_PKINIT_DH_KEY_DATA[] = {OID_PKINIT, 2}; 100static const uint8 OID_PKINIT_RKEY_DATA[] = {OID_PKINIT, 3}; 101static const uint8 OID_PKINIT_KP_CLIENTAUTH[] = {OID_PKINIT, 3}; 102static const uint8 OID_PKINIT_KPKDC[] = {OID_PKINIT, 5}; 103 104static const CSSM_OID CSSMOID_PKINIT_AUTH_DATA = 105 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_AUTH_DATA}; 106static const CSSM_OID CSSMOID_PKINIT_DH_KEY_DATA = 107 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_DH_KEY_DATA}; 108static const CSSM_OID CSSMOID_PKINIT_RKEY_DATA = 109 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_RKEY_DATA}; 110static const CSSM_OID CSSMOID_PKINIT_KP_CLIENTAUTH = 111 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_KP_CLIENTAUTH}; 112static const CSSM_OID CSSMOID_PKINIT_KPKDC = 113 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_KPKDC}; 114 115/* 116 * Find a cert in specified keychain or keychain list matching specified 117 * email address. We happen to know that the email address is stored with the 118 * kSecAlias attribute. 119 */ 120static OSStatus findCert( 121 const char *emailAddress, 122 CFTypeRef kcArArray, // kc, array, or even NULL 123 SecCertificateRef *cert) 124{ 125 OSStatus ortn; 126 SecKeychainSearchRef srch; 127 SecKeychainAttributeList attrList; 128 SecKeychainAttribute attr; 129 130 attr.tag = kSecAlias; 131 attr.length = strlen(emailAddress); 132 attr.data = (void *)emailAddress; 133 attrList.count = 1; 134 attrList.attr = &attr; 135 136 ortn = SecKeychainSearchCreateFromAttributes(kcArArray, 137 kSecCertificateItemClass, 138 &attrList, 139 &srch); 140 if(ortn) { 141 cssmPerror("SecKeychainSearchCreateFromAttributes", ortn); 142 return ortn; 143 } 144 145 ortn = SecKeychainSearchCopyNext(srch, (SecKeychainItemRef *)cert); 146 if(ortn) { 147 printf("***No certs found matching recipient %s. Aborting.\n", 148 emailAddress); 149 return ortn; 150 } 151 CFRelease(srch); 152 return noErr; 153} 154 155/* create a SecCertificateRef from a file */ 156static SecCertificateRef readCertFile( 157 const char *fileName) 158{ 159 unsigned char *certData = NULL; 160 unsigned certDataLen; 161 SecCertificateRef rtnCert = NULL; 162 163 if(readFile(fileName, &certData, &certDataLen)) { 164 printf("***Error reading %s. Aborting.\n", fileName); 165 return NULL; 166 } 167 CSSM_DATA cssmCert = {certDataLen, (uint8 *)certData}; 168 OSStatus ortn = SecCertificateCreateFromData(&cssmCert, 169 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, 170 &rtnCert); 171 if(ortn) { 172 cssmPerror("SecCertificateCreateFromData", ortn); 173 printf("***Error creating cert fromn %s. Aborting.\n", fileName); 174 } 175 free(certData); 176 return rtnCert; 177} 178 179static int dumpCertFiles( 180 CFArrayRef allCerts, 181 const char *fileBase, 182 bool quiet) 183{ 184 char fileName[200]; 185 186 if(allCerts == NULL) { 187 printf("...no certs to write.\n"); 188 return 0; 189 } 190 CFIndex numCerts = CFArrayGetCount(allCerts); 191 if(numCerts == 0) { 192 printf("...no certs to write.\n"); 193 return 0; 194 } 195 for(CFIndex dex=0; dex<numCerts; dex++) { 196 SecCertificateRef secCert = 197 (SecCertificateRef)CFArrayGetValueAtIndex(allCerts, dex); 198 CSSM_DATA certData; 199 OSStatus ortn; 200 201 ortn = SecCertificateGetData(secCert, &certData); 202 if(ortn) { 203 cssmPerror("SecCertificateGetData", ortn); 204 return -1; 205 } 206 sprintf(fileName, "%s_%u.cer", fileBase, (unsigned)dex); 207 if(writeFile(fileName, certData.Data, certData.Length)) { 208 printf("***Error writing cert data to %s. Aborting.\n", fileName); 209 return 1; 210 } 211 else if(!quiet) { 212 printf("...wrote %u bytes to %s.\n", 213 (unsigned)certData.Length, fileName); 214 } 215 } 216 return 0; 217} 218 219/* 220 * Do a random number of random-sized updates on a CMSEncoder. 221 */ 222static OSStatus updateEncoder( 223 CMSEncoderRef cmsEncoder, 224 const unsigned char *inData, 225 unsigned inDataLen) 226{ 227 unsigned toMove = inDataLen; 228 unsigned thisMove; 229 230 while(toMove != 0) { 231 thisMove = genRand(1, toMove); 232 OSStatus ortn = CMSEncoderUpdateContent(cmsEncoder, inData, thisMove); 233 if(ortn) { 234 cssmPerror("CMSEncoderUpdateContent", ortn); 235 return ortn; 236 } 237 toMove -= thisMove; 238 inData += thisMove; 239 } 240 return noErr; 241} 242 243/* 244 * Do a random number of random-sized updates on a CMSDecoder. 245 */ 246static OSStatus updateDecoder( 247 CMSDecoderRef cmsDecoder, 248 const unsigned char *inData, 249 unsigned inDataLen) 250{ 251 unsigned toMove = inDataLen; 252 unsigned thisMove; 253 254 while(toMove != 0) { 255 thisMove = genRand(1, toMove); 256 OSStatus ortn = CMSDecoderUpdateMessage(cmsDecoder, inData, thisMove); 257 if(ortn) { 258 cssmPerror("CMSDecoderUpdateMessage", ortn); 259 return ortn; 260 } 261 toMove -= thisMove; 262 inData += thisMove; 263 } 264 return noErr; 265} 266 267#define TRUST_STRING_MAX 128 268 269static OSStatus evalSecTrust( 270 SecTrustRef secTrust, 271 CFMutableArrayRef anchorArray, // optional 272 char *trustStr, // caller-mallocd, TRUST_STRING_MAX chars 273 bool quiet) 274{ 275 OSStatus ortn; 276 SecTrustResultType secTrustResult; 277 278 if(anchorArray) { 279 ortn = SecTrustSetAnchorCertificates(secTrust, anchorArray); 280 if(ortn) { 281 /* should never happen */ 282 cssmPerror("SecTrustSetAnchorCertificates", ortn); 283 return ortn; 284 } 285 } 286 ortn = SecTrustEvaluate(secTrust, &secTrustResult); 287 if(ortn) { 288 /* should never happen */ 289 cssmPerror("SecTrustEvaluate", ortn); 290 return ortn; 291 } 292 switch(secTrustResult) { 293 case kSecTrustResultUnspecified: 294 /* cert chain valid, no special UserTrust assignments */ 295 case kSecTrustResultProceed: 296 /* cert chain valid AND user explicitly trusts this */ 297 sprintf(trustStr, "Successful\n"); 298 return noErr; 299 case kSecTrustResultDeny: 300 case kSecTrustResultConfirm: 301 /* 302 * Cert chain may well have verified OK, but user has flagged 303 * one of these certs as untrustable. 304 */ 305 sprintf(trustStr, "Not trusted per user-specified Trust level\n"); 306 /* bogus return code I know */ 307 return errSecInvalidTrustSetting; 308 default: 309 { 310 /* get low-level TP error */ 311 OSStatus tpStatus; 312 ortn = SecTrustGetCssmResultCode(secTrust, &tpStatus); 313 if(ortn) { 314 cssmPerror("SecTrustGetCssmResultCode", ortn); 315 return ortn; 316 } 317 switch(tpStatus) { 318 case CSSMERR_TP_INVALID_ANCHOR_CERT: 319 sprintf(trustStr, "Untrusted root\n"); 320 break; 321 case CSSMERR_TP_NOT_TRUSTED: 322 /* no root, not even in implicit SSL roots */ 323 sprintf(trustStr, "No root cert found\n"); 324 break; 325 case CSSMERR_TP_CERT_EXPIRED: 326 sprintf(trustStr, "Expired cert\n"); 327 break; 328 case CSSMERR_TP_CERT_NOT_VALID_YET: 329 sprintf(trustStr, "Cert not valid yet\n"); 330 break; 331 default: 332 sprintf(trustStr, "Other cert failure (%s)", 333 cssmErrToStr(tpStatus)); 334 break; 335 } 336 return tpStatus; 337 } 338 } /* SecTrustEvaluate error */ 339 /* NOT REACHED */ 340} 341 342static OSStatus doParse( 343 const unsigned char *data, 344 unsigned dataLen, 345 const unsigned char *detachedContent, 346 unsigned detachedContentLen, 347 bool multiUpdate, 348 CT_Vfy vfyOp, 349 const CSSM_OID *eContentVfy, // optional to verify 350 int numSignersVfy, // optional (>=0) to verify 351 int numCertsVfy, // optionjal (>= 0) to verify 352 bool parseSignerCert, 353 const char *certFileBase, // optionally write certs here 354 bool customDecoder, // invoke CMSDecoderSetDecoder() 355 bool manTrustEval, // evaluate SecTrust ourself 356 CFMutableArrayRef anchorArray, // optional, and only for manTrustEval 357 bool quiet, 358 CFDataRef *outData) // RETURNED 359{ 360 if((data == NULL) || (dataLen == 0)) { 361 fprintf(stderr, "***Parse requires input file. Aborting.\n"); 362 return paramErr; 363 } 364 365 CMSDecoderRef cmsDecoder; 366 size_t numSigners; 367 Boolean isEncrypted; 368 CFArrayRef allCerts = NULL; 369 unsigned signerDex; 370 SecPolicyRef policy = NULL; 371 SecPolicySearchRef policySearch = NULL; 372 CFIndex numCerts = 0; 373 int addDetachedAfterDecode = 0; 374 SecArenaPoolRef arena = NULL; 375 376 /* 377 * Four different return codes: 378 * -- ortn used for function returns; if nonzero, bail immediately and goto errOut 379 * -- ourRtn is manually set per the output of CMSDecoderCopySignerStatus and 380 * evalSecTrust 381 * -- trustRtn is the output of manual SecTrustEvaluate (via evalSecTrust()) 382 * -- vfyErr indicates mismatch in caller-specified error params 383 * 384 * All four have to be zero fgor us to return zero. 385 */ 386 OSStatus ourRtn = noErr; 387 OSStatus ortn = noErr; 388 OSStatus trustRtn = noErr; 389 int vfyErr = 0; 390 391 ortn = CMSDecoderCreate(&cmsDecoder); 392 if(ortn) { 393 cssmPerror("CMSDecoderCreate", ortn); 394 return ortn; 395 } 396 397 /* subsequent errors to errOut: */ 398 399 if(detachedContent != NULL) { 400 /* 401 * We can add detached content either before or after the 402 * update/finalize; to test and verify, flip a coin to decide 403 * when to do it. 404 */ 405 addDetachedAfterDecode = genRand(0, 1); 406 if(!addDetachedAfterDecode) { 407 CFDataRef cfDetach = CFDataCreate(NULL, detachedContent, detachedContentLen); 408 ortn = CMSDecoderSetDetachedContent(cmsDecoder, cfDetach); 409 CFRelease(cfDetach); 410 if(ortn) { 411 cssmPerror("CMSDecoderSetDetachedContent", ortn); 412 goto errOut; 413 } 414 } 415 } 416 417 if(customDecoder) { 418 /* Create a decoder; we don't have to free it, but we do have to free the 419 * arena pool */ 420 SecCmsDecoderRef coder = NULL; 421 422 ortn = SecArenaPoolCreate(1024, &arena); 423 if(ortn) { 424 cssmPerror("SecArenaPoolCreate", ortn); 425 goto errOut; 426 } 427 ortn = SecCmsDecoderCreate(arena, 428 NULL, NULL, NULL, NULL, NULL, NULL, &coder); 429 if(ortn) { 430 cssmPerror("SecCmsDecoderCreate", ortn); 431 goto errOut; 432 } 433 ortn = CMSDecoderSetDecoder(cmsDecoder, coder); 434 if(ortn) { 435 cssmPerror("CMSDecoderSetDecoder", ortn); 436 goto errOut; 437 } 438 else if(!quiet) { 439 printf("...set up custom SecCmsDecoderRef\n"); 440 } 441 } 442 if(multiUpdate) { 443 ortn = updateDecoder(cmsDecoder, data, dataLen); 444 if(ortn) { 445 goto errOut; 446 } 447 } 448 else { 449 ortn = CMSDecoderUpdateMessage(cmsDecoder, data, dataLen); 450 if(ortn) { 451 cssmPerror("CMSDecoderUpdateMessage", ortn); 452 goto errOut; 453 } 454 } 455 ortn = CMSDecoderFinalizeMessage(cmsDecoder); 456 if(ortn) { 457 cssmPerror("CMSDecoderFinalizeMessage", ortn); 458 goto errOut; 459 } 460 if(addDetachedAfterDecode) { 461 CFDataRef cfDetach = CFDataCreate(NULL, detachedContent, detachedContentLen); 462 ortn = CMSDecoderSetDetachedContent(cmsDecoder, cfDetach); 463 CFRelease(cfDetach); 464 if(ortn) { 465 cssmPerror("CMSDecoderSetDetachedContent", ortn); 466 goto errOut; 467 } 468 } 469 ortn = CMSDecoderGetNumSigners(cmsDecoder, &numSigners); 470 if(ortn) { 471 cssmPerror("CMSDecoderGetNumSigners", ortn); 472 goto errOut; 473 } 474 ortn = CMSDecoderIsContentEncrypted(cmsDecoder, &isEncrypted); 475 if(ortn) { 476 cssmPerror("CMSDecoderIsContentEncrypted", ortn); 477 goto errOut; 478 } 479 ortn = CMSDecoderCopyAllCerts(cmsDecoder, &allCerts); 480 if(ortn) { 481 cssmPerror("CMSDecoderCopyAllCerts", ortn); 482 goto errOut; 483 } 484 if(allCerts) { 485 numCerts = CFArrayGetCount(allCerts); 486 } 487 488 /* optional verify of expected message type */ 489 switch(vfyOp) { 490 case CTV_None: 491 break; 492 case CTV_Sign: 493 if((numSigners == 0) && (allCerts == NULL)) { 494 fprintf(stderr, "***Expected SignedData, but no signersFound\n"); 495 vfyErr = 1; 496 /* but keep going */ 497 } 498 if(isEncrypted) { 499 fprintf(stderr, "***Expected SignedData, but msg IS encrypted\n"); 500 vfyErr = 1; 501 } 502 break; 503 case CTV_SignEnvelop: 504 if(numSigners == 0) { 505 fprintf(stderr, "***Expected Signed&Enveloped, but no signersFound\n"); 506 vfyErr = 1; 507 } 508 if(!isEncrypted) { 509 fprintf(stderr, "***Expected Signed&Enveloped, but msg not encrypted\n"); 510 vfyErr = 1; 511 } 512 break; 513 case CTV_Envelop: 514 if(numSigners != 0) { 515 fprintf(stderr, "***Expected EnvelopedData, but signers found\n"); 516 vfyErr = 1; 517 } 518 if(!isEncrypted) { 519 fprintf(stderr, "***Expected EnvelopedData, but msg not encrypted\n"); 520 vfyErr = 1; 521 } 522 break; 523 } 524 525 if(numSignersVfy >= 0) { 526 if((unsigned)numSignersVfy != numSigners) { 527 fprintf(stderr, "***Expected %d signers; found %lu\n", 528 numSignersVfy, numSigners); 529 vfyErr = 1; 530 } 531 } 532 if(numCertsVfy >= 0) { 533 if((int)numCerts != numCertsVfy) { 534 fprintf(stderr, "***Expected %d certs; found %d\n", 535 numCertsVfy, (int)numCerts); 536 vfyErr = 1; 537 } 538 } 539 if(!quiet) { 540 fprintf(stderr, "=== CMS message info ===\n"); 541 fprintf(stderr, " Num Signers : %lu\n", (unsigned long)numSigners); 542 fprintf(stderr, " Encrypted : %s\n", isEncrypted ? "true" : "false"); 543 fprintf(stderr, " Num Certs : %lu\n", 544 allCerts ? (unsigned long)CFArrayGetCount(allCerts) : 0); 545 } 546 547 if((certFileBase != NULL) & (allCerts != NULL)) { 548 dumpCertFiles(allCerts, certFileBase, quiet); 549 } 550 551 552 if(numSigners) { 553 CSSM_OID eContentType = {0, NULL}; 554 CFDataRef eContentData = NULL; 555 OidParser oidParser; 556 char str[OID_PARSER_STRING_SIZE]; 557 558 ortn = CMSDecoderCopyEncapsulatedContentType(cmsDecoder, &eContentData); 559 if(ortn) { 560 cssmPerror("CMSDecoderCopyEncapsulatedContentType", ortn); 561 goto errOut; 562 } 563 if(eContentData != NULL) { 564 eContentType.Data = (uint8 *)CFDataGetBytePtr(eContentData); 565 eContentType.Length = CFDataGetLength(eContentData); 566 } 567 if(!quiet) { 568 /* can't use stderr - oidparser is fixed w/stdout */ 569 printf(" eContentType : "); 570 if(eContentType.Data == NULL) { 571 printf("***NONE FOUND***\n"); 572 } 573 else if(eContentType.Length == 0) { 574 printf("***EMPTY***\n"); 575 } 576 else { 577 oidParser.oidParse(eContentType.Data, eContentType.Length, str); 578 printf("%s\n", str); 579 } 580 } 581 582 if(eContentVfy != NULL) { 583 if(eContentType.Data == NULL) { 584 fprintf(stderr, "***Tried to verify eContentType, but none found\n"); 585 vfyErr = 1; 586 } 587 else if(!appCompareCssmData(eContentVfy, &eContentType)) { 588 fprintf(stderr, "***eContentType verify error\n"); 589 fprintf(stderr, " Expected: "); 590 oidParser.oidParse(eContentVfy->Data, eContentVfy->Length, str); 591 printf("%s\n", str); 592 fprintf(stderr, " Found : "); 593 oidParser.oidParse(eContentType.Data, eContentType.Length, str); 594 printf("%s\n", str); 595 vfyErr = 1; 596 } 597 } 598 CFRELEASE(eContentData); 599 600 /* get a policy for cert evaluation */ 601 ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, 602 &CSSMOID_APPLE_X509_BASIC, 603 NULL, 604 &policySearch); 605 if(ortn) { 606 cssmPerror("SecPolicySearchCreate", ortn); 607 goto errOut; 608 } 609 ortn = SecPolicySearchCopyNext(policySearch, &policy); 610 if(ortn) { 611 cssmPerror("SecPolicySearchCopyNext", ortn); 612 goto errOut; 613 } 614 } 615 for(signerDex=0; signerDex<numSigners; signerDex++) { 616 CMSSignerStatus signerStatus = kCMSSignerInvalidIndex; 617 SecCertificateRef signerCert; 618 CFStringRef signerEmailAddress; 619 SecTrustRef secTrust; 620 OSStatus certVerifyResultCode; 621 char trustStr[TRUST_STRING_MAX]; 622 623 ortn = CMSDecoderCopySignerStatus(cmsDecoder, signerDex, 624 policy, 625 manTrustEval ? FALSE : TRUE, /* evaluateSecTrust */ 626 &signerStatus, 627 &secTrust, 628 &certVerifyResultCode); 629 if(ortn) { 630 cssmPerror("CMSDecoderCopySignerStatus", ortn); 631 goto errOut; 632 } 633 if(ourRtn == noErr) { 634 if((signerStatus != kCMSSignerValid) || 635 (certVerifyResultCode != CSSM_OK)) { 636 ourRtn = -1; 637 } 638 } 639 ortn = CMSDecoderCopySignerEmailAddress(cmsDecoder, signerDex, 640 &signerEmailAddress); 641 if(ortn) { 642 cssmPerror("CMSDecoderCopySignerEmailAddress", ortn); 643 goto errOut; 644 } 645 ortn = CMSDecoderCopySignerCert(cmsDecoder, signerDex, 646 &signerCert); 647 if(ortn) { 648 cssmPerror("CMSDecoderCopySignerCertificate", ortn); 649 goto errOut; 650 } 651 if(manTrustEval) { 652 trustRtn = evalSecTrust(secTrust, anchorArray, trustStr, quiet); 653 } 654 655 /* display nothing here if quiet true and status is copacetic */ 656 if(!quiet || (signerStatus != kCMSSignerValid) || (trustRtn != noErr)) { 657 fprintf(stderr, " Signer %u:\n", signerDex); 658 fprintf(stderr, " signerStatus : "); 659 switch(signerStatus) { 660 case kCMSSignerUnsigned: 661 fprintf(stderr, "kCMSSignerUnsigned\n"); break; 662 case kCMSSignerValid: 663 fprintf(stderr, "kCMSSignerValid\n"); break; 664 case kCMSSignerNeedsDetachedContent: 665 fprintf(stderr, "kCMSSignerNeedsDetachedContent\n"); break; 666 case kCMSSignerInvalidSignature: 667 fprintf(stderr, "kCMSSignerInvalidSignature\n"); break; 668 case kCMSSignerInvalidCert: 669 fprintf(stderr, "kCMSSignerInvalidCert\n"); break; 670 case kCMSSignerInvalidIndex: 671 fprintf(stderr, "kCMSSignerInvalidIndex\n"); break; 672 } 673 if(manTrustEval) { 674 fprintf(stderr, " Trust Eval : %s\n", trustStr); 675 } 676 fprintf(stderr, " emailAddrs : "); 677 if(signerEmailAddress == NULL) { 678 fprintf(stderr, "<<none found>>\n"); 679 } 680 else { 681 char emailStr[1000]; 682 if(!CFStringGetCString(signerEmailAddress, 683 emailStr, 1000, kCFStringEncodingASCII)) { 684 fprintf(stderr, "<<<Error converting email address to C string>>>\n"); 685 } 686 else { 687 fprintf(stderr, "%s\n", emailStr); 688 } 689 } 690 691 fprintf(stderr, " vfyResult : %s\n", 692 certVerifyResultCode ? 693 cssmErrToStr(certVerifyResultCode) : "Success"); 694 695 /* TBD: optionally manually verify the SecTrust object */ 696 697 if(parseSignerCert) { 698 699 if(signerCert == NULL) { 700 fprintf(stderr, " <<<Unable to obtain signer cert>>>\n"); 701 } 702 else { 703 CSSM_DATA certData; 704 ortn = SecCertificateGetData(signerCert, &certData); 705 if(ortn) { 706 fprintf(stderr, " <<<Unable to obtain signer cert>>>\n"); 707 cssmPerror("SecCertificateGetData", ortn); 708 } 709 else { 710 printf("========== Signer Cert==========\n\n"); 711 printCert(certData.Data, certData.Length, CSSM_FALSE); 712 printf("========== End Signer Cert==========\n\n"); 713 } 714 } 715 } /* parseSignerCert */ 716 } /* displaying per-signer info */ 717 718 CFRELEASE(signerCert); 719 signerCert = NULL; 720 CFRELEASE(signerEmailAddress); 721 signerEmailAddress = NULL; 722 CFRELEASE(secTrust); 723 secTrust = NULL; 724 } /* for signerDex */ 725 726 if(ortn == noErr) { 727 ortn = CMSDecoderCopyContent(cmsDecoder, outData); 728 if(ortn) { 729 cssmPerror("CMSDecoderCopyContent", ortn); 730 } 731 } 732 733errOut: 734 CFRelease(cmsDecoder); 735 if(arena != NULL) { 736 SecArenaPoolFree(arena, false); 737 } 738 739 CFRELEASE(allCerts); 740 CFRELEASE(policySearch); 741 CFRELEASE(policy); 742 if(ourRtn) { 743 return ourRtn; 744 } 745 else if(trustRtn) { 746 return trustRtn; 747 } 748 else if(vfyErr) { 749 return vfyErr; 750 } 751 else { 752 return ortn; 753 } 754} 755 756static OSStatus doSign( 757 CFTypeRef signerOrArray, 758 const unsigned char *inData, 759 unsigned inDataLen, 760 bool multiUpdate, 761 bool detachedContent, 762 const CSSM_OID *eContentType, // OPTIONAL 763 CMSSignedAttributes attrs, 764 CFTypeRef otherCerts, // OPTIONAL 765 bool customCoder, 766 bool getCmsMsg, 767 CMSCertificateChainMode chainMode, 768 bool quiet, 769 CFDataRef *outData) // RETURNED 770{ 771 if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { 772 fprintf(stderr, "***Sign requires input file. Aborting.\n"); 773 return paramErr; 774 } 775 if(signerOrArray == NULL) { 776 fprintf(stderr, "***Sign requires a signing identity. Aborting.\n"); 777 return paramErr; 778 } 779 780 OSStatus ortn; 781 CMSEncoderRef cmsEncoder = NULL; 782 SecCmsMessageRef msg = NULL; /* for optional CMSEncoderGetCmsMessage */ 783 SecArenaPoolRef arena = NULL; 784 CSSM_DATA encoderOut = {0, NULL}; 785 786 if(multiUpdate || otherCerts || getCmsMsg || customCoder || 787 (chainMode != kCMSCertificateChain)) { 788 /* one-shot encode doesn't support otherCerts or chainOptions*/ 789 790 ortn = CMSEncoderCreate(&cmsEncoder); 791 if(ortn) { 792 cssmPerror("CMSEncoderCreate", ortn); 793 return ortn; 794 } 795 /* subsequent errors to errOut: */ 796 if(signerOrArray != NULL) { 797 ortn = CMSEncoderAddSigners(cmsEncoder, signerOrArray); 798 if(ortn) { 799 goto errOut; 800 } 801 } 802 if(eContentType) { 803 ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType); 804 if(ortn) { 805 goto errOut; 806 } 807 } 808 if(detachedContent) { 809 ortn = CMSEncoderSetHasDetachedContent(cmsEncoder, detachedContent); 810 if(ortn) { 811 goto errOut; 812 } 813 } 814 if(otherCerts) { 815 ortn = CMSEncoderAddSupportingCerts(cmsEncoder, otherCerts); 816 if(ortn) { 817 goto errOut; 818 } 819 } 820 if(attrs) { 821 ortn = CMSEncoderAddSignedAttributes(cmsEncoder, attrs); 822 if(ortn) { 823 goto errOut; 824 } 825 } 826 if(chainMode != kCMSCertificateChain) { 827 ortn = CMSEncoderSetCertificateChainMode(cmsEncoder, chainMode); 828 if(ortn) { 829 goto errOut; 830 } 831 } 832 if(getCmsMsg || customCoder) { 833 /* 834 * We just want to trigger the state transition 835 * that we know should happen. We also might need 836 * the msg to create a custom coder. 837 */ 838 ortn = CMSEncoderGetCmsMessage(cmsEncoder, &msg); 839 if(ortn) { 840 cssmPerror("CMSEncoderGetCmsMessage", ortn); 841 goto errOut; 842 } 843 } 844 845 if(customCoder) { 846 SecCmsEncoderRef coder = NULL; 847 ortn = SecArenaPoolCreate(1024, &arena); 848 if(ortn) { 849 cssmPerror("SecArenaPoolCreate", ortn); 850 goto errOut; 851 } 852 ortn = SecCmsEncoderCreate(msg, 853 NULL, NULL, // no callback 854 &encoderOut, // data goes here 855 arena, 856 NULL, NULL, // no password callback (right?) 857 NULL, NULL, // decrypt key callback 858 NULL, NULL, // detached digests 859 &coder); 860 if(ortn) { 861 cssmPerror("SecCmsEncoderCreate", ortn); 862 goto errOut; 863 } 864 ortn = CMSEncoderSetEncoder(cmsEncoder, coder); 865 if(ortn) { 866 cssmPerror("CMSEncoderSetEncoder", ortn); 867 goto errOut; 868 } 869 else if(!quiet) { 870 printf("...set up custom SecCmsEncoderRef\n"); 871 } 872 } 873 /* random number of random-sized updates */ 874 ortn = updateEncoder(cmsEncoder, inData, inDataLen); 875 if(ortn) { 876 goto errOut; 877 } 878 879 ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); 880 if(ortn) { 881 cssmPerror("CMSEncoderCopyEncodedContent", ortn); 882 } 883 if(customCoder) { 884 /* we have the data right here */ 885 *outData = CFDataCreate(NULL, 886 (const UInt8 *)encoderOut.Data, encoderOut.Length); 887 } 888 } 889 else { 890 ortn = CMSEncode(signerOrArray, 891 NULL, /* recipients */ 892 eContentType, 893 detachedContent, 894 attrs, 895 inData, inDataLen, 896 outData); 897 if(ortn) { 898 printf("***CMSEncode returned %ld\n", (long)ortn); 899 cssmPerror("CMSEncode", ortn); 900 } 901 } 902errOut: 903 if(cmsEncoder) { 904 CFRelease(cmsEncoder); 905 } 906 if(arena) { 907 SecArenaPoolFree(arena, false); 908 } 909 return ortn; 910} 911 912static OSStatus doEncrypt( 913 CFTypeRef recipOrArray, 914 const unsigned char *inData, 915 unsigned inDataLen, 916 bool multiUpdate, 917 CFDataRef *outData) // RETURNED 918{ 919 if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { 920 fprintf(stderr, "***Encrypt requires input file. Aborting.\n"); 921 return paramErr; 922 } 923 if(recipOrArray == NULL) { 924 fprintf(stderr, "***Encrypt requires a recipient certificate. Aborting.\n"); 925 return paramErr; 926 } 927 928 OSStatus ortn; 929 CMSEncoderRef cmsEncoder = NULL; 930 931 if(multiUpdate) { 932 ortn = CMSEncoderCreate(&cmsEncoder); 933 if(ortn) { 934 cssmPerror("CMSEncoderCreate", ortn); 935 return ortn; 936 } 937 /* subsequent errors to errOut: */ 938 ortn = CMSEncoderAddRecipients(cmsEncoder, recipOrArray); 939 if(ortn) { 940 goto errOut; 941 } 942 943 /* random number of random-sized updates */ 944 ortn = updateEncoder(cmsEncoder, inData, inDataLen); 945 if(ortn) { 946 goto errOut; 947 } 948 ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); 949 if(ortn) { 950 cssmPerror("CMSEncoderCopyEncodedContent", ortn); 951 } 952 } 953 else { 954 /* one-shot */ 955 ortn = CMSEncode(NULL, /* signers */ 956 recipOrArray, 957 NULL, /* eContentType */ 958 FALSE, /* detachedContent */ 959 kCMSAttrNone, 960 inData, inDataLen, 961 outData); 962 if(ortn) { 963 printf("***CMSEncode returned %ld\n", (long)ortn); 964 cssmPerror("CMSEncode", ortn); 965 } 966 } 967errOut: 968 if(cmsEncoder) { 969 CFRelease(cmsEncoder); 970 } 971 return ortn; 972} 973 974/* create nested message: msg = EnvelopedData(SignedData(inData)) */ 975static OSStatus doSignEncrypt( 976 CFTypeRef recipOrArray, // encryption recipients 977 CFTypeRef signerOrArray, // signers 978 const CSSM_OID *eContentType, // OPTIONAL - for signedData 979 CMSSignedAttributes attrs, 980 const unsigned char *inData, 981 unsigned inDataLen, 982 bool multiUpdate, 983 CFTypeRef otherCerts, // OPTIONAL 984 CFDataRef *outData) // RETURNED 985{ 986 if((inData == NULL) || (inDataLen == 0) || (outData == NULL)) { 987 fprintf(stderr, "***Sign/Encrypt requires input file. Aborting.\n"); 988 return paramErr; 989 } 990 if(recipOrArray == NULL) { 991 fprintf(stderr, "***Sign/Encrypt requires a recipient certificate. Aborting.\n"); 992 return paramErr; 993 } 994 if(signerOrArray == NULL) { 995 fprintf(stderr, "***Sign/Encrypt requires a signer Identity. Aborting.\n"); 996 return paramErr; 997 } 998 999 OSStatus ortn; 1000 CMSEncoderRef cmsEncoder = NULL; 1001 1002 if(multiUpdate || otherCerts) { 1003 ortn = CMSEncoderCreate(&cmsEncoder); 1004 if(ortn) { 1005 cssmPerror("CMSEncoderCreate", ortn); 1006 return ortn; 1007 } 1008 /* subsequent errors to errOut: */ 1009 ortn = CMSEncoderAddRecipients(cmsEncoder, recipOrArray); 1010 if(ortn) { 1011 goto errOut; 1012 } 1013 ortn = CMSEncoderAddSigners(cmsEncoder, signerOrArray); 1014 if(ortn) { 1015 goto errOut; 1016 } 1017 if(eContentType) { 1018 ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType); 1019 if(ortn) { 1020 goto errOut; 1021 } 1022 } 1023 if(otherCerts) { 1024 ortn = CMSEncoderAddSupportingCerts(cmsEncoder, otherCerts); 1025 if(ortn) { 1026 goto errOut; 1027 } 1028 } 1029 if(attrs) { 1030 ortn = CMSEncoderAddSignedAttributes(cmsEncoder, attrs); 1031 if(ortn) { 1032 goto errOut; 1033 } 1034 } 1035 1036 /* random number of random-sized updates */ 1037 ortn = updateEncoder(cmsEncoder, inData, inDataLen); 1038 if(ortn) { 1039 goto errOut; 1040 } 1041 ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); 1042 if(ortn) { 1043 cssmPerror("CMSEncoderCopyEncodedContent", ortn); 1044 } 1045 } 1046 else { 1047 ortn = CMSEncode(signerOrArray, 1048 recipOrArray, 1049 eContentType, 1050 FALSE, /* detachedContent */ 1051 attrs, 1052 inData, inDataLen, 1053 outData); 1054 if(ortn) { 1055 printf("***CMSEncode returned %ld\n", (long)ortn); 1056 cssmPerror("CMSEncode", ortn); 1057 } 1058 } 1059 1060errOut: 1061 if(cmsEncoder) { 1062 CFRelease(cmsEncoder); 1063 } 1064 return ortn; 1065} 1066 1067/* 1068 * Create a CMS message containing only certs. 1069 */ 1070static OSStatus makeCertBag( 1071 CFTypeRef certsOrArray, 1072 CFDataRef *outData) 1073{ 1074 if(certsOrArray == NULL) { 1075 printf("***Need some certs to generate this type of message.\n"); 1076 return -1; 1077 } 1078 1079 OSStatus ortn; 1080 CMSEncoderRef cmsEncoder = NULL; 1081 1082 ortn = CMSEncoderCreate(&cmsEncoder); 1083 if(ortn) { 1084 cssmPerror("CMSEncoderCreate", ortn); 1085 return ortn; 1086 } 1087 /* subsequent errors to errOut: */ 1088 ortn = CMSEncoderAddSupportingCerts(cmsEncoder, certsOrArray); 1089 if(ortn) { 1090 goto errOut; 1091 } 1092 ortn = CMSEncoderCopyEncodedContent(cmsEncoder, outData); 1093 if(ortn) { 1094 cssmPerror("CMSEncoderCopyEncodedContent", ortn); 1095 } 1096errOut: 1097 CFRelease(cmsEncoder); 1098 return ortn; 1099} 1100 1101/* 1102 * Support maintanance of single item or array of them. 1103 * 1104 * Given new incoming 'newThing': 1105 * if both *thingArray and *currThing are NULL 1106 * *currThing = newThing; 1107 * done; 1108 * create *thingArray; 1109 * add *currThing to *thingArray if present; 1110 * add newThing to *thingArray; 1111 */ 1112static void addThing( 1113 CFTypeRef newThing, 1114 CFTypeRef *currThing, 1115 CFMutableArrayRef *thingArray) 1116{ 1117 if((*currThing == NULL) && (*thingArray == NULL)) { 1118 /* first occurrence of a thing */ 1119 *currThing = newThing; 1120 return; 1121 } 1122 1123 /* at least two things - prepare array */ 1124 if(*thingArray == NULL) { 1125 *thingArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1126 } 1127 if(*currThing != NULL) { 1128 /* move current thing to array */ 1129 CFArrayAppendValue(*thingArray, *currThing); 1130 CFRelease(*currThing); 1131 *currThing = NULL; 1132 } 1133 CFArrayAppendValue(*thingArray, newThing); 1134 CFRelease(newThing); 1135} 1136 1137int main(int argc, char **argv) 1138{ 1139 if(argc < 2) { 1140 usage(argv); 1141 } 1142 1143 CT_Op op; 1144 bool needId = false; 1145 if(!strcmp(argv[1], "sign")) { 1146 op = CTO_Sign; 1147 needId = true; 1148 } 1149 else if(!strcmp(argv[1], "envel")) { 1150 op = CTO_Envelop; 1151 } 1152 else if(!strcmp(argv[1], "signEnv")) { 1153 op = CTO_SignEnvelop; 1154 needId = true; 1155 } 1156 else if(!strcmp(argv[1], "certs")) { 1157 op = CTO_CertsOnly; 1158 } 1159 else if(!strcmp(argv[1], "parse")) { 1160 op = CTO_Parse; 1161 } 1162 else { 1163 fprintf(stderr, "***Unrecognized cmd.\n"); 1164 usage(argv); 1165 } 1166 1167 extern int optind; 1168 extern char *optarg; 1169 int arg; 1170 OSStatus ortn; 1171 1172 /* optional args */ 1173 char *inFileName = NULL; 1174 char *outFileName = NULL; 1175 bool detachedContent = false; 1176 char *detachedFile = NULL; 1177 bool useIdPicker = false; 1178 bool quiet = false; 1179 bool silent = false; 1180 bool parseSignerCert = false; 1181 const CSSM_OID *eContentType = NULL; 1182 bool multiUpdate = false; 1183 bool loopPause = false; 1184 char *certFileBase = NULL; 1185 CMSSignedAttributes signedAttrs = 0; 1186 char *anchorFile = NULL; 1187 bool manTrustEval = false; 1188 CMSCertificateChainMode chainMode = kCMSCertificateChain; 1189 1190 /* for verification, usually in quiet/script mode */ 1191 CT_Vfy vfyOp = CTV_None; 1192 const CSSM_OID *eContentVfy = NULL; 1193 int numSignersVfy = -1; 1194 int numCertsVfy = -1; 1195 1196 /* for verifying functions in CMSPrivate.h */ 1197 bool customCoder = false; 1198 bool fetchSecCmsMsg = false; 1199 1200 /* 1201 * Signer/recipient items and arrays - use one item if possible, 1202 * else array (to test both paths) 1203 */ 1204 SecIdentityRef signerId = NULL; 1205 CFMutableArrayRef signerArray = NULL; 1206 SecCertificateRef recipCert = NULL; 1207 CFMutableArrayRef recipArray = NULL; 1208 SecCertificateRef generalCert = NULL; 1209 CFMutableArrayRef generalCertArray = NULL; 1210 SecKeychainRef kcRef = NULL; 1211 CFMutableArrayRef anchorArray = NULL; 1212 1213 optind = 2; 1214 while ((arg = getopt(argc, argv, "i:o:k:pr:R:dD:e:mlqcv:s:E:S:C:f:N:a:A:M12t:Z")) != -1) { 1215 switch (arg) { 1216 case 'i': 1217 inFileName = optarg; 1218 break; 1219 case 'o': 1220 outFileName = optarg; 1221 break; 1222 case 'k': 1223 kcRef = keychain_open(optarg); 1224 if(!kcRef) { 1225 // cssmPerror("SecKeychainOpen", ortn); 1226 exit(1); 1227 } 1228 break; 1229 case 'p': 1230 useIdPicker = true; 1231 break; 1232 case 'r': 1233 { 1234 SecCertificateRef newCert = NULL; 1235 char *recipient = optarg; 1236 ortn = findCert(recipient, kcRef, &newCert); 1237 if(ortn) { 1238 exit(1); 1239 } 1240 addThing(newCert, (CFTypeRef *)&recipCert, &recipArray); 1241 break; 1242 } 1243 case 'R': 1244 { 1245 SecCertificateRef certRef = readCertFile(optarg); 1246 if(certRef == NULL) { 1247 exit(1); 1248 } 1249 addThing(certRef, (CFTypeRef *)&recipCert, &recipArray); 1250 break; 1251 } 1252 case 'S': 1253 { 1254 SecIdentityRef newId = NULL; 1255 SecCertificateRef newCert = NULL; 1256 char *signerEmail = optarg; 1257 1258 /* 1259 * first find the cert, optionally in the keychain already 1260 * specified via -k 1261 */ 1262 ortn = findCert(signerEmail, kcRef, &newCert); 1263 if(ortn) { 1264 exit(1); 1265 } 1266 1267 /* map cert to an identity */ 1268 ortn = SecIdentityCreateWithCertificate(kcRef, newCert, &newId); 1269 if(ortn) { 1270 cssmPerror("SecIdentityCreateWithCertificate", ortn); 1271 exit(1); 1272 } 1273 1274 addThing(newId, (CFTypeRef *)&signerId, &signerArray); 1275 CFRelease(newCert); 1276 break; 1277 } 1278 case 'C': 1279 { 1280 SecCertificateRef newCert = readCertFile(optarg); 1281 if(newCert == NULL) { 1282 exit(1); 1283 } 1284 addThing(newCert, (CFTypeRef *)&generalCert, &generalCertArray); 1285 break; 1286 } 1287 case 'c': 1288 parseSignerCert = true; 1289 break; 1290 case 'v': 1291 if(!strcmp(optarg, "sign")) { 1292 vfyOp = CTV_Sign; 1293 } 1294 else if(!strcmp(optarg, "encr")) { 1295 vfyOp = CTV_Envelop; 1296 } 1297 else if(!strcmp(optarg, "signEnv")) { 1298 vfyOp = CTV_SignEnvelop; 1299 } 1300 else { 1301 usage(argv); 1302 } 1303 break; 1304 case 'e': 1305 switch(optarg[0]) { 1306 case 'a': 1307 eContentType = &CSSMOID_PKINIT_AUTH_DATA; 1308 break; 1309 case 'r': 1310 eContentType = &CSSMOID_PKINIT_RKEY_DATA; 1311 break; 1312 default: 1313 usage(argv); 1314 } 1315 break; 1316 case 'E': 1317 switch(optarg[0]) { 1318 case 'a': 1319 eContentVfy = &CSSMOID_PKINIT_AUTH_DATA; 1320 break; 1321 case 'r': 1322 eContentVfy = &CSSMOID_PKINIT_RKEY_DATA; 1323 break; 1324 case 'd': 1325 eContentVfy = &CSSMOID_PKCS7_Data; 1326 break; 1327 default: 1328 usage(argv); 1329 } 1330 break; 1331 case 'd': 1332 if(op != CTO_Sign) { 1333 printf("-d only valid for op sign\n"); 1334 exit(1); 1335 } 1336 detachedContent = true; 1337 break; 1338 case 'D': 1339 if(op != CTO_Parse) { 1340 printf("-D only valid for op sign\n"); 1341 exit(1); 1342 } 1343 detachedFile = optarg; 1344 break; 1345 case 'l': 1346 loopPause = true; 1347 break; 1348 case 'm': 1349 multiUpdate = true; 1350 break; 1351 case 's': 1352 numSignersVfy = atoi(optarg); 1353 break; 1354 case 'f': 1355 certFileBase = optarg; 1356 break; 1357 case 'N': 1358 numCertsVfy = atoi(optarg); 1359 break; 1360 case '1': 1361 customCoder = true; 1362 break; 1363 case '2': 1364 fetchSecCmsMsg = true; 1365 break; 1366 case 'a': 1367 for(; *optarg; optarg++) { 1368 switch(*optarg) { 1369 case 'c': 1370 signedAttrs |= kCMSAttrSmimeCapabilities; 1371 break; 1372 case 'e': 1373 signedAttrs |= kCMSAttrSmimeEncryptionKeyPrefs; 1374 break; 1375 case 'E': 1376 signedAttrs |= kCMSAttrSmimeMSEncryptionKeyPrefs; 1377 break; 1378 case 't': 1379 signedAttrs |= kCMSAttrSigningTime; 1380 break; 1381 default: 1382 usage(argv); 1383 } 1384 } 1385 break; 1386 case 'A': 1387 anchorFile = optarg; 1388 break; 1389 case 'M': 1390 manTrustEval = true; 1391 break; 1392 case 't': 1393 if(!strcmp(optarg, "none")) { 1394 chainMode = kCMSCertificateNone; 1395 } 1396 else if(!strcmp(optarg, "signer")) { 1397 chainMode = kCMSCertificateSignerOnly; 1398 } 1399 else if(!strcmp(optarg, "chain")) { 1400 chainMode = kCMSCertificateChain; 1401 } 1402 else if(!strcmp(optarg, "chainWithRoot")) { 1403 chainMode = kCMSCertificateChainWithRoot; 1404 } 1405 else { 1406 printf("***Bogus cert chain spec***\n"); 1407 usage(argv); 1408 } 1409 break; 1410 case 'q': 1411 quiet = true; 1412 break; 1413 case 'Z': 1414 quiet = true; 1415 silent = true; 1416 break; 1417 default: 1418 case '?': 1419 usage(argv); 1420 } 1421 } 1422 if(optind != argc) { 1423 /* getopt does not return '?' */ 1424 usage(argv); 1425 } 1426 1427 unsigned char *inData = NULL; 1428 unsigned inDataLen = 0; 1429 unsigned char *detachedData = NULL; 1430 unsigned detachedDataLen = 0; 1431 CFDataRef outData = NULL; 1432 CFIndex byteCount = 0; 1433 if(!silent) { 1434 testStartBanner((char *)"newCmsTool", argc, argv); 1435 } 1436 1437 if(inFileName) { 1438 if(readFile(inFileName, &inData, &inDataLen)) { 1439 fprintf(stderr, "***Error reading infile %s. Aborting.\n", inFileName); 1440 exit(1); 1441 } 1442 } 1443 if(detachedFile) { 1444 if(readFile(detachedFile, &detachedData, &detachedDataLen)) { 1445 fprintf(stderr, "***Error reading detachedFile %s. Aborting.\n", detachedFile); 1446 exit(1); 1447 } 1448 } 1449 1450 /* signer IDs */ 1451 if(useIdPicker) { 1452 ortn = sslSimpleIdentPicker(kcRef, &signerId); 1453 if(ortn) { 1454 fprintf(stderr, "***Error obtaining identity via picker. Aborting.\n"); 1455 exit(1); 1456 } 1457 } 1458 if(anchorFile) { 1459 SecCertificateRef secCert = readCertFile(anchorFile); 1460 if(secCert == NULL) { 1461 exit(1); 1462 } 1463 anchorArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1464 CFArrayAppendValue(anchorArray, secCert); 1465 CFRelease(secCert); 1466 } 1467 1468 /* 1469 * In order for signed blobs to contain a full cert chain, and to find 1470 * certs matching a specific recipient cert email address, the keychain 1471 * containing intermediates must be in the user's keychain search list 1472 * (or, alternatively, the intermedaite certs must be added manually). 1473 * To alleviate the burden on test scripts, we'll ensure that an optionally 1474 * specified keychain is in factin the search list when we sign a message 1475 * here. 1476 * Careful - make sure to ALWAYS restore the search list! 1477 */ 1478 CFArrayRef originalSearchList = NULL; 1479 if(kcRef != NULL) { 1480 ortn = SecKeychainCopySearchList(&originalSearchList); 1481 if(ortn) { 1482 cssmPerror("SecKeychainCopySearchList", ortn); 1483 exit(1); 1484 } 1485 CFMutableArrayRef newList = CFArrayCreateMutableCopy( 1486 NULL, 0, originalSearchList); 1487 CFArrayAppendValue(newList, kcRef); 1488 ortn = SecKeychainSetSearchList(newList); 1489 if(ortn) { 1490 cssmPerror("SecKeychainSetSearchList", ortn); 1491 exit(1); 1492 } 1493 /* DO NOT EXIT WITHOUT RESTORING TO originalSearchList */ 1494 } 1495 do { 1496 switch(op) { 1497 case CTO_Sign: 1498 ortn = doSign((signerArray != NULL) ? 1499 (CFTypeRef)signerArray : (CFTypeRef)signerId, 1500 inData, inDataLen, 1501 multiUpdate, detachedContent, eContentType, signedAttrs, 1502 (generalCertArray != NULL) ? 1503 (CFTypeRef)generalCertArray : (CFTypeRef)generalCert, 1504 customCoder, fetchSecCmsMsg, chainMode, quiet, 1505 &outData); 1506 break; 1507 case CTO_Envelop: 1508 ortn = doEncrypt(recipArray ? 1509 (CFTypeRef)recipArray : (CFTypeRef)recipCert, 1510 inData, inDataLen, 1511 multiUpdate, &outData); 1512 break; 1513 case CTO_SignEnvelop: 1514 ortn = doSignEncrypt(recipArray ? 1515 (CFTypeRef)recipArray : (CFTypeRef)recipCert, 1516 signerArray ? 1517 (CFTypeRef)signerArray : (CFTypeRef)signerId, 1518 eContentType, signedAttrs, 1519 inData, inDataLen, multiUpdate, 1520 (generalCertArray != NULL) ? 1521 (CFTypeRef)generalCertArray : (CFTypeRef)generalCert, 1522 &outData); 1523 break; 1524 case CTO_CertsOnly: 1525 ortn = makeCertBag((generalCertArray != NULL) ? 1526 (CFTypeRef)generalCertArray : (CFTypeRef)generalCert, 1527 &outData); 1528 break; 1529 case CTO_Parse: 1530 ortn = doParse(inData, inDataLen, 1531 detachedData, detachedDataLen, 1532 multiUpdate, 1533 vfyOp, eContentVfy, numSignersVfy, numCertsVfy, 1534 parseSignerCert, certFileBase, customCoder, 1535 manTrustEval, anchorArray, 1536 quiet, &outData); 1537 break; 1538 } 1539 1540 if(loopPause) { 1541 if(outData) { 1542 printf("...generated %u bytes of data.\n", 1543 (unsigned)CFDataGetLength(outData)); 1544 } 1545 fpurge(stdin); 1546 printf("q to quit, anything else to loop again: "); 1547 char resp = getchar(); 1548 if(resp == 'q') { 1549 break; 1550 } 1551 else { 1552 CFRELEASE(outData); 1553 outData = NULL; 1554 } 1555 } 1556 } while (loopPause); 1557 1558 if(originalSearchList) { 1559 ortn = SecKeychainSetSearchList(originalSearchList); 1560 if(ortn) { 1561 cssmPerror("SecKeychainSetSearchList", ortn); 1562 /* keep going */ 1563 } 1564 } 1565 1566 if(ortn) { 1567 goto errOut; 1568 } 1569 1570 byteCount = outData ? CFDataGetLength(outData) : 0; 1571 if(outData && outFileName) { 1572 if(writeFile(outFileName, CFDataGetBytePtr(outData), byteCount)) { 1573 fprintf(stderr, "***Error writing to %s.\n", outFileName); 1574 ortn = -1; 1575 } 1576 else { 1577 if(!quiet) { 1578 fprintf(stderr, "...wrote %u bytes to %s.\n", 1579 (unsigned)byteCount, outFileName); 1580 } 1581 } 1582 } 1583 else if(byteCount) { 1584 fprintf(stderr, "...generated %u bytes but no place to write it.\n", 1585 (unsigned)byteCount); 1586 } 1587 else if(outFileName) { 1588 fprintf(stderr, "...nothing to write to file %s.\n", outFileName); 1589 /* assume this is an error, caller wanted something */ 1590 ortn = -1; 1591 } 1592errOut: 1593 return ortn; 1594} 1595 1596/* 1597 From SecurityTool/keychain_utilites.cpp 1598 This properly supports dynamic keychains, i.e. smartcards 1599*/ 1600 1601SecKeychainRef keychain_open(const char *name) 1602{ 1603 SecKeychainRef keychain = NULL; 1604 OSStatus result; 1605 1606// check_obsolete_keychain(name); 1607 if (name && name[0] != '/') 1608 { 1609 CFArrayRef dynamic = NULL; 1610 result = SecKeychainCopyDomainSearchList( 1611 kSecPreferencesDomainDynamic, &dynamic); 1612 if (result) 1613 { 1614 // cssmPerror("SecKeychainOpen", ortn); 1615 // sec_error("SecKeychainCopyDomainSearchList %s: %s", 1616 // name, sec_errstr(result)); 1617 cssmPerror("SecKeychainCopyDomainSearchList", result); 1618 return NULL; 1619 } 1620 else 1621 { 1622 uint32_t i; 1623 uint32_t count = dynamic ? CFArrayGetCount(dynamic) : 0; 1624 1625 for (i = 0; i < count; ++i) 1626 { 1627 char pathName[PATH_MAX]; 1628 UInt32 ioPathLength = sizeof(pathName); 1629 bzero(pathName, ioPathLength); 1630 keychain = (SecKeychainRef)CFArrayGetValueAtIndex(dynamic, i); 1631 result = SecKeychainGetPath(keychain, &ioPathLength, pathName); 1632 if (result) 1633 { 1634 // sec_error("SecKeychainGetPath %s: %s", name, sec_errstr(result)); 1635 cssmPerror("SecKeychainCopyDomainSearchList", result); 1636 return NULL; 1637 } 1638 if (!strncmp(pathName, name, ioPathLength)) 1639 { 1640 CFRetain(keychain); 1641 CFRelease(dynamic); 1642 return keychain; 1643 } 1644 } 1645 CFRelease(dynamic); 1646 } 1647 } 1648 1649 result = SecKeychainOpen(name, &keychain); 1650 if (result) 1651 { 1652 // sec_error("SecKeychainOpen %s: %s", name, sec_errstr(result)); 1653 cssmPerror("SecKeychainOpen", result); 1654 } 1655 1656 return keychain; 1657} 1658 1659