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 ASSERT(cmsDecoder
->arena
== NULL
);
227 ortn
= SecCmsDecoderCreate(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsDecoder
->decoder
);
229 ortn
= cmsRtnToOSStatus(ortn
);
230 CSSM_PERROR("SecCmsDecoderCreate", ortn
);
233 cmsDecoder
->decState
= DS_Updating
;
237 ASSERT(cmsDecoder
->decoder
!= NULL
);
241 /* Too late for another update */
245 dprintf("CMSDecoderUpdateMessage: bad decState\n");
246 return errSecInternalComponent
;
249 /* FIXME - CFIndex same size as size_t on 64bit? */
250 ortn
= SecCmsDecoderUpdate(cmsDecoder
->decoder
, msgBytes
, (CFIndex
)msgBytesLen
);
252 ortn
= cmsRtnToOSStatusDefault(ortn
, errSecUnknownFormat
);
253 CSSM_PERROR("SecCmsDecoderUpdate", ortn
);
259 * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
260 * finish decoding the message. We parse the message as best we can, up to
261 * but not including verifying individual signerInfos.
263 OSStatus
CMSDecoderFinalizeMessage(
264 CMSDecoderRef cmsDecoder
)
266 if(cmsDecoder
== NULL
) {
269 if(cmsDecoder
->decState
!= DS_Updating
) {
272 ASSERT(cmsDecoder
->decoder
!= NULL
);
273 OSStatus ortn
= SecCmsDecoderFinish(cmsDecoder
->decoder
, &cmsDecoder
->cmsMsg
);
274 cmsDecoder
->decState
= DS_Final
;
276 /* SecCmsDecoderFinish destroyed the decoder even on failure */
277 cmsDecoder
->decoder
= NULL
;
280 ortn
= cmsRtnToOSStatusDefault(ortn
, errSecUnknownFormat
);
281 CSSM_PERROR("SecCmsDecoderFinish", ortn
);
285 ASSERT(cmsDecoder
->cmsMsg
!= NULL
);
286 cmsDecoder
->wasEncrypted
= SecCmsMessageIsEncrypted(cmsDecoder
->cmsMsg
);
288 /* Look for a SignedData */
289 int numContentInfos
= SecCmsMessageContentLevelCount(cmsDecoder
->cmsMsg
);
291 for(dex
=0; dex
<numContentInfos
; dex
++) {
292 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsDecoder
->cmsMsg
, dex
);
293 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
295 case SEC_OID_PKCS7_SIGNED_DATA
:
296 cmsDecoder
->signedData
=
297 (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
);
298 /* dig down one more layer for eContentType */
299 ci
= SecCmsSignedDataGetContentInfo(cmsDecoder
->signedData
);
301 cmsDecoder
->eContentType
= SecCmsContentInfoGetContentTypeOID(ci
);
307 if(cmsDecoder
->signedData
!= NULL
) {
313 /* minimal processing of optional signedData... */
314 if(cmsDecoder
->signedData
!= NULL
) {
315 cmsDecoder
->numSigners
= (size_t)
316 SecCmsSignedDataSignerInfoCount(cmsDecoder
->signedData
);
317 if(cmsDecoder
->detachedContent
!= NULL
) {
318 /* time to calculate digests from detached content */
319 ortn
= cmsDigestDetachedContent(cmsDecoder
);
326 * A signed CMS message optionally includes the data which was signed. If the
327 * message does not include the signed data, caller specifies the signed data
328 * (the "detached content") here.
330 * This can be called either before or after the actual decoding of the message
331 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
332 * restriction is that, if detached content is required, this function must
333 * be called befoere successfully ascertaining the signature status via
334 * CMSDecoderCopySignerStatus().
336 OSStatus
CMSDecoderSetDetachedContent(
337 CMSDecoderRef cmsDecoder
,
338 CFDataRef detachedContent
)
340 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
343 cmsDecoder
->detachedContent
= detachedContent
;
344 CFRetain(detachedContent
);
346 if(cmsDecoder
->signedData
!= NULL
) {
347 /* time to calculate digests from detached content */
348 ASSERT(cmsDecoder
->decState
== DS_Final
);
349 return cmsDigestDetachedContent(cmsDecoder
);
351 return errSecSuccess
;
355 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
356 * Returns a NULL detachedContent if no detached content has been specified.
357 * Caller must CFRelease() the result.
359 OSStatus
CMSDecoderCopyDetachedContent(
360 CMSDecoderRef cmsDecoder
,
361 CFDataRef
*detachedContent
) /* RETURNED */
363 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
366 if(cmsDecoder
->detachedContent
!= NULL
) {
367 CFRetain(cmsDecoder
->detachedContent
);
369 *detachedContent
= cmsDecoder
->detachedContent
;
370 return errSecSuccess
;
374 * Obtain the number of signers of a message. A result of zero indicates that
375 * the message was not signed.
377 OSStatus
CMSDecoderGetNumSigners(
378 CMSDecoderRef cmsDecoder
,
379 size_t *numSigners
) /* RETURNED */
381 if((cmsDecoder
== NULL
) || (numSigners
== NULL
)) {
384 if(cmsDecoder
->decState
!= DS_Final
) {
387 *numSigners
= cmsDecoder
->numSigners
;
388 return errSecSuccess
;
392 * Obtain the status of a CMS message's signature. A CMS message can
393 * be signed my multiple signers; this function returns the status
394 * associated with signer 'n' as indicated by the signerIndex parameter.
396 OSStatus
CMSDecoderCopySignerStatus(
397 CMSDecoderRef cmsDecoder
,
399 CFTypeRef policyOrArray
,
400 Boolean evaluateSecTrust
,
401 CMSSignerStatus
*signerStatus
, /* optional; RETURNED */
402 SecTrustRef
*secTrust
, /* optional; RETURNED */
403 OSStatus
*certVerifyResultCode
) /* optional; RETURNED */
405 if((cmsDecoder
== NULL
) || (cmsDecoder
->decState
!= DS_Final
) || (!policyOrArray
) || !signerStatus
) {
409 /* initialize return values */
411 *signerStatus
= kCMSSignerUnsigned
;
416 if(certVerifyResultCode
) {
417 *certVerifyResultCode
= 0;
420 if(cmsDecoder
->signedData
== NULL
) {
421 *signerStatus
= kCMSSignerUnsigned
; /* redundant, I know, but explicit */
422 return errSecSuccess
;
424 ASSERT(cmsDecoder
->numSigners
> 0);
425 if(signerIndex
>= cmsDecoder
->numSigners
) {
426 *signerStatus
= kCMSSignerInvalidIndex
;
427 return errSecSuccess
;
429 if(!SecCmsSignedDataHasDigests(cmsDecoder
->signedData
)) {
430 *signerStatus
= kCMSSignerNeedsDetachedContent
;
431 return errSecSuccess
;
435 * OK, we should be able to verify this signerInfo.
436 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
437 * in order get all the cert pieces into place before returning them
440 SecTrustRef theTrust
= NULL
;
441 OSStatus vfyRtn
= SecCmsSignedDataVerifySignerInfo(cmsDecoder
->signedData
,
447 #if SECTRUST_VERBOSE_DEBUG
448 syslog(LOG_ERR
, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn
);
449 if (policyOrArray
) CFShow(policyOrArray
);
450 if (theTrust
) CFShow(theTrust
);
453 /* Subsequent errors to errOut: */
456 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
457 * SecTrustEvaluate() if we don't ask for a copy.
459 * FIXME deal with multitudes of status returns here...for now, proceed with
460 * obtaining components the caller wants and assume that a nonzero vfyRtn
461 * means "bad signature".
463 OSStatus ortn
= errSecSuccess
;
464 SecTrustResultType secTrustResult
;
465 OSStatus evalRtn
, verifyStatus
= errSecSuccess
;
467 if(secTrust
!= NULL
) {
468 *secTrust
= theTrust
;
469 /* we'll release our reference at the end */
470 CFRetainSafe(theTrust
);
472 SecCmsSignerInfoRef signerInfo
=
473 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
474 if(signerInfo
== NULL
) {
475 /* should never happen */
477 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
478 ortn
= errSecInternalComponent
;
482 /* now do the actual cert verify */
483 if(evaluateSecTrust
) {
484 evalRtn
= SecTrustEvaluate(theTrust
, &secTrustResult
);
486 /* should never happen */
487 CSSM_PERROR("SecTrustEvaluate", evalRtn
);
488 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
489 ortn
= errSecInternalComponent
;
492 switch(secTrustResult
) {
493 case kSecTrustResultUnspecified
:
494 /* cert chain valid, no special UserTrust assignments */
495 case kSecTrustResultProceed
:
496 /* cert chain valid AND user explicitly trusts this */
498 case kSecTrustResultDeny
:
499 verifyStatus
= errSecTrustSettingDeny
;
503 verifyStatus
= errSecNotTrusted
;
506 } /* switch(secTrustResult) */
507 } /* evaluateSecTrust true */
508 if(certVerifyResultCode
!= NULL
) {
509 *certVerifyResultCode
= verifyStatus
;
512 /* cook up global status based on vfyRtn and tpVfyStatus */
513 if(signerStatus
!= NULL
) {
514 if((vfyRtn
== errSecSuccess
) && (verifyStatus
== errSecSuccess
)) {
515 *signerStatus
= kCMSSignerValid
;
517 else if(vfyRtn
!= errSecSuccess
) {
518 /* this could mean other things, but for now... */
519 *signerStatus
= kCMSSignerInvalidSignature
;
522 *signerStatus
= kCMSSignerInvalidCert
;
531 * Obtain the email address of signer 'signerIndex' of a CMS message, if
534 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
536 OSStatus
CMSDecoderCopySignerEmailAddress(
537 CMSDecoderRef cmsDecoder
,
539 CFStringRef
*signerEmailAddress
) /* RETURNED */
541 if((cmsDecoder
== NULL
) ||
542 (signerEmailAddress
== NULL
) ||
543 (cmsDecoder
->signedData
== NULL
) || /* not signed */
544 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
545 (cmsDecoder
->decState
!= DS_Final
)) {
549 SecCmsSignerInfoRef signerInfo
=
550 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
551 if(signerInfo
== NULL
) {
552 /* should never happen */
554 dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
555 return errSecInternalComponent
;
559 * This is leaking memory in libsecurityKeychain per Radar 4412699.
561 *signerEmailAddress
= SecCmsSignerInfoGetSignerEmailAddress(signerInfo
);
562 return errSecSuccess
;
566 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
569 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
571 OSStatus
CMSDecoderCopySignerCert(
572 CMSDecoderRef cmsDecoder
,
574 SecCertificateRef
*signerCert
) /* RETURNED */
576 if((cmsDecoder
== NULL
) ||
577 (signerCert
== NULL
) ||
578 (cmsDecoder
->signedData
== NULL
) || /* not signed */
579 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
580 (cmsDecoder
->decState
!= DS_Final
)) {
584 SecCmsSignerInfoRef signerInfo
=
585 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
586 if(signerInfo
== NULL
) {
587 /* should never happen */
589 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
590 return errSecInternalComponent
;
592 *signerCert
= SecCmsSignerInfoGetSigningCertificate(signerInfo
, NULL
);
593 /* libsecurity_smime does NOT retain that */
594 if(*signerCert
== NULL
) {
595 /* should never happen */
597 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
598 return errSecInternalComponent
;
600 CFRetain(*signerCert
);
601 return errSecSuccess
;
605 * Determine whether a CMS message was encrypted, and if so, whether we were
606 * able to decrypt it.
608 OSStatus
CMSDecoderIsContentEncrypted(
609 CMSDecoderRef cmsDecoder
,
610 Boolean
*wasEncrypted
)
612 if((cmsDecoder
== NULL
) || (wasEncrypted
== NULL
)) {
615 if(cmsDecoder
->decState
!= DS_Final
) {
618 *wasEncrypted
= cmsDecoder
->wasEncrypted
;
619 return errSecSuccess
;
623 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
626 OSStatus
CMSDecoderCopyEncapsulatedContentType(
627 CMSDecoderRef cmsDecoder
,
628 CFDataRef
*eContentType
) /* RETURNED */
630 if((cmsDecoder
== NULL
) || (eContentType
== NULL
)) {
633 if(cmsDecoder
->decState
!= DS_Final
) {
636 if(cmsDecoder
->signedData
== NULL
) {
637 *eContentType
= NULL
;
640 SecAsn1Oid
*ecOid
= cmsDecoder
->eContentType
;
641 *eContentType
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
);
643 return errSecSuccess
;
647 * Obtain an array of all of the certificates in a message. Elements of the
648 * returned array are SecCertificateRefs. The caller must CFRelease the returned
650 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
652 OSStatus
CMSDecoderCopyAllCerts(
653 CMSDecoderRef cmsDecoder
,
654 CFArrayRef
*certs
) /* RETURNED */
656 if((cmsDecoder
== NULL
) || (certs
== NULL
)) {
659 if(cmsDecoder
->decState
!= DS_Final
) {
662 if(cmsDecoder
->signedData
== NULL
) {
663 /* message wasn't signed */
665 return errSecSuccess
;
668 /* NULL_terminated array of CSSM_DATA ptrs */
669 SecAsn1Item
**cssmCerts
= SecCmsSignedDataGetCertificateList(cmsDecoder
->signedData
);
670 if((cssmCerts
== NULL
) || (*cssmCerts
== NULL
)) {
672 return errSecSuccess
;
675 CFMutableArrayRef allCerts
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
676 SecAsn1Item
**cssmCert
;
677 for(cssmCert
=cssmCerts
; *cssmCert
!=NULL
; cssmCert
++) {
678 SecCertificateRef cfCert
= SecCertificateCreateWithBytes(NULL
, (*cssmCert
)->Data
, (*cssmCert
)->Length
);
683 CFArrayAppendValue(allCerts
, cfCert
);
684 /* the array holds the only needed refcount */
688 return errSecSuccess
;
692 * Obtain the actual message content (payload), if any. If the message was
693 * signed with detached content this will return NULL.
694 * Caller must CFRelease the result.
696 OSStatus
CMSDecoderCopyContent(
697 CMSDecoderRef cmsDecoder
,
698 CFDataRef
*content
) /* RETURNED */
700 if((cmsDecoder
== NULL
) || (content
== NULL
)) {
703 if(cmsDecoder
->decState
!= DS_Final
) {
706 if(cmsDecoder
->cmsMsg
== NULL
) {
707 /* Hmmm....looks like the finalize call failed */
710 const SecAsn1Item
*odata
= SecCmsMessageGetContent(cmsDecoder
->cmsMsg
);
711 if((odata
== NULL
) || (odata
->Length
== 0)) {
712 /* i.e., detached content */
714 return errSecSuccess
;
716 *content
= CFDataCreate(NULL
, (const UInt8
*)odata
->Data
, odata
->Length
);
717 return errSecSuccess
;
720 #pragma mark --- SPI declared in CMSPrivate.h ---
723 * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
724 * to be called after decoding the message (i.e., after
725 * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
726 * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
727 * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
730 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
732 OSStatus
CMSDecoderGetCmsMessage(
733 CMSDecoderRef cmsDecoder
,
734 SecCmsMessageRef
*cmsMessage
) /* RETURNED */
736 if((cmsDecoder
== NULL
) || (cmsMessage
== NULL
)) {
739 /* any state, whether we have a msg or not is OK */
740 *cmsMessage
= cmsDecoder
->cmsMsg
;
741 return errSecSuccess
;
745 * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
746 * If this is called, it must be called before the first call to
747 * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
748 * incoming SecCmsDecoderRef.
750 OSStatus
CMSDecoderSetDecoder(
751 CMSDecoderRef cmsDecoder
,
752 SecCmsDecoderRef decoder
)
754 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
757 switch(cmsDecoder
->decState
) {
759 ASSERT(cmsDecoder
->decoder
== NULL
);
760 cmsDecoder
->decoder
= decoder
;
761 cmsDecoder
->decState
= DS_Updating
;
762 return errSecSuccess
;
767 return errSecSuccess
;
771 * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
772 * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
773 * CMSDecoderUpdateMessage() has been called.
774 * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
776 OSStatus
CMSDecoderGetDecoder(
777 CMSDecoderRef cmsDecoder
,
778 SecCmsDecoderRef
*decoder
) /* RETURNED */
780 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
783 /* any state, whether we have a decoder or not is OK */
784 *decoder
= cmsDecoder
->decoder
;
785 return errSecSuccess
;
789 * Obtain the signing time of signer 'signerIndex' of a CMS message, if
790 * present. This is an unauthenticate time, although it is part of the
791 * signed attributes of the message.
793 * Returns errSecParam if the CMS message was not signed or if signerIndex
794 * is greater than the number of signers of the message minus one.
796 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
798 OSStatus
CMSDecoderCopySignerSigningTime(
799 CMSDecoderRef cmsDecoder
,
800 size_t signerIndex
, /* usually 0 */
801 CFAbsoluteTime
*signingTime
) /* RETURNED */
803 OSStatus status
= errSecParam
;
804 SecCmsMessageRef cmsg
;
805 SecCmsSignedDataRef signedData
= NULL
;
806 int numContentInfos
= 0;
808 require(cmsDecoder
&& signingTime
, xit
);
809 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
810 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
811 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
813 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
814 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
815 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
816 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
817 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
820 status
= SecCmsSignerInfoGetSigningTime(signerInfo
, signingTime
);
829 #if TIMESTAMPING_SUPPORTED
831 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
832 * present. This timestamp is an authenticated timestamp provided by
833 * a timestamping authority.
835 * Returns errSecParam if the CMS message was not signed or if signerIndex
836 * is greater than the number of signers of the message minus one.
838 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
841 OSStatus
CMSDecoderCopySignerTimestamp(
842 CMSDecoderRef cmsDecoder
,
843 size_t signerIndex
, /* usually 0 */
844 CFAbsoluteTime
*timestamp
) /* RETURNED */
846 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder
, NULL
, signerIndex
, timestamp
);
849 OSStatus
CMSDecoderCopySignerTimestampWithPolicy(
850 CMSDecoderRef cmsDecoder
,
851 CFTypeRef timeStampPolicy
,
852 size_t signerIndex
, /* usually 0 */
853 CFAbsoluteTime
*timestamp
) /* RETURNED */
855 OSStatus status
= errSecParam
;
856 SecCmsMessageRef cmsg
;
857 SecCmsSignedDataRef signedData
= NULL
;
858 int numContentInfos
= 0;
860 require(cmsDecoder
&& timestamp
, xit
);
861 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
862 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
863 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
865 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
866 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
867 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
868 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
869 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
872 status
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);
883 * Obtain an array of the certificates in a timestamp response. Elements of the
884 * returned array are SecCertificateRefs. The caller must CFRelease the returned
885 * array. This timestamp is an authenticated timestamp provided by
886 * a timestamping authority.
888 * Returns errSecParam if the CMS message was not signed or if signerIndex
889 * is greater than the number of signers of the message minus one. It returns
890 * errSecItemNotFound if no certificates were found.
892 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
894 OSStatus
CMSDecoderCopySignerTimestampCertificates(
895 CMSDecoderRef cmsDecoder
,
896 size_t signerIndex
, /* usually 0 */
897 CFArrayRef
*certificateRefs
) /* RETURNED */
899 OSStatus status
= errSecParam
;
900 SecCmsMessageRef cmsg
= NULL
;
901 SecCmsSignedDataRef signedData
= NULL
;
902 int numContentInfos
= 0;
906 require(cmsDecoder
&& certificateRefs
, xit
);
907 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
908 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
909 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
911 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
912 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
913 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
914 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
915 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
918 CFArrayRef certList
= SecCmsSignerInfoGetTimestampCertList(signerInfo
);
919 require_action(certList
, xit
, status
= errSecItemNotFound
);
920 CFMutableArrayRef certs
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, CFArrayGetCount(certList
), certList
);
923 //reorder certificates:
924 tsn
= CFArrayGetCount(certs
);
925 good
= tsn
> 0 && SecIsAppleTrustAnchor((SecCertificateRef
)CFArrayGetValueAtIndex(certs
, tsn
-1), 0);
929 //change TS certificate ordering.
930 for (CFIndex n
= 0; n
< tsn
; n
++)
932 SecCertificateRef tsRoot
= (SecCertificateRef
)CFArrayGetValueAtIndex(certs
, n
);
934 if ((good
= SecIsAppleTrustAnchor(tsRoot
, 0))) {
935 CFArrayExchangeValuesAtIndices(certs
, n
, tsn
-1);
941 *certificateRefs
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
943 status
= errSecSuccess
;
957 * Obtain the Hash Agility attribute value of signer 'signerIndex'
958 * of a CMS message, if present.
960 * Returns errSecParam if the CMS message was not signed or if signerIndex
961 * is greater than the number of signers of the message minus one.
963 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
965 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgility(
966 CMSDecoderRef cmsDecoder
,
967 size_t signerIndex
, /* usually 0 */
968 CFDataRef CF_RETURNS_RETAINED
*hashAgilityAttrValue
) /* RETURNED */
970 OSStatus status
= errSecParam
;
971 SecCmsMessageRef cmsg
;
972 SecCmsSignedDataRef signedData
= NULL
;
973 int numContentInfos
= 0;
974 CFDataRef returnedValue
= NULL
;
976 require(cmsDecoder
&& hashAgilityAttrValue
, exit
);
977 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), exit
);
978 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
979 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
981 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
982 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
983 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
984 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
985 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
988 status
= SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo
, &returnedValue
);
994 if (status
== errSecSuccess
&& returnedValue
) {
995 *hashAgilityAttrValue
= (CFDataRef
) CFRetain(returnedValue
);
997 *hashAgilityAttrValue
= NULL
;
1003 * Obtain the Hash Agility V2 attribute value of signer 'signerIndex'
1004 * of a CMS message, if present.
1006 * Returns errSecParam if the CMS message was not signed or if signerIndex
1007 * is greater than the number of signers of the message minus one.
1009 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1011 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgilityV2(
1012 CMSDecoderRef cmsDecoder
,
1013 size_t signerIndex
, /* usually 0 */
1014 CFDictionaryRef CF_RETURNS_RETAINED
*hashAgilityV2AttrValues
) /* RETURNED */
1016 OSStatus status
= errSecParam
;
1017 SecCmsMessageRef cmsg
;
1018 SecCmsSignedDataRef signedData
= NULL
;
1019 int numContentInfos
= 0;
1020 CFDictionaryRef returnedValue
= NULL
;
1022 require(cmsDecoder
&& hashAgilityV2AttrValues
, exit
);
1023 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), exit
);
1024 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1025 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
1027 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1028 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1029 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
1030 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
1031 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
1034 status
= SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(signerInfo
, &returnedValue
);
1040 if (status
== errSecSuccess
&& returnedValue
) {
1041 *hashAgilityV2AttrValues
= (CFDictionaryRef
) CFRetain(returnedValue
);
1043 *hashAgilityV2AttrValues
= NULL
;
1049 * Obtain the expiration time of signer 'signerIndex' of a CMS message, if
1050 * present. This is part of the signed attributes of the message.
1052 * Returns errSecParam if the CMS message was not signed or if signerIndex
1053 * is greater than the number of signers of the message minus one.
1055 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1057 OSStatus
CMSDecoderCopySignerAppleExpirationTime(
1058 CMSDecoderRef cmsDecoder
,
1060 CFAbsoluteTime
*expirationTime
) /* RETURNED */
1062 OSStatus status
= errSecParam
;
1063 SecCmsMessageRef cmsg
= NULL
;
1064 int numContentInfos
= 0;
1065 SecCmsSignedDataRef signedData
= NULL
;
1067 require(cmsDecoder
&& expirationTime
, xit
);
1068 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
1069 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1070 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++) {
1071 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1072 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1073 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
) {
1074 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
1075 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
1077 status
= SecCmsSignerInfoGetAppleExpirationTime(signerInfo
, expirationTime
);