2 * Copyright (c) 2006-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * CMSDecoder.c - Interface for decoding CMS messages.
28 #include "CMSDecoder.h"
31 #include <Security/SecCmsDecoder.h>
32 #include <Security/SecCmsEnvelopedData.h>
33 #include <Security/SecCmsMessage.h>
34 #include <Security/SecCmsSignedData.h>
35 #include <Security/SecCmsSignerInfo.h>
36 #include <Security/SecCmsContentInfo.h>
37 #include <Security/SecCmsDigestContext.h>
38 #include <Security/SecCertificate.h>
39 #include <Security/SecCertificatePriv.h>
40 #include <Security/SecSMIME.h>
41 #include <Security/oidsattr.h>
42 #include <Security/SecTrustPriv.h>
43 #include <utilities/SecAppleAnchorPriv.h>
44 #include <CoreFoundation/CFRuntime.h>
47 #include <AssertMacros.h>
49 #pragma mark --- Private types and definitions ---
55 DS_Init
, /* between CMSDecoderCreate and CMSDecoderUpdateMessage */
56 DS_Updating
, /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */
57 DS_Final
/* CMSDecoderFinalizeMessage has been called */
61 * Caller's CMSDecoderRef points to one of these.
65 CMSDecoderState decState
;
66 SecCmsDecoderRef decoder
;
67 CFDataRef detachedContent
;
70 * The following are valid (and quiescent) after CMSDecoderFinalizeMessage().
72 SecCmsMessageRef cmsMsg
;
73 Boolean wasEncrypted
; /* valid after CMSDecoderFinalizeMessage() */
74 SecCmsSignedDataRef signedData
; /* if there is one... */
75 /* only non-NULL if we found a signedData */
77 SecAsn1Oid
*eContentType
;
81 static void cmsDecoderInit(CFTypeRef dec
);
82 static void cmsDecoderFinalize(CFTypeRef dec
);
84 static CFRuntimeClass cmsDecoderRuntimeClass
=
91 NULL
, /* equal - just use pointer equality */
92 NULL
, /* hash, ditto */
93 NULL
, /* copyFormattingDesc */
94 NULL
/* copyDebugDesc */
97 #pragma mark --- Private Routines ---
99 static CFTypeID cmsDecoderTypeID
= _kCFRuntimeNotATypeID
;
101 /* one time only class init, called via pthread_once() in CMSDecoderGetTypeID() */
102 static void cmsDecoderClassInitialize(void)
105 _CFRuntimeRegisterClass((const CFRuntimeClass
* const)&cmsDecoderRuntimeClass
);
108 /* init called out from _CFRuntimeCreateInstance() */
109 static void cmsDecoderInit(CFTypeRef dec
)
111 char *start
= ((char *)dec
) + sizeof(CFRuntimeBase
);
112 memset(start
, 0, sizeof(struct _CMSDecoder
) - sizeof(CFRuntimeBase
));
116 * Dispose of a CMSDecoder. Called out from CFRelease().
118 static void cmsDecoderFinalize(
121 CMSDecoderRef cmsDecoder
= (CMSDecoderRef
)dec
;
122 if(cmsDecoder
== NULL
) {
125 if(cmsDecoder
->decoder
!= NULL
) {
127 * Normally this gets freed in SecCmsDecoderFinish - this is
128 * an error case. Unlike Finish, this calls SecCmsMessageDestroy.
130 SecCmsDecoderDestroy(cmsDecoder
->decoder
);
131 cmsDecoder
->cmsMsg
= NULL
;
133 CFRELEASE(cmsDecoder
->detachedContent
);
134 if(cmsDecoder
->cmsMsg
!= NULL
) {
135 SecCmsMessageDestroy(cmsDecoder
->cmsMsg
);
136 cmsDecoder
->cmsMsg
= NULL
;
142 * Given detached content and a valid (decoded) SignedData, digest the detached
143 * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a
144 * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent()
145 * when we already have a SignedData).
147 static OSStatus
cmsDigestDetachedContent(
148 CMSDecoderRef cmsDecoder
)
150 ASSERT((cmsDecoder
->signedData
!= NULL
) && (cmsDecoder
->detachedContent
!= NULL
));
152 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(cmsDecoder
->signedData
);
153 if(digestAlgorithms
== NULL
) {
154 return errSecUnknownFormat
;
156 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestAlgorithms
);
158 return errSecAllocate
;
161 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(cmsDecoder
->detachedContent
),
162 CFDataGetLength(cmsDecoder
->detachedContent
));
163 OSStatus ortn
= SecCmsSignedDataSetDigestContext(cmsDecoder
->signedData
, digcx
);
164 SecCmsDigestContextDestroy(digcx
);
167 ortn
= cmsRtnToOSStatus(ortn
);
168 CSSM_PERROR("SecCmsSignedDataSetDigestContext", ortn
);
175 #pragma mark --- Start of Public API ---
177 CFTypeID
CMSDecoderGetTypeID(void)
179 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
181 if(cmsDecoderTypeID
== _kCFRuntimeNotATypeID
) {
182 pthread_once(&once
, &cmsDecoderClassInitialize
);
184 return cmsDecoderTypeID
;
188 * Create a CMSDecoder. Result must eventually be freed via CFRelease().
190 OSStatus
CMSDecoderCreate(
191 CMSDecoderRef
*cmsDecoderOut
) /* RETURNED */
193 CMSDecoderRef cmsDecoder
= NULL
;
195 uint32_t extra
= sizeof(*cmsDecoder
) - sizeof(cmsDecoder
->base
);
196 cmsDecoder
= (CMSDecoderRef
)_CFRuntimeCreateInstance(NULL
, CMSDecoderGetTypeID(),
198 if(cmsDecoder
== NULL
) {
199 return errSecAllocate
;
201 cmsDecoder
->decState
= DS_Init
;
202 *cmsDecoderOut
= cmsDecoder
;
203 return errSecSuccess
;
207 * Feed raw bytes of the message to be decoded into the decoder. Can be called
210 OSStatus
CMSDecoderUpdateMessage(
211 CMSDecoderRef cmsDecoder
,
212 const void *msgBytes
,
215 if(cmsDecoder
== NULL
) {
220 switch(cmsDecoder
->decState
) {
222 /* First time through; set up */
223 ASSERT(cmsDecoder
->decoder
== NULL
);
224 ASSERT(cmsDecoder
->arena
== NULL
);
225 ortn
= SecCmsDecoderCreate(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsDecoder
->decoder
);
227 ortn
= cmsRtnToOSStatus(ortn
);
228 CSSM_PERROR("SecCmsDecoderCreate", ortn
);
231 cmsDecoder
->decState
= DS_Updating
;
235 ASSERT(cmsDecoder
->decoder
!= NULL
);
239 /* Too late for another update */
243 dprintf("CMSDecoderUpdateMessage: bad decState\n");
244 return errSecInternalComponent
;
247 /* FIXME - CFIndex same size as size_t on 64bit? */
248 ortn
= SecCmsDecoderUpdate(cmsDecoder
->decoder
, msgBytes
, (CFIndex
)msgBytesLen
);
250 ortn
= cmsRtnToOSStatusDefault(ortn
, errSecUnknownFormat
);
251 CSSM_PERROR("SecCmsDecoderUpdate", ortn
);
257 * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
258 * finish decoding the message. We parse the message as best we can, up to
259 * but not including verifying individual signerInfos.
261 OSStatus
CMSDecoderFinalizeMessage(
262 CMSDecoderRef cmsDecoder
)
264 if(cmsDecoder
== NULL
) {
267 if(cmsDecoder
->decState
!= DS_Updating
) {
270 ASSERT(cmsDecoder
->decoder
!= NULL
);
271 OSStatus ortn
= SecCmsDecoderFinish(cmsDecoder
->decoder
, &cmsDecoder
->cmsMsg
);
272 cmsDecoder
->decState
= DS_Final
;
274 /* SecCmsDecoderFinish destroyed the decoder even on failure */
275 cmsDecoder
->decoder
= NULL
;
278 ortn
= cmsRtnToOSStatusDefault(ortn
, errSecUnknownFormat
);
279 CSSM_PERROR("SecCmsDecoderFinish", ortn
);
283 ASSERT(cmsDecoder
->cmsMsg
!= NULL
);
284 cmsDecoder
->wasEncrypted
= SecCmsMessageIsEncrypted(cmsDecoder
->cmsMsg
);
286 /* Look for a SignedData */
287 int numContentInfos
= SecCmsMessageContentLevelCount(cmsDecoder
->cmsMsg
);
289 for(dex
=0; dex
<numContentInfos
; dex
++) {
290 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsDecoder
->cmsMsg
, dex
);
291 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
293 case SEC_OID_PKCS7_SIGNED_DATA
:
294 cmsDecoder
->signedData
=
295 (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
);
296 /* dig down one more layer for eContentType */
297 ci
= SecCmsSignedDataGetContentInfo(cmsDecoder
->signedData
);
298 cmsDecoder
->eContentType
= SecCmsContentInfoGetContentTypeOID(ci
);
303 if(cmsDecoder
->signedData
!= NULL
) {
309 /* minimal processing of optional signedData... */
310 if(cmsDecoder
->signedData
!= NULL
) {
311 cmsDecoder
->numSigners
= (size_t)
312 SecCmsSignedDataSignerInfoCount(cmsDecoder
->signedData
);
313 if(cmsDecoder
->detachedContent
!= NULL
) {
314 /* time to calculate digests from detached content */
315 ortn
= cmsDigestDetachedContent(cmsDecoder
);
322 * A signed CMS message optionally includes the data which was signed. If the
323 * message does not include the signed data, caller specifies the signed data
324 * (the "detached content") here.
326 * This can be called either before or after the actual decoding of the message
327 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
328 * restriction is that, if detached content is required, this function must
329 * be called befoere successfully ascertaining the signature status via
330 * CMSDecoderCopySignerStatus().
332 OSStatus
CMSDecoderSetDetachedContent(
333 CMSDecoderRef cmsDecoder
,
334 CFDataRef detachedContent
)
336 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
339 cmsDecoder
->detachedContent
= detachedContent
;
340 CFRetain(detachedContent
);
342 if(cmsDecoder
->signedData
!= NULL
) {
343 /* time to calculate digests from detached content */
344 ASSERT(cmsDecoder
->decState
== DS_Final
);
345 return cmsDigestDetachedContent(cmsDecoder
);
347 return errSecSuccess
;
351 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
352 * Returns a NULL detachedContent if no detached content has been specified.
353 * Caller must CFRelease() the result.
355 OSStatus
CMSDecoderCopyDetachedContent(
356 CMSDecoderRef cmsDecoder
,
357 CFDataRef
*detachedContent
) /* RETURNED */
359 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
362 if(cmsDecoder
->detachedContent
!= NULL
) {
363 CFRetain(cmsDecoder
->detachedContent
);
365 *detachedContent
= cmsDecoder
->detachedContent
;
366 return errSecSuccess
;
370 * Obtain the number of signers of a message. A result of zero indicates that
371 * the message was not signed.
373 OSStatus
CMSDecoderGetNumSigners(
374 CMSDecoderRef cmsDecoder
,
375 size_t *numSigners
) /* RETURNED */
377 if((cmsDecoder
== NULL
) || (numSigners
== NULL
)) {
380 if(cmsDecoder
->decState
!= DS_Final
) {
383 *numSigners
= cmsDecoder
->numSigners
;
384 return errSecSuccess
;
388 * Obtain the status of a CMS message's signature. A CMS message can
389 * be signed my multiple signers; this function returns the status
390 * associated with signer 'n' as indicated by the signerIndex parameter.
392 OSStatus
CMSDecoderCopySignerStatus(
393 CMSDecoderRef cmsDecoder
,
395 CFTypeRef policyOrArray
,
396 Boolean evaluateSecTrust
,
397 CMSSignerStatus
*signerStatus
, /* optional; RETURNED */
398 SecTrustRef
*secTrust
, /* optional; RETURNED */
399 OSStatus
*certVerifyResultCode
) /* optional; RETURNED */
401 if((cmsDecoder
== NULL
) || (cmsDecoder
->decState
!= DS_Final
) || (!policyOrArray
)) {
405 /* initialize return values */
407 *signerStatus
= kCMSSignerUnsigned
;
412 if(certVerifyResultCode
) {
413 *certVerifyResultCode
= 0;
416 if(cmsDecoder
->signedData
== NULL
) {
417 *signerStatus
= kCMSSignerUnsigned
; /* redundant, I know, but explicit */
418 return errSecSuccess
;
420 ASSERT(cmsDecoder
->numSigners
> 0);
421 if(signerIndex
>= cmsDecoder
->numSigners
) {
422 *signerStatus
= kCMSSignerInvalidIndex
;
423 return errSecSuccess
;
425 if(!SecCmsSignedDataHasDigests(cmsDecoder
->signedData
)) {
426 *signerStatus
= kCMSSignerNeedsDetachedContent
;
427 return errSecSuccess
;
431 * OK, we should be able to verify this signerInfo.
432 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
433 * in order get all the cert pieces into place before returning them
436 SecTrustRef theTrust
= NULL
;
437 OSStatus vfyRtn
= SecCmsSignedDataVerifySignerInfo(cmsDecoder
->signedData
,
443 #if SECTRUST_VERBOSE_DEBUG
444 syslog(LOG_ERR
, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn
);
445 if (policyOrArray
) CFShow(policyOrArray
);
446 if (theTrust
) CFShow(theTrust
);
449 /* Subsequent errors to errOut: */
452 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
453 * SecTrustEvaluate() if we don't ask for a copy.
455 * FIXME deal with multitudes of status returns here...for now, proceed with
456 * obtaining components the caller wants and assume that a nonzero vfyRtn
457 * means "bad signature".
459 OSStatus ortn
= errSecSuccess
;
460 SecTrustResultType secTrustResult
;
461 OSStatus evalRtn
, verifyStatus
= errSecSuccess
;
463 if(secTrust
!= NULL
) {
464 *secTrust
= theTrust
;
465 /* we'll release our reference at the end */
469 SecCmsSignerInfoRef signerInfo
=
470 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
471 if(signerInfo
== NULL
) {
472 /* should never happen */
474 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
475 ortn
= errSecInternalComponent
;
479 /* now do the actual cert verify */
480 if(evaluateSecTrust
) {
481 evalRtn
= SecTrustEvaluate(theTrust
, &secTrustResult
);
483 /* should never happen */
484 CSSM_PERROR("SecTrustEvaluate", evalRtn
);
485 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
486 ortn
= errSecInternalComponent
;
489 switch(secTrustResult
) {
490 case kSecTrustResultUnspecified
:
491 /* cert chain valid, no special UserTrust assignments */
492 case kSecTrustResultProceed
:
493 /* cert chain valid AND user explicitly trusts this */
495 case kSecTrustResultDeny
:
496 verifyStatus
= errSecTrustSettingDeny
;
500 verifyStatus
= errSecNotTrusted
;
503 } /* switch(secTrustResult) */
504 } /* evaluateSecTrust true */
505 if(certVerifyResultCode
!= NULL
) {
506 *certVerifyResultCode
= verifyStatus
;
509 /* cook up global status based on vfyRtn and tpVfyStatus */
510 if(signerStatus
!= NULL
) {
511 if((vfyRtn
== errSecSuccess
) && (verifyStatus
== errSecSuccess
)) {
512 *signerStatus
= kCMSSignerValid
;
514 else if(vfyRtn
!= errSecSuccess
) {
515 /* this could mean other things, but for now... */
516 *signerStatus
= kCMSSignerInvalidSignature
;
519 *signerStatus
= kCMSSignerInvalidCert
;
528 * Obtain the email address of signer 'signerIndex' of a CMS message, if
531 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
533 OSStatus
CMSDecoderCopySignerEmailAddress(
534 CMSDecoderRef cmsDecoder
,
536 CFStringRef
*signerEmailAddress
) /* RETURNED */
538 if((cmsDecoder
== NULL
) ||
539 (signerEmailAddress
== NULL
) ||
540 (cmsDecoder
->signedData
== NULL
) || /* not signed */
541 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
542 (cmsDecoder
->decState
!= DS_Final
)) {
546 SecCmsSignerInfoRef signerInfo
=
547 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
548 if(signerInfo
== NULL
) {
549 /* should never happen */
551 dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
552 return errSecInternalComponent
;
556 * This is leaking memory in libsecurityKeychain per Radar 4412699.
558 *signerEmailAddress
= SecCmsSignerInfoGetSignerEmailAddress(signerInfo
);
559 return errSecSuccess
;
563 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
566 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
568 OSStatus
CMSDecoderCopySignerCert(
569 CMSDecoderRef cmsDecoder
,
571 SecCertificateRef
*signerCert
) /* RETURNED */
573 if((cmsDecoder
== NULL
) ||
574 (signerCert
== NULL
) ||
575 (cmsDecoder
->signedData
== NULL
) || /* not signed */
576 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
577 (cmsDecoder
->decState
!= DS_Final
)) {
581 SecCmsSignerInfoRef signerInfo
=
582 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
583 if(signerInfo
== NULL
) {
584 /* should never happen */
586 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
587 return errSecInternalComponent
;
589 *signerCert
= SecCmsSignerInfoGetSigningCertificate(signerInfo
, NULL
);
590 /* libsecurity_smime does NOT retain that */
591 if(*signerCert
== NULL
) {
592 /* should never happen */
594 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
595 return errSecInternalComponent
;
597 CFRetain(*signerCert
);
598 return errSecSuccess
;
602 * Determine whether a CMS message was encrypted, and if so, whether we were
603 * able to decrypt it.
605 OSStatus
CMSDecoderIsContentEncrypted(
606 CMSDecoderRef cmsDecoder
,
607 Boolean
*wasEncrypted
)
609 if((cmsDecoder
== NULL
) || (wasEncrypted
== NULL
)) {
612 if(cmsDecoder
->decState
!= DS_Final
) {
615 *wasEncrypted
= cmsDecoder
->wasEncrypted
;
616 return errSecSuccess
;
620 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
623 OSStatus
CMSDecoderCopyEncapsulatedContentType(
624 CMSDecoderRef cmsDecoder
,
625 CFDataRef
*eContentType
) /* RETURNED */
627 if((cmsDecoder
== NULL
) || (eContentType
== NULL
)) {
630 if(cmsDecoder
->decState
!= DS_Final
) {
633 if(cmsDecoder
->signedData
== NULL
) {
634 *eContentType
= NULL
;
637 SecAsn1Oid
*ecOid
= cmsDecoder
->eContentType
;
638 *eContentType
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
);
640 return errSecSuccess
;
644 * Obtain an array of all of the certificates in a message. Elements of the
645 * returned array are SecCertificateRefs. The caller must CFRelease the returned
647 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
649 OSStatus
CMSDecoderCopyAllCerts(
650 CMSDecoderRef cmsDecoder
,
651 CFArrayRef
*certs
) /* RETURNED */
653 if((cmsDecoder
== NULL
) || (certs
== NULL
)) {
656 if(cmsDecoder
->decState
!= DS_Final
) {
659 if(cmsDecoder
->signedData
== NULL
) {
660 /* message wasn't signed */
662 return errSecSuccess
;
665 /* NULL_terminated array of CSSM_DATA ptrs */
666 SecAsn1Item
**cssmCerts
= SecCmsSignedDataGetCertificateList(cmsDecoder
->signedData
);
667 if((cssmCerts
== NULL
) || (*cssmCerts
== NULL
)) {
669 return errSecSuccess
;
672 CFMutableArrayRef allCerts
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
673 SecAsn1Item
**cssmCert
;
674 for(cssmCert
=cssmCerts
; *cssmCert
!=NULL
; cssmCert
++) {
675 SecCertificateRef cfCert
= SecCertificateCreateWithBytes(NULL
, (*cssmCert
)->Data
, (*cssmCert
)->Length
);
680 CFArrayAppendValue(allCerts
, cfCert
);
681 /* the array holds the only needed refcount */
685 return errSecSuccess
;
689 * Obtain the actual message content (payload), if any. If the message was
690 * signed with detached content this will return NULL.
691 * Caller must CFRelease the result.
693 OSStatus
CMSDecoderCopyContent(
694 CMSDecoderRef cmsDecoder
,
695 CFDataRef
*content
) /* RETURNED */
697 if((cmsDecoder
== NULL
) || (content
== NULL
)) {
700 if(cmsDecoder
->decState
!= DS_Final
) {
703 if(cmsDecoder
->cmsMsg
== NULL
) {
704 /* Hmmm....looks like the finalize call failed */
707 const SecAsn1Item
*odata
= SecCmsMessageGetContent(cmsDecoder
->cmsMsg
);
708 if((odata
== NULL
) || (odata
->Length
== 0)) {
709 /* i.e., detached content */
711 return errSecSuccess
;
713 *content
= CFDataCreate(NULL
, (const UInt8
*)odata
->Data
, odata
->Length
);
714 return errSecSuccess
;
717 #pragma mark --- SPI declared in CMSPrivate.h ---
720 * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
721 * to be called after decoding the message (i.e., after
722 * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
723 * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
724 * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
727 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
729 OSStatus
CMSDecoderGetCmsMessage(
730 CMSDecoderRef cmsDecoder
,
731 SecCmsMessageRef
*cmsMessage
) /* RETURNED */
733 if((cmsDecoder
== NULL
) || (cmsMessage
== NULL
)) {
736 /* any state, whether we have a msg or not is OK */
737 *cmsMessage
= cmsDecoder
->cmsMsg
;
738 return errSecSuccess
;
742 * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
743 * If this is called, it must be called before the first call to
744 * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
745 * incoming SecCmsDecoderRef.
747 OSStatus
CMSDecoderSetDecoder(
748 CMSDecoderRef cmsDecoder
,
749 SecCmsDecoderRef decoder
)
751 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
754 switch(cmsDecoder
->decState
) {
756 ASSERT(cmsDecoder
->decoder
== NULL
);
757 cmsDecoder
->decoder
= decoder
;
758 cmsDecoder
->decState
= DS_Updating
;
759 return errSecSuccess
;
764 return errSecSuccess
;
768 * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
769 * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
770 * CMSDecoderUpdateMessage() has been called.
771 * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
773 OSStatus
CMSDecoderGetDecoder(
774 CMSDecoderRef cmsDecoder
,
775 SecCmsDecoderRef
*decoder
) /* RETURNED */
777 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
780 /* any state, whether we have a decoder or not is OK */
781 *decoder
= cmsDecoder
->decoder
;
782 return errSecSuccess
;
786 * Obtain the signing time of signer 'signerIndex' of a CMS message, if
787 * present. This is an unauthenticate time, although it is part of the
788 * signed attributes of the message.
790 * Returns errSecParam if the CMS message was not signed or if signerIndex
791 * is greater than the number of signers of the message minus one.
793 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
795 OSStatus
CMSDecoderCopySignerSigningTime(
796 CMSDecoderRef cmsDecoder
,
797 size_t signerIndex
, /* usually 0 */
798 CFAbsoluteTime
*signingTime
) /* RETURNED */
800 OSStatus status
= errSecParam
;
801 SecCmsMessageRef cmsg
;
802 SecCmsSignedDataRef signedData
= NULL
;
803 int numContentInfos
= 0;
805 require(cmsDecoder
&& signingTime
, xit
);
806 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
807 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
808 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
810 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
811 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
812 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
813 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
814 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
817 status
= SecCmsSignerInfoGetSigningTime(signerInfo
, signingTime
);
826 #if TIMESTAMPING_SUPPORTED
828 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
829 * present. This timestamp is an authenticated timestamp provided by
830 * a timestamping authority.
832 * Returns errSecParam if the CMS message was not signed or if signerIndex
833 * is greater than the number of signers of the message minus one.
835 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
838 OSStatus
CMSDecoderCopySignerTimestamp(
839 CMSDecoderRef cmsDecoder
,
840 size_t signerIndex
, /* usually 0 */
841 CFAbsoluteTime
*timestamp
) /* RETURNED */
843 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder
, NULL
, signerIndex
, timestamp
);
846 OSStatus
CMSDecoderCopySignerTimestampWithPolicy(
847 CMSDecoderRef cmsDecoder
,
848 CFTypeRef timeStampPolicy
,
849 size_t signerIndex
, /* usually 0 */
850 CFAbsoluteTime
*timestamp
) /* RETURNED */
852 OSStatus status
= errSecParam
;
853 SecCmsMessageRef cmsg
;
854 SecCmsSignedDataRef signedData
= NULL
;
855 int numContentInfos
= 0;
857 require(cmsDecoder
&& timestamp
, xit
);
858 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
859 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
860 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
862 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
863 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
864 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
865 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
866 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
869 status
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);
880 * Obtain an array of the certificates in a timestamp response. Elements of the
881 * returned array are SecCertificateRefs. The caller must CFRelease the returned
882 * array. This timestamp is an authenticated timestamp provided by
883 * a timestamping authority.
885 * Returns errSecParam if the CMS message was not signed or if signerIndex
886 * is greater than the number of signers of the message minus one. It returns
887 * errSecItemNotFound if no certificates were found.
889 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
891 OSStatus
CMSDecoderCopySignerTimestampCertificates(
892 CMSDecoderRef cmsDecoder
,
893 size_t signerIndex
, /* usually 0 */
894 CFArrayRef
*certificateRefs
) /* RETURNED */
896 OSStatus status
= errSecParam
;
897 SecCmsMessageRef cmsg
= NULL
;
898 SecCmsSignedDataRef signedData
= NULL
;
899 int numContentInfos
= 0;
903 require(cmsDecoder
&& certificateRefs
, xit
);
904 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
905 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
906 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
908 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
909 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
910 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
911 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
912 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
915 CFArrayRef certList
= SecCmsSignerInfoGetTimestampCertList(signerInfo
);
916 require_action(certList
, xit
, status
= errSecItemNotFound
);
917 CFMutableArrayRef certs
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, CFArrayGetCount(certList
), certList
);
920 //reorder certificates:
921 tsn
= CFArrayGetCount(certs
);
922 good
= tsn
> 0 && SecIsAppleTrustAnchor((SecCertificateRef
)CFArrayGetValueAtIndex(certs
, tsn
-1), 0);
926 //change TS certificate ordering.
927 for (CFIndex n
= 0; n
< tsn
; n
++)
929 SecCertificateRef tsRoot
= (SecCertificateRef
)CFArrayGetValueAtIndex(certs
, n
);
931 if ((good
= SecIsAppleTrustAnchor(tsRoot
, 0))) {
932 CFArrayExchangeValuesAtIndices(certs
, n
, tsn
-1);
938 *certificateRefs
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
940 status
= errSecSuccess
;
954 * Obtain the Hash Agility attribute value of signer 'signerIndex'
955 * of a CMS message, if present.
957 * Returns errSecParam if the CMS message was not signed or if signerIndex
958 * is greater than the number of signers of the message minus one.
960 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
962 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgility(
963 CMSDecoderRef cmsDecoder
,
964 size_t signerIndex
, /* usually 0 */
965 CFDataRef CF_RETURNS_RETAINED
*hashAgilityAttrValue
) /* RETURNED */
967 OSStatus status
= errSecParam
;
968 SecCmsMessageRef cmsg
;
969 SecCmsSignedDataRef signedData
= NULL
;
970 int numContentInfos
= 0;
971 CFDataRef returnedValue
= NULL
;
973 require(cmsDecoder
&& hashAgilityAttrValue
, xit
);
974 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
975 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
976 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
978 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
979 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
980 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
981 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
982 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
985 status
= SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo
, &returnedValue
);
991 if (status
== errSecSuccess
&& returnedValue
) {
992 *hashAgilityAttrValue
= (CFDataRef
) CFRetain(returnedValue
);
994 *hashAgilityAttrValue
= NULL
;