]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/CMSDecoder.c
Security-59754.80.3.tar.gz
[apple/security.git] / libsecurity_smime / lib / CMSDecoder.c
1 /*
2 * Copyright (c) 2006-2016 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 * CMSDecoder.c - Interface for decoding CMS messages.
26 */
27
28 #include <Security/CMSDecoder.h>
29 #include <Security/CMSPrivate.h>
30 #include "CMSUtils.h"
31
32 #include <Security/SecCmsDecoder.h>
33 #include <Security/SecCmsEnvelopedData.h>
34 #include <Security/SecCmsMessage.h>
35 #include <Security/SecCmsSignedData.h>
36 #include <Security/SecCmsSignerInfo.h>
37 #include <Security/SecCmsContentInfo.h>
38 #include <Security/SecCmsDigestContext.h>
39 #include <Security/SecCertificate.h>
40 #include <Security/SecCertificatePriv.h>
41 #include <Security/SecSMIME.h>
42 #include <Security/oidsattr.h>
43 #include <Security/SecTrustPriv.h>
44 #include <utilities/SecAppleAnchorPriv.h>
45 #include <utilities/SecCFWrappers.h>
46 #include <CoreFoundation/CFRuntime.h>
47 #include <pthread.h>
48 #include <syslog.h>
49 #include <AssertMacros.h>
50
51 #pragma mark --- Private types and definitions ---
52
53 /*
54 * Decoder state.
55 */
56 typedef enum {
57 DS_Init, /* between CMSDecoderCreate and CMSDecoderUpdateMessage */
58 DS_Updating, /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */
59 DS_Final /* CMSDecoderFinalizeMessage has been called */
60 } CMSDecoderState;
61
62 /*
63 * Caller's CMSDecoderRef points to one of these.
64 */
65 struct _CMSDecoder {
66 CFRuntimeBase base;
67 CMSDecoderState decState;
68 SecCmsDecoderRef decoder;
69 CFDataRef detachedContent;
70
71 /*
72 * The following are valid (and quiescent) after CMSDecoderFinalizeMessage().
73 */
74 SecCmsMessageRef cmsMsg;
75 Boolean wasEncrypted; /* valid after CMSDecoderFinalizeMessage() */
76 SecCmsSignedDataRef signedData; /* if there is one... */
77 /* only non-NULL if we found a signedData */
78 size_t numSigners;
79 SecAsn1Oid *eContentType;
80 /* etc. */
81 };
82
83 static void cmsDecoderInit(CFTypeRef dec);
84 static void cmsDecoderFinalize(CFTypeRef dec);
85
86 static CFRuntimeClass cmsDecoderRuntimeClass =
87 {
88 0, /* version */
89 "CMSDecoder",
90 cmsDecoderInit,
91 NULL, /* copy */
92 cmsDecoderFinalize,
93 NULL, /* equal - just use pointer equality */
94 NULL, /* hash, ditto */
95 NULL, /* copyFormattingDesc */
96 NULL /* copyDebugDesc */
97 };
98
99 #pragma mark --- Private Routines ---
100
101 static CFTypeID cmsDecoderTypeID = _kCFRuntimeNotATypeID;
102
103 /* one time only class init, called via pthread_once() in CMSDecoderGetTypeID() */
104 static void cmsDecoderClassInitialize(void)
105 {
106 cmsDecoderTypeID =
107 _CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsDecoderRuntimeClass);
108 }
109
110 /* init called out from _CFRuntimeCreateInstance() */
111 static void cmsDecoderInit(CFTypeRef dec)
112 {
113 char *start = ((char *)dec) + sizeof(CFRuntimeBase);
114 memset(start, 0, sizeof(struct _CMSDecoder) - sizeof(CFRuntimeBase));
115 }
116
117 /*
118 * Dispose of a CMSDecoder. Called out from CFRelease().
119 */
120 static void cmsDecoderFinalize(
121 CFTypeRef dec)
122 {
123 CMSDecoderRef cmsDecoder = (CMSDecoderRef)dec;
124 if(cmsDecoder == NULL) {
125 return;
126 }
127 if(cmsDecoder->decoder != NULL) {
128 /*
129 * Normally this gets freed in SecCmsDecoderFinish - this is
130 * an error case. Unlike Finish, this calls SecCmsMessageDestroy.
131 */
132 SecCmsDecoderDestroy(cmsDecoder->decoder);
133 cmsDecoder->cmsMsg = NULL;
134 }
135 CFRELEASE(cmsDecoder->detachedContent);
136 if(cmsDecoder->cmsMsg != NULL) {
137 SecCmsMessageDestroy(cmsDecoder->cmsMsg);
138 cmsDecoder->cmsMsg = NULL;
139 }
140 }
141
142
143 /*
144 * Given detached content and a valid (decoded) SignedData, digest the detached
145 * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a
146 * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent()
147 * when we already have a SignedData).
148 */
149 static OSStatus cmsDigestDetachedContent(
150 CMSDecoderRef cmsDecoder)
151 {
152 ASSERT((cmsDecoder->signedData != NULL) && (cmsDecoder->detachedContent != NULL));
153
154 SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(cmsDecoder->signedData);
155 if(digestAlgorithms == NULL) {
156 return errSecUnknownFormat;
157 }
158 SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestAlgorithms);
159 if(digcx == NULL) {
160 return errSecAllocate;
161 }
162
163 SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(cmsDecoder->detachedContent),
164 CFDataGetLength(cmsDecoder->detachedContent));
165 OSStatus ortn = SecCmsSignedDataSetDigestContext(cmsDecoder->signedData, digcx);
166 SecCmsDigestContextDestroy(digcx);
167
168 if(ortn) {
169 ortn = cmsRtnToOSStatus(ortn);
170 CSSM_PERROR("SecCmsSignedDataSetDigestContext", ortn);
171 return ortn;
172 }
173
174 return ortn;
175 }
176
177 #pragma mark --- Start of Public API ---
178
179 CFTypeID CMSDecoderGetTypeID(void)
180 {
181 static pthread_once_t once = PTHREAD_ONCE_INIT;
182
183 if(cmsDecoderTypeID == _kCFRuntimeNotATypeID) {
184 pthread_once(&once, &cmsDecoderClassInitialize);
185 }
186 return cmsDecoderTypeID;
187 }
188
189 /*
190 * Create a CMSDecoder. Result must eventually be freed via CFRelease().
191 */
192 OSStatus CMSDecoderCreate(
193 CMSDecoderRef *cmsDecoderOut) /* RETURNED */
194 {
195 CMSDecoderRef cmsDecoder = NULL;
196
197 uint32_t extra = sizeof(*cmsDecoder) - sizeof(cmsDecoder->base);
198 cmsDecoder = (CMSDecoderRef)_CFRuntimeCreateInstance(NULL, CMSDecoderGetTypeID(),
199 extra, NULL);
200 if(cmsDecoder == NULL) {
201 return errSecAllocate;
202 }
203 cmsDecoder->decState = DS_Init;
204 *cmsDecoderOut = cmsDecoder;
205 return errSecSuccess;
206 }
207
208 /*
209 * Feed raw bytes of the message to be decoded into the decoder. Can be called
210 * multiple times.
211 */
212 OSStatus CMSDecoderUpdateMessage(
213 CMSDecoderRef cmsDecoder,
214 const void *msgBytes,
215 size_t msgBytesLen)
216 {
217 if(cmsDecoder == NULL) {
218 return errSecParam;
219 }
220
221 OSStatus ortn;
222 switch(cmsDecoder->decState) {
223 case DS_Init:
224 /* First time through; set up */
225 ASSERT(cmsDecoder->decoder == NULL);
226 ortn = SecCmsDecoderCreate(NULL, NULL, NULL, NULL, NULL, NULL, &cmsDecoder->decoder);
227 if(ortn) {
228 ortn = cmsRtnToOSStatus(ortn);
229 CSSM_PERROR("SecCmsDecoderCreate", ortn);
230 return ortn;
231 }
232 cmsDecoder->decState = DS_Updating;
233 break;
234
235 case DS_Updating:
236 ASSERT(cmsDecoder->decoder != NULL);
237 break;
238
239 case DS_Final:
240 /* Too late for another update */
241 return errSecParam;
242
243 default:
244 dprintf("CMSDecoderUpdateMessage: bad decState\n");
245 return errSecInternalComponent;
246 }
247
248 /* FIXME - CFIndex same size as size_t on 64bit? */
249 ortn = SecCmsDecoderUpdate(cmsDecoder->decoder, msgBytes, (CFIndex)msgBytesLen);
250 if(ortn) {
251 ortn = cmsRtnToOSStatusDefault(ortn, errSecUnknownFormat);
252 CSSM_PERROR("SecCmsDecoderUpdate", ortn);
253 }
254 return ortn;
255 }
256
257 /*
258 * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
259 * finish decoding the message. We parse the message as best we can, up to
260 * but not including verifying individual signerInfos.
261 */
262 OSStatus CMSDecoderFinalizeMessage(
263 CMSDecoderRef cmsDecoder)
264 {
265 if(cmsDecoder == NULL) {
266 return errSecParam;
267 }
268 if(cmsDecoder->decState != DS_Updating) {
269 return errSecParam;
270 }
271 ASSERT(cmsDecoder->decoder != NULL);
272 OSStatus ortn = SecCmsDecoderFinish(cmsDecoder->decoder, &cmsDecoder->cmsMsg);
273 cmsDecoder->decState = DS_Final;
274
275 /* SecCmsDecoderFinish destroyed the decoder even on failure */
276 cmsDecoder->decoder = NULL;
277
278 if(ortn) {
279 ortn = cmsRtnToOSStatusDefault(ortn, errSecUnknownFormat);
280 CSSM_PERROR("SecCmsDecoderFinish", ortn);
281 return ortn;
282 }
283
284 ASSERT(cmsDecoder->cmsMsg != NULL);
285 cmsDecoder->wasEncrypted = SecCmsMessageIsEncrypted(cmsDecoder->cmsMsg);
286
287 /* Look for a SignedData */
288 int numContentInfos = SecCmsMessageContentLevelCount(cmsDecoder->cmsMsg);
289 int dex;
290 for(dex=0; dex<numContentInfos; dex++) {
291 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsDecoder->cmsMsg, dex);
292 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
293 switch(tag) {
294 case SEC_OID_PKCS7_SIGNED_DATA:
295 cmsDecoder->signedData =
296 (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci);
297 /* dig down one more layer for eContentType */
298 ci = SecCmsSignedDataGetContentInfo(cmsDecoder->signedData);
299 if (ci) {
300 cmsDecoder->eContentType = SecCmsContentInfoGetContentTypeOID(ci);
301 }
302 break;
303 default:
304 break;
305 }
306 if(cmsDecoder->signedData != NULL) {
307 break;
308 }
309
310 }
311
312 /* minimal processing of optional signedData... */
313 if(cmsDecoder->signedData != NULL) {
314 cmsDecoder->numSigners = (size_t)
315 SecCmsSignedDataSignerInfoCount(cmsDecoder->signedData);
316 if(cmsDecoder->detachedContent != NULL) {
317 /* time to calculate digests from detached content */
318 ortn = cmsDigestDetachedContent(cmsDecoder);
319 }
320 }
321 return ortn;
322 }
323
324 /*
325 * A signed CMS message optionally includes the data which was signed. If the
326 * message does not include the signed data, caller specifies the signed data
327 * (the "detached content") here.
328 *
329 * This can be called either before or after the actual decoding of the message
330 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
331 * restriction is that, if detached content is required, this function must
332 * be called befoere successfully ascertaining the signature status via
333 * CMSDecoderCopySignerStatus().
334 */
335 OSStatus CMSDecoderSetDetachedContent(
336 CMSDecoderRef cmsDecoder,
337 CFDataRef detachedContent)
338 {
339 if((cmsDecoder == NULL) || (detachedContent == NULL)) {
340 return errSecParam;
341 }
342 cmsDecoder->detachedContent = detachedContent;
343 CFRetain(detachedContent);
344
345 if(cmsDecoder->signedData != NULL) {
346 /* time to calculate digests from detached content */
347 ASSERT(cmsDecoder->decState == DS_Final);
348 return cmsDigestDetachedContent(cmsDecoder);
349 }
350 return errSecSuccess;
351 }
352
353 /*
354 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
355 * Returns a NULL detachedContent if no detached content has been specified.
356 * Caller must CFRelease() the result.
357 */
358 OSStatus CMSDecoderCopyDetachedContent(
359 CMSDecoderRef cmsDecoder,
360 CFDataRef *detachedContent) /* RETURNED */
361 {
362 if((cmsDecoder == NULL) || (detachedContent == NULL)) {
363 return errSecParam;
364 }
365 if(cmsDecoder->detachedContent != NULL) {
366 CFRetain(cmsDecoder->detachedContent);
367 }
368 *detachedContent = cmsDecoder->detachedContent;
369 return errSecSuccess;
370 }
371
372 /*
373 * Obtain the number of signers of a message. A result of zero indicates that
374 * the message was not signed.
375 */
376 OSStatus CMSDecoderGetNumSigners(
377 CMSDecoderRef cmsDecoder,
378 size_t *numSigners) /* RETURNED */
379 {
380 if((cmsDecoder == NULL) || (numSigners == NULL)) {
381 return errSecParam;
382 }
383 if(cmsDecoder->decState != DS_Final) {
384 return errSecParam;
385 }
386 *numSigners = cmsDecoder->numSigners;
387 return errSecSuccess;
388 }
389
390 /*
391 * Obtain the status of a CMS message's signature. A CMS message can
392 * be signed my multiple signers; this function returns the status
393 * associated with signer 'n' as indicated by the signerIndex parameter.
394 */
395 OSStatus CMSDecoderCopySignerStatus(
396 CMSDecoderRef cmsDecoder,
397 size_t signerIndex,
398 CFTypeRef policyOrArray,
399 Boolean evaluateSecTrust,
400 CMSSignerStatus *signerStatus, /* optional; RETURNED */
401 SecTrustRef *secTrust, /* optional; RETURNED */
402 OSStatus *certVerifyResultCode) /* optional; RETURNED */
403 {
404 if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final) || (!policyOrArray) || !signerStatus) {
405 return errSecParam;
406 }
407
408 /* initialize return values */
409 if(signerStatus) {
410 *signerStatus = kCMSSignerUnsigned;
411 }
412 if(secTrust) {
413 *secTrust = NULL;
414 }
415 if(certVerifyResultCode) {
416 *certVerifyResultCode = 0;
417 }
418
419 if(cmsDecoder->signedData == NULL) {
420 *signerStatus = kCMSSignerUnsigned; /* redundant, I know, but explicit */
421 return errSecSuccess;
422 }
423 ASSERT(cmsDecoder->numSigners > 0);
424 if(signerIndex >= cmsDecoder->numSigners) {
425 *signerStatus = kCMSSignerInvalidIndex;
426 return errSecSuccess;
427 }
428 if(!SecCmsSignedDataHasDigests(cmsDecoder->signedData)) {
429 *signerStatus = kCMSSignerNeedsDetachedContent;
430 return errSecSuccess;
431 }
432
433 /*
434 * OK, we should be able to verify this signerInfo.
435 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
436 * in order get all the cert pieces into place before returning them
437 * to the caller.
438 */
439 SecTrustRef theTrust = NULL;
440 OSStatus vfyRtn = SecCmsSignedDataVerifySignerInfo(cmsDecoder->signedData,
441 (int)signerIndex,
442 NULL,
443 policyOrArray,
444 &theTrust);
445
446 #if SECTRUST_VERBOSE_DEBUG
447 syslog(LOG_ERR, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn);
448 if (policyOrArray) CFShow(policyOrArray);
449 if (theTrust) CFShow(theTrust);
450 #endif
451
452 /* Subsequent errors to errOut: */
453
454 /*
455 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
456 * SecTrustEvaluate() if we don't ask for a copy.
457 *
458 * FIXME deal with multitudes of status returns here...for now, proceed with
459 * obtaining components the caller wants and assume that a nonzero vfyRtn
460 * means "bad signature".
461 */
462 OSStatus ortn = errSecSuccess;
463 SecTrustResultType secTrustResult;
464 OSStatus evalRtn, verifyStatus = errSecSuccess;
465
466 if(secTrust != NULL) {
467 *secTrust = theTrust;
468 /* we'll release our reference at the end */
469 CFRetainSafe(theTrust);
470 }
471 SecCmsSignerInfoRef signerInfo =
472 SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
473 if(signerInfo == NULL) {
474 /* should never happen */
475 ASSERT(0);
476 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
477 ortn = errSecInternalComponent;
478 goto errOut;
479 }
480
481 /* now do the actual cert verify */
482 if(evaluateSecTrust) {
483 evalRtn = SecTrustEvaluate(theTrust, &secTrustResult);
484 if(evalRtn) {
485 /* should never happen */
486 CSSM_PERROR("SecTrustEvaluate", evalRtn);
487 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
488 ortn = errSecInternalComponent;
489 goto errOut;
490 }
491 switch(secTrustResult) {
492 case kSecTrustResultUnspecified:
493 /* cert chain valid, no special UserTrust assignments */
494 case kSecTrustResultProceed:
495 /* cert chain valid AND user explicitly trusts this */
496 break;
497 case kSecTrustResultDeny:
498 verifyStatus = errSecTrustSettingDeny;
499 break;
500 default:
501 {
502 verifyStatus = errSecNotTrusted;
503 break;
504 }
505 } /* switch(secTrustResult) */
506 } /* evaluateSecTrust true */
507 if(certVerifyResultCode != NULL) {
508 *certVerifyResultCode = verifyStatus;
509 }
510
511 /* cook up global status based on vfyRtn and tpVfyStatus */
512 if(signerStatus != NULL) {
513 if((vfyRtn == errSecSuccess) && (verifyStatus == errSecSuccess)) {
514 *signerStatus = kCMSSignerValid;
515 }
516 else if(vfyRtn != errSecSuccess) {
517 /* this could mean other things, but for now... */
518 *signerStatus = kCMSSignerInvalidSignature;
519 }
520 else {
521 *signerStatus = kCMSSignerInvalidCert;
522 }
523 }
524 errOut:
525 CFRELEASE(theTrust);
526 return ortn;
527 }
528
529 /*
530 * Obtain the email address of signer 'signerIndex' of a CMS message, if
531 * present.
532 *
533 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
534 */
535 OSStatus CMSDecoderCopySignerEmailAddress(
536 CMSDecoderRef cmsDecoder,
537 size_t signerIndex,
538 CFStringRef *signerEmailAddress) /* RETURNED */
539 {
540 if((cmsDecoder == NULL) ||
541 (signerEmailAddress == NULL) ||
542 (cmsDecoder->signedData == NULL) || /* not signed */
543 (signerIndex >= cmsDecoder->numSigners) || /* index out of range */
544 (cmsDecoder->decState != DS_Final)) {
545 return errSecParam;
546 }
547
548 SecCmsSignerInfoRef signerInfo =
549 SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
550 if(signerInfo == NULL) {
551 /* should never happen */
552 ASSERT(0);
553 dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
554 return errSecInternalComponent;
555 }
556
557 /*
558 * This is leaking memory in libsecurityKeychain per Radar 4412699.
559 */
560 *signerEmailAddress = SecCmsSignerInfoGetSignerEmailAddress(signerInfo);
561 return errSecSuccess;
562 }
563
564 /*
565 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
566 * present.
567 *
568 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
569 */
570 OSStatus CMSDecoderCopySignerCert(
571 CMSDecoderRef cmsDecoder,
572 size_t signerIndex,
573 SecCertificateRef *signerCert) /* RETURNED */
574 {
575 if((cmsDecoder == NULL) ||
576 (signerCert == NULL) ||
577 (cmsDecoder->signedData == NULL) || /* not signed */
578 (signerIndex >= cmsDecoder->numSigners) || /* index out of range */
579 (cmsDecoder->decState != DS_Final)) {
580 return errSecParam;
581 }
582
583 SecCmsSignerInfoRef signerInfo =
584 SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
585 if(signerInfo == NULL) {
586 /* should never happen */
587 ASSERT(0);
588 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
589 return errSecInternalComponent;
590 }
591 *signerCert = SecCmsSignerInfoGetSigningCertificate(signerInfo, NULL);
592 /* libsecurity_smime does NOT retain that */
593 if(*signerCert == NULL) {
594 /* should never happen */
595 ASSERT(0);
596 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
597 return errSecInternalComponent;
598 }
599 CFRetain(*signerCert);
600 return errSecSuccess;
601 }
602
603 /*
604 * Determine whether a CMS message was encrypted, and if so, whether we were
605 * able to decrypt it.
606 */
607 OSStatus CMSDecoderIsContentEncrypted(
608 CMSDecoderRef cmsDecoder,
609 Boolean *wasEncrypted)
610 {
611 if((cmsDecoder == NULL) || (wasEncrypted == NULL)) {
612 return errSecParam;
613 }
614 if(cmsDecoder->decState != DS_Final) {
615 return errSecParam;
616 }
617 *wasEncrypted = cmsDecoder->wasEncrypted;
618 return errSecSuccess;
619 }
620
621 /*
622 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
623 * present.
624 */
625 OSStatus CMSDecoderCopyEncapsulatedContentType(
626 CMSDecoderRef cmsDecoder,
627 CFDataRef *eContentType) /* RETURNED */
628 {
629 if((cmsDecoder == NULL) || (eContentType == NULL)) {
630 return errSecParam;
631 }
632 if(cmsDecoder->decState != DS_Final) {
633 return errSecParam;
634 }
635 if(cmsDecoder->signedData == NULL) {
636 *eContentType = NULL;
637 }
638 else {
639 SecAsn1Oid *ecOid = cmsDecoder->eContentType;
640 *eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length);
641 }
642 return errSecSuccess;
643 }
644
645 /*
646 * Obtain an array of all of the certificates in a message. Elements of the
647 * returned array are SecCertificateRefs. The caller must CFRelease the returned
648 * array.
649 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
650 */
651 OSStatus CMSDecoderCopyAllCerts(
652 CMSDecoderRef cmsDecoder,
653 CFArrayRef *certs) /* RETURNED */
654 {
655 if((cmsDecoder == NULL) || (certs == NULL)) {
656 return errSecParam;
657 }
658 if(cmsDecoder->decState != DS_Final) {
659 return errSecParam;
660 }
661 if(cmsDecoder->signedData == NULL) {
662 /* message wasn't signed */
663 *certs = NULL;
664 return errSecSuccess;
665 }
666
667 /* NULL_terminated array of CSSM_DATA ptrs */
668 SecAsn1Item **cssmCerts = SecCmsSignedDataGetCertificateList(cmsDecoder->signedData);
669 if((cssmCerts == NULL) || (*cssmCerts == NULL)) {
670 *certs = NULL;
671 return errSecSuccess;
672 }
673
674 CFMutableArrayRef allCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
675 SecAsn1Item **cssmCert;
676 for(cssmCert=cssmCerts; *cssmCert!=NULL; cssmCert++) {
677 SecCertificateRef cfCert = SecCertificateCreateWithBytes(NULL, (*cssmCert)->Data, (*cssmCert)->Length);
678 if(!cfCert) {
679 CFRelease(allCerts);
680 return errSecDecode;
681 }
682 CFArrayAppendValue(allCerts, cfCert);
683 /* the array holds the only needed refcount */
684 CFRelease(cfCert);
685 }
686 *certs = allCerts;
687 return errSecSuccess;
688 }
689
690 /*
691 * Obtain the actual message content (payload), if any. If the message was
692 * signed with detached content this will return NULL.
693 * Caller must CFRelease the result.
694 */
695 OSStatus CMSDecoderCopyContent(
696 CMSDecoderRef cmsDecoder,
697 CFDataRef *content) /* RETURNED */
698 {
699 if((cmsDecoder == NULL) || (content == NULL)) {
700 return errSecParam;
701 }
702 if(cmsDecoder->decState != DS_Final) {
703 return errSecParam;
704 }
705 if(cmsDecoder->cmsMsg == NULL) {
706 /* Hmmm....looks like the finalize call failed */
707 return errSecParam;
708 }
709 const SecAsn1Item *odata = SecCmsMessageGetContent(cmsDecoder->cmsMsg);
710 if((odata == NULL) || (odata->Length == 0)) {
711 /* i.e., detached content */
712 *content = NULL;
713 return errSecSuccess;
714 }
715 *content = CFDataCreate(NULL, (const UInt8 *)odata->Data, odata->Length);
716 return errSecSuccess;
717 }
718
719 #pragma mark --- SPI declared in CMSPrivate.h ---
720
721 /*
722 * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
723 * to be called after decoding the message (i.e., after
724 * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
725 * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
726 * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
727 * called.
728 *
729 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
730 */
731 OSStatus CMSDecoderGetCmsMessage(
732 CMSDecoderRef cmsDecoder,
733 SecCmsMessageRef *cmsMessage) /* RETURNED */
734 {
735 if((cmsDecoder == NULL) || (cmsMessage == NULL)) {
736 return errSecParam;
737 }
738 /* any state, whether we have a msg or not is OK */
739 *cmsMessage = cmsDecoder->cmsMsg;
740 return errSecSuccess;
741 }
742
743 /*
744 * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
745 * If this is called, it must be called before the first call to
746 * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
747 * incoming SecCmsDecoderRef.
748 */
749 OSStatus CMSDecoderSetDecoder(
750 CMSDecoderRef cmsDecoder,
751 SecCmsDecoderRef decoder)
752 {
753 if((cmsDecoder == NULL) || (decoder == NULL)) {
754 return errSecParam;
755 }
756 switch(cmsDecoder->decState) {
757 case DS_Init:
758 ASSERT(cmsDecoder->decoder == NULL);
759 cmsDecoder->decoder = decoder;
760 cmsDecoder->decState = DS_Updating;
761 return errSecSuccess;
762 case DS_Updating:
763 case DS_Final:
764 return errSecParam;
765 }
766 return errSecSuccess;
767 }
768
769 /*
770 * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
771 * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
772 * CMSDecoderUpdateMessage() has been called.
773 * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
774 */
775 OSStatus CMSDecoderGetDecoder(
776 CMSDecoderRef cmsDecoder,
777 SecCmsDecoderRef *decoder) /* RETURNED */
778 {
779 if((cmsDecoder == NULL) || (decoder == NULL)) {
780 return errSecParam;
781 }
782 /* any state, whether we have a decoder or not is OK */
783 *decoder = cmsDecoder->decoder;
784 return errSecSuccess;
785 }
786
787 /*
788 * Obtain the signing time of signer 'signerIndex' of a CMS message, if
789 * present. This is an unauthenticate time, although it is part of the
790 * signed attributes of the message.
791 *
792 * Returns errSecParam if the CMS message was not signed or if signerIndex
793 * is greater than the number of signers of the message minus one.
794 *
795 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
796 */
797 OSStatus CMSDecoderCopySignerSigningTime(
798 CMSDecoderRef cmsDecoder,
799 size_t signerIndex, /* usually 0 */
800 CFAbsoluteTime *signingTime) /* RETURNED */
801 {
802 OSStatus status = errSecParam;
803 SecCmsMessageRef cmsg;
804 SecCmsSignedDataRef signedData = NULL;
805 int numContentInfos = 0;
806
807 require(cmsDecoder && signingTime, xit);
808 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
809 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
810 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
811 {
812 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
813 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
814 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
815 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
816 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
817 if (signerInfo)
818 {
819 status = SecCmsSignerInfoGetSigningTime(signerInfo, signingTime);
820 break;
821 }
822 }
823 }
824 xit:
825 return status;
826 }
827
828 #if TIMESTAMPING_SUPPORTED
829 /*
830 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
831 * present. This timestamp is an authenticated timestamp provided by
832 * a timestamping authority.
833 *
834 * Returns errSecParam if the CMS message was not signed or if signerIndex
835 * is greater than the number of signers of the message minus one.
836 *
837 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
838 */
839
840 OSStatus CMSDecoderCopySignerTimestamp(
841 CMSDecoderRef cmsDecoder,
842 size_t signerIndex, /* usually 0 */
843 CFAbsoluteTime *timestamp) /* RETURNED */
844 {
845 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder, NULL, signerIndex, timestamp);
846 }
847
848 OSStatus CMSDecoderCopySignerTimestampWithPolicy(
849 CMSDecoderRef cmsDecoder,
850 CFTypeRef timeStampPolicy,
851 size_t signerIndex, /* usually 0 */
852 CFAbsoluteTime *timestamp) /* RETURNED */
853 {
854 OSStatus status = errSecParam;
855 SecCmsMessageRef cmsg;
856 SecCmsSignedDataRef signedData = NULL;
857 int numContentInfos = 0;
858
859 require(cmsDecoder && timestamp, xit);
860 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
861 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
862 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
863 {
864 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
865 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
866 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
867 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
868 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
869 if (signerInfo)
870 {
871 status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp);
872 break;
873 }
874 }
875 }
876
877 xit:
878 return status;
879 }
880
881 /*
882 * Obtain an array of the certificates in a timestamp response. Elements of the
883 * returned array are SecCertificateRefs. The caller must CFRelease the returned
884 * array. This timestamp is an authenticated timestamp provided by
885 * a timestamping authority.
886 *
887 * Returns errSecParam if the CMS message was not signed or if signerIndex
888 * is greater than the number of signers of the message minus one. It returns
889 * errSecItemNotFound if no certificates were found.
890 *
891 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
892 */
893 OSStatus CMSDecoderCopySignerTimestampCertificates(
894 CMSDecoderRef cmsDecoder,
895 size_t signerIndex, /* usually 0 */
896 CFArrayRef *certificateRefs) /* RETURNED */
897 {
898 OSStatus status = errSecParam;
899 SecCmsMessageRef cmsg = NULL;
900 SecCmsSignedDataRef signedData = NULL;
901 int numContentInfos = 0;
902 CFIndex tsn = 0;
903 bool good = false;
904
905 require(cmsDecoder && certificateRefs, xit);
906 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
907 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
908 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
909 {
910 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
911 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
912 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
913 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
914 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
915 if (signerInfo)
916 {
917 CFArrayRef certList = SecCmsSignerInfoGetTimestampCertList(signerInfo);
918 require_action(certList, xit, status = errSecItemNotFound);
919 CFMutableArrayRef certs = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(certList), certList);
920
921 if(certs){
922 //reorder certificates:
923 tsn = CFArrayGetCount(certs);
924 good = tsn > 0 && SecIsAppleTrustAnchor((SecCertificateRef)CFArrayGetValueAtIndex(certs, tsn-1), 0);
925
926 if ( good == false )
927 {
928 //change TS certificate ordering.
929 for (CFIndex n = 0; n < tsn; n++)
930 {
931 SecCertificateRef tsRoot = (SecCertificateRef)CFArrayGetValueAtIndex(certs, n);
932 if (tsRoot)
933 if ((good = SecIsAppleTrustAnchor(tsRoot, 0))) {
934 CFArrayExchangeValuesAtIndices(certs, n, tsn-1);
935 break;
936 }
937 }
938 }
939
940 *certificateRefs = CFArrayCreateCopy(kCFAllocatorDefault, certs);
941 CFRelease(certs);
942 status = errSecSuccess;
943 }
944 break;
945 }
946 }
947 }
948
949
950 xit:
951 return status;
952 }
953 #endif
954
955 /*
956 * Obtain the Hash Agility attribute value of signer 'signerIndex'
957 * of a CMS message, if present.
958 *
959 * Returns errSecParam if the CMS message was not signed or if signerIndex
960 * is greater than the number of signers of the message minus one.
961 *
962 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
963 */
964 OSStatus CMSDecoderCopySignerAppleCodesigningHashAgility(
965 CMSDecoderRef cmsDecoder,
966 size_t signerIndex, /* usually 0 */
967 CFDataRef CF_RETURNS_RETAINED *hashAgilityAttrValue) /* RETURNED */
968 {
969 OSStatus status = errSecParam;
970 SecCmsMessageRef cmsg;
971 SecCmsSignedDataRef signedData = NULL;
972 int numContentInfos = 0;
973 CFDataRef returnedValue = NULL;
974
975 require(cmsDecoder && hashAgilityAttrValue, exit);
976 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), exit);
977 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
978 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
979 {
980 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
981 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
982 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
983 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
984 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
985 if (signerInfo)
986 {
987 status = SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo, &returnedValue);
988 break;
989 }
990 }
991 }
992 exit:
993 if (status == errSecSuccess && returnedValue) {
994 *hashAgilityAttrValue = (CFDataRef) CFRetain(returnedValue);
995 } else {
996 *hashAgilityAttrValue = NULL;
997 }
998 return status;
999 }
1000
1001 /*
1002 * Obtain the Hash Agility V2 attribute value of signer 'signerIndex'
1003 * of a CMS message, if present.
1004 *
1005 * Returns errSecParam if the CMS message was not signed or if signerIndex
1006 * is greater than the number of signers of the message minus one.
1007 *
1008 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1009 */
1010 OSStatus CMSDecoderCopySignerAppleCodesigningHashAgilityV2(
1011 CMSDecoderRef cmsDecoder,
1012 size_t signerIndex, /* usually 0 */
1013 CFDictionaryRef CF_RETURNS_RETAINED *hashAgilityV2AttrValues) /* RETURNED */
1014 {
1015 OSStatus status = errSecParam;
1016 SecCmsMessageRef cmsg;
1017 SecCmsSignedDataRef signedData = NULL;
1018 int numContentInfos = 0;
1019 CFDictionaryRef returnedValue = NULL;
1020
1021 require(cmsDecoder && hashAgilityV2AttrValues, exit);
1022 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), exit);
1023 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
1024 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
1025 {
1026 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
1027 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
1028 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
1029 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
1030 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
1031 if (signerInfo)
1032 {
1033 status = SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(signerInfo, &returnedValue);
1034 break;
1035 }
1036 }
1037 }
1038 exit:
1039 if (status == errSecSuccess && returnedValue) {
1040 *hashAgilityV2AttrValues = (CFDictionaryRef) CFRetain(returnedValue);
1041 } else {
1042 *hashAgilityV2AttrValues = NULL;
1043 }
1044 return status;
1045 }
1046
1047 /*
1048 * Obtain the expiration time of signer 'signerIndex' of a CMS message, if
1049 * present. This is part of the signed attributes of the message.
1050 *
1051 * Returns errSecParam if the CMS message was not signed or if signerIndex
1052 * is greater than the number of signers of the message minus one.
1053 *
1054 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1055 */
1056 OSStatus CMSDecoderCopySignerAppleExpirationTime(
1057 CMSDecoderRef cmsDecoder,
1058 size_t signerIndex,
1059 CFAbsoluteTime *expirationTime) /* RETURNED */
1060 {
1061 OSStatus status = errSecParam;
1062 SecCmsMessageRef cmsg = NULL;
1063 int numContentInfos = 0;
1064 SecCmsSignedDataRef signedData = NULL;
1065
1066 require(cmsDecoder && expirationTime, xit);
1067 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
1068 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
1069 for (int dex = 0; !signedData && dex < numContentInfos; dex++) {
1070 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
1071 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
1072 if (tag == SEC_OID_PKCS7_SIGNED_DATA) {
1073 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
1074 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
1075 if (signerInfo) {
1076 status = SecCmsSignerInfoGetAppleExpirationTime(signerInfo, expirationTime);
1077 break;
1078 }
1079 }
1080 }
1081 }
1082 xit:
1083 return status;
1084 }