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
; /* from CMSDecoderSetSearchKeychain() */
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
131 * FIXME: SecCmsDecoderDestroy() appears to destroy the
132 * cmsMsg too! Plus there's a comment there re: a leak...
134 SecCmsDecoderDestroy(cmsDecoder
->decoder
);
136 CFRELEASE(cmsDecoder
->detachedContent
);
137 CFRELEASE(cmsDecoder
->keychainOrArray
);
138 if(cmsDecoder
->cmsMsg
!= NULL
) {
139 SecCmsMessageDestroy(cmsDecoder
->cmsMsg
);
141 if(cmsDecoder
->arena
!= NULL
) {
142 SecArenaPoolFree(cmsDecoder
->arena
, false);
148 * Given detached content and a valid (decoded) SignedData, digest the detached
149 * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a
150 * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent()
151 * when we already have a SignedData).
153 static OSStatus
cmsDigestDetachedContent(
154 CMSDecoderRef cmsDecoder
)
156 ASSERT((cmsDecoder
->signedData
!= NULL
) && (cmsDecoder
->detachedContent
!= NULL
));
158 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(cmsDecoder
->signedData
);
159 if(digestAlgorithms
== NULL
) {
160 return errSecUnknownFormat
;
162 SecCmsDigestContextRef digcx
= SecCmsDigestContextStartMultiple(digestAlgorithms
);
164 return errSecAllocate
;
166 CSSM_DATA
**digests
= NULL
;
168 SecCmsDigestContextUpdate(digcx
, CFDataGetBytePtr(cmsDecoder
->detachedContent
),
169 CFDataGetLength(cmsDecoder
->detachedContent
));
170 /* note this frees the digest content regardless */
171 OSStatus ortn
= SecCmsDigestContextFinishMultiple(digcx
, cmsDecoder
->arena
, &digests
);
173 ortn
= cmsRtnToOSStatus(ortn
);
174 CSSM_PERROR("SecCmsDigestContextFinishMultiple", ortn
);
177 ortn
= SecCmsSignedDataSetDigests(cmsDecoder
->signedData
, digestAlgorithms
, digests
);
179 ortn
= cmsRtnToOSStatus(ortn
);
180 CSSM_PERROR("SecCmsSignedDataSetDigests", ortn
);
185 #pragma mark --- Start of Public API ---
187 CFTypeID
CMSDecoderGetTypeID(void)
189 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
191 if(cmsDecoderTypeID
== _kCFRuntimeNotATypeID
) {
192 pthread_once(&once
, &cmsDecoderClassInitialize
);
194 return cmsDecoderTypeID
;
198 * Create a CMSDecoder. Result must eventually be freed via CFRelease().
200 OSStatus
CMSDecoderCreate(
201 CMSDecoderRef
*cmsDecoderOut
) /* RETURNED */
203 CMSDecoderRef cmsDecoder
= NULL
;
205 uint32_t extra
= sizeof(*cmsDecoder
) - sizeof(cmsDecoder
->base
);
206 cmsDecoder
= (CMSDecoderRef
)_CFRuntimeCreateInstance(NULL
, CMSDecoderGetTypeID(),
208 if(cmsDecoder
== NULL
) {
209 return errSecAllocate
;
211 cmsDecoder
->decState
= DS_Init
;
212 *cmsDecoderOut
= cmsDecoder
;
213 return errSecSuccess
;
217 * Feed raw bytes of the message to be decoded into the decoder. Can be called
220 OSStatus
CMSDecoderUpdateMessage(
221 CMSDecoderRef cmsDecoder
,
222 const void *msgBytes
,
225 if(cmsDecoder
== NULL
) {
230 switch(cmsDecoder
->decState
) {
232 /* First time through; set up */
233 ASSERT(cmsDecoder
->decoder
== NULL
);
234 ASSERT(cmsDecoder
->arena
== NULL
);
235 ortn
= SecArenaPoolCreate(1024, &cmsDecoder
->arena
);
237 return cmsRtnToOSStatus(ortn
);
239 ortn
= SecCmsDecoderCreate(cmsDecoder
->arena
,
240 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &cmsDecoder
->decoder
);
242 ortn
= cmsRtnToOSStatus(ortn
);
243 CSSM_PERROR("SecCmsDecoderCreate", ortn
);
246 cmsDecoder
->decState
= DS_Updating
;
250 ASSERT(cmsDecoder
->decoder
!= NULL
);
254 /* Too late for another update */
258 dprintf("CMSDecoderUpdateMessage: bad decState\n");
259 return errSecInternalComponent
;
262 /* FIXME - CFIndex same size as size_t on 64bit? */
263 ortn
= SecCmsDecoderUpdate(cmsDecoder
->decoder
, msgBytes
, (CFIndex
)msgBytesLen
);
265 ortn
= cmsRtnToOSStatus(ortn
, errSecUnknownFormat
);
266 CSSM_PERROR("SecCmsDecoderUpdate", ortn
);
272 * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
273 * finish decoding the message. We parse the message as best we can, up to
274 * but not including verifying individual signerInfos.
276 OSStatus
CMSDecoderFinalizeMessage(
277 CMSDecoderRef cmsDecoder
)
279 if(cmsDecoder
== NULL
) {
282 if(cmsDecoder
->decState
!= DS_Updating
) {
285 ASSERT(cmsDecoder
->decoder
!= NULL
);
286 OSStatus ortn
= SecCmsDecoderFinish(cmsDecoder
->decoder
, &cmsDecoder
->cmsMsg
);
287 cmsDecoder
->decState
= DS_Final
;
289 /* SecCmsDecoderFinish destroyed the decoder even on failure */
290 cmsDecoder
->decoder
= NULL
;
293 ortn
= cmsRtnToOSStatus(ortn
, errSecUnknownFormat
);
294 CSSM_PERROR("SecCmsDecoderFinish", ortn
);
298 ASSERT(cmsDecoder
->cmsMsg
!= NULL
);
299 cmsDecoder
->wasEncrypted
= SecCmsMessageIsEncrypted(cmsDecoder
->cmsMsg
);
301 /* Look for a SignedData */
302 int numContentInfos
= SecCmsMessageContentLevelCount(cmsDecoder
->cmsMsg
);
304 for(dex
=0; dex
<numContentInfos
; dex
++) {
305 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsDecoder
->cmsMsg
, dex
);
306 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
308 case SEC_OID_PKCS7_SIGNED_DATA
:
309 cmsDecoder
->signedData
=
310 (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(ci
);
311 /* dig down one more layer for eContentType */
312 ci
= SecCmsSignedDataGetContentInfo(cmsDecoder
->signedData
);
313 cmsDecoder
->eContentType
= SecCmsContentInfoGetContentTypeOID(ci
);
318 if(cmsDecoder
->signedData
!= NULL
) {
324 /* minimal processing of optional signedData... */
325 if(cmsDecoder
->signedData
!= NULL
) {
326 cmsDecoder
->numSigners
= (size_t)
327 SecCmsSignedDataSignerInfoCount(cmsDecoder
->signedData
);
328 if(cmsDecoder
->detachedContent
!= NULL
) {
329 /* time to calculate digests from detached content */
330 ortn
= cmsDigestDetachedContent(cmsDecoder
);
337 * A signed CMS message optionally includes the data which was signed. If the
338 * message does not include the signed data, caller specifies the signed data
339 * (the "detached content") here.
341 * This can be called either before or after the actual decoding of the message
342 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
343 * restriction is that, if detached content is required, this function must
344 * be called befoere successfully ascertaining the signature status via
345 * CMSDecoderCopySignerStatus().
347 OSStatus
CMSDecoderSetDetachedContent(
348 CMSDecoderRef cmsDecoder
,
349 CFDataRef detachedContent
)
351 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
354 cmsDecoder
->detachedContent
= detachedContent
;
355 CFRetain(detachedContent
);
357 if(cmsDecoder
->signedData
!= NULL
) {
358 /* time to calculate digests from detached content */
359 ASSERT(cmsDecoder
->decState
== DS_Final
);
360 return cmsDigestDetachedContent(cmsDecoder
);
362 return errSecSuccess
;
366 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
367 * Returns a NULL detachedContent if no detached content has been specified.
368 * Caller must CFRelease() the result.
370 OSStatus
CMSDecoderCopyDetachedContent(
371 CMSDecoderRef cmsDecoder
,
372 CFDataRef
*detachedContent
) /* RETURNED */
374 if((cmsDecoder
== NULL
) || (detachedContent
== NULL
)) {
377 if(cmsDecoder
->detachedContent
!= NULL
) {
378 CFRetain(cmsDecoder
->detachedContent
);
380 *detachedContent
= cmsDecoder
->detachedContent
;
381 return errSecSuccess
;
385 * Optionally specify a SecKeychainRef, or an array of them, containing
386 * intermediate certs to be used in verifying a signed message's signer
387 * certs. By default, the default keychain search list is used for this.
388 * Specify an empty CFArrayRef to search *no* keychains for intermediate
390 * IF this is called, it must be called before CMSDecoderCopySignerStatus().
392 OSStatus
CMSDecoderSetSearchKeychain(
393 CMSDecoderRef cmsDecoder
,
394 CFTypeRef keychainOrArray
)
396 if(cmsDecoder
== NULL
) {
399 cmsDecoder
->keychainOrArray
= keychainOrArray
;
400 if(keychainOrArray
) {
401 CFRetain(keychainOrArray
);
403 return errSecSuccess
;
407 * Obtain the number of signers of a message. A result of zero indicates that
408 * the message was not signed.
410 OSStatus
CMSDecoderGetNumSigners(
411 CMSDecoderRef cmsDecoder
,
412 size_t *numSigners
) /* RETURNED */
414 if((cmsDecoder
== NULL
) || (numSigners
== NULL
)) {
417 if(cmsDecoder
->decState
!= DS_Final
) {
420 *numSigners
= cmsDecoder
->numSigners
;
421 return errSecSuccess
;
425 * Obtain the status of a CMS message's signature. A CMS message can
426 * be signed my multiple signers; this function returns the status
427 * associated with signer 'n' as indicated by the signerIndex parameter.
429 OSStatus
CMSDecoderCopySignerStatus(
430 CMSDecoderRef cmsDecoder
,
432 CFTypeRef policyOrArray
,
433 Boolean evaluateSecTrust
,
434 CMSSignerStatus
*signerStatus
, /* optional; RETURNED */
435 SecTrustRef
*secTrust
, /* optional; RETURNED */
436 OSStatus
*certVerifyResultCode
) /* optional; RETURNED */
438 if((cmsDecoder
== NULL
) || (cmsDecoder
->decState
!= DS_Final
) || (!policyOrArray
)) {
442 /* initialize return values */
444 *signerStatus
= kCMSSignerUnsigned
;
449 if(certVerifyResultCode
) {
450 *certVerifyResultCode
= 0;
453 if(cmsDecoder
->signedData
== NULL
) {
454 *signerStatus
= kCMSSignerUnsigned
; /* redundant, I know, but explicit */
455 return errSecSuccess
;
457 ASSERT(cmsDecoder
->numSigners
> 0);
458 if(signerIndex
>= cmsDecoder
->numSigners
) {
459 *signerStatus
= kCMSSignerInvalidIndex
;
460 return errSecSuccess
;
462 if(!SecCmsSignedDataHasDigests(cmsDecoder
->signedData
)) {
463 *signerStatus
= kCMSSignerNeedsDetachedContent
;
464 return errSecSuccess
;
468 * OK, we should be able to verify this signerInfo.
469 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
470 * in order get all the cert pieces into place before returning them
473 SecTrustRef theTrust
= NULL
;
474 OSStatus vfyRtn
= SecCmsSignedDataVerifySignerInfo(cmsDecoder
->signedData
,
477 * FIXME this cast should not be necessary, but libsecurity_smime
478 * declares this argument as a SecKeychainRef
480 (SecKeychainRef
)cmsDecoder
->keychainOrArray
,
484 #if SECTRUST_VERBOSE_DEBUG
485 syslog(LOG_ERR
, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn
);
486 if (policyOrArray
) CFShow(policyOrArray
);
487 if (theTrust
) CFShow(theTrust
);
490 /* Subsequent errors to errOut: */
493 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
494 * SecTrustEvaluate() if we don't ask for a copy.
496 * FIXME deal with multitudes of status returns here...for now, proceed with
497 * obtaining components the caller wants and assume that a nonzero vfyRtn
498 * means "bad signature".
500 OSStatus ortn
= errSecSuccess
;
501 SecTrustResultType secTrustResult
;
502 CSSM_RETURN tpVfyStatus
= CSSM_OK
;
505 if(secTrust
!= NULL
) {
506 *secTrust
= theTrust
;
507 /* we'll release our reference at the end */
511 SecCmsSignerInfoRef signerInfo
=
512 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
513 if(signerInfo
== NULL
) {
514 /* should never happen */
516 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
517 ortn
= errSecInternalComponent
;
521 /* now do the actual cert verify */
522 if(evaluateSecTrust
) {
523 evalRtn
= SecTrustEvaluate(theTrust
, &secTrustResult
);
525 /* should never happen */
526 CSSM_PERROR("SecTrustEvaluate", evalRtn
);
527 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
528 ortn
= errSecInternalComponent
;
531 switch(secTrustResult
) {
532 case kSecTrustResultUnspecified
:
533 /* cert chain valid, no special UserTrust assignments */
534 case kSecTrustResultProceed
:
535 /* cert chain valid AND user explicitly trusts this */
537 case kSecTrustResultDeny
:
538 tpVfyStatus
= CSSMERR_APPLETP_TRUST_SETTING_DENY
;
540 case kSecTrustResultConfirm
:
541 dprintf("SecTrustEvaluate reported confirm\n");
542 tpVfyStatus
= CSSMERR_TP_NOT_TRUSTED
;
546 /* get low-level TP error */
548 ortn
= SecTrustGetCssmResultCode(theTrust
, &tpStatus
);
550 CSSM_PERROR("SecTrustGetCssmResultCode", ortn
);
553 tpVfyStatus
= tpStatus
;
555 CSSM_PERROR("TP status after SecTrustEvaluate", tpVfyStatus
);
558 } /* switch(secTrustResult) */
559 } /* evaluateSecTrust true */
560 if(certVerifyResultCode
!= NULL
) {
561 *certVerifyResultCode
= tpVfyStatus
;
564 /* cook up global status based on vfyRtn and tpVfyStatus */
565 if(signerStatus
!= NULL
) {
566 if((vfyRtn
== errSecSuccess
) && (tpVfyStatus
== CSSM_OK
)) {
567 *signerStatus
= kCMSSignerValid
;
569 else if(vfyRtn
!= errSecSuccess
) {
570 /* this could mean other things, but for now... */
571 *signerStatus
= kCMSSignerInvalidSignature
;
574 *signerStatus
= kCMSSignerInvalidCert
;
583 * Obtain the email address of signer 'signerIndex' of a CMS message, if
586 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
588 OSStatus
CMSDecoderCopySignerEmailAddress(
589 CMSDecoderRef cmsDecoder
,
591 CFStringRef
*signerEmailAddress
) /* RETURNED */
593 if((cmsDecoder
== NULL
) ||
594 (signerEmailAddress
== NULL
) ||
595 (cmsDecoder
->signedData
== NULL
) || /* not signed */
596 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
597 (cmsDecoder
->decState
!= DS_Final
)) {
601 SecCmsSignerInfoRef signerInfo
=
602 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
603 if(signerInfo
== NULL
) {
604 /* should never happen */
606 dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
607 return errSecInternalComponent
;
611 * This is leaking memory in libsecurityKeychain per Radar 4412699.
613 *signerEmailAddress
= SecCmsSignerInfoGetSignerEmailAddress(signerInfo
);
614 return errSecSuccess
;
618 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
621 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
623 OSStatus
CMSDecoderCopySignerCert(
624 CMSDecoderRef cmsDecoder
,
626 SecCertificateRef
*signerCert
) /* RETURNED */
628 if((cmsDecoder
== NULL
) ||
629 (signerCert
== NULL
) ||
630 (cmsDecoder
->signedData
== NULL
) || /* not signed */
631 (signerIndex
>= cmsDecoder
->numSigners
) || /* index out of range */
632 (cmsDecoder
->decState
!= DS_Final
)) {
636 SecCmsSignerInfoRef signerInfo
=
637 SecCmsSignedDataGetSignerInfo(cmsDecoder
->signedData
, (int)signerIndex
);
638 if(signerInfo
== NULL
) {
639 /* should never happen */
641 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
642 return errSecInternalComponent
;
644 *signerCert
= SecCmsSignerInfoGetSigningCertificate(signerInfo
, NULL
);
645 /* libsecurity_smime does NOT retain that */
646 if(*signerCert
== NULL
) {
647 /* should never happen */
649 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
650 return errSecInternalComponent
;
652 CFRetain(*signerCert
);
653 return errSecSuccess
;
657 * Determine whether a CMS message was encrypted, and if so, whether we were
658 * able to decrypt it.
660 OSStatus
CMSDecoderIsContentEncrypted(
661 CMSDecoderRef cmsDecoder
,
662 Boolean
*wasEncrypted
)
664 if((cmsDecoder
== NULL
) || (wasEncrypted
== NULL
)) {
667 if(cmsDecoder
->decState
!= DS_Final
) {
670 *wasEncrypted
= cmsDecoder
->wasEncrypted
;
671 return errSecSuccess
;
675 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
678 OSStatus
CMSDecoderCopyEncapsulatedContentType(
679 CMSDecoderRef cmsDecoder
,
680 CFDataRef
*eContentType
) /* RETURNED */
682 if((cmsDecoder
== NULL
) || (eContentType
== NULL
)) {
685 if(cmsDecoder
->decState
!= DS_Final
) {
688 if(cmsDecoder
->signedData
== NULL
) {
689 *eContentType
= NULL
;
692 CSSM_OID
*ecOid
= cmsDecoder
->eContentType
;
693 *eContentType
= CFDataCreate(NULL
, ecOid
->Data
, ecOid
->Length
);
695 return errSecSuccess
;
699 * Obtain an array of all of the certificates in a message. Elements of the
700 * returned array are SecCertificateRefs. The caller must CFRelease the returned
702 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
704 OSStatus
CMSDecoderCopyAllCerts(
705 CMSDecoderRef cmsDecoder
,
706 CFArrayRef
*certs
) /* RETURNED */
708 if((cmsDecoder
== NULL
) || (certs
== NULL
)) {
711 if(cmsDecoder
->decState
!= DS_Final
) {
714 if(cmsDecoder
->signedData
== NULL
) {
715 /* message wasn't signed */
717 return errSecSuccess
;
720 /* NULL_terminated array of CSSM_DATA ptrs */
721 CSSM_DATA_PTR
*cssmCerts
= SecCmsSignedDataGetCertificateList(cmsDecoder
->signedData
);
722 if((cssmCerts
== NULL
) || (*cssmCerts
== NULL
)) {
724 return errSecSuccess
;
727 CFMutableArrayRef allCerts
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
728 CSSM_DATA_PTR
*cssmCert
;
729 for(cssmCert
=cssmCerts
; *cssmCert
!=NULL
; cssmCert
++) {
731 SecCertificateRef cfCert
;
732 ortn
= SecCertificateCreateFromData(*cssmCert
,
733 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
,
739 CFArrayAppendValue(allCerts
, cfCert
);
740 /* the array holds the only needed refcount */
744 return errSecSuccess
;
748 * Obtain the actual message content (payload), if any. If the message was
749 * signed with detached content this will return NULL.
750 * Caller must CFRelease the result.
752 OSStatus
CMSDecoderCopyContent(
753 CMSDecoderRef cmsDecoder
,
754 CFDataRef
*content
) /* RETURNED */
756 if((cmsDecoder
== NULL
) || (content
== NULL
)) {
759 if(cmsDecoder
->decState
!= DS_Final
) {
762 if(cmsDecoder
->cmsMsg
== NULL
) {
763 /* Hmmm....looks like the finalize call failed */
766 CSSM_DATA_PTR odata
= SecCmsMessageGetContent(cmsDecoder
->cmsMsg
);
767 if((odata
== NULL
) || (odata
->Length
== 0)) {
768 /* i.e., detached content */
770 return errSecSuccess
;
772 *content
= CFDataCreate(NULL
, (const UInt8
*)odata
->Data
, odata
->Length
);
773 return errSecSuccess
;
776 #pragma mark --- SPI declared in CMSPrivate.h ---
779 * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
780 * to be called after decoding the message (i.e., after
781 * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
782 * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
783 * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
786 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
788 OSStatus
CMSDecoderGetCmsMessage(
789 CMSDecoderRef cmsDecoder
,
790 SecCmsMessageRef
*cmsMessage
) /* RETURNED */
792 if((cmsDecoder
== NULL
) || (cmsMessage
== NULL
)) {
795 /* any state, whether we have a msg or not is OK */
796 *cmsMessage
= cmsDecoder
->cmsMsg
;
797 return errSecSuccess
;
801 * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
802 * If this is called, it must be called before the first call to
803 * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
804 * incoming SecCmsDecoderRef.
806 OSStatus
CMSDecoderSetDecoder(
807 CMSDecoderRef cmsDecoder
,
808 SecCmsDecoderRef decoder
)
810 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
813 switch(cmsDecoder
->decState
) {
815 ASSERT(cmsDecoder
->decoder
== NULL
);
816 cmsDecoder
->decoder
= decoder
;
817 cmsDecoder
->decState
= DS_Updating
;
818 return errSecSuccess
;
823 return errSecSuccess
;
827 * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
828 * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
829 * CMSDecoderUpdateMessage() has been called.
830 * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
832 OSStatus
CMSDecoderGetDecoder(
833 CMSDecoderRef cmsDecoder
,
834 SecCmsDecoderRef
*decoder
) /* RETURNED */
836 if((cmsDecoder
== NULL
) || (decoder
== NULL
)) {
839 /* any state, whether we have a decoder or not is OK */
840 *decoder
= cmsDecoder
->decoder
;
841 return errSecSuccess
;
845 * Obtain the signing time of signer 'signerIndex' of a CMS message, if
846 * present. This is an unauthenticate time, although it is part of the
847 * signed attributes of the message.
849 * Returns errSecParam if the CMS message was not signed or if signerIndex
850 * is greater than the number of signers of the message minus one.
852 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
854 OSStatus
CMSDecoderCopySignerSigningTime(
855 CMSDecoderRef cmsDecoder
,
856 size_t signerIndex
, /* usually 0 */
857 CFAbsoluteTime
*signingTime
) /* RETURNED */
859 OSStatus status
= errSecParam
;
860 SecCmsMessageRef cmsg
;
861 SecCmsSignedDataRef signedData
= NULL
;
862 int numContentInfos
= 0;
864 require(cmsDecoder
&& signingTime
, xit
);
865 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
866 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
867 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
869 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
870 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
871 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
872 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
873 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
875 status
= SecCmsSignerInfoGetSigningTime(signerInfo
, signingTime
);
884 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
885 * present. 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.
891 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
894 OSStatus
CMSDecoderCopySignerTimestamp(
895 CMSDecoderRef cmsDecoder
,
896 size_t signerIndex
, /* usually 0 */
897 CFAbsoluteTime
*timestamp
) /* RETURNED */
899 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder
, NULL
, signerIndex
, timestamp
);
902 OSStatus
CMSDecoderCopySignerTimestampWithPolicy(
903 CMSDecoderRef cmsDecoder
,
904 CFTypeRef timeStampPolicy
,
905 size_t signerIndex
, /* usually 0 */
906 CFAbsoluteTime
*timestamp
) /* RETURNED */
908 OSStatus status
= errSecParam
;
909 SecCmsMessageRef cmsg
;
910 SecCmsSignedDataRef signedData
= NULL
;
911 int numContentInfos
= 0;
913 require(cmsDecoder
&& timestamp
, xit
);
914 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
915 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
916 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
918 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
919 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
920 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
921 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
922 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
924 status
= SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo
, timeStampPolicy
, timestamp
);
934 * Obtain an array of the certificates in a timestamp response. Elements of the
935 * returned array are SecCertificateRefs. The caller must CFRelease the returned
936 * array. This timestamp is an authenticated timestamp provided by
937 * a timestamping authority.
939 * Returns errSecParam if the CMS message was not signed or if signerIndex
940 * is greater than the number of signers of the message minus one. It returns
941 * errSecItemNotFound if no certificates were found.
943 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
945 OSStatus
CMSDecoderCopySignerTimestampCertificates(
946 CMSDecoderRef cmsDecoder
,
947 size_t signerIndex
, /* usually 0 */
948 CFArrayRef
*certificateRefs
) /* RETURNED */
950 OSStatus status
= errSecParam
;
951 SecCmsMessageRef cmsg
= NULL
;
952 SecCmsSignedDataRef signedData
= NULL
;
953 int numContentInfos
= 0;
957 require(cmsDecoder
&& certificateRefs
, xit
);
958 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
959 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
960 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
962 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
963 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
964 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
965 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
966 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
968 CFArrayRef certList
= SecCmsSignerInfoGetTimestampCertList(signerInfo
);
969 require_action(certList
, xit
, status
= errSecItemNotFound
);
970 CFMutableArrayRef certs
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, CFArrayGetCount(certList
), certList
);
973 //reorder certificates:
974 tsn
= CFArrayGetCount(certs
);
975 good
= tsn
> 0 && Security::CodeSigning::isAppleCA(SecCertificateRef(CFArrayGetValueAtIndex(certs
, tsn
-1)));
979 //change TS certificate ordering.
980 for (CFIndex n
= 0; n
< tsn
; n
++)
982 if (SecCertificateRef tsRoot
= SecCertificateRef(CFArrayGetValueAtIndex(certs
, n
)))
983 if ((good
= Security::CodeSigning::isAppleCA(tsRoot
))) {
984 CFArrayExchangeValuesAtIndices(certs
, n
, tsn
-1);
990 *certificateRefs
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
992 status
= errSecSuccess
;
1004 * Obtain the Hash Agility attribute value of signer 'signerIndex'
1005 * of a CMS message, if present.
1007 * Returns errSecParam if the CMS message was not signed or if signerIndex
1008 * is greater than the number of signers of the message minus one.
1010 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1012 OSStatus
CMSDecoderCopySignerAppleCodesigningHashAgility(
1013 CMSDecoderRef cmsDecoder
,
1014 size_t signerIndex
, /* usually 0 */
1015 CFDataRef CF_RETURNS_RETAINED
*hashAgilityAttrValue
) /* RETURNED */
1017 OSStatus status
= errSecParam
;
1018 SecCmsMessageRef cmsg
;
1019 SecCmsSignedDataRef signedData
= NULL
;
1020 int numContentInfos
= 0;
1021 CFDataRef returnedValue
= NULL
;
1023 require(cmsDecoder
&& hashAgilityAttrValue
, xit
);
1024 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder
, &cmsg
), xit
);
1025 numContentInfos
= SecCmsMessageContentLevelCount(cmsg
);
1026 for (int dex
= 0; !signedData
&& dex
< numContentInfos
; dex
++)
1028 SecCmsContentInfoRef ci
= SecCmsMessageContentLevel(cmsg
, dex
);
1029 SECOidTag tag
= SecCmsContentInfoGetContentTypeTag(ci
);
1030 if (tag
== SEC_OID_PKCS7_SIGNED_DATA
)
1031 if ((signedData
= SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci
))))
1032 if (SecCmsSignerInfoRef signerInfo
= SecCmsSignedDataGetSignerInfo(signedData
, (int)signerIndex
))
1034 status
= SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo
, &returnedValue
);
1039 if (status
== errSecSuccess
&& returnedValue
) {
1040 *hashAgilityAttrValue
= (CFDataRef
) CFRetain(returnedValue
);
1042 *hashAgilityAttrValue
= NULL
;