]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/newCmsTool/newCmsTool.cpp
Security-57031.30.12.tar.gz
[apple/security.git] / SecurityTests / clxutils / newCmsTool / newCmsTool.cpp
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
31 static SecKeychainRef keychain_open(const char *name);
32
33 static 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 */
78 typedef enum {
79 CTO_Sign,
80 CTO_Envelop,
81 CTO_SignEnvelop,
82 CTO_CertsOnly,
83 CTO_Parse
84 } CT_Op;
85
86 /* to verify */
87 typedef 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
98 static const uint8 OID_PKINIT_AUTH_DATA[] = {OID_PKINIT, 1};
99 static const uint8 OID_PKINIT_DH_KEY_DATA[] = {OID_PKINIT, 2};
100 static const uint8 OID_PKINIT_RKEY_DATA[] = {OID_PKINIT, 3};
101 static const uint8 OID_PKINIT_KP_CLIENTAUTH[] = {OID_PKINIT, 3};
102 static const uint8 OID_PKINIT_KPKDC[] = {OID_PKINIT, 5};
103
104 static const CSSM_OID CSSMOID_PKINIT_AUTH_DATA =
105 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_AUTH_DATA};
106 static const CSSM_OID CSSMOID_PKINIT_DH_KEY_DATA =
107 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_DH_KEY_DATA};
108 static const CSSM_OID CSSMOID_PKINIT_RKEY_DATA =
109 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_RKEY_DATA};
110 static const CSSM_OID CSSMOID_PKINIT_KP_CLIENTAUTH =
111 {OID_PKINIT_LEN+1, (uint8 *)OID_PKINIT_KP_CLIENTAUTH};
112 static 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 */
120 static 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 */
156 static 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
179 static 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 */
222 static 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 */
246 static 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
269 static 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
342 static 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
733 errOut:
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
756 static 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 }
902 errOut:
903 if(cmsEncoder) {
904 CFRelease(cmsEncoder);
905 }
906 if(arena) {
907 SecArenaPoolFree(arena, false);
908 }
909 return ortn;
910 }
911
912 static 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 }
967 errOut:
968 if(cmsEncoder) {
969 CFRelease(cmsEncoder);
970 }
971 return ortn;
972 }
973
974 /* create nested message: msg = EnvelopedData(SignedData(inData)) */
975 static 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
1060 errOut:
1061 if(cmsEncoder) {
1062 CFRelease(cmsEncoder);
1063 }
1064 return ortn;
1065 }
1066
1067 /*
1068 * Create a CMS message containing only certs.
1069 */
1070 static 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 }
1096 errOut:
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 */
1112 static 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
1137 int 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 }
1592 errOut:
1593 return ortn;
1594 }
1595
1596 /*
1597 From SecurityTool/keychain_utilites.cpp
1598 This properly supports dynamic keychains, i.e. smartcards
1599 */
1600
1601 SecKeychainRef 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