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 <Security/CMSDecoder.h>
29 #include <Security/CMSPrivate.h>
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>
49 #include <AssertMacros.h>
51 #pragma mark --- Private types and definitions ---
57 DS_Init
, /* between CMSDecoderCreate and CMSDecoderUpdateMessage */
58 DS_Updating
, /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */
59 DS_Final
/* CMSDecoderFinalizeMessage has been called */
63 * Caller's CMSDecoderRef points to one of these.
67 CMSDecoderState decState
;
68 SecCmsDecoderRef decoder
;
69 CFDataRef detachedContent
;
72 * The following are valid (and quiescent) after CMSDecoderFinalizeMessage().
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 */
79 SecAsn1Oid
*eContentType
;
83 static void cmsDecoderInit(CFTypeRef dec
);
84 static void cmsDecoderFinalize(CFTypeRef dec
);
86 static CFRuntimeClass cmsDecoderRuntimeClass
=
93 NULL
, /* equal - just use pointer equality */
94 NULL
, /* hash, ditto */
95 NULL
, /* copyFormattingDesc */
96 NULL
/* copyDebugDesc */
99 #pragma mark --- Private Routines ---
101 static CFTypeID cmsDecoderTypeID
= _kCFRuntimeNotATypeID
;
103 /* one time only class init, called via pthread_once() in CMSDecoderGetTypeID() */
104 static void cmsDecoderClassInitialize(void)
107 _CFRuntimeRegisterClass((const CFRuntimeClass
* const)&cmsDecoderRuntimeClass
);
110 /* init called out from _CFRuntimeCreateInstance() */
111 static void cmsDecoderInit(CFTypeRef dec
)
113 char *start
= ((char *)dec
) + sizeof(CFRuntimeBase
);
114 memset(start
, 0, sizeof(struct _CMSDecoder
) - sizeof(CFRuntimeBase
));
118 * Dispose of a CMSDecoder. Called out from CFRelease().
120 static void cmsDecoderFinalize(
123 CMSDecoderRef cmsDecoder
= (CMSDecoderRef
)dec
;
124 if(cmsDecoder
== NULL
) {
127 if(cmsDecoder
->decoder
!= NULL
) {
129 * Normally this gets freed in SecCmsDecoderFinish - this is
130 * an error case. Unlike Finish, this calls SecCmsMessageDestroy.
132 SecCmsDecoderDestroy(cmsDecoder
->decoder
);
133 cmsDecoder
->cmsMsg
= NULL
;
135 CFRELEASE(cmsDecoder
->detachedContent
);
136 if(cmsDecoder
->cmsMsg
!= NULL
) {
137 SecCmsMessageDestroy(cmsDecoder
->cmsMsg
);
138 cmsDecoder
->cmsMsg
= NULL
;
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).
149 static OSStatus
cmsDigestDetachedContent(
150 CMSDecoderRef cmsDecoder
)
152 ASSERT((cmsDecoder
->signedData
!= NULL
) && (cmsDecoder
->detachedContent
!= NULL
));
154 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(cmsDecoder
->signedData
);
155 if(digestAlgorithms
== NULL
) {
156 return errSecUnknownFormat
;
158 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestAlgorithms
);
160 return errSecAllocate
;
163 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(cmsDecoder
->detachedContent
),
164 CFDataGetLength(cmsDecoder
->detachedContent
));
165 OSStatus ortn
= SecCmsSignedDataSetDigestContext(cmsDecoder
->signedData
, digcx
);
166 SecCmsDigestContextDestroy(digcx
);
169 ortn
= cmsRtnToOSStatus(ortn
);
170 CSSM_PERROR("SecCmsSignedDataSetDigestContext", ortn
);
177 #pragma mark --- Start of Public API ---
179 CFTypeID
CMSDecoderGetTypeID(void)
181 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
183 if(cmsDecoderTypeID
== _kCFRuntimeNotATypeID
) {
184 pthread_once(&once
, &cmsDecoderClassInitialize
);
186 return cmsDecoderTypeID
;
190 * Create a CMSDecoder. Result must eventually be freed via CFRelease().
192 OSStatus
CMSDecoderCreate(
193 CMSDecoderRef
*cmsDecoderOut
) /* RETURNED */
195 CMSDecoderRef cmsDecoder
= NULL
;
197 uint32_t extra
= sizeof(*cmsDecoder
) - sizeof(cmsDecoder
->base
);
198 cmsDecoder
= (CMSDecoderRef
)_CFRuntimeCreateInstance(NULL
, CMSDecoderGetTypeID(),
200 if(cmsDecoder
== NULL
) {
201 return errSecAllocate
;
203 cmsDecoder
->decState
= DS_Init
;
204 *cmsDecoderOut
= cmsDecoder
;
205 return errSecSuccess
;
209 * Feed raw bytes of the message to be decoded into the decoder. Can be called
212 OSStatus
CMSDecoderUpdateMessage(
213 CMSDecoderRef cmsDecoder
,
214 const void *msgBytes
,
217 if(cmsDecoder
== NULL
) {
222 switch(cmsDecoder
->decState
) {
224 /* First time through; set up */
225 ASSERT(cmsDecoder
->decoder
== NULL
);
226 ortn
= SecCmsDecoderCreate(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsDecoder
->decoder
);
228 ortn
= cmsRtnToOSStatus(ortn
);
229 CSSM_PERROR("SecCmsDecoderCreate", ortn
);
232 cmsDecoder
->decState
= DS_Updating
;
236 ASSERT(cmsDecoder
->decoder
!= NULL
);
240 /* Too late for another update */
244 dprintf("CMSDecoderUpdateMessage: bad decState\n");
245 return errSecInternalComponent
;
248 /* FIXME - CFIndex same size as size_t on 64bit? */
249 ortn
= SecCmsDecoderUpdate(cmsDecoder
->decoder
, msgBytes
, (CFIndex
)msgBytesLen
);
251 ortn
= cmsRtnToOSStatusDefault(ortn
, errSecUnknownFormat
);
252 CSSM_PERROR("SecCmsDecoderUpdate", ortn
);
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.
262 OSStatus
CMSDecoderFinalizeMessage(
263 CMSDecoderRef cmsDecoder
)
265 if(cmsDecoder
== NULL
) {
268 if(cmsDecoder
->decState
!= DS_Updating
) {
271 ASSERT(cmsDecoder
->decoder
!= NULL
);
272 OSStatus ortn
= SecCmsDecoderFinish(cmsDecoder
->decoder
, &cmsDecoder
->cmsMsg
);
273 cmsDecoder
->decState
= DS_Final
;
275 /* SecCmsDecoderFinish destroyed the decoder even on failure */
276 cmsDecoder
->decoder
= NULL
;
279 ortn
= cmsRtnToOSStatusDefault(ortn
, errSecUnknownFormat
);
280 CSSM_PERROR("SecCmsDecoderFinish", ortn
);
284 ASSERT(cmsDecoder
->cmsMsg
!= NULL
);
285 cmsDecoder
->wasEncrypted
= SecCmsMessageIsEncrypted(cmsDecoder
->cmsMsg
);
287 /* Look for a SignedData */
288 int numContentInfos
= SecCmsMessageContentLevelCount(cmsDecoder
->cmsMsg
);
290 for(dex
=0; dex
<numContentInfos
; dex
++) {
291 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsDecoder
->cmsMsg
, dex
);
292 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
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
);
300 cmsDecoder
->eContentType
= SecCmsContentInfoGetContentTypeOID(ci
);
306 if(cmsDecoder
->signedData
!= NULL
) {
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
);
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.
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().
335 OSStatus
CMSDecoderSetDetachedContent(
336 CMSDecoderRef cmsDecoder
,
337 CFDataRef detachedContent
)
339 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
342 cmsDecoder
->detachedContent
= detachedContent
;
343 CFRetain(detachedContent
);
345 if(cmsDecoder
->signedData
!= NULL
) {
346 /* time to calculate digests from detached content */
347 ASSERT(cmsDecoder
->decState
== DS_Final
);
348 return cmsDigestDetachedContent(cmsDecoder
);
350 return errSecSuccess
;
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.
358 OSStatus
CMSDecoderCopyDetachedContent(
359 CMSDecoderRef cmsDecoder
,
360 CFDataRef
*detachedContent
) /* RETURNED */
362 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
365 if(cmsDecoder
->detachedContent
!= NULL
) {
366 CFRetain(cmsDecoder
->detachedContent
);
368 *detachedContent
= cmsDecoder
->detachedContent
;
369 return errSecSuccess
;
373 * Obtain the number of signers of a message. A result of zero indicates that
374 * the message was not signed.
376 OSStatus
CMSDecoderGetNumSigners(
377 CMSDecoderRef cmsDecoder
,
378 size_t *numSigners
) /* RETURNED */
380 if((cmsDecoder
== NULL
) || (numSigners
== NULL
)) {
383 if(cmsDecoder
->decState
!= DS_Final
) {
386 *numSigners
= cmsDecoder
->numSigners
;
387 return errSecSuccess
;
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.
395 OSStatus
CMSDecoderCopySignerStatus(
396 CMSDecoderRef cmsDecoder
,
398 CFTypeRef policyOrArray
,
399 Boolean evaluateSecTrust
,
400 CMSSignerStatus
*signerStatus
, /* optional; RETURNED */
401 SecTrustRef
*secTrust
, /* optional; RETURNED */
402 OSStatus
*certVerifyResultCode
) /* optional; RETURNED */
404 if((cmsDecoder
== NULL
) || (cmsDecoder
->decState
!= DS_Final
) || (!policyOrArray
) || !signerStatus
) {
408 /* initialize return values */
410 *signerStatus
= kCMSSignerUnsigned
;
415 if(certVerifyResultCode
) {
416 *certVerifyResultCode
= 0;
419 if(cmsDecoder
->signedData
== NULL
) {
420 *signerStatus
= kCMSSignerUnsigned
; /* redundant, I know, but explicit */
421 return errSecSuccess
;
423 ASSERT(cmsDecoder
->numSigners
> 0);
424 if(signerIndex
>= cmsDecoder
->numSigners
) {
425 *signerStatus
= kCMSSignerInvalidIndex
;
426 return errSecSuccess
;
428 if(!SecCmsSignedDataHasDigests(cmsDecoder
->signedData
)) {
429 *signerStatus
= kCMSSignerNeedsDetachedContent
;
430 return errSecSuccess
;
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
439 SecTrustRef theTrust
= NULL
;
440 OSStatus vfyRtn
= SecCmsSignedDataVerifySignerInfo(cmsDecoder
->signedData
,
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
);
452 /* Subsequent errors to errOut: */
455 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
456 * SecTrustEvaluate() if we don't ask for a copy.
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".
462 OSStatus ortn
= errSecSuccess
;
463 SecTrustResultType secTrustResult
;
464 OSStatus evalRtn
, verifyStatus
= errSecSuccess
;
466 if(secTrust
!= NULL
) {
467 *secTrust
= theTrust
;
468 /* we'll release our reference at the end */
469 CFRetainSafe(theTrust
);
471 SecCmsSignerInfoRef signerInfo
=
472 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
473 if(signerInfo
== NULL
) {
474 /* should never happen */
476 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
477 ortn
= errSecInternalComponent
;
481 /* now do the actual cert verify */
482 if(evaluateSecTrust
) {
483 evalRtn
= SecTrustEvaluate(theTrust
, &secTrustResult
);
485 /* should never happen */
486 CSSM_PERROR("SecTrustEvaluate", evalRtn
);
487 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
488 ortn
= errSecInternalComponent
;
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 */
497 case kSecTrustResultDeny
:
498 verifyStatus
= errSecTrustSettingDeny
;
502 verifyStatus
= errSecNotTrusted
;
505 } /* switch(secTrustResult) */
506 } /* evaluateSecTrust true */
507 if(certVerifyResultCode
!= NULL
) {
508 *certVerifyResultCode
= verifyStatus
;
511 /* cook up global status based on vfyRtn and tpVfyStatus */
512 if(signerStatus
!= NULL
) {
513 if((vfyRtn
== errSecSuccess
) && (verifyStatus
== errSecSuccess
)) {
514 *signerStatus
= kCMSSignerValid
;
516 else if(vfyRtn
!= errSecSuccess
) {
517 /* this could mean other things, but for now... */
518 *signerStatus
= kCMSSignerInvalidSignature
;
521 *signerStatus
= kCMSSignerInvalidCert
;
530 * Obtain the email address of signer 'signerIndex' of a CMS message, if
533 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
535 OSStatus
CMSDecoderCopySignerEmailAddress(
536 CMSDecoderRef cmsDecoder
,
538 CFStringRef
*signerEmailAddress
) /* RETURNED */
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
)) {
548 SecCmsSignerInfoRef signerInfo
=
549 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
550 if(signerInfo
== NULL
) {
551 /* should never happen */
553 dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
554 return errSecInternalComponent
;
558 * This is leaking memory in libsecurityKeychain per Radar 4412699.
560 *signerEmailAddress
= SecCmsSignerInfoGetSignerEmailAddress(signerInfo
);
561 return errSecSuccess
;
565 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
568 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
570 OSStatus
CMSDecoderCopySignerCert(
571 CMSDecoderRef cmsDecoder
,
573 SecCertificateRef
*signerCert
) /* RETURNED */
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
)) {
583 SecCmsSignerInfoRef signerInfo
=
584 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
585 if(signerInfo
== NULL
) {
586 /* should never happen */
588 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
589 return errSecInternalComponent
;
591 *signerCert
= SecCmsSignerInfoGetSigningCertificate(signerInfo
, NULL
);
592 /* libsecurity_smime does NOT retain that */
593 if(*signerCert
== NULL
) {
594 /* should never happen */
596 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
597 return errSecInternalComponent
;
599 CFRetain(*signerCert
);
600 return errSecSuccess
;
604 * Determine whether a CMS message was encrypted, and if so, whether we were
605 * able to decrypt it.
607 OSStatus
CMSDecoderIsContentEncrypted(
608 CMSDecoderRef cmsDecoder
,
609 Boolean
*wasEncrypted
)
611 if((cmsDecoder
== NULL
) || (wasEncrypted
== NULL
)) {
614 if(cmsDecoder
->decState
!= DS_Final
) {
617 *wasEncrypted
= cmsDecoder
->wasEncrypted
;
618 return errSecSuccess
;
622 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
625 OSStatus
CMSDecoderCopyEncapsulatedContentType(
626 CMSDecoderRef cmsDecoder
,
627 CFDataRef
*eContentType
) /* RETURNED */
629 if((cmsDecoder
== NULL
) || (eContentType
== NULL
)) {
632 if(cmsDecoder
->decState
!= DS_Final
) {
635 if(cmsDecoder
->signedData
== NULL
) {
636 *eContentType
= NULL
;
639 SecAsn1Oid
*ecOid
= cmsDecoder
->eContentType
;
640 *eContentType
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
);
642 return errSecSuccess
;
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
649 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
651 OSStatus
CMSDecoderCopyAllCerts(
652 CMSDecoderRef cmsDecoder
,
653 CFArrayRef
*certs
) /* RETURNED */
655 if((cmsDecoder
== NULL
) || (certs
== NULL
)) {
658 if(cmsDecoder
->decState
!= DS_Final
) {
661 if(cmsDecoder
->signedData
== NULL
) {
662 /* message wasn't signed */
664 return errSecSuccess
;
667 /* NULL_terminated array of CSSM_DATA ptrs */
668 SecAsn1Item
**cssmCerts
= SecCmsSignedDataGetCertificateList(cmsDecoder
->signedData
);
669 if((cssmCerts
== NULL
) || (*cssmCerts
== NULL
)) {
671 return errSecSuccess
;
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
);
682 CFArrayAppendValue(allCerts
, cfCert
);
683 /* the array holds the only needed refcount */
687 return errSecSuccess
;
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.
695 OSStatus
CMSDecoderCopyContent(
696 CMSDecoderRef cmsDecoder
,
697 CFDataRef
*content
) /* RETURNED */
699 if((cmsDecoder
== NULL
) || (content
== NULL
)) {
702 if(cmsDecoder
->decState
!= DS_Final
) {
705 if(cmsDecoder
->cmsMsg
== NULL
) {
706 /* Hmmm....looks like the finalize call failed */
709 const SecAsn1Item
*odata
= SecCmsMessageGetContent(cmsDecoder
->cmsMsg
);
710 if((odata
== NULL
) || (odata
->Length
== 0)) {
711 /* i.e., detached content */
713 return errSecSuccess
;
715 *content
= CFDataCreate(NULL
, (const UInt8
*)odata
->Data
, odata
->Length
);
716 return errSecSuccess
;
719 #pragma mark --- SPI declared in CMSPrivate.h ---
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
729 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
731 OSStatus
CMSDecoderGetCmsMessage(
732 CMSDecoderRef cmsDecoder
,
733 SecCmsMessageRef
*cmsMessage
) /* RETURNED */
735 if((cmsDecoder
== NULL
) || (cmsMessage
== NULL
)) {
738 /* any state, whether we have a msg or not is OK */
739 *cmsMessage
= cmsDecoder
->cmsMsg
;
740 return errSecSuccess
;
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.
749 OSStatus
CMSDecoderSetDecoder(
750 CMSDecoderRef cmsDecoder
,
751 SecCmsDecoderRef decoder
)
753 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
756 switch(cmsDecoder
->decState
) {
758 ASSERT(cmsDecoder
->decoder
== NULL
);
759 cmsDecoder
->decoder
= decoder
;
760 cmsDecoder
->decState
= DS_Updating
;
761 return errSecSuccess
;
766 return errSecSuccess
;
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.
775 OSStatus
CMSDecoderGetDecoder(
776 CMSDecoderRef cmsDecoder
,
777 SecCmsDecoderRef
*decoder
) /* RETURNED */
779 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
782 /* any state, whether we have a decoder or not is OK */
783 *decoder
= cmsDecoder
->decoder
;
784 return errSecSuccess
;
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.
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.
795 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
797 OSStatus
CMSDecoderCopySignerSigningTime(
798 CMSDecoderRef cmsDecoder
,
799 size_t signerIndex
, /* usually 0 */
800 CFAbsoluteTime
*signingTime
) /* RETURNED */
802 OSStatus status
= errSecParam
;
803 SecCmsMessageRef cmsg
;
804 SecCmsSignedDataRef signedData
= NULL
;
805 int numContentInfos
= 0;
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
++)
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
);
819 status
= SecCmsSignerInfoGetSigningTime(signerInfo
, signingTime
);
828 #if TIMESTAMPING_SUPPORTED
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.
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.
837 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
840 OSStatus
CMSDecoderCopySignerTimestamp(
841 CMSDecoderRef cmsDecoder
,
842 size_t signerIndex
, /* usually 0 */
843 CFAbsoluteTime
*timestamp
) /* RETURNED */
845 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder
, NULL
, signerIndex
, timestamp
);
848 OSStatus
CMSDecoderCopySignerTimestampWithPolicy(
849 CMSDecoderRef cmsDecoder
,
850 CFTypeRef timeStampPolicy
,
851 size_t signerIndex
, /* usually 0 */
852 CFAbsoluteTime
*timestamp
) /* RETURNED */
854 OSStatus status
= errSecParam
;
855 SecCmsMessageRef cmsg
;
856 SecCmsSignedDataRef signedData
= NULL
;
857 int numContentInfos
= 0;
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
++)
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
);
871 status
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);
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.
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.
891 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
893 OSStatus
CMSDecoderCopySignerTimestampCertificates(
894 CMSDecoderRef cmsDecoder
,
895 size_t signerIndex
, /* usually 0 */
896 CFArrayRef
*certificateRefs
) /* RETURNED */
898 OSStatus status
= errSecParam
;
899 SecCmsMessageRef cmsg
= NULL
;
900 SecCmsSignedDataRef signedData
= NULL
;
901 int numContentInfos
= 0;
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
++)
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
);
917 CFArrayRef certList
= SecCmsSignerInfoGetTimestampCertList(signerInfo
);
918 require_action(certList
, xit
, status
= errSecItemNotFound
);
919 CFMutableArrayRef certs
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, CFArrayGetCount(certList
), certList
);
922 //reorder certificates:
923 tsn
= CFArrayGetCount(certs
);
924 good
= tsn
> 0 && SecIsAppleTrustAnchor((SecCertificateRef
)CFArrayGetValueAtIndex(certs
, tsn
-1), 0);
928 //change TS certificate ordering.
929 for (CFIndex n
= 0; n
< tsn
; n
++)
931 SecCertificateRef tsRoot
= (SecCertificateRef
)CFArrayGetValueAtIndex(certs
, n
);
933 if ((good
= SecIsAppleTrustAnchor(tsRoot
, 0))) {
934 CFArrayExchangeValuesAtIndices(certs
, n
, tsn
-1);
940 *certificateRefs
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
942 status
= errSecSuccess
;
956 * Obtain the Hash Agility attribute value of signer 'signerIndex'
957 * of a CMS message, if present.
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.
962 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
964 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgility(
965 CMSDecoderRef cmsDecoder
,
966 size_t signerIndex
, /* usually 0 */
967 CFDataRef CF_RETURNS_RETAINED
*hashAgilityAttrValue
) /* RETURNED */
969 OSStatus status
= errSecParam
;
970 SecCmsMessageRef cmsg
;
971 SecCmsSignedDataRef signedData
= NULL
;
972 int numContentInfos
= 0;
973 CFDataRef returnedValue
= NULL
;
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
++)
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
);
987 status
= SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo
, &returnedValue
);
993 if (status
== errSecSuccess
&& returnedValue
) {
994 *hashAgilityAttrValue
= (CFDataRef
) CFRetain(returnedValue
);
996 *hashAgilityAttrValue
= NULL
;
1002 * Obtain the Hash Agility V2 attribute value of signer 'signerIndex'
1003 * of a CMS message, if present.
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.
1008 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1010 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgilityV2(
1011 CMSDecoderRef cmsDecoder
,
1012 size_t signerIndex
, /* usually 0 */
1013 CFDictionaryRef CF_RETURNS_RETAINED
*hashAgilityV2AttrValues
) /* RETURNED */
1015 OSStatus status
= errSecParam
;
1016 SecCmsMessageRef cmsg
;
1017 SecCmsSignedDataRef signedData
= NULL
;
1018 int numContentInfos
= 0;
1019 CFDictionaryRef returnedValue
= NULL
;
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
++)
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
);
1033 status
= SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(signerInfo
, &returnedValue
);
1039 if (status
== errSecSuccess
&& returnedValue
) {
1040 *hashAgilityV2AttrValues
= (CFDictionaryRef
) CFRetain(returnedValue
);
1042 *hashAgilityV2AttrValues
= NULL
;
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.
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.
1054 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1056 OSStatus
CMSDecoderCopySignerAppleExpirationTime(
1057 CMSDecoderRef cmsDecoder
,
1059 CFAbsoluteTime
*expirationTime
) /* RETURNED */
1061 OSStatus status
= errSecParam
;
1062 SecCmsMessageRef cmsg
= NULL
;
1063 int numContentInfos
= 0;
1064 SecCmsSignedDataRef signedData
= NULL
;
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
);
1076 status
= SecCmsSignerInfoGetAppleExpirationTime(signerInfo
, expirationTime
);