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 "CMSDecoder.h"
29 #include "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>
47 #include <AssertMacros.h>
49 #pragma mark --- Private types and definitions ---
55 DS_Init
, /* between CMSDecoderCreate and CMSDecoderUpdateMessage */
56 DS_Updating
, /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */
57 DS_Final
/* CMSDecoderFinalizeMessage has been called */
61 * Caller's CMSDecoderRef points to one of these.
65 CMSDecoderState decState
;
66 SecArenaPoolRef arena
; /* the decoder's arena */
67 SecCmsDecoderRef decoder
;
68 CFDataRef detachedContent
;
69 CFTypeRef keychainOrArray
; /* unused */
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 CSSM_OID
*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 CFRELEASE(cmsDecoder
->keychainOrArray
);
137 if(cmsDecoder
->cmsMsg
!= NULL
) {
138 SecCmsMessageDestroy(cmsDecoder
->cmsMsg
);
139 cmsDecoder
->cmsMsg
= NULL
;
141 if(cmsDecoder
->arena
!= NULL
) {
142 SecArenaPoolFree(cmsDecoder
->arena
, false);
143 cmsDecoder
->arena
= NULL
;
149 * Given detached content and a valid (decoded) SignedData, digest the detached
150 * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a
151 * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent()
152 * when we already have a SignedData).
154 static OSStatus
cmsDigestDetachedContent(
155 CMSDecoderRef cmsDecoder
)
157 ASSERT((cmsDecoder
->signedData
!= NULL
) && (cmsDecoder
->detachedContent
!= NULL
));
159 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(cmsDecoder
->signedData
);
160 if(digestAlgorithms
== NULL
) {
161 return errSecUnknownFormat
;
163 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestAlgorithms
);
165 return errSecAllocate
;
167 CSSM_DATA
**digests
= NULL
;
169 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(cmsDecoder
->detachedContent
),
170 CFDataGetLength(cmsDecoder
->detachedContent
));
171 /* note this frees the digest content regardless */
172 OSStatus ortn
= SecCmsDigestContextFinishMultiple(digcx
, cmsDecoder
->arena
, &digests
);
174 ortn
= cmsRtnToOSStatus(ortn
);
175 CSSM_PERROR("SecCmsDigestContextFinishMultiple", ortn
);
178 ortn
= SecCmsSignedDataSetDigests(cmsDecoder
->signedData
, digestAlgorithms
, digests
);
180 ortn
= cmsRtnToOSStatus(ortn
);
181 CSSM_PERROR("SecCmsSignedDataSetDigests", ortn
);
186 #pragma mark --- Start of Public API ---
188 CFTypeID
CMSDecoderGetTypeID(void)
190 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
192 if(cmsDecoderTypeID
== _kCFRuntimeNotATypeID
) {
193 pthread_once(&once
, &cmsDecoderClassInitialize
);
195 return cmsDecoderTypeID
;
199 * Create a CMSDecoder. Result must eventually be freed via CFRelease().
201 OSStatus
CMSDecoderCreate(
202 CMSDecoderRef
*cmsDecoderOut
) /* RETURNED */
204 CMSDecoderRef cmsDecoder
= NULL
;
206 uint32_t extra
= sizeof(*cmsDecoder
) - sizeof(cmsDecoder
->base
);
207 cmsDecoder
= (CMSDecoderRef
)_CFRuntimeCreateInstance(NULL
, CMSDecoderGetTypeID(),
209 if(cmsDecoder
== NULL
) {
210 return errSecAllocate
;
212 cmsDecoder
->decState
= DS_Init
;
213 *cmsDecoderOut
= cmsDecoder
;
214 return errSecSuccess
;
218 * Feed raw bytes of the message to be decoded into the decoder. Can be called
221 OSStatus
CMSDecoderUpdateMessage(
222 CMSDecoderRef cmsDecoder
,
223 const void *msgBytes
,
226 if(cmsDecoder
== NULL
) {
231 switch(cmsDecoder
->decState
) {
233 /* First time through; set up */
234 ASSERT(cmsDecoder
->decoder
== NULL
);
235 ASSERT(cmsDecoder
->arena
== NULL
);
236 ortn
= SecArenaPoolCreate(1024, &cmsDecoder
->arena
);
238 return cmsRtnToOSStatus(ortn
);
240 ortn
= SecCmsDecoderCreate(cmsDecoder
->arena
,
241 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsDecoder
->decoder
);
243 ortn
= cmsRtnToOSStatus(ortn
);
244 CSSM_PERROR("SecCmsDecoderCreate", ortn
);
247 cmsDecoder
->decState
= DS_Updating
;
251 ASSERT(cmsDecoder
->decoder
!= NULL
);
255 /* Too late for another update */
259 dprintf("CMSDecoderUpdateMessage: bad decState\n");
260 return errSecInternalComponent
;
263 /* FIXME - CFIndex same size as size_t on 64bit? */
264 ortn
= SecCmsDecoderUpdate(cmsDecoder
->decoder
, msgBytes
, (CFIndex
)msgBytesLen
);
266 ortn
= cmsRtnToOSStatus(ortn
, errSecUnknownFormat
);
267 CSSM_PERROR("SecCmsDecoderUpdate", ortn
);
273 * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
274 * finish decoding the message. We parse the message as best we can, up to
275 * but not including verifying individual signerInfos.
277 OSStatus
CMSDecoderFinalizeMessage(
278 CMSDecoderRef cmsDecoder
)
280 if(cmsDecoder
== NULL
) {
283 if(cmsDecoder
->decState
!= DS_Updating
) {
286 ASSERT(cmsDecoder
->decoder
!= NULL
);
287 OSStatus ortn
= SecCmsDecoderFinish(cmsDecoder
->decoder
, &cmsDecoder
->cmsMsg
);
288 cmsDecoder
->decState
= DS_Final
;
290 /* SecCmsDecoderFinish destroyed the decoder even on failure */
291 cmsDecoder
->decoder
= NULL
;
294 ortn
= cmsRtnToOSStatus(ortn
, errSecUnknownFormat
);
295 CSSM_PERROR("SecCmsDecoderFinish", ortn
);
299 ASSERT(cmsDecoder
->cmsMsg
!= NULL
);
300 cmsDecoder
->wasEncrypted
= SecCmsMessageIsEncrypted(cmsDecoder
->cmsMsg
);
302 /* Look for a SignedData */
303 int numContentInfos
= SecCmsMessageContentLevelCount(cmsDecoder
->cmsMsg
);
305 for(dex
=0; dex
<numContentInfos
; dex
++) {
306 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsDecoder
->cmsMsg
, dex
);
307 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
309 case SEC_OID_PKCS7_SIGNED_DATA
:
310 cmsDecoder
->signedData
=
311 (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
);
312 /* dig down one more layer for eContentType */
313 ci
= SecCmsSignedDataGetContentInfo(cmsDecoder
->signedData
);
314 cmsDecoder
->eContentType
= SecCmsContentInfoGetContentTypeOID(ci
);
319 if(cmsDecoder
->signedData
!= NULL
) {
325 /* minimal processing of optional signedData... */
326 if(cmsDecoder
->signedData
!= NULL
) {
327 cmsDecoder
->numSigners
= (size_t)
328 SecCmsSignedDataSignerInfoCount(cmsDecoder
->signedData
);
329 if(cmsDecoder
->detachedContent
!= NULL
) {
330 /* time to calculate digests from detached content */
331 ortn
= cmsDigestDetachedContent(cmsDecoder
);
338 * A signed CMS message optionally includes the data which was signed. If the
339 * message does not include the signed data, caller specifies the signed data
340 * (the "detached content") here.
342 * This can be called either before or after the actual decoding of the message
343 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
344 * restriction is that, if detached content is required, this function must
345 * be called befoere successfully ascertaining the signature status via
346 * CMSDecoderCopySignerStatus().
348 OSStatus
CMSDecoderSetDetachedContent(
349 CMSDecoderRef cmsDecoder
,
350 CFDataRef detachedContent
)
352 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
355 cmsDecoder
->detachedContent
= detachedContent
;
356 CFRetain(detachedContent
);
358 if(cmsDecoder
->signedData
!= NULL
) {
359 /* time to calculate digests from detached content */
360 ASSERT(cmsDecoder
->decState
== DS_Final
);
361 return cmsDigestDetachedContent(cmsDecoder
);
363 return errSecSuccess
;
367 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
368 * Returns a NULL detachedContent if no detached content has been specified.
369 * Caller must CFRelease() the result.
371 OSStatus
CMSDecoderCopyDetachedContent(
372 CMSDecoderRef cmsDecoder
,
373 CFDataRef
*detachedContent
) /* RETURNED */
375 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
378 if(cmsDecoder
->detachedContent
!= NULL
) {
379 CFRetain(cmsDecoder
->detachedContent
);
381 *detachedContent
= cmsDecoder
->detachedContent
;
382 return errSecSuccess
;
386 * Beginning in 10.12, this function stopped affecting the behavior of the
387 * CMS Decoder. Its only use was in SecTrustSetKeychains which is a no-op.
388 * Please discontinue use.
390 OSStatus
CMSDecoderSetSearchKeychain(
391 CMSDecoderRef cmsDecoder
,
392 CFTypeRef keychainOrArray
)
394 return errSecSuccess
;
398 * Obtain the number of signers of a message. A result of zero indicates that
399 * the message was not signed.
401 OSStatus
CMSDecoderGetNumSigners(
402 CMSDecoderRef cmsDecoder
,
403 size_t *numSigners
) /* RETURNED */
405 if((cmsDecoder
== NULL
) || (numSigners
== NULL
)) {
408 if(cmsDecoder
->decState
!= DS_Final
) {
411 *numSigners
= cmsDecoder
->numSigners
;
412 return errSecSuccess
;
416 * Obtain the status of a CMS message's signature. A CMS message can
417 * be signed my multiple signers; this function returns the status
418 * associated with signer 'n' as indicated by the signerIndex parameter.
420 OSStatus
CMSDecoderCopySignerStatus(
421 CMSDecoderRef cmsDecoder
,
423 CFTypeRef policyOrArray
,
424 Boolean evaluateSecTrust
,
425 CMSSignerStatus
*signerStatus
, /* optional; RETURNED */
426 SecTrustRef
*secTrust
, /* optional; RETURNED */
427 OSStatus
*certVerifyResultCode
) /* optional; RETURNED */
429 if((cmsDecoder
== NULL
) || (cmsDecoder
->decState
!= DS_Final
) || (!policyOrArray
)) {
433 /* initialize return values */
435 *signerStatus
= kCMSSignerUnsigned
;
440 if(certVerifyResultCode
) {
441 *certVerifyResultCode
= 0;
444 if(cmsDecoder
->signedData
== NULL
) {
445 *signerStatus
= kCMSSignerUnsigned
; /* redundant, I know, but explicit */
446 return errSecSuccess
;
448 ASSERT(cmsDecoder
->numSigners
> 0);
449 if(signerIndex
>= cmsDecoder
->numSigners
) {
450 *signerStatus
= kCMSSignerInvalidIndex
;
451 return errSecSuccess
;
453 if(!SecCmsSignedDataHasDigests(cmsDecoder
->signedData
)) {
454 *signerStatus
= kCMSSignerNeedsDetachedContent
;
455 return errSecSuccess
;
459 * OK, we should be able to verify this signerInfo.
460 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
461 * in order get all the cert pieces into place before returning them
464 SecTrustRef theTrust
= NULL
;
465 OSStatus vfyRtn
= SecCmsSignedDataVerifySignerInfo(cmsDecoder
->signedData
,
471 #if SECTRUST_VERBOSE_DEBUG
472 syslog(LOG_ERR
, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn
);
473 if (policyOrArray
) CFShow(policyOrArray
);
474 if (theTrust
) CFShow(theTrust
);
477 /* Subsequent errors to errOut: */
480 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
481 * SecTrustEvaluate() if we don't ask for a copy.
483 * FIXME deal with multitudes of status returns here...for now, proceed with
484 * obtaining components the caller wants and assume that a nonzero vfyRtn
485 * means "bad signature".
487 OSStatus ortn
= errSecSuccess
;
488 SecTrustResultType secTrustResult
;
489 CSSM_RETURN tpVfyStatus
= CSSM_OK
;
492 if(secTrust
!= NULL
) {
493 *secTrust
= theTrust
;
494 /* we'll release our reference at the end */
498 SecCmsSignerInfoRef signerInfo
=
499 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
500 if(signerInfo
== NULL
) {
501 /* should never happen */
503 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
504 ortn
= errSecInternalComponent
;
508 /* now do the actual cert verify */
509 if(evaluateSecTrust
) {
510 evalRtn
= SecTrustEvaluate(theTrust
, &secTrustResult
);
512 /* should never happen */
513 CSSM_PERROR("SecTrustEvaluate", evalRtn
);
514 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
515 ortn
= errSecInternalComponent
;
518 switch(secTrustResult
) {
519 case kSecTrustResultUnspecified
:
520 /* cert chain valid, no special UserTrust assignments */
521 case kSecTrustResultProceed
:
522 /* cert chain valid AND user explicitly trusts this */
524 case kSecTrustResultDeny
:
525 tpVfyStatus
= CSSMERR_APPLETP_TRUST_SETTING_DENY
;
529 /* get low-level TP error */
531 ortn
= SecTrustGetCssmResultCode(theTrust
, &tpStatus
);
533 CSSM_PERROR("SecTrustGetCssmResultCode", ortn
);
536 tpVfyStatus
= tpStatus
;
538 CSSM_PERROR("TP status after SecTrustEvaluate", tpVfyStatus
);
541 } /* switch(secTrustResult) */
542 } /* evaluateSecTrust true */
543 if(certVerifyResultCode
!= NULL
) {
544 *certVerifyResultCode
= tpVfyStatus
;
547 /* cook up global status based on vfyRtn and tpVfyStatus */
548 if(signerStatus
!= NULL
) {
549 if((vfyRtn
== errSecSuccess
) && (tpVfyStatus
== CSSM_OK
)) {
550 *signerStatus
= kCMSSignerValid
;
552 else if(vfyRtn
!= errSecSuccess
) {
553 /* this could mean other things, but for now... */
554 *signerStatus
= kCMSSignerInvalidSignature
;
557 *signerStatus
= kCMSSignerInvalidCert
;
566 * Obtain the email address of signer 'signerIndex' of a CMS message, if
569 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
571 OSStatus
CMSDecoderCopySignerEmailAddress(
572 CMSDecoderRef cmsDecoder
,
574 CFStringRef
*signerEmailAddress
) /* RETURNED */
576 if((cmsDecoder
== NULL
) ||
577 (signerEmailAddress
== 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("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
590 return errSecInternalComponent
;
594 * This is leaking memory in libsecurityKeychain per Radar 4412699.
596 *signerEmailAddress
= SecCmsSignerInfoGetSignerEmailAddress(signerInfo
);
597 return errSecSuccess
;
601 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
604 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
606 OSStatus
CMSDecoderCopySignerCert(
607 CMSDecoderRef cmsDecoder
,
609 SecCertificateRef
*signerCert
) /* RETURNED */
611 if((cmsDecoder
== NULL
) ||
612 (signerCert
== NULL
) ||
613 (cmsDecoder
->signedData
== NULL
) || /* not signed */
614 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
615 (cmsDecoder
->decState
!= DS_Final
)) {
619 SecCmsSignerInfoRef signerInfo
=
620 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
621 if(signerInfo
== NULL
) {
622 /* should never happen */
624 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
625 return errSecInternalComponent
;
627 *signerCert
= SecCmsSignerInfoGetSigningCertificate(signerInfo
, NULL
);
628 /* libsecurity_smime does NOT retain that */
629 if(*signerCert
== NULL
) {
630 /* should never happen */
632 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
633 return errSecInternalComponent
;
635 CFRetain(*signerCert
);
636 return errSecSuccess
;
640 * Determine whether a CMS message was encrypted, and if so, whether we were
641 * able to decrypt it.
643 OSStatus
CMSDecoderIsContentEncrypted(
644 CMSDecoderRef cmsDecoder
,
645 Boolean
*wasEncrypted
)
647 if((cmsDecoder
== NULL
) || (wasEncrypted
== NULL
)) {
650 if(cmsDecoder
->decState
!= DS_Final
) {
653 *wasEncrypted
= cmsDecoder
->wasEncrypted
;
654 return errSecSuccess
;
658 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
661 OSStatus
CMSDecoderCopyEncapsulatedContentType(
662 CMSDecoderRef cmsDecoder
,
663 CFDataRef
*eContentType
) /* RETURNED */
665 if((cmsDecoder
== NULL
) || (eContentType
== NULL
)) {
668 if(cmsDecoder
->decState
!= DS_Final
) {
671 if(cmsDecoder
->signedData
== NULL
) {
672 *eContentType
= NULL
;
675 CSSM_OID
*ecOid
= cmsDecoder
->eContentType
;
676 *eContentType
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
);
678 return errSecSuccess
;
682 * Obtain an array of all of the certificates in a message. Elements of the
683 * returned array are SecCertificateRefs. The caller must CFRelease the returned
685 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
687 OSStatus
CMSDecoderCopyAllCerts(
688 CMSDecoderRef cmsDecoder
,
689 CFArrayRef
*certs
) /* RETURNED */
691 if((cmsDecoder
== NULL
) || (certs
== NULL
)) {
694 if(cmsDecoder
->decState
!= DS_Final
) {
697 if(cmsDecoder
->signedData
== NULL
) {
698 /* message wasn't signed */
700 return errSecSuccess
;
703 /* NULL_terminated array of CSSM_DATA ptrs */
704 CSSM_DATA_PTR
*cssmCerts
= SecCmsSignedDataGetCertificateList(cmsDecoder
->signedData
);
705 if((cssmCerts
== NULL
) || (*cssmCerts
== NULL
)) {
707 return errSecSuccess
;
710 CFMutableArrayRef allCerts
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
711 CSSM_DATA_PTR
*cssmCert
;
712 for(cssmCert
=cssmCerts
; *cssmCert
!=NULL
; cssmCert
++) {
714 SecCertificateRef cfCert
;
715 ortn
= SecCertificateCreateFromData(*cssmCert
,
716 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
,
722 CFArrayAppendValue(allCerts
, cfCert
);
723 /* the array holds the only needed refcount */
727 return errSecSuccess
;
731 * Obtain the actual message content (payload), if any. If the message was
732 * signed with detached content this will return NULL.
733 * Caller must CFRelease the result.
735 OSStatus
CMSDecoderCopyContent(
736 CMSDecoderRef cmsDecoder
,
737 CFDataRef
*content
) /* RETURNED */
739 if((cmsDecoder
== NULL
) || (content
== NULL
)) {
742 if(cmsDecoder
->decState
!= DS_Final
) {
745 if(cmsDecoder
->cmsMsg
== NULL
) {
746 /* Hmmm....looks like the finalize call failed */
749 CSSM_DATA_PTR odata
= SecCmsMessageGetContent(cmsDecoder
->cmsMsg
);
750 if((odata
== NULL
) || (odata
->Length
== 0)) {
751 /* i.e., detached content */
753 return errSecSuccess
;
755 *content
= CFDataCreate(NULL
, (const UInt8
*)odata
->Data
, odata
->Length
);
756 return errSecSuccess
;
759 #pragma mark --- SPI declared in CMSPrivate.h ---
762 * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
763 * to be called after decoding the message (i.e., after
764 * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
765 * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
766 * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
769 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
771 OSStatus
CMSDecoderGetCmsMessage(
772 CMSDecoderRef cmsDecoder
,
773 SecCmsMessageRef
*cmsMessage
) /* RETURNED */
775 if((cmsDecoder
== NULL
) || (cmsMessage
== NULL
)) {
778 /* any state, whether we have a msg or not is OK */
779 *cmsMessage
= cmsDecoder
->cmsMsg
;
780 return errSecSuccess
;
784 * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
785 * If this is called, it must be called before the first call to
786 * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
787 * incoming SecCmsDecoderRef.
789 OSStatus
CMSDecoderSetDecoder(
790 CMSDecoderRef cmsDecoder
,
791 SecCmsDecoderRef decoder
)
793 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
796 switch(cmsDecoder
->decState
) {
798 ASSERT(cmsDecoder
->decoder
== NULL
);
799 cmsDecoder
->decoder
= decoder
;
800 cmsDecoder
->decState
= DS_Updating
;
801 return errSecSuccess
;
806 return errSecSuccess
;
810 * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
811 * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
812 * CMSDecoderUpdateMessage() has been called.
813 * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
815 OSStatus
CMSDecoderGetDecoder(
816 CMSDecoderRef cmsDecoder
,
817 SecCmsDecoderRef
*decoder
) /* RETURNED */
819 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
822 /* any state, whether we have a decoder or not is OK */
823 *decoder
= cmsDecoder
->decoder
;
824 return errSecSuccess
;
828 * Obtain the signing time of signer 'signerIndex' of a CMS message, if
829 * present. This is an unauthenticate time, although it is part of the
830 * signed attributes of the message.
832 * Returns errSecParam if the CMS message was not signed or if signerIndex
833 * is greater than the number of signers of the message minus one.
835 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
837 OSStatus
CMSDecoderCopySignerSigningTime(
838 CMSDecoderRef cmsDecoder
,
839 size_t signerIndex
, /* usually 0 */
840 CFAbsoluteTime
*signingTime
) /* RETURNED */
842 OSStatus status
= errSecParam
;
843 SecCmsMessageRef cmsg
;
844 SecCmsSignedDataRef signedData
= NULL
;
845 int numContentInfos
= 0;
847 require(cmsDecoder
&& signingTime
, xit
);
848 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
849 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
850 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
852 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
853 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
854 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
855 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
856 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
858 status
= SecCmsSignerInfoGetSigningTime(signerInfo
, signingTime
);
867 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
868 * present. This timestamp is an authenticated timestamp provided by
869 * a timestamping authority.
871 * Returns errSecParam if the CMS message was not signed or if signerIndex
872 * is greater than the number of signers of the message minus one.
874 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
877 OSStatus
CMSDecoderCopySignerTimestamp(
878 CMSDecoderRef cmsDecoder
,
879 size_t signerIndex
, /* usually 0 */
880 CFAbsoluteTime
*timestamp
) /* RETURNED */
882 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder
, NULL
, signerIndex
, timestamp
);
885 OSStatus
CMSDecoderCopySignerTimestampWithPolicy(
886 CMSDecoderRef cmsDecoder
,
887 CFTypeRef timeStampPolicy
,
888 size_t signerIndex
, /* usually 0 */
889 CFAbsoluteTime
*timestamp
) /* RETURNED */
891 OSStatus status
= errSecParam
;
892 SecCmsMessageRef cmsg
;
893 SecCmsSignedDataRef signedData
= NULL
;
894 int numContentInfos
= 0;
896 require(cmsDecoder
&& timestamp
, xit
);
897 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
898 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
899 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
901 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
902 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
903 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
904 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
905 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
907 status
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);
917 * Obtain an array of the certificates in a timestamp response. Elements of the
918 * returned array are SecCertificateRefs. The caller must CFRelease the returned
919 * array. This timestamp is an authenticated timestamp provided by
920 * a timestamping authority.
922 * Returns errSecParam if the CMS message was not signed or if signerIndex
923 * is greater than the number of signers of the message minus one. It returns
924 * errSecItemNotFound if no certificates were found.
926 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
928 OSStatus
CMSDecoderCopySignerTimestampCertificates(
929 CMSDecoderRef cmsDecoder
,
930 size_t signerIndex
, /* usually 0 */
931 CFArrayRef
*certificateRefs
) /* RETURNED */
933 OSStatus status
= errSecParam
;
934 SecCmsMessageRef cmsg
= NULL
;
935 SecCmsSignedDataRef signedData
= NULL
;
936 int numContentInfos
= 0;
940 require(cmsDecoder
&& certificateRefs
, xit
);
941 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
942 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
943 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
945 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
946 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
947 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
948 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
949 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
951 CFArrayRef certList
= SecCmsSignerInfoGetTimestampCertList(signerInfo
);
952 require_action(certList
, xit
, status
= errSecItemNotFound
);
953 CFMutableArrayRef certs
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, CFArrayGetCount(certList
), certList
);
956 //reorder certificates:
957 tsn
= CFArrayGetCount(certs
);
958 good
= tsn
> 0 && Security::CodeSigning::isAppleCA(SecCertificateRef(CFArrayGetValueAtIndex(certs
, tsn
-1)));
962 //change TS certificate ordering.
963 for (CFIndex n
= 0; n
< tsn
; n
++)
965 if (SecCertificateRef tsRoot
= SecCertificateRef(CFArrayGetValueAtIndex(certs
, n
)))
966 if ((good
= Security::CodeSigning::isAppleCA(tsRoot
))) {
967 CFArrayExchangeValuesAtIndices(certs
, n
, tsn
-1);
973 *certificateRefs
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
975 status
= errSecSuccess
;
987 * Obtain the Hash Agility attribute value of signer 'signerIndex'
988 * of a CMS message, if present.
990 * Returns errSecParam if the CMS message was not signed or if signerIndex
991 * is greater than the number of signers of the message minus one.
993 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
995 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgility(
996 CMSDecoderRef cmsDecoder
,
997 size_t signerIndex
, /* usually 0 */
998 CFDataRef CF_RETURNS_RETAINED
*hashAgilityAttrValue
) /* RETURNED */
1000 OSStatus status
= errSecParam
;
1001 SecCmsMessageRef cmsg
;
1002 SecCmsSignedDataRef signedData
= NULL
;
1003 int numContentInfos
= 0;
1004 CFDataRef returnedValue
= NULL
;
1006 require(cmsDecoder
&& hashAgilityAttrValue
, exit
);
1007 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), exit
);
1008 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1009 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
1011 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1012 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1013 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
1014 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
1015 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
1017 status
= SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo
, &returnedValue
);
1022 if (status
== errSecSuccess
&& returnedValue
) {
1023 *hashAgilityAttrValue
= (CFDataRef
) CFRetain(returnedValue
);
1025 *hashAgilityAttrValue
= NULL
;
1031 * Obtain the Hash Agility V2 attribute value of signer 'signerIndex'
1032 * of a CMS message, if present.
1034 * Returns errSecParam if the CMS message was not signed or if signerIndex
1035 * is greater than the number of signers of the message minus one.
1037 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1039 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgilityV2(
1040 CMSDecoderRef cmsDecoder
,
1041 size_t signerIndex
, /* usually 0 */
1042 CFDictionaryRef CF_RETURNS_RETAINED
*hashAgilityV2AttrValues
) /* RETURNED */
1044 OSStatus status
= errSecParam
;
1045 SecCmsMessageRef cmsg
;
1046 SecCmsSignedDataRef signedData
= NULL
;
1047 int numContentInfos
= 0;
1048 CFDictionaryRef returnedValue
= NULL
;
1050 require(cmsDecoder
&& hashAgilityV2AttrValues
, exit
);
1051 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), exit
);
1052 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1053 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
1055 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1056 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1057 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
1058 if ((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
))) {
1059 SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
);
1062 status
= SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(signerInfo
, &returnedValue
);
1068 if (status
== errSecSuccess
&& returnedValue
) {
1069 *hashAgilityV2AttrValues
= (CFDictionaryRef
) CFRetain(returnedValue
);
1071 *hashAgilityV2AttrValues
= NULL
;