2 * Copyright (c) 2006-2014 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.cpp - Interface for decoding CMS messages.
28 #include <Security/CMSDecoder.h>
29 #include <Security/CMSPrivate.h>
31 #include <../libsecurity_codesigning/lib/csutilities.h>
33 #include <Security/SecCmsDecoder.h>
34 #include <Security/SecCmsEnvelopedData.h>
35 #include <Security/SecCmsMessage.h>
36 #include <Security/SecCmsSignedData.h>
37 #include <Security/SecCmsSignerInfo.h>
38 #include <Security/SecCmsContentInfo.h>
39 #include <Security/SecCmsDigestContext.h>
40 #include <Security/SecCertificate.h>
41 #include <Security/SecSMIME.h>
42 #include <Security/oidsattr.h>
43 #include <Security/SecTrustPriv.h>
44 #include <CoreFoundation/CFRuntime.h>
45 #include <utilities/SecCFWrappers.h>
48 #include <AssertMacros.h>
50 #pragma mark --- Private types and definitions ---
56 DS_Init
, /* between CMSDecoderCreate and CMSDecoderUpdateMessage */
57 DS_Updating
, /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */
58 DS_Final
/* CMSDecoderFinalizeMessage has been called */
62 * Caller's CMSDecoderRef points to one of these.
66 CMSDecoderState decState
;
67 SecArenaPoolRef arena
; /* the decoder's arena */
68 SecCmsDecoderRef decoder
;
69 CFDataRef detachedContent
;
70 CFTypeRef keychainOrArray
; /* unused */
73 * The following are valid (and quiescent) after CMSDecoderFinalizeMessage().
75 SecCmsMessageRef cmsMsg
;
76 Boolean wasEncrypted
; /* valid after CMSDecoderFinalizeMessage() */
77 SecCmsSignedDataRef signedData
; /* if there is one... */
78 /* only non-NULL if we found a signedData */
80 CSSM_OID
*eContentType
;
84 static void cmsDecoderInit(CFTypeRef dec
);
85 static void cmsDecoderFinalize(CFTypeRef dec
);
87 static CFRuntimeClass cmsDecoderRuntimeClass
=
94 NULL
, /* equal - just use pointer equality */
95 NULL
, /* hash, ditto */
96 NULL
, /* copyFormattingDesc */
97 NULL
/* copyDebugDesc */
100 #pragma mark --- Private Routines ---
102 static CFTypeID cmsDecoderTypeID
= _kCFRuntimeNotATypeID
;
104 /* one time only class init, called via pthread_once() in CMSDecoderGetTypeID() */
105 static void cmsDecoderClassInitialize(void)
108 _CFRuntimeRegisterClass((const CFRuntimeClass
* const)&cmsDecoderRuntimeClass
);
111 /* init called out from _CFRuntimeCreateInstance() */
112 static void cmsDecoderInit(CFTypeRef dec
)
114 char *start
= ((char *)dec
) + sizeof(CFRuntimeBase
);
115 memset(start
, 0, sizeof(struct _CMSDecoder
) - sizeof(CFRuntimeBase
));
119 * Dispose of a CMSDecoder. Called out from CFRelease().
121 static void cmsDecoderFinalize(
124 CMSDecoderRef cmsDecoder
= (CMSDecoderRef
)dec
;
125 if(cmsDecoder
== NULL
) {
128 if(cmsDecoder
->decoder
!= NULL
) {
130 * Normally this gets freed in SecCmsDecoderFinish - this is
131 * an error case. Unlike Finish, this calls SecCmsMessageDestroy.
133 SecCmsDecoderDestroy(cmsDecoder
->decoder
);
134 cmsDecoder
->cmsMsg
= NULL
;
136 CFRELEASE(cmsDecoder
->detachedContent
);
137 CFRELEASE(cmsDecoder
->keychainOrArray
);
138 if(cmsDecoder
->cmsMsg
!= NULL
) {
139 SecCmsMessageDestroy(cmsDecoder
->cmsMsg
);
140 cmsDecoder
->cmsMsg
= NULL
;
142 if(cmsDecoder
->arena
!= NULL
) {
143 SecArenaPoolFree(cmsDecoder
->arena
, false);
144 cmsDecoder
->arena
= NULL
;
150 * Given detached content and a valid (decoded) SignedData, digest the detached
151 * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a
152 * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent()
153 * when we already have a SignedData).
155 static OSStatus
cmsDigestDetachedContent(
156 CMSDecoderRef cmsDecoder
)
158 ASSERT((cmsDecoder
->signedData
!= NULL
) && (cmsDecoder
->detachedContent
!= NULL
));
160 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(cmsDecoder
->signedData
);
161 if(digestAlgorithms
== NULL
) {
162 return errSecUnknownFormat
;
164 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestAlgorithms
);
166 return errSecAllocate
;
168 CSSM_DATA
**digests
= NULL
;
170 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(cmsDecoder
->detachedContent
),
171 CFDataGetLength(cmsDecoder
->detachedContent
));
172 /* note this frees the digest content regardless */
173 OSStatus ortn
= SecCmsDigestContextFinishMultiple(digcx
, cmsDecoder
->arena
, &digests
);
175 ortn
= cmsRtnToOSStatus(ortn
);
176 CSSM_PERROR("SecCmsDigestContextFinishMultiple", ortn
);
179 ortn
= SecCmsSignedDataSetDigests(cmsDecoder
->signedData
, digestAlgorithms
, digests
);
181 ortn
= cmsRtnToOSStatus(ortn
);
182 CSSM_PERROR("SecCmsSignedDataSetDigests", ortn
);
187 #pragma mark --- Start of Public API ---
189 CFTypeID
CMSDecoderGetTypeID(void)
191 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
193 if(cmsDecoderTypeID
== _kCFRuntimeNotATypeID
) {
194 pthread_once(&once
, &cmsDecoderClassInitialize
);
196 return cmsDecoderTypeID
;
200 * Create a CMSDecoder. Result must eventually be freed via CFRelease().
202 OSStatus
CMSDecoderCreate(
203 CMSDecoderRef
*cmsDecoderOut
) /* RETURNED */
205 CMSDecoderRef cmsDecoder
= NULL
;
207 uint32_t extra
= sizeof(*cmsDecoder
) - sizeof(cmsDecoder
->base
);
208 cmsDecoder
= (CMSDecoderRef
)_CFRuntimeCreateInstance(NULL
, CMSDecoderGetTypeID(),
210 if(cmsDecoder
== NULL
) {
211 return errSecAllocate
;
213 cmsDecoder
->decState
= DS_Init
;
214 *cmsDecoderOut
= cmsDecoder
;
215 return errSecSuccess
;
219 * Feed raw bytes of the message to be decoded into the decoder. Can be called
222 OSStatus
CMSDecoderUpdateMessage(
223 CMSDecoderRef cmsDecoder
,
224 const void *msgBytes
,
227 if(cmsDecoder
== NULL
) {
232 switch(cmsDecoder
->decState
) {
234 /* First time through; set up */
235 ASSERT(cmsDecoder
->decoder
== NULL
);
236 ASSERT(cmsDecoder
->arena
== NULL
);
237 ortn
= SecArenaPoolCreate(1024, &cmsDecoder
->arena
);
239 return cmsRtnToOSStatus(ortn
);
241 ortn
= SecCmsDecoderCreate(cmsDecoder
->arena
,
242 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsDecoder
->decoder
);
244 ortn
= cmsRtnToOSStatus(ortn
);
245 CSSM_PERROR("SecCmsDecoderCreate", ortn
);
248 cmsDecoder
->decState
= DS_Updating
;
252 ASSERT(cmsDecoder
->decoder
!= NULL
);
256 /* Too late for another update */
260 dprintf("CMSDecoderUpdateMessage: bad decState\n");
261 return errSecInternalComponent
;
264 /* FIXME - CFIndex same size as size_t on 64bit? */
265 ortn
= SecCmsDecoderUpdate(cmsDecoder
->decoder
, msgBytes
, (CFIndex
)msgBytesLen
);
267 ortn
= cmsRtnToOSStatus(ortn
, errSecUnknownFormat
);
268 CSSM_PERROR("SecCmsDecoderUpdate", ortn
);
274 * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
275 * finish decoding the message. We parse the message as best we can, up to
276 * but not including verifying individual signerInfos.
278 OSStatus
CMSDecoderFinalizeMessage(
279 CMSDecoderRef cmsDecoder
)
281 if(cmsDecoder
== NULL
) {
284 if(cmsDecoder
->decState
!= DS_Updating
) {
287 ASSERT(cmsDecoder
->decoder
!= NULL
);
288 OSStatus ortn
= SecCmsDecoderFinish(cmsDecoder
->decoder
, &cmsDecoder
->cmsMsg
);
289 cmsDecoder
->decState
= DS_Final
;
291 /* SecCmsDecoderFinish destroyed the decoder even on failure */
292 cmsDecoder
->decoder
= NULL
;
295 ortn
= cmsRtnToOSStatus(ortn
, errSecUnknownFormat
);
296 CSSM_PERROR("SecCmsDecoderFinish", ortn
);
300 ASSERT(cmsDecoder
->cmsMsg
!= NULL
);
301 cmsDecoder
->wasEncrypted
= SecCmsMessageIsEncrypted(cmsDecoder
->cmsMsg
);
303 /* Look for a SignedData */
304 int numContentInfos
= SecCmsMessageContentLevelCount(cmsDecoder
->cmsMsg
);
306 for(dex
=0; dex
<numContentInfos
; dex
++) {
307 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsDecoder
->cmsMsg
, dex
);
308 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
310 case SEC_OID_PKCS7_SIGNED_DATA
:
311 cmsDecoder
->signedData
=
312 (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
);
313 /* dig down one more layer for eContentType */
314 ci
= SecCmsSignedDataGetContentInfo(cmsDecoder
->signedData
);
316 cmsDecoder
->eContentType
= SecCmsContentInfoGetContentTypeOID(ci
);
322 if(cmsDecoder
->signedData
!= NULL
) {
328 /* minimal processing of optional signedData... */
329 if(cmsDecoder
->signedData
!= NULL
) {
330 cmsDecoder
->numSigners
= (size_t)
331 SecCmsSignedDataSignerInfoCount(cmsDecoder
->signedData
);
332 if(cmsDecoder
->detachedContent
!= NULL
) {
333 /* time to calculate digests from detached content */
334 ortn
= cmsDigestDetachedContent(cmsDecoder
);
341 * A signed CMS message optionally includes the data which was signed. If the
342 * message does not include the signed data, caller specifies the signed data
343 * (the "detached content") here.
345 * This can be called either before or after the actual decoding of the message
346 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
347 * restriction is that, if detached content is required, this function must
348 * be called befoere successfully ascertaining the signature status via
349 * CMSDecoderCopySignerStatus().
351 OSStatus
CMSDecoderSetDetachedContent(
352 CMSDecoderRef cmsDecoder
,
353 CFDataRef detachedContent
)
355 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
358 cmsDecoder
->detachedContent
= detachedContent
;
359 CFRetain(detachedContent
);
361 if(cmsDecoder
->signedData
!= NULL
) {
362 /* time to calculate digests from detached content */
363 ASSERT(cmsDecoder
->decState
== DS_Final
);
364 return cmsDigestDetachedContent(cmsDecoder
);
366 return errSecSuccess
;
370 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
371 * Returns a NULL detachedContent if no detached content has been specified.
372 * Caller must CFRelease() the result.
374 OSStatus
CMSDecoderCopyDetachedContent(
375 CMSDecoderRef cmsDecoder
,
376 CFDataRef
*detachedContent
) /* RETURNED */
378 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
381 if(cmsDecoder
->detachedContent
!= NULL
) {
382 CFRetain(cmsDecoder
->detachedContent
);
384 *detachedContent
= cmsDecoder
->detachedContent
;
385 return errSecSuccess
;
389 * Beginning in 10.12, this function stopped affecting the behavior of the
390 * CMS Decoder. Its only use was in SecTrustSetKeychains which is a no-op.
391 * Please discontinue use.
393 OSStatus
CMSDecoderSetSearchKeychain(
394 CMSDecoderRef cmsDecoder
,
395 CFTypeRef keychainOrArray
)
397 return errSecSuccess
;
401 * Obtain the number of signers of a message. A result of zero indicates that
402 * the message was not signed.
404 OSStatus
CMSDecoderGetNumSigners(
405 CMSDecoderRef cmsDecoder
,
406 size_t *numSigners
) /* RETURNED */
408 if((cmsDecoder
== NULL
) || (numSigners
== NULL
)) {
411 if(cmsDecoder
->decState
!= DS_Final
) {
414 *numSigners
= cmsDecoder
->numSigners
;
415 return errSecSuccess
;
419 * Obtain the status of a CMS message's signature. A CMS message can
420 * be signed my multiple signers; this function returns the status
421 * associated with signer 'n' as indicated by the signerIndex parameter.
423 OSStatus
CMSDecoderCopySignerStatus(
424 CMSDecoderRef cmsDecoder
,
426 CFTypeRef policyOrArray
,
427 Boolean evaluateSecTrust
,
428 CMSSignerStatus
*signerStatus
, /* optional; RETURNED */
429 SecTrustRef
*secTrust
, /* optional; RETURNED */
430 OSStatus
*certVerifyResultCode
) /* optional; RETURNED */
432 if((cmsDecoder
== NULL
) || (cmsDecoder
->decState
!= DS_Final
) || (!policyOrArray
) || !signerStatus
) {
436 /* initialize return values */
438 *signerStatus
= kCMSSignerUnsigned
;
443 if(certVerifyResultCode
) {
444 *certVerifyResultCode
= 0;
447 if(cmsDecoder
->signedData
== NULL
) {
448 *signerStatus
= kCMSSignerUnsigned
; /* redundant, I know, but explicit */
449 return errSecSuccess
;
451 ASSERT(cmsDecoder
->numSigners
> 0);
452 if(signerIndex
>= cmsDecoder
->numSigners
) {
453 *signerStatus
= kCMSSignerInvalidIndex
;
454 return errSecSuccess
;
456 if(!SecCmsSignedDataHasDigests(cmsDecoder
->signedData
)) {
457 *signerStatus
= kCMSSignerNeedsDetachedContent
;
458 return errSecSuccess
;
462 * OK, we should be able to verify this signerInfo.
463 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
464 * in order get all the cert pieces into place before returning them
467 SecTrustRef theTrust
= NULL
;
468 OSStatus vfyRtn
= SecCmsSignedDataVerifySignerInfo(cmsDecoder
->signedData
,
474 #if SECTRUST_VERBOSE_DEBUG
475 syslog(LOG_ERR
, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn
);
476 if (policyOrArray
) CFShow(policyOrArray
);
477 if (theTrust
) CFShow(theTrust
);
480 /* Subsequent errors to errOut: */
483 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
484 * SecTrustEvaluate() if we don't ask for a copy.
486 * FIXME deal with multitudes of status returns here...for now, proceed with
487 * obtaining components the caller wants and assume that a nonzero vfyRtn
488 * means "bad signature".
490 OSStatus ortn
= errSecSuccess
;
491 SecTrustResultType secTrustResult
;
492 CSSM_RETURN tpVfyStatus
= CSSM_OK
;
495 if(secTrust
!= NULL
) {
496 *secTrust
= theTrust
;
497 /* we'll release our reference at the end */
498 CFRetainSafe(theTrust
);
500 SecCmsSignerInfoRef signerInfo
=
501 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
502 if(signerInfo
== NULL
) {
503 /* should never happen */
505 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
506 ortn
= errSecInternalComponent
;
510 /* now do the actual cert verify */
511 if(evaluateSecTrust
) {
512 evalRtn
= SecTrustEvaluate(theTrust
, &secTrustResult
);
514 /* should never happen */
515 CSSM_PERROR("SecTrustEvaluate", evalRtn
);
516 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
517 ortn
= errSecInternalComponent
;
520 switch(secTrustResult
) {
521 case kSecTrustResultUnspecified
:
522 /* cert chain valid, no special UserTrust assignments */
523 case kSecTrustResultProceed
:
524 /* cert chain valid AND user explicitly trusts this */
526 case kSecTrustResultDeny
:
527 tpVfyStatus
= CSSMERR_APPLETP_TRUST_SETTING_DENY
;
531 /* get low-level TP error */
533 ortn
= SecTrustGetCssmResultCode(theTrust
, &tpStatus
);
535 CSSM_PERROR("SecTrustGetCssmResultCode", ortn
);
538 tpVfyStatus
= tpStatus
;
540 CSSM_PERROR("TP status after SecTrustEvaluate", tpVfyStatus
);
543 } /* switch(secTrustResult) */
544 } /* evaluateSecTrust true */
545 if(certVerifyResultCode
!= NULL
) {
546 *certVerifyResultCode
= tpVfyStatus
;
549 /* cook up global status based on vfyRtn and tpVfyStatus */
550 if(signerStatus
!= NULL
) {
551 if((vfyRtn
== errSecSuccess
) && (tpVfyStatus
== CSSM_OK
)) {
552 *signerStatus
= kCMSSignerValid
;
554 else if(vfyRtn
!= errSecSuccess
) {
555 /* this could mean other things, but for now... */
556 *signerStatus
= kCMSSignerInvalidSignature
;
559 *signerStatus
= kCMSSignerInvalidCert
;
568 * Obtain the email address of signer 'signerIndex' of a CMS message, if
571 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
573 OSStatus
CMSDecoderCopySignerEmailAddress(
574 CMSDecoderRef cmsDecoder
,
576 CFStringRef
*signerEmailAddress
) /* RETURNED */
578 if((cmsDecoder
== NULL
) ||
579 (signerEmailAddress
== NULL
) ||
580 (cmsDecoder
->signedData
== NULL
) || /* not signed */
581 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
582 (cmsDecoder
->decState
!= DS_Final
)) {
586 SecCmsSignerInfoRef signerInfo
=
587 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
588 if(signerInfo
== NULL
) {
589 /* should never happen */
591 dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
592 return errSecInternalComponent
;
596 * This is leaking memory in libsecurityKeychain per Radar 4412699.
598 *signerEmailAddress
= SecCmsSignerInfoGetSignerEmailAddress(signerInfo
);
599 return errSecSuccess
;
603 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
606 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
608 OSStatus
CMSDecoderCopySignerCert(
609 CMSDecoderRef cmsDecoder
,
611 SecCertificateRef
*signerCert
) /* RETURNED */
613 if((cmsDecoder
== NULL
) ||
614 (signerCert
== NULL
) ||
615 (cmsDecoder
->signedData
== NULL
) || /* not signed */
616 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
617 (cmsDecoder
->decState
!= DS_Final
)) {
621 SecCmsSignerInfoRef signerInfo
=
622 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
623 if(signerInfo
== NULL
) {
624 /* should never happen */
626 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
627 return errSecInternalComponent
;
629 *signerCert
= SecCmsSignerInfoGetSigningCertificate(signerInfo
, NULL
);
630 /* libsecurity_smime does NOT retain that */
631 if(*signerCert
== NULL
) {
632 /* should never happen */
634 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
635 return errSecInternalComponent
;
637 CFRetain(*signerCert
);
638 return errSecSuccess
;
642 * Determine whether a CMS message was encrypted, and if so, whether we were
643 * able to decrypt it.
645 OSStatus
CMSDecoderIsContentEncrypted(
646 CMSDecoderRef cmsDecoder
,
647 Boolean
*wasEncrypted
)
649 if((cmsDecoder
== NULL
) || (wasEncrypted
== NULL
)) {
652 if(cmsDecoder
->decState
!= DS_Final
) {
655 *wasEncrypted
= cmsDecoder
->wasEncrypted
;
656 return errSecSuccess
;
660 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
663 OSStatus
CMSDecoderCopyEncapsulatedContentType(
664 CMSDecoderRef cmsDecoder
,
665 CFDataRef
*eContentType
) /* RETURNED */
667 if((cmsDecoder
== NULL
) || (eContentType
== NULL
)) {
670 if(cmsDecoder
->decState
!= DS_Final
) {
673 if(cmsDecoder
->signedData
== NULL
) {
674 *eContentType
= NULL
;
677 CSSM_OID
*ecOid
= cmsDecoder
->eContentType
;
678 *eContentType
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
);
680 return errSecSuccess
;
684 * Obtain an array of all of the certificates in a message. Elements of the
685 * returned array are SecCertificateRefs. The caller must CFRelease the returned
687 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
689 OSStatus
CMSDecoderCopyAllCerts(
690 CMSDecoderRef cmsDecoder
,
691 CFArrayRef
*certs
) /* RETURNED */
693 if((cmsDecoder
== NULL
) || (certs
== NULL
)) {
696 if(cmsDecoder
->decState
!= DS_Final
) {
699 if(cmsDecoder
->signedData
== NULL
) {
700 /* message wasn't signed */
702 return errSecSuccess
;
705 /* NULL_terminated array of CSSM_DATA ptrs */
706 CSSM_DATA_PTR
*cssmCerts
= SecCmsSignedDataGetCertificateList(cmsDecoder
->signedData
);
707 if((cssmCerts
== NULL
) || (*cssmCerts
== NULL
)) {
709 return errSecSuccess
;
712 CFMutableArrayRef allCerts
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
713 CSSM_DATA_PTR
*cssmCert
;
714 for(cssmCert
=cssmCerts
; *cssmCert
!=NULL
; cssmCert
++) {
716 SecCertificateRef cfCert
;
717 ortn
= SecCertificateCreateFromData(*cssmCert
,
718 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
,
724 CFArrayAppendValue(allCerts
, cfCert
);
725 /* the array holds the only needed refcount */
729 return errSecSuccess
;
733 * Obtain the actual message content (payload), if any. If the message was
734 * signed with detached content this will return NULL.
735 * Caller must CFRelease the result.
737 OSStatus
CMSDecoderCopyContent(
738 CMSDecoderRef cmsDecoder
,
739 CFDataRef
*content
) /* RETURNED */
741 if((cmsDecoder
== NULL
) || (content
== NULL
)) {
744 if(cmsDecoder
->decState
!= DS_Final
) {
747 if(cmsDecoder
->cmsMsg
== NULL
) {
748 /* Hmmm....looks like the finalize call failed */
751 CSSM_DATA_PTR odata
= SecCmsMessageGetContent(cmsDecoder
->cmsMsg
);
752 if((odata
== NULL
) || (odata
->Length
== 0)) {
753 /* i.e., detached content */
755 return errSecSuccess
;
757 *content
= CFDataCreate(NULL
, (const UInt8
*)odata
->Data
, odata
->Length
);
758 return errSecSuccess
;
761 #pragma mark --- SPI declared in CMSPrivate.h ---
764 * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
765 * to be called after decoding the message (i.e., after
766 * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
767 * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
768 * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
771 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
773 OSStatus
CMSDecoderGetCmsMessage(
774 CMSDecoderRef cmsDecoder
,
775 SecCmsMessageRef
*cmsMessage
) /* RETURNED */
777 if((cmsDecoder
== NULL
) || (cmsMessage
== NULL
)) {
780 /* any state, whether we have a msg or not is OK */
781 *cmsMessage
= cmsDecoder
->cmsMsg
;
782 return errSecSuccess
;
786 * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
787 * If this is called, it must be called before the first call to
788 * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
789 * incoming SecCmsDecoderRef.
791 OSStatus
CMSDecoderSetDecoder(
792 CMSDecoderRef cmsDecoder
,
793 SecCmsDecoderRef decoder
)
795 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
798 switch(cmsDecoder
->decState
) {
800 ASSERT(cmsDecoder
->decoder
== NULL
);
801 cmsDecoder
->decoder
= decoder
;
802 cmsDecoder
->decState
= DS_Updating
;
803 return errSecSuccess
;
808 return errSecSuccess
;
812 * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
813 * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
814 * CMSDecoderUpdateMessage() has been called.
815 * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
817 OSStatus
CMSDecoderGetDecoder(
818 CMSDecoderRef cmsDecoder
,
819 SecCmsDecoderRef
*decoder
) /* RETURNED */
821 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
824 /* any state, whether we have a decoder or not is OK */
825 *decoder
= cmsDecoder
->decoder
;
826 return errSecSuccess
;
830 * Obtain the signing time of signer 'signerIndex' of a CMS message, if
831 * present. This is an unauthenticate time, although it is part of the
832 * signed attributes of the message.
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.
839 OSStatus
CMSDecoderCopySignerSigningTime(
840 CMSDecoderRef cmsDecoder
,
841 size_t signerIndex
, /* usually 0 */
842 CFAbsoluteTime
*signingTime
) /* RETURNED */
844 OSStatus status
= errSecParam
;
845 SecCmsMessageRef cmsg
;
846 SecCmsSignedDataRef signedData
= NULL
;
847 int numContentInfos
= 0;
849 require(cmsDecoder
&& signingTime
, xit
);
850 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
851 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
852 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
854 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
855 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
856 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
857 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
858 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
860 status
= SecCmsSignerInfoGetSigningTime(signerInfo
, signingTime
);
869 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
870 * present. This timestamp is an authenticated timestamp provided by
871 * a timestamping authority.
873 * Returns errSecParam if the CMS message was not signed or if signerIndex
874 * is greater than the number of signers of the message minus one.
876 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
879 OSStatus
CMSDecoderCopySignerTimestamp(
880 CMSDecoderRef cmsDecoder
,
881 size_t signerIndex
, /* usually 0 */
882 CFAbsoluteTime
*timestamp
) /* RETURNED */
884 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder
, NULL
, signerIndex
, timestamp
);
887 OSStatus
CMSDecoderCopySignerTimestampWithPolicy(
888 CMSDecoderRef cmsDecoder
,
889 CFTypeRef timeStampPolicy
,
890 size_t signerIndex
, /* usually 0 */
891 CFAbsoluteTime
*timestamp
) /* RETURNED */
893 OSStatus status
= errSecParam
;
894 SecCmsMessageRef cmsg
;
895 SecCmsSignedDataRef signedData
= NULL
;
896 int numContentInfos
= 0;
898 require(cmsDecoder
&& timestamp
, xit
);
899 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
900 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
901 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
903 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
904 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
905 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
906 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
907 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
909 status
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);
919 * Obtain an array of the certificates in a timestamp response. Elements of the
920 * returned array are SecCertificateRefs. The caller must CFRelease the returned
921 * array. This timestamp is an authenticated timestamp provided by
922 * a timestamping authority.
924 * Returns errSecParam if the CMS message was not signed or if signerIndex
925 * is greater than the number of signers of the message minus one. It returns
926 * errSecItemNotFound if no certificates were found.
928 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
930 OSStatus
CMSDecoderCopySignerTimestampCertificates(
931 CMSDecoderRef cmsDecoder
,
932 size_t signerIndex
, /* usually 0 */
933 CFArrayRef
*certificateRefs
) /* RETURNED */
935 OSStatus status
= errSecParam
;
936 SecCmsMessageRef cmsg
= NULL
;
937 SecCmsSignedDataRef signedData
= NULL
;
938 int numContentInfos
= 0;
942 require(cmsDecoder
&& certificateRefs
, xit
);
943 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
944 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
945 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
947 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
948 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
949 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
950 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
951 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
953 CFArrayRef certList
= SecCmsSignerInfoGetTimestampCertList(signerInfo
);
954 require_action(certList
, xit
, status
= errSecItemNotFound
);
955 CFMutableArrayRef certs
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, CFArrayGetCount(certList
), certList
);
958 //reorder certificates:
959 tsn
= CFArrayGetCount(certs
);
960 good
= tsn
> 0 && Security::CodeSigning::isAppleCA(SecCertificateRef(CFArrayGetValueAtIndex(certs
, tsn
-1)));
964 //change TS certificate ordering.
965 for (CFIndex n
= 0; n
< tsn
; n
++)
967 if (SecCertificateRef tsRoot
= SecCertificateRef(CFArrayGetValueAtIndex(certs
, n
)))
968 if ((good
= Security::CodeSigning::isAppleCA(tsRoot
))) {
969 CFArrayExchangeValuesAtIndices(certs
, n
, tsn
-1);
975 *certificateRefs
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
977 status
= errSecSuccess
;
989 * Obtain the Hash Agility attribute value of signer 'signerIndex'
990 * of a CMS message, if present.
992 * Returns errSecParam if the CMS message was not signed or if signerIndex
993 * is greater than the number of signers of the message minus one.
995 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
997 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgility(
998 CMSDecoderRef cmsDecoder
,
999 size_t signerIndex
, /* usually 0 */
1000 CFDataRef CF_RETURNS_RETAINED
*hashAgilityAttrValue
) /* RETURNED */
1002 OSStatus status
= errSecParam
;
1003 SecCmsMessageRef cmsg
;
1004 SecCmsSignedDataRef signedData
= NULL
;
1005 int numContentInfos
= 0;
1006 CFDataRef returnedValue
= NULL
;
1008 require(cmsDecoder
&& hashAgilityAttrValue
, exit
);
1009 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), exit
);
1010 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1011 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
1013 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1014 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1015 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
1016 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
1017 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
1019 status
= SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo
, &returnedValue
);
1024 if (status
== errSecSuccess
&& returnedValue
) {
1025 *hashAgilityAttrValue
= (CFDataRef
) CFRetain(returnedValue
);
1027 *hashAgilityAttrValue
= NULL
;
1033 * Obtain the Hash Agility V2 attribute value of signer 'signerIndex'
1034 * of a CMS message, if present.
1036 * Returns errSecParam if the CMS message was not signed or if signerIndex
1037 * is greater than the number of signers of the message minus one.
1039 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1041 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgilityV2(
1042 CMSDecoderRef cmsDecoder
,
1043 size_t signerIndex
, /* usually 0 */
1044 CFDictionaryRef CF_RETURNS_RETAINED
*hashAgilityV2AttrValues
) /* RETURNED */
1046 OSStatus status
= errSecParam
;
1047 SecCmsMessageRef cmsg
;
1048 SecCmsSignedDataRef signedData
= NULL
;
1049 int numContentInfos
= 0;
1050 CFDictionaryRef returnedValue
= NULL
;
1052 require(cmsDecoder
&& hashAgilityV2AttrValues
, exit
);
1053 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), exit
);
1054 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1055 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
1057 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1058 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1059 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
1060 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
1061 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
1064 status
= SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(signerInfo
, &returnedValue
);
1070 if (status
== errSecSuccess
&& returnedValue
) {
1071 *hashAgilityV2AttrValues
= (CFDictionaryRef
) CFRetain(returnedValue
);
1073 *hashAgilityV2AttrValues
= NULL
;
1079 * Obtain the expiration time of signer 'signerIndex' of a CMS message, if
1080 * present. This is part of the signed attributes of the message.
1082 * Returns errSecParam if the CMS message was not signed or if signerIndex
1083 * is greater than the number of signers of the message minus one.
1085 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1087 OSStatus
CMSDecoderCopySignerAppleExpirationTime(
1088 CMSDecoderRef cmsDecoder
,
1090 CFAbsoluteTime
*expirationTime
) /* RETURNED */
1092 OSStatus status
= errSecParam
;
1093 SecCmsMessageRef cmsg
= NULL
;
1094 int numContentInfos
= 0;
1095 SecCmsSignedDataRef signedData
= NULL
;
1097 require(cmsDecoder
&& expirationTime
, xit
);
1098 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
1099 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1100 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++) {
1101 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1102 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1103 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
) {
1104 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
1105 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
1107 status
= SecCmsSignerInfoGetAppleExpirationTime(signerInfo
, expirationTime
);