]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_cms/lib/CMSEncoder.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_cms / lib / CMSEncoder.cpp
1 /*
2 * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * CMSEncoder.cpp - encode, sign, and/or encrypt CMS messages.
26 */
27
28 #include "CMSEncoder.h"
29 #include "CMSPrivate.h"
30 #include "CMSUtils.h"
31 #include <Security/SecBase.h>
32 #include <Security/SecCmsEncoder.h>
33 #include <Security/SecCmsEnvelopedData.h>
34 #include <Security/SecCmsMessage.h>
35 #include <Security/SecCmsRecipientInfo.h>
36 #include <Security/SecCmsSignedData.h>
37 #include <Security/SecCmsSignerInfo.h>
38 #include <Security/SecCmsContentInfo.h>
39 #include <Security/SecCertificate.h>
40 #include <Security/SecIdentity.h>
41 #include <Security/SecKeychain.h>
42 #include <Security/SecKeychainItem.h>
43 #include <Security/SecSMIME.h>
44 #include <Security/oidsattr.h>
45 #include <Security/SecAsn1Coder.h>
46 #include <Security/SecAsn1Types.h>
47 #include <Security/SecAsn1Templates.h>
48 #include <CoreFoundation/CFRuntime.h>
49 #include <pthread.h>
50
51 #include <security_smime/tsaSupport.h>
52 #include <security_smime/cmspriv.h>
53
54 #pragma mark --- Private types and definitions ---
55
56 /*
57 * Encoder state.
58 */
59 typedef enum {
60 ES_Init, /* between CMSEncoderCreate and earlier of CMSEncoderUpdateContent
61 * and CMSEncodeGetCmsMessage */
62 ES_Msg, /* created cmsMsg in CMSEncodeGetCmsMessage, but no encoder yet */
63 ES_Updating, /* between first CMSEncoderUpdateContent and CMSEncoderCopyEncodedContent */
64 ES_Final /* CMSEncoderCopyEncodedContent has been called */
65 } CMSEncoderState;
66
67 /*
68 * High-level operation: what are we doing?
69 */
70 typedef enum {
71 EO_Sign,
72 EO_Encrypt,
73 EO_SignEncrypt
74 } CMSEncoderOp;
75
76 /*
77 * Caller's CMSEncoderRef points to one of these.
78 */
79 struct _CMSEncoder {
80 CFRuntimeBase base;
81 CMSEncoderState encState;
82 CMSEncoderOp op;
83 Boolean detachedContent;
84 CSSM_OID eContentType;
85 CFMutableArrayRef signers;
86 CFMutableArrayRef recipients;
87 CFMutableArrayRef otherCerts;
88 CMSSignedAttributes signedAttributes;
89 CFAbsoluteTime signingTime;
90 SecCmsMessageRef cmsMsg;
91 SecArenaPoolRef arena; /* the encoder's arena */
92 SecCmsEncoderRef encoder;
93 CSSM_DATA encoderOut; /* output goes here... */
94 bool customCoder; /* unless this is set by
95 * CMSEncoderSetEncoder */
96 CMSCertificateChainMode chainMode;
97 };
98
99 static void cmsEncoderInit(CFTypeRef enc);
100 static void cmsEncoderFinalize(CFTypeRef enc);
101
102 static CFRuntimeClass cmsEncoderRuntimeClass =
103 {
104 0, /* version */
105 "CMSEncoder",
106 cmsEncoderInit,
107 NULL, /* copy */
108 cmsEncoderFinalize,
109 NULL, /* equal - just use pointer equality */
110 NULL, /* hash, ditto */
111 NULL, /* copyFormattingDesc */
112 NULL /* copyDebugDesc */
113 };
114
115 void
116 CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback);
117
118 #pragma mark --- Private routines ---
119
120 /*
121 * Decode a CFStringRef representation of an integer
122 */
123 static int cfStringToNumber(
124 CFStringRef inStr)
125 {
126 int max = 32;
127 char buf[max];
128 if (!inStr || !CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII))
129 return -1;
130 return atoi(buf);
131 }
132
133 /*
134 * Encode an integer component of an OID, return resulting number of bytes;
135 * actual bytes are mallocd and returned in *encodeArray.
136 */
137 static unsigned encodeNumber(
138 int num,
139 unsigned char **encodeArray) // mallocd and RETURNED
140 {
141 unsigned char *result;
142 unsigned dex;
143 unsigned numDigits = 0;
144 unsigned scratch;
145
146 /* trival case - 0 maps to 0 */
147 if(num == 0) {
148 *encodeArray = (unsigned char *)malloc(1);
149 **encodeArray = 0;
150 return 1;
151 }
152
153 /* first calculate the number of digits in num, base 128 */
154 scratch = (unsigned)num;
155 while(scratch != 0) {
156 numDigits++;
157 scratch >>= 7;
158 }
159
160 result = (unsigned char *)malloc(numDigits);
161 scratch = (unsigned)num;
162 for(dex=0; dex<numDigits; dex++) {
163 result[numDigits - dex - 1] = scratch & 0x7f;
164 scratch >>= 7;
165 }
166
167 /* all digits except the last one have m.s. bit set */
168 for(dex=0; dex<(numDigits - 1); dex++) {
169 result[dex] |= 0x80;
170 }
171
172 *encodeArray = result;
173 return numDigits;
174 }
175
176 /*
177 * Given an OID in dotted-decimal string representation, convert to binary
178 * DER format. Returns a pointer in outOid which the caller must free(),
179 * as well as the length of the data in outLen.
180 * Function returns 0 if successful, non-zero otherwise.
181 */
182 static int encodeOid(
183 const unsigned char *inStr,
184 unsigned char **outOid,
185 unsigned int *outLen)
186 {
187 unsigned char **digits = NULL; /* array of char * from encodeNumber */
188 unsigned *numDigits = NULL; /* array of unsigned from encodeNumber */
189 CFIndex digit;
190 unsigned numDigitBytes; /* total #of output chars */
191 unsigned char firstByte;
192 unsigned char *outP;
193 CFIndex numsToProcess;
194 CFStringRef oidStr = NULL;
195 CFArrayRef argvRef = NULL;
196 int num, result = 1;
197 CFIndex argc;
198
199 /* parse input string into array of substrings */
200 if (!inStr || !outOid || !outLen) goto cleanExit;
201 oidStr = CFStringCreateWithCString(NULL, (const char *)inStr, kCFStringEncodingASCII);
202 if (!oidStr) goto cleanExit;
203 argvRef = CFStringCreateArrayBySeparatingStrings(NULL, oidStr, CFSTR("."));
204 if (!argvRef) goto cleanExit;
205 argc = CFArrayGetCount(argvRef);
206 if (argc < 3) goto cleanExit;
207
208 /* first two numbers in OID munge together */
209 num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 0));
210 if (num < 0) goto cleanExit;
211 firstByte = (40 * num);
212 num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 1));
213 if (num < 0) goto cleanExit;
214 firstByte += num;
215 numDigitBytes = 1;
216
217 numsToProcess = argc - 2;
218 if(numsToProcess > 0) {
219 /* skip this loop in the unlikely event that input is only two numbers */
220 digits = (unsigned char **) malloc(numsToProcess * sizeof(unsigned char *));
221 numDigits = (unsigned *) malloc(numsToProcess * sizeof(unsigned));
222 for(digit=0; digit<numsToProcess; digit++) {
223 num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, digit+2));
224 if (num < 0) goto cleanExit;
225 numDigits[digit] = encodeNumber(num, &digits[digit]);
226 numDigitBytes += numDigits[digit];
227 }
228 }
229 *outLen = (2 + numDigitBytes);
230 *outOid = outP = (unsigned char *) malloc(*outLen);
231 *outP++ = 0x06;
232 *outP++ = numDigitBytes;
233 *outP++ = firstByte;
234 for(digit=0; digit<numsToProcess; digit++) {
235 unsigned int byteDex;
236 for(byteDex=0; byteDex<numDigits[digit]; byteDex++) {
237 *outP++ = digits[digit][byteDex];
238 }
239 }
240 if(digits) {
241 for(digit=0; digit<numsToProcess; digit++) {
242 free(digits[digit]);
243 }
244 free(digits);
245 free(numDigits);
246 }
247 result = 0;
248
249 cleanExit:
250 if (oidStr) CFRelease(oidStr);
251 if (argvRef) CFRelease(argvRef);
252
253 return result;
254 }
255
256 /*
257 * Given a CF object reference describing an OID, convert to binary DER format
258 * and fill out the CSSM_OID structure provided by the caller. Caller is
259 * responsible for freeing the data pointer in outOid->Data.
260 *
261 * Function returns 0 if successful, non-zero otherwise.
262 */
263
264 static int convertOid(
265 CFTypeRef inRef,
266 CSSM_OID *outOid)
267 {
268 if (!inRef || !outOid)
269 return errSecParam;
270
271 unsigned char *oidData = NULL;
272 unsigned int oidLen = 0;
273
274 if (CFGetTypeID(inRef) == CFStringGetTypeID()) {
275 // CFStringRef: OID representation is a dotted-decimal string
276 CFStringRef inStr = (CFStringRef)inRef;
277 CFIndex max = CFStringGetLength(inStr) * 3;
278 char buf[max];
279 if (!CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII))
280 return errSecParam;
281
282 if(encodeOid((unsigned char *)buf, &oidData, &oidLen) != 0)
283 return errSecParam;
284 }
285 else if (CFGetTypeID(inRef) == CFDataGetTypeID()) {
286 // CFDataRef: OID representation is in binary DER format
287 CFDataRef inData = (CFDataRef)inRef;
288 oidLen = (unsigned int) CFDataGetLength(inData);
289 oidData = (unsigned char *) malloc(oidLen);
290 memcpy(oidData, CFDataGetBytePtr(inData), oidLen);
291 }
292 else {
293 // Not in a format we understand
294 return errSecParam;
295 }
296 outOid->Length = oidLen;
297 outOid->Data = (uint8 *)oidData;
298 return 0;
299 }
300
301 static CFTypeID cmsEncoderTypeID = _kCFRuntimeNotATypeID;
302
303 /* one time only class init, called via pthread_once() in CMSEncoderGetTypeID() */
304 static void cmsEncoderClassInitialize(void)
305 {
306 cmsEncoderTypeID =
307 _CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsEncoderRuntimeClass);
308 }
309
310 /* init called out from _CFRuntimeCreateInstance() */
311 static void cmsEncoderInit(CFTypeRef enc)
312 {
313 char *start = ((char *)enc) + sizeof(CFRuntimeBase);
314 memset(start, 0, sizeof(struct _CMSEncoder) - sizeof(CFRuntimeBase));
315 }
316
317 /*
318 * Dispose of a CMSEncoder. Called out from CFRelease().
319 */
320 static void cmsEncoderFinalize(
321 CFTypeRef enc)
322 {
323 CMSEncoderRef cmsEncoder = (CMSEncoderRef)enc;
324 if(cmsEncoder == NULL) {
325 return;
326 }
327 if(cmsEncoder->eContentType.Data != NULL) {
328 free(cmsEncoder->eContentType.Data);
329 }
330 CFRELEASE(cmsEncoder->signers);
331 CFRELEASE(cmsEncoder->recipients);
332 CFRELEASE(cmsEncoder->otherCerts);
333 if(cmsEncoder->cmsMsg != NULL) {
334 SecCmsMessageDestroy(cmsEncoder->cmsMsg);
335 }
336 if(cmsEncoder->arena != NULL) {
337 SecArenaPoolFree(cmsEncoder->arena, false);
338 }
339 if(cmsEncoder->encoder != NULL) {
340 /*
341 * Normally this gets freed in SecCmsEncoderFinish - this is
342 * an error case.
343 */
344 SecCmsEncoderDestroy(cmsEncoder->encoder);
345 }
346 }
347
348 static OSStatus cmsSetupEncoder(
349 CMSEncoderRef cmsEncoder)
350 {
351 OSStatus ortn;
352
353 ASSERT(cmsEncoder->arena == NULL);
354 ASSERT(cmsEncoder->encoder == NULL);
355
356 ortn = SecArenaPoolCreate(1024, &cmsEncoder->arena);
357 if(ortn) {
358 return cmsRtnToOSStatus(ortn);
359 }
360 ortn = SecCmsEncoderCreate(cmsEncoder->cmsMsg,
361 NULL, NULL, // no callback
362 &cmsEncoder->encoderOut, // data goes here
363 cmsEncoder->arena,
364 NULL, NULL, // no password callback (right?)
365 NULL, NULL, // decrypt key callback
366 NULL, NULL, // detached digests
367 &cmsEncoder->encoder);
368 if(ortn) {
369 return cmsRtnToOSStatus(ortn);
370 }
371 return errSecSuccess;
372 }
373
374 /*
375 * Set up a SecCmsMessageRef for a SignedData creation.
376 */
377 static OSStatus cmsSetupForSignedData(
378 CMSEncoderRef cmsEncoder)
379 {
380 ASSERT((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL));
381
382 SecCmsContentInfoRef contentInfo = NULL;
383 SecCmsSignedDataRef signedData = NULL;
384 OSStatus ortn;
385
386 /* build chain of objects: message->signedData->data */
387 if(cmsEncoder->cmsMsg != NULL) {
388 SecCmsMessageDestroy(cmsEncoder->cmsMsg);
389 }
390 cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL);
391 if(cmsEncoder->cmsMsg == NULL) {
392 return errSecInternalComponent;
393 }
394
395 signedData = SecCmsSignedDataCreate(cmsEncoder->cmsMsg);
396 if(signedData == NULL) {
397 return errSecInternalComponent;
398 }
399 contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg);
400 ortn = SecCmsContentInfoSetContentSignedData(cmsEncoder->cmsMsg, contentInfo,
401 signedData);
402 if(ortn) {
403 return cmsRtnToOSStatus(ortn);
404 }
405 contentInfo = SecCmsSignedDataGetContentInfo(signedData);
406 if(cmsEncoder->eContentType.Data != NULL) {
407 /* Override the default eContentType of id-data */
408 ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg,
409 contentInfo,
410 NULL, /* data - provided to encoder, not here */
411 cmsEncoder->detachedContent,
412 &cmsEncoder->eContentType);
413 }
414 else {
415 ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg,
416 contentInfo,
417 NULL, /* data - provided to encoder, not here */
418 cmsEncoder->detachedContent);
419 }
420 if(ortn) {
421 ortn = cmsRtnToOSStatus(ortn);
422 CSSM_PERROR("SecCmsContentInfoSetContent*", ortn);
423 return ortn;
424 }
425
426 /* optional 'global' (per-SignedData) certs */
427 if(cmsEncoder->otherCerts != NULL) {
428 ortn = SecCmsSignedDataAddCertList(signedData, cmsEncoder->otherCerts);
429 if(ortn) {
430 ortn = cmsRtnToOSStatus(ortn);
431 CSSM_PERROR("SecCmsSignedDataAddCertList", ortn);
432 return ortn;
433 }
434 }
435
436 /* SignerInfos, one per signer */
437 CFIndex numSigners = 0;
438 if(cmsEncoder->signers != NULL) {
439 /* this is optional...in case we're just creating a cert bundle */
440 numSigners = CFArrayGetCount(cmsEncoder->signers);
441 }
442 CFIndex dex;
443 SecKeychainRef ourKc = NULL;
444 SecCertificateRef ourCert = NULL;
445 SecCmsCertChainMode chainMode = SecCmsCMCertChain;
446
447 switch(cmsEncoder->chainMode) {
448 case kCMSCertificateNone:
449 chainMode = SecCmsCMNone;
450 break;
451 case kCMSCertificateSignerOnly:
452 chainMode = SecCmsCMCertOnly;
453 break;
454 case kCMSCertificateChainWithRoot:
455 chainMode = SecCmsCMCertChainWithRoot;
456 break;
457 default:
458 break;
459 }
460 for(dex=0; dex<numSigners; dex++) {
461 SecCmsSignerInfoRef signerInfo;
462
463 SecIdentityRef ourId =
464 (SecIdentityRef)CFArrayGetValueAtIndex(cmsEncoder->signers, dex);
465 ortn = SecIdentityCopyCertificate(ourId, &ourCert);
466 if(ortn) {
467 CSSM_PERROR("SecIdentityCopyCertificate", ortn);
468 break;
469 }
470 ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)ourCert, &ourKc);
471 if(ortn) {
472 CSSM_PERROR("SecKeychainItemCopyKeychain", ortn);
473 break;
474 }
475 signerInfo = SecCmsSignerInfoCreate(cmsEncoder->cmsMsg, ourId, SEC_OID_SHA1);
476 if (signerInfo == NULL) {
477 ortn = errSecInternalComponent;
478 break;
479 }
480
481 /* we want the cert chain included for this one */
482 /* NOTE the usage parameter is currently unused by the SMIME lib */
483 ortn = SecCmsSignerInfoIncludeCerts(signerInfo, chainMode,
484 certUsageEmailSigner);
485 if(ortn) {
486 ortn = cmsRtnToOSStatus(ortn);
487 CSSM_PERROR("SecCmsSignerInfoIncludeCerts", ortn);
488 break;
489 }
490
491 /* other options */
492 if(cmsEncoder->signedAttributes & kCMSAttrSmimeCapabilities) {
493 ortn = SecCmsSignerInfoAddSMIMECaps(signerInfo);
494 if(ortn) {
495 ortn = cmsRtnToOSStatus(ortn);
496 CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn);
497 break;
498 }
499 }
500 if(cmsEncoder->signedAttributes & kCMSAttrSmimeEncryptionKeyPrefs) {
501 ortn = SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo, ourCert, ourKc);
502 if(ortn) {
503 ortn = cmsRtnToOSStatus(ortn);
504 CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn);
505 break;
506 }
507 }
508 if(cmsEncoder->signedAttributes & kCMSAttrSmimeMSEncryptionKeyPrefs) {
509 ortn = SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerInfo, ourCert, ourKc);
510 if(ortn) {
511 ortn = cmsRtnToOSStatus(ortn);
512 CSSM_PERROR("SecCmsSignerInfoAddMSSMIMEEncKeyPrefs", ortn);
513 break;
514 }
515 }
516 if(cmsEncoder->signedAttributes & kCMSAttrSigningTime) {
517 if (cmsEncoder->signingTime == 0)
518 cmsEncoder->signingTime = CFAbsoluteTimeGetCurrent();
519 ortn = SecCmsSignerInfoAddSigningTime(signerInfo, cmsEncoder->signingTime);
520 if(ortn) {
521 ortn = cmsRtnToOSStatus(ortn);
522 CSSM_PERROR("SecCmsSignerInfoAddSigningTime", ortn);
523 break;
524 }
525 }
526
527 ortn = SecCmsSignedDataAddSignerInfo(signedData, signerInfo);
528 if(ortn) {
529 ortn = cmsRtnToOSStatus(ortn);
530 CSSM_PERROR("SecCmsSignedDataAddSignerInfo", ortn);
531 break;
532 }
533
534 CFRELEASE(ourKc);
535 CFRELEASE(ourCert);
536 ourKc = NULL;
537 ourCert = NULL;
538 }
539 if(ortn) {
540 CFRELEASE(ourKc);
541 CFRELEASE(ourCert);
542 }
543 return ortn;
544 }
545
546 /*
547 * Set up a SecCmsMessageRef for a EnvelopedData creation.
548 */
549 static OSStatus cmsSetupForEnvelopedData(
550 CMSEncoderRef cmsEncoder)
551 {
552 ASSERT(cmsEncoder->op == EO_Encrypt);
553 ASSERT(cmsEncoder->recipients != NULL);
554
555 SecCmsContentInfoRef contentInfo = NULL;
556 SecCmsEnvelopedDataRef envelopedData = NULL;
557 SECOidTag algorithmTag;
558 int keySize;
559 OSStatus ortn;
560
561 /*
562 * Find encryption algorithm...unfortunately we need a NULL-terminated array
563 * of SecCertificateRefs for this.
564 */
565 CFIndex numCerts = CFArrayGetCount(cmsEncoder->recipients);
566 CFIndex dex;
567 SecCertificateRef *certArray = (SecCertificateRef *)malloc(
568 (numCerts+1) * sizeof(SecCertificateRef));
569
570 for(dex=0; dex<numCerts; dex++) {
571 certArray[dex] = (SecCertificateRef)CFArrayGetValueAtIndex(
572 cmsEncoder->recipients, dex);
573 }
574 certArray[numCerts] = NULL;
575 ortn = SecSMIMEFindBulkAlgForRecipients(certArray, &algorithmTag, &keySize);
576 free(certArray);
577 if(ortn) {
578 CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn);
579 return ortn;
580 }
581
582 /* build chain of objects: message->envelopedData->data */
583 if(cmsEncoder->cmsMsg != NULL) {
584 SecCmsMessageDestroy(cmsEncoder->cmsMsg);
585 }
586 cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL);
587 if(cmsEncoder->cmsMsg == NULL) {
588 return errSecInternalComponent;
589 }
590 envelopedData = SecCmsEnvelopedDataCreate(cmsEncoder->cmsMsg,
591 algorithmTag, keySize);
592 if(envelopedData == NULL) {
593 return errSecInternalComponent;
594 }
595 contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg);
596 ortn = SecCmsContentInfoSetContentEnvelopedData(cmsEncoder->cmsMsg,
597 contentInfo, envelopedData);
598 if(ortn) {
599 ortn = cmsRtnToOSStatus(ortn);
600 CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn);
601 return ortn;
602 }
603 contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData);
604 if(cmsEncoder->eContentType.Data != NULL) {
605 /* Override the default ContentType of id-data */
606 ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg,
607 contentInfo,
608 NULL, /* data - provided to encoder, not here */
609 FALSE, /* detachedContent */
610 &cmsEncoder->eContentType);
611 }
612 else {
613 ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg,
614 contentInfo,
615 NULL /* data - provided to encoder, not here */,
616 cmsEncoder->detachedContent);
617 }
618 if(ortn) {
619 ortn = cmsRtnToOSStatus(ortn);
620 CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn);
621 return ortn;
622 }
623
624 /*
625 * create & attach recipient information, one for each recipient
626 */
627 for(dex=0; dex<numCerts; dex++) {
628 SecCmsRecipientInfoRef recipientInfo = NULL;
629
630 SecCertificateRef thisRecip = (SecCertificateRef)CFArrayGetValueAtIndex(
631 cmsEncoder->recipients, dex);
632 recipientInfo = SecCmsRecipientInfoCreate(cmsEncoder->cmsMsg, thisRecip);
633 ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo);
634 if(ortn) {
635 ortn = cmsRtnToOSStatus(ortn);
636 CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn);
637 return ortn;
638 }
639 }
640 return errSecSuccess;
641 }
642
643 /*
644 * Set up cmsMsg. Called from either the first call to CMSEncoderUpdateContent, or
645 * from CMSEncodeGetCmsMessage().
646 */
647 static OSStatus cmsSetupCmsMsg(
648 CMSEncoderRef cmsEncoder)
649 {
650 ASSERT(cmsEncoder != NULL);
651 ASSERT(cmsEncoder->encState == ES_Init);
652
653 /* figure out what high-level operation we're doing */
654 if((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL)) {
655 if(cmsEncoder->recipients != NULL) {
656 cmsEncoder->op = EO_SignEncrypt;
657 }
658 else {
659 cmsEncoder->op = EO_Sign;
660 }
661 }
662 else if(cmsEncoder->recipients != NULL) {
663 cmsEncoder->op = EO_Encrypt;
664 }
665 else {
666 dprintf("CMSEncoderUpdateContent: nothing to do\n");
667 return errSecParam;
668 }
669
670 OSStatus ortn = errSecSuccess;
671
672 switch(cmsEncoder->op) {
673 case EO_Sign:
674 case EO_SignEncrypt:
675 /* If we're signing & encrypting, do the signing first */
676 ortn = cmsSetupForSignedData(cmsEncoder);
677 break;
678 case EO_Encrypt:
679 ortn = cmsSetupForEnvelopedData(cmsEncoder);
680 break;
681 }
682 cmsEncoder->encState = ES_Msg;
683 return ortn;
684 }
685
686 /*
687 * ASN.1 template for decoding a ContentInfo.
688 */
689 typedef struct {
690 CSSM_OID contentType;
691 CSSM_DATA content;
692 } SimpleContentInfo;
693
694 static const SecAsn1Template cmsSimpleContentInfoTemplate[] = {
695 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SimpleContentInfo) },
696 { SEC_ASN1_OBJECT_ID, offsetof(SimpleContentInfo, contentType) },
697 { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
698 offsetof(SimpleContentInfo, content),
699 kSecAsn1AnyTemplate },
700 { 0, }
701 };
702
703 /*
704 * Obtain the content of a contentInfo, This basically strips off the contentType OID
705 * and returns its ASN_ANY content, allocated the provided coder's memory space.
706 */
707 static OSStatus cmsContentInfoContent(
708 SecAsn1CoderRef asn1Coder,
709 const CSSM_DATA *contentInfo,
710 CSSM_DATA *content) /* RETURNED */
711 {
712 OSStatus ortn;
713 SimpleContentInfo decodedInfo;
714
715 memset(&decodedInfo, 0, sizeof(decodedInfo));
716 ortn = SecAsn1DecodeData(asn1Coder, contentInfo,
717 cmsSimpleContentInfoTemplate, &decodedInfo);
718 if(ortn) {
719 return ortn;
720 }
721 if(decodedInfo.content.Data == NULL) {
722 dprintf("***Error decoding contentInfo: no content\n");
723 return errSecInternalComponent;
724 }
725 *content = decodedInfo.content;
726 return errSecSuccess;
727 }
728
729 #pragma mark --- Start of Public API ---
730
731 CFTypeID CMSEncoderGetTypeID(void)
732 {
733 static pthread_once_t once = PTHREAD_ONCE_INIT;
734
735 if(cmsEncoderTypeID == _kCFRuntimeNotATypeID) {
736 pthread_once(&once, &cmsEncoderClassInitialize);
737 }
738 return cmsEncoderTypeID;
739 }
740
741 /*
742 * Create a CMSEncoder. Result must eventually be freed via CFRelease().
743 */
744 OSStatus CMSEncoderCreate(
745 CMSEncoderRef *cmsEncoderOut) /* RETURNED */
746 {
747 CMSEncoderRef cmsEncoder = NULL;
748
749 uint32_t extra = sizeof(*cmsEncoder) - sizeof(cmsEncoder->base);
750 cmsEncoder = (CMSEncoderRef)_CFRuntimeCreateInstance(NULL, CMSEncoderGetTypeID(),
751 extra, NULL);
752 if(cmsEncoder == NULL) {
753 return errSecAllocate;
754 }
755 cmsEncoder->encState = ES_Init;
756 cmsEncoder->chainMode = kCMSCertificateChain;
757 *cmsEncoderOut = cmsEncoder;
758 return errSecSuccess;
759 }
760
761 #pragma mark --- Getters & Setters ---
762
763 /*
764 * Specify signers of the CMS message; implies that the message will be signed.
765 */
766 OSStatus CMSEncoderAddSigners(
767 CMSEncoderRef cmsEncoder,
768 CFTypeRef signerOrArray)
769 {
770 if(cmsEncoder == NULL) {
771 return errSecParam;
772 }
773 if(cmsEncoder->encState != ES_Init) {
774 return errSecParam;
775 }
776 return cmsAppendToArray(signerOrArray, &cmsEncoder->signers, SecIdentityGetTypeID());
777 }
778
779 /*
780 * Obtain an array of signers as specified in CMSEncoderSetSigners().
781 */
782 OSStatus CMSEncoderCopySigners(
783 CMSEncoderRef cmsEncoder,
784 CFArrayRef *signers)
785 {
786 if((cmsEncoder == NULL) || (signers == NULL)) {
787 return errSecParam;
788 }
789 if(cmsEncoder->signers != NULL) {
790 CFRetain(cmsEncoder->signers);
791 }
792 *signers = cmsEncoder->signers;
793 return errSecSuccess;
794 }
795
796 /*
797 * Specify recipients of the message. Implies that the message will be encrypted.
798 */
799 OSStatus CMSEncoderAddRecipients(
800 CMSEncoderRef cmsEncoder,
801 CFTypeRef recipientOrArray)
802 {
803 if(cmsEncoder == NULL) {
804 return errSecParam;
805 }
806 if(cmsEncoder->encState != ES_Init) {
807 return errSecParam;
808 }
809 return cmsAppendToArray(recipientOrArray, &cmsEncoder->recipients,
810 SecCertificateGetTypeID());
811 }
812
813 /*
814 * Obtain an array of recipients as specified in CMSEncoderSetRecipients().
815 */
816 OSStatus CMSEncoderCopyRecipients(
817 CMSEncoderRef cmsEncoder,
818 CFArrayRef *recipients)
819 {
820 if((cmsEncoder == NULL) || (recipients == NULL)) {
821 return errSecParam;
822 }
823 if(cmsEncoder->recipients != NULL) {
824 CFRetain(cmsEncoder->recipients);
825 }
826 *recipients = cmsEncoder->recipients;
827 return errSecSuccess;
828 }
829
830 /*
831 * Specify additional certs to include in a signed message.
832 */
833 OSStatus CMSEncoderAddSupportingCerts(
834 CMSEncoderRef cmsEncoder,
835 CFTypeRef certOrArray)
836 {
837 if(cmsEncoder == NULL) {
838 return errSecParam;
839 }
840 if(cmsEncoder->encState != ES_Init) {
841 return errSecParam;
842 }
843 return cmsAppendToArray(certOrArray, &cmsEncoder->otherCerts,
844 SecCertificateGetTypeID());
845 }
846
847 /*
848 * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts().
849 */
850 OSStatus CMSEncoderCopySupportingCerts(
851 CMSEncoderRef cmsEncoder,
852 CFArrayRef *certs) /* RETURNED */
853 {
854 if((cmsEncoder == NULL) || (certs == NULL)) {
855 return errSecParam;
856 }
857 if(cmsEncoder->otherCerts != NULL) {
858 CFRetain(cmsEncoder->otherCerts);
859 }
860 *certs = cmsEncoder->otherCerts;
861 return errSecSuccess;
862 }
863
864 OSStatus CMSEncoderSetHasDetachedContent(
865 CMSEncoderRef cmsEncoder,
866 Boolean detachedContent)
867 {
868 if(cmsEncoder == NULL) {
869 return errSecParam;
870 }
871 if(cmsEncoder->encState != ES_Init) {
872 return errSecParam;
873 }
874 cmsEncoder->detachedContent = detachedContent;
875 return errSecSuccess;
876 }
877
878 OSStatus CMSEncoderGetHasDetachedContent(
879 CMSEncoderRef cmsEncoder,
880 Boolean *detachedContent) /* RETURNED */
881 {
882 if((cmsEncoder == NULL) || (detachedContent == NULL)) {
883 return errSecParam;
884 }
885 *detachedContent = cmsEncoder->detachedContent;
886 return errSecSuccess;
887 }
888
889 /*
890 * Optionally specify an eContentType OID for the inner EncapsulatedData for
891 * a signed message. The default eContentType, used of this function is not
892 * called, is id-data.
893 */
894 OSStatus CMSEncoderSetEncapsulatedContentType(
895 CMSEncoderRef cmsEncoder,
896 const CSSM_OID *eContentType)
897 {
898 if((cmsEncoder == NULL) || (eContentType == NULL)) {
899 return errSecParam;
900 }
901 if(cmsEncoder->encState != ES_Init) {
902 return errSecParam;
903 }
904
905 CSSM_OID *ecOid = &cmsEncoder->eContentType;
906 if(ecOid->Data != NULL) {
907 free(ecOid->Data);
908 }
909 cmsCopyCmsData(eContentType, ecOid);
910 return errSecSuccess;
911 }
912
913 OSStatus CMSEncoderSetEncapsulatedContentTypeOID(
914 CMSEncoderRef cmsEncoder,
915 CFTypeRef eContentTypeOID)
916 {
917 // convert eContentTypeOID to a CSSM_OID
918 CSSM_OID contentType = { 0, NULL };
919 if (!eContentTypeOID || convertOid(eContentTypeOID, &contentType) != 0)
920 return errSecParam;
921 OSStatus result = CMSEncoderSetEncapsulatedContentType(cmsEncoder, &contentType);
922 if (contentType.Data)
923 free(contentType.Data);
924 return result;
925 }
926
927 /*
928 * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType().
929 */
930 OSStatus CMSEncoderCopyEncapsulatedContentType(
931 CMSEncoderRef cmsEncoder,
932 CFDataRef *eContentType)
933 {
934 if((cmsEncoder == NULL) || (eContentType == NULL)) {
935 return errSecParam;
936 }
937
938 CSSM_OID *ecOid = &cmsEncoder->eContentType;
939 if(ecOid->Data == NULL) {
940 *eContentType = NULL;
941 }
942 else {
943 *eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length);
944 }
945 return errSecSuccess;
946 }
947
948 /*
949 * Optionally specify signed attributes. Only meaningful when creating a
950 * signed message. If this is called, it must be called before
951 * CMSEncoderUpdateContent().
952 */
953 OSStatus CMSEncoderAddSignedAttributes(
954 CMSEncoderRef cmsEncoder,
955 CMSSignedAttributes signedAttributes)
956 {
957 if(cmsEncoder == NULL) {
958 return errSecParam;
959 }
960 if(cmsEncoder->encState != ES_Init) {
961 return errSecParam;
962 }
963 cmsEncoder->signedAttributes = signedAttributes;
964 return errSecSuccess;
965 }
966
967 /*
968 * Set the signing time for a CMSEncoder.
969 * This is only used if the kCMSAttrSigningTime attribute is included.
970 */
971 OSStatus CMSEncoderSetSigningTime(
972 CMSEncoderRef cmsEncoder,
973 CFAbsoluteTime time)
974 {
975 if(cmsEncoder == NULL) {
976 return errSecParam;
977 }
978 if(cmsEncoder->encState != ES_Init) {
979 return errSecParam;
980 }
981 cmsEncoder->signingTime = time;
982 return errSecSuccess;
983 }
984
985
986 OSStatus CMSEncoderSetCertificateChainMode(
987 CMSEncoderRef cmsEncoder,
988 CMSCertificateChainMode chainMode)
989 {
990 if(cmsEncoder == NULL) {
991 return errSecParam;
992 }
993 if(cmsEncoder->encState != ES_Init) {
994 return errSecParam;
995 }
996 switch(chainMode) {
997 case kCMSCertificateNone:
998 case kCMSCertificateSignerOnly:
999 case kCMSCertificateChain:
1000 case kCMSCertificateChainWithRoot:
1001 break;
1002 default:
1003 return errSecParam;
1004 }
1005 cmsEncoder->chainMode = chainMode;
1006 return errSecSuccess;
1007 }
1008
1009 OSStatus CMSEncoderGetCertificateChainMode(
1010 CMSEncoderRef cmsEncoder,
1011 CMSCertificateChainMode *chainModeOut)
1012 {
1013 if(cmsEncoder == NULL) {
1014 return errSecParam;
1015 }
1016 *chainModeOut = cmsEncoder->chainMode;
1017 return errSecSuccess;
1018 }
1019
1020 void
1021 CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback)
1022 {
1023 if (cmsEncoder->cmsMsg)
1024 SecCmsMessageSetTSACallback(cmsEncoder->cmsMsg, tsaCallback);
1025 }
1026
1027 void
1028 CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder, CFTypeRef tsaContext)
1029 {
1030 if (cmsEncoder->cmsMsg)
1031 SecCmsMessageSetTSAContext(cmsEncoder->cmsMsg, tsaContext);
1032 }
1033
1034 #pragma mark --- Action ---
1035
1036 /*
1037 * Feed content bytes into the encoder.
1038 * Can be called multiple times.
1039 * No 'setter' routines can be called after this function has been called.
1040 */
1041 OSStatus CMSEncoderUpdateContent(
1042 CMSEncoderRef cmsEncoder,
1043 const void *content,
1044 size_t contentLen)
1045 {
1046 if(cmsEncoder == NULL) {
1047 return errSecParam;
1048 }
1049
1050 OSStatus ortn = errSecSuccess;
1051 switch(cmsEncoder->encState) {
1052 case ES_Init:
1053 /*
1054 * First time thru: do the CmsMsg setup.
1055 */
1056 ortn = cmsSetupCmsMsg(cmsEncoder);
1057 if(ortn) {
1058 return ortn;
1059 }
1060 /* fall thru to set up the encoder */
1061
1062 case ES_Msg:
1063 /* We have a cmsMsg but no encoder; create one */
1064 ASSERT(cmsEncoder->cmsMsg != NULL);
1065 ASSERT(cmsEncoder->encoder == NULL);
1066 ortn = cmsSetupEncoder(cmsEncoder);
1067 if(ortn) {
1068 return ortn;
1069 }
1070 /* only legal calls now are update and finalize */
1071 cmsEncoder->encState = ES_Updating;
1072 break;
1073
1074 case ES_Updating:
1075 ASSERT(cmsEncoder->encoder != NULL);
1076 break;
1077
1078 case ES_Final:
1079 /* Too late for another update */
1080 return errSecParam;
1081
1082 default:
1083 return errSecInternalComponent;
1084 }
1085
1086 /* FIXME - CFIndex same size as size_t on 64bit? */
1087 ortn = SecCmsEncoderUpdate(cmsEncoder->encoder, content, (CFIndex)contentLen);
1088 if(ortn) {
1089 ortn = cmsRtnToOSStatus(ortn);
1090 CSSM_PERROR("SecCmsEncoderUpdate", ortn);
1091 }
1092 return ortn;
1093 }
1094
1095 /*
1096 * Finish encoding the message and obtain the encoded result.
1097 * Caller must CFRelease the result.
1098 */
1099 OSStatus CMSEncoderCopyEncodedContent(
1100 CMSEncoderRef cmsEncoder,
1101 CFDataRef *encodedContent)
1102 {
1103 if((cmsEncoder == NULL) || (encodedContent == NULL)) {
1104 return errSecParam;
1105 }
1106
1107 OSStatus ortn;
1108
1109 switch(cmsEncoder->encState) {
1110 case ES_Updating:
1111 /* normal termination */
1112 break;
1113 case ES_Final:
1114 /* already been called */
1115 return errSecParam;
1116 case ES_Msg:
1117 case ES_Init:
1118 /*
1119 * The only time these are legal is when we're doing a SignedData
1120 * with certificates only (no signers, no content).
1121 */
1122 if((cmsEncoder->signers != NULL) ||
1123 (cmsEncoder->recipients != NULL) ||
1124 (cmsEncoder->otherCerts == NULL)) {
1125 return errSecParam;
1126 }
1127
1128 /* Set up for certs only */
1129 ortn = cmsSetupForSignedData(cmsEncoder);
1130 if(ortn) {
1131 return ortn;
1132 }
1133 /* and an encoder */
1134 ortn = cmsSetupEncoder(cmsEncoder);
1135 if(ortn) {
1136 return ortn;
1137 }
1138 break;
1139 }
1140
1141
1142 ASSERT(cmsEncoder->encoder != NULL);
1143 ortn = SecCmsEncoderFinish(cmsEncoder->encoder);
1144 /* regardless of the outcome, the encoder itself has been freed */
1145 cmsEncoder->encoder = NULL;
1146 if(ortn) {
1147 return cmsRtnToOSStatus(ortn);
1148 }
1149 cmsEncoder->encState = ES_Final;
1150
1151 if((cmsEncoder->encoderOut.Data == NULL) && !cmsEncoder->customCoder) {
1152 /* not sure how this could happen... */
1153 dprintf("Successful encode, but no data\n");
1154 return errSecInternalComponent;
1155 }
1156 if(cmsEncoder->customCoder) {
1157 /* we're done */
1158 *encodedContent = NULL;
1159 return errSecSuccess;
1160 }
1161
1162 /* in two out of three cases, we're done */
1163 switch(cmsEncoder->op) {
1164 case EO_Sign:
1165 case EO_Encrypt:
1166 *encodedContent = CFDataCreate(NULL, (const UInt8 *)cmsEncoder->encoderOut.Data,
1167 cmsEncoder->encoderOut.Length);
1168 return errSecSuccess;
1169 case EO_SignEncrypt:
1170 /* proceed, more work to do */
1171 break;
1172 }
1173
1174 /*
1175 * Signing & encrypting.
1176 * Due to bugs in the libsecurity_smime encoder, it can't encode nested
1177 * ContentInfos in one shot. So we do another pass, specifying the SignedData
1178 * inside of the ContentInfo we just created as the data to encrypt.
1179 */
1180 SecAsn1CoderRef asn1Coder = NULL;
1181 CSSM_DATA signedData = {0, NULL};
1182
1183 ortn = SecAsn1CoderCreate(&asn1Coder);
1184 if(ortn) {
1185 return ortn;
1186 }
1187 ortn = cmsContentInfoContent(asn1Coder, &cmsEncoder->encoderOut, &signedData);
1188 if(ortn) {
1189 goto errOut;
1190 }
1191
1192 /* now just encrypt that, one-shot */
1193 ortn = CMSEncode(NULL, /* no signers this time */
1194 cmsEncoder->recipients,
1195 &CSSMOID_PKCS7_SignedData, /* fake out encoder so it doesn't try to actually
1196 * encode the signedData - this asserts the
1197 * SEC_OID_OTHER OID tag in the EnvelopedData's
1198 * ContentInfo */
1199 FALSE, /* detachedContent */
1200 kCMSAttrNone, /* signedAttributes - none this time */
1201 signedData.Data, signedData.Length,
1202 encodedContent);
1203
1204 errOut:
1205 if(asn1Coder) {
1206 SecAsn1CoderRelease(asn1Coder);
1207 }
1208 return ortn;
1209 }
1210
1211 #pragma mark --- High-level API ---
1212
1213 /*
1214 * High-level, one-shot encoder function.
1215 */
1216 OSStatus CMSEncode(
1217 CFTypeRef signers,
1218 CFTypeRef recipients,
1219 const CSSM_OID *eContentType,
1220 Boolean detachedContent,
1221 CMSSignedAttributes signedAttributes,
1222 const void *content,
1223 size_t contentLen,
1224 CFDataRef *encodedContent) /* RETURNED */
1225 {
1226 if((signers == NULL) && (recipients == NULL)) {
1227 return errSecParam;
1228 }
1229 if(encodedContent == NULL) {
1230 return errSecParam;
1231 }
1232
1233 CMSEncoderRef cmsEncoder;
1234 OSStatus ortn;
1235
1236 /* set up the encoder */
1237 ortn = CMSEncoderCreate(&cmsEncoder);
1238 if(ortn) {
1239 return ortn;
1240 }
1241
1242 /* subsequent errors to errOut: */
1243 if(signers) {
1244 ortn = CMSEncoderAddSigners(cmsEncoder, signers);
1245 if(ortn) {
1246 goto errOut;
1247 }
1248 }
1249 if(recipients) {
1250 ortn = CMSEncoderAddRecipients(cmsEncoder, recipients);
1251 if(ortn) {
1252 goto errOut;
1253 }
1254 }
1255 if(eContentType) {
1256 ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType);
1257 if(ortn) {
1258 goto errOut;
1259 }
1260 }
1261 if(detachedContent) {
1262 ortn = CMSEncoderSetHasDetachedContent(cmsEncoder, detachedContent);
1263 if(ortn) {
1264 goto errOut;
1265 }
1266 }
1267 if(signedAttributes) {
1268 ortn = CMSEncoderAddSignedAttributes(cmsEncoder, signedAttributes);
1269 if(ortn) {
1270 goto errOut;
1271 }
1272 }
1273 /* GO */
1274 ortn = CMSEncoderUpdateContent(cmsEncoder, content, contentLen);
1275 if(ortn) {
1276 goto errOut;
1277 }
1278 ortn = CMSEncoderCopyEncodedContent(cmsEncoder, encodedContent);
1279
1280 errOut:
1281 CFRelease(cmsEncoder);
1282 return ortn;
1283 }
1284
1285 OSStatus CMSEncodeContent(
1286 CFTypeRef signers,
1287 CFTypeRef recipients,
1288 CFTypeRef eContentTypeOID,
1289 Boolean detachedContent,
1290 CMSSignedAttributes signedAttributes,
1291 const void *content,
1292 size_t contentLen,
1293 CFDataRef *encodedContentOut) /* RETURNED */
1294 {
1295 // convert eContentTypeOID to a CSSM_OID
1296 CSSM_OID contentType = { 0, NULL };
1297 if (eContentTypeOID && convertOid(eContentTypeOID, &contentType) != 0)
1298 return errSecParam;
1299 const CSSM_OID *contentTypePtr = (eContentTypeOID) ? &contentType : NULL;
1300 OSStatus result = CMSEncode(signers, recipients, contentTypePtr,
1301 detachedContent, signedAttributes,
1302 content, contentLen, encodedContentOut);
1303 if (contentType.Data)
1304 free(contentType.Data);
1305 return result;
1306 }
1307
1308 #pragma mark --- SPI routines declared in CMSPrivate.h ---
1309
1310 /*
1311 * Obtain the SecCmsMessageRef associated with a CMSEncoderRef.
1312 * If we don't have a SecCmsMessageRef yet, we create one now.
1313 * This is the only place where we go to state ES_Msg.
1314 */
1315 OSStatus CMSEncoderGetCmsMessage(
1316 CMSEncoderRef cmsEncoder,
1317 SecCmsMessageRef *cmsMessage) /* RETURNED */
1318 {
1319 if((cmsEncoder == NULL) || (cmsMessage == NULL)) {
1320 return errSecParam;
1321 }
1322 if(cmsEncoder->cmsMsg != NULL) {
1323 ASSERT(cmsEncoder->encState != ES_Init);
1324 *cmsMessage = cmsEncoder->cmsMsg;
1325 return errSecSuccess;
1326 }
1327
1328 OSStatus ortn = cmsSetupCmsMsg(cmsEncoder);
1329 if(ortn) {
1330 return ortn;
1331 }
1332 *cmsMessage = cmsEncoder->cmsMsg;
1333
1334 /* Don't set up encoder yet; caller might do that via CMSEncoderSetEncoder */
1335 cmsEncoder->encState = ES_Msg;
1336 return errSecSuccess;
1337 }
1338
1339 /*
1340 * Optionally specify a SecCmsEncoderRef to use with a CMSEncoderRef.
1341 * If this is called, it must be called before the first call to
1342 * CMSEncoderUpdateContent(). The CMSEncoderRef takes ownership of the
1343 * incoming SecCmsEncoderRef.
1344 */
1345 OSStatus CMSEncoderSetEncoder(
1346 CMSEncoderRef cmsEncoder,
1347 SecCmsEncoderRef encoder)
1348 {
1349 if((cmsEncoder == NULL) || (encoder == NULL)) {
1350 return errSecParam;
1351 }
1352
1353 OSStatus ortn;
1354
1355 switch(cmsEncoder->encState) {
1356 case ES_Init:
1357 /* No message, no encoder */
1358 ASSERT(cmsEncoder->cmsMsg == NULL);
1359 ASSERT(cmsEncoder->encoder == NULL);
1360 ortn = cmsSetupCmsMsg(cmsEncoder);
1361 if(ortn) {
1362 return ortn;
1363 }
1364 /* drop thru to set encoder */
1365 case ES_Msg:
1366 /* cmsMsg but no encoder */
1367 ASSERT(cmsEncoder->cmsMsg != NULL);
1368 ASSERT(cmsEncoder->encoder == NULL);
1369 cmsEncoder->encoder = encoder;
1370 cmsEncoder->encState = ES_Updating;
1371 cmsEncoder->customCoder = true; /* we won't see data */
1372 return errSecSuccess;
1373 default:
1374 /* no can do, too late */
1375 return errSecParam;
1376 }
1377 }
1378
1379 /*
1380 * Obtain the SecCmsEncoderRef associated with a CMSEncoderRef.
1381 * Returns a NULL SecCmsEncoderRef if neither CMSEncoderSetEncoder nor
1382 * CMSEncoderUpdateContent() has been called.
1383 * The CMSEncoderRef retains ownership of the SecCmsEncoderRef.
1384 */
1385 OSStatus CMSEncoderGetEncoder(
1386 CMSEncoderRef cmsEncoder,
1387 SecCmsEncoderRef *encoder) /* RETURNED */
1388 {
1389 if((cmsEncoder == NULL) || (encoder == NULL)) {
1390 return errSecParam;
1391 }
1392
1393 /* any state, whether we have an encoder or not is OK */
1394 *encoder = cmsEncoder->encoder;
1395 return errSecSuccess;
1396 }
1397
1398 #include <AssertMacros.h>
1399
1400 /*
1401 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
1402 * present. This timestamp is an authenticated timestamp provided by
1403 * a timestamping authority.
1404 *
1405 * Returns errSecParam if the CMS message was not signed or if signerIndex
1406 * is greater than the number of signers of the message minus one.
1407 *
1408 * This cannot be called until after CMSEncoderCopyEncodedContent() is called.
1409 */
1410 OSStatus CMSEncoderCopySignerTimestamp(
1411 CMSEncoderRef cmsEncoder,
1412 size_t signerIndex, /* usually 0 */
1413 CFAbsoluteTime *timestamp) /* RETURNED */
1414 {
1415 return CMSEncoderCopySignerTimestampWithPolicy(
1416 cmsEncoder,
1417 NULL,
1418 signerIndex,
1419 timestamp);
1420 }
1421
1422 OSStatus CMSEncoderCopySignerTimestampWithPolicy(
1423 CMSEncoderRef cmsEncoder,
1424 CFTypeRef timeStampPolicy,
1425 size_t signerIndex, /* usually 0 */
1426 CFAbsoluteTime *timestamp) /* RETURNED */
1427 {
1428 OSStatus status = errSecParam;
1429 SecCmsMessageRef cmsg;
1430 SecCmsSignedDataRef signedData = NULL;
1431 int numContentInfos = 0;
1432
1433 require(cmsEncoder && timestamp, xit);
1434 require_noerr(CMSEncoderGetCmsMessage(cmsEncoder, &cmsg), xit);
1435 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
1436 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
1437 {
1438 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
1439 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
1440 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
1441 if ((signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci))))
1442 if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex))
1443 {
1444 status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp);
1445 break;
1446 }
1447 }
1448
1449 xit:
1450 return status;
1451 }