]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_cms/lib/CMSDecoder.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_cms / lib / CMSDecoder.cpp
diff --git a/Security/libsecurity_cms/lib/CMSDecoder.cpp b/Security/libsecurity_cms/lib/CMSDecoder.cpp
deleted file mode 100644 (file)
index e4ed76a..0000000
+++ /dev/null
@@ -1,993 +0,0 @@
-/*
- * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * CMSDecoder.cpp - Interface for decoding CMS messages.
- */
-
-#include "CMSDecoder.h"
-#include "CMSPrivate.h"
-#include "CMSUtils.h"
-#include <../libsecurity_codesigning/lib/csutilities.h>
-
-#include <Security/SecCmsDecoder.h>
-#include <Security/SecCmsEnvelopedData.h>
-#include <Security/SecCmsMessage.h>
-#include <Security/SecCmsSignedData.h>
-#include <Security/SecCmsSignerInfo.h>
-#include <Security/SecCmsContentInfo.h>
-#include <Security/SecCmsDigestContext.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecSMIME.h>
-#include <Security/oidsattr.h>
-#include <Security/SecTrustPriv.h>
-#include <CoreFoundation/CFRuntime.h>
-#include <pthread.h>
-#include <AssertMacros.h>
-
-#pragma mark --- Private types and definitions ---
-
-/*
- * Decoder state.
- */
-typedef enum {
-       DS_Init,                /* between CMSDecoderCreate and CMSDecoderUpdateMessage */
-       DS_Updating,    /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */
-       DS_Final                /* CMSDecoderFinalizeMessage has been called */
-} CMSDecoderState;
-
-/*
- * Caller's CMSDecoderRef points to one of these.
- */
-struct _CMSDecoder {
-       CFRuntimeBase           base;
-       CMSDecoderState         decState;
-       SecArenaPoolRef         arena;                          /* the decoder's arena */
-       SecCmsDecoderRef        decoder;
-       CFDataRef                       detachedContent;
-       CFTypeRef                       keychainOrArray;        /* from CMSDecoderSetSearchKeychain() */
-       
-       /*
-        * The following are valid (and quiescent) after CMSDecoderFinalizeMessage().
-        */
-       SecCmsMessageRef        cmsMsg;
-       Boolean                         wasEncrypted;   /* valid after CMSDecoderFinalizeMessage() */
-       SecCmsSignedDataRef     signedData;             /* if there is one... */
-       /* only non-NULL if we found a signedData */
-       size_t                          numSigners;
-       CSSM_OID                        *eContentType;
-       /* etc. */
-};
-
-static void cmsDecoderInit(CFTypeRef dec);
-static void cmsDecoderFinalize(CFTypeRef dec);
-
-static CFRuntimeClass cmsDecoderRuntimeClass =
-{
-       0,                      /* version */
-       "CMSDecoder",
-       cmsDecoderInit,
-       NULL,           /* copy */
-       cmsDecoderFinalize,
-       NULL,           /* equal - just use pointer equality */
-       NULL,           /* hash, ditto */
-       NULL,           /* copyFormattingDesc */
-       NULL            /* copyDebugDesc */
-};
-
-#pragma mark --- Private Routines ---
-
-static CFTypeID cmsDecoderTypeID = _kCFRuntimeNotATypeID;
-
-/* one time only class init, called via pthread_once() in CMSDecoderGetTypeID() */
-static void cmsDecoderClassInitialize(void)
-{
-       cmsDecoderTypeID =
-    _CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsDecoderRuntimeClass);
-}
-
-/* init called out from _CFRuntimeCreateInstance() */
-static void cmsDecoderInit(CFTypeRef dec)
-{
-       char *start = ((char *)dec) + sizeof(CFRuntimeBase);
-       memset(start, 0, sizeof(struct _CMSDecoder) - sizeof(CFRuntimeBase));
-}
-
-/*
- * Dispose of a CMSDecoder. Called out from CFRelease().
- */
-static void cmsDecoderFinalize(
-                               CFTypeRef               dec)
-{
-       CMSDecoderRef cmsDecoder = (CMSDecoderRef)dec;
-       if(cmsDecoder == NULL) {
-               return;
-       }
-       if(cmsDecoder->decoder != NULL) {
-               /*
-                * Normally this gets freed in SecCmsDecoderFinish - this is
-                * an error case.
-                * FIXME: SecCmsDecoderDestroy() appears to destroy the
-                * cmsMsg too! Plus there's a comment there re: a leak...
-                */
-               SecCmsDecoderDestroy(cmsDecoder->decoder);
-       }
-       CFRELEASE(cmsDecoder->detachedContent);
-       CFRELEASE(cmsDecoder->keychainOrArray);
-       if(cmsDecoder->cmsMsg != NULL) {
-               SecCmsMessageDestroy(cmsDecoder->cmsMsg);
-       }
-       if(cmsDecoder->arena != NULL) {
-               SecArenaPoolFree(cmsDecoder->arena, false);
-       }
-}
-
-
-/*
- * Given detached content and a valid (decoded) SignedData, digest the detached
- * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a
- * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent()
- * when we already have a SignedData).
- */
-static OSStatus cmsDigestDetachedContent(
-                                         CMSDecoderRef cmsDecoder)
-{
-       ASSERT((cmsDecoder->signedData != NULL) && (cmsDecoder->detachedContent != NULL));
-       
-       SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(cmsDecoder->signedData);
-       if(digestAlgorithms == NULL) {
-               return errSecUnknownFormat;
-       }
-       SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestAlgorithms);
-       if(digcx == NULL) {
-               return errSecAllocate;
-       }
-       CSSM_DATA **digests = NULL;
-       
-       SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(cmsDecoder->detachedContent),
-                              CFDataGetLength(cmsDecoder->detachedContent));
-       /* note this frees the digest content regardless */
-       OSStatus ortn = SecCmsDigestContextFinishMultiple(digcx, cmsDecoder->arena, &digests);
-       if(ortn) {
-               ortn = cmsRtnToOSStatus(ortn);
-               CSSM_PERROR("SecCmsDigestContextFinishMultiple", ortn);
-               return ortn;
-       }
-       ortn = SecCmsSignedDataSetDigests(cmsDecoder->signedData, digestAlgorithms, digests);
-       if(ortn) {
-               ortn = cmsRtnToOSStatus(ortn);
-               CSSM_PERROR("SecCmsSignedDataSetDigests", ortn);
-       }
-       return ortn;
-}
-
-#pragma mark --- Start of Public API ---
-
-CFTypeID CMSDecoderGetTypeID(void)
-{
-       static pthread_once_t once = PTHREAD_ONCE_INIT;
-       
-       if(cmsDecoderTypeID == _kCFRuntimeNotATypeID) {
-               pthread_once(&once, &cmsDecoderClassInitialize);
-       }
-       return cmsDecoderTypeID;
-}
-
-/*
- * Create a CMSDecoder. Result must eventually be freed via CFRelease().
- */
-OSStatus CMSDecoderCreate(
-                          CMSDecoderRef                *cmsDecoderOut) /* RETURNED */
-{
-       CMSDecoderRef cmsDecoder = NULL;
-    
-       uint32_t extra = sizeof(*cmsDecoder) - sizeof(cmsDecoder->base);
-       cmsDecoder = (CMSDecoderRef)_CFRuntimeCreateInstance(NULL, CMSDecoderGetTypeID(),
-                                                         extra, NULL);
-       if(cmsDecoder == NULL) {
-               return errSecAllocate;
-       }
-       cmsDecoder->decState = DS_Init;
-       *cmsDecoderOut = cmsDecoder;
-       return errSecSuccess;
-}
-
-/*
- * Feed raw bytes of the message to be decoded into the decoder. Can be called
- * multiple times.
- */
-OSStatus CMSDecoderUpdateMessage(
-                                 CMSDecoderRef         cmsDecoder,
-                                 const void                    *msgBytes,
-                                 size_t                                msgBytesLen)
-{
-       if(cmsDecoder == NULL) {
-               return errSecParam;
-       }
-       
-       OSStatus ortn;
-       switch(cmsDecoder->decState) {
-               case DS_Init:
-                       /* First time through; set up */
-                       ASSERT(cmsDecoder->decoder == NULL);
-                       ASSERT(cmsDecoder->arena == NULL);
-                       ortn = SecArenaPoolCreate(1024, &cmsDecoder->arena);
-                       if(ortn) {
-                               return cmsRtnToOSStatus(ortn);
-                       }
-                       ortn = SecCmsDecoderCreate(cmsDecoder->arena,
-                                       NULL, NULL, NULL, NULL, NULL, NULL, &cmsDecoder->decoder);
-                       if(ortn) {
-                               ortn = cmsRtnToOSStatus(ortn);
-                               CSSM_PERROR("SecCmsDecoderCreate", ortn);
-                               return ortn;
-                       }
-                       cmsDecoder->decState = DS_Updating;
-                       break;
-            
-               case DS_Updating:
-                       ASSERT(cmsDecoder->decoder != NULL);
-                       break;
-                       
-               case DS_Final:
-                       /* Too late for another update */
-                       return errSecParam;
-                       
-               default:
-                       dprintf("CMSDecoderUpdateMessage: bad decState\n");
-                       return errSecInternalComponent;
-       }
-       
-       /* FIXME - CFIndex same size as size_t on 64bit? */
-       ortn = SecCmsDecoderUpdate(cmsDecoder->decoder, msgBytes, (CFIndex)msgBytesLen);
-       if(ortn) {
-               ortn = cmsRtnToOSStatus(ortn, errSecUnknownFormat);
-               CSSM_PERROR("SecCmsDecoderUpdate", ortn);
-       }
-       return ortn;
-}
-
-/*
- * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
- * finish decoding the message. We parse the message as best we can, up to
- * but not including verifying individual signerInfos.
- */
-OSStatus CMSDecoderFinalizeMessage(
-                                   CMSDecoderRef               cmsDecoder)
-{
-       if(cmsDecoder == NULL) {
-               return errSecParam;
-       }
-       if(cmsDecoder->decState != DS_Updating) {
-               return errSecParam;
-       }
-       ASSERT(cmsDecoder->decoder != NULL);
-       OSStatus ortn = SecCmsDecoderFinish(cmsDecoder->decoder, &cmsDecoder->cmsMsg);
-       cmsDecoder->decState = DS_Final;
-       
-       /* SecCmsDecoderFinish destroyed the decoder even on failure */
-       cmsDecoder->decoder = NULL;
-       
-       if(ortn) {
-               ortn = cmsRtnToOSStatus(ortn, errSecUnknownFormat);
-               CSSM_PERROR("SecCmsDecoderFinish", ortn);
-               return ortn;
-       }
-       
-       ASSERT(cmsDecoder->cmsMsg != NULL);
-       cmsDecoder->wasEncrypted = SecCmsMessageIsEncrypted(cmsDecoder->cmsMsg);
-       
-       /* Look for a SignedData */
-       int numContentInfos = SecCmsMessageContentLevelCount(cmsDecoder->cmsMsg);
-       int dex;
-       for(dex=0; dex<numContentInfos; dex++) {
-               SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsDecoder->cmsMsg, dex);
-               SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
-               switch(tag) {
-                       case SEC_OID_PKCS7_SIGNED_DATA:
-                               cmsDecoder->signedData =
-                (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci);
-                               /* dig down one more layer for eContentType */
-                               ci = SecCmsSignedDataGetContentInfo(cmsDecoder->signedData);
-                               cmsDecoder->eContentType = SecCmsContentInfoGetContentTypeOID(ci);
-                               break;
-                       default:
-                               break;
-               }
-               if(cmsDecoder->signedData != NULL) {
-                       break;
-               }
-        
-       }
-       
-       /* minimal processing of optional signedData... */
-       if(cmsDecoder->signedData != NULL) {
-               cmsDecoder->numSigners = (size_t)
-        SecCmsSignedDataSignerInfoCount(cmsDecoder->signedData);
-               if(cmsDecoder->detachedContent != NULL) {
-                       /* time to calculate digests from detached content */
-                       ortn = cmsDigestDetachedContent(cmsDecoder);
-               }
-       }
-       return ortn;
-}
-
-/*
- * A signed CMS message optionally includes the data which was signed. If the
- * message does not include the signed data, caller specifies the signed data
- * (the "detached content") here.
- *
- * This can be called either before or after the actual decoding of the message
- * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
- * restriction is that, if detached content is required, this function must
- * be called befoere successfully ascertaining the signature status via
- * CMSDecoderCopySignerStatus().
- */
-OSStatus CMSDecoderSetDetachedContent(
-                                      CMSDecoderRef            cmsDecoder,
-                                      CFDataRef                        detachedContent)
-{
-       if((cmsDecoder == NULL) || (detachedContent == NULL)) {
-               return errSecParam;
-       }
-       cmsDecoder->detachedContent = detachedContent;
-       CFRetain(detachedContent);
-       
-       if(cmsDecoder->signedData != NULL) {
-               /* time to calculate digests from detached content */
-               ASSERT(cmsDecoder->decState == DS_Final);
-               return cmsDigestDetachedContent(cmsDecoder);
-       }
-       return errSecSuccess;
-}
-
-/*
- * Obtain the detached content specified in CMSDecoderSetDetachedContent().
- * Returns a NULL detachedContent if no detached content has been specified.
- * Caller must CFRelease() the result.
- */
-OSStatus CMSDecoderCopyDetachedContent(
-                                       CMSDecoderRef           cmsDecoder,
-                                       CFDataRef                       *detachedContent)               /* RETURNED */
-{
-       if((cmsDecoder == NULL) || (detachedContent == NULL)) {
-               return errSecParam;
-       }
-       if(cmsDecoder->detachedContent != NULL) {
-               CFRetain(cmsDecoder->detachedContent);
-       }
-       *detachedContent = cmsDecoder->detachedContent;
-       return errSecSuccess;
-}
-
-/*
- * Optionally specify a SecKeychainRef, or an array of them, containing
- * intermediate certs to be used in verifying a signed message's signer
- * certs. By default, the default keychain search list is used for this.
- * Specify an empty CFArrayRef to search *no* keychains for intermediate
- * certs.
- * IF this is called, it must be called before CMSDecoderCopySignerStatus().
- */
-OSStatus CMSDecoderSetSearchKeychain(
-                                     CMSDecoderRef             cmsDecoder,
-                                     CFTypeRef                 keychainOrArray)
-{
-       if(cmsDecoder == NULL) {
-               return errSecParam;
-       }
-       cmsDecoder->keychainOrArray = keychainOrArray;
-       if(keychainOrArray) {
-               CFRetain(keychainOrArray);
-       }
-       return errSecSuccess;
-}
-
-/*
- * Obtain the number of signers of a message. A result of zero indicates that
- * the message was not signed.
- */
-OSStatus CMSDecoderGetNumSigners(
-                                 CMSDecoderRef         cmsDecoder,
-                                 size_t                                *numSigners)                    /* RETURNED */
-{
-       if((cmsDecoder == NULL) || (numSigners == NULL)) {
-               return errSecParam;
-       }
-       if(cmsDecoder->decState != DS_Final) {
-               return errSecParam;
-       }
-       *numSigners = cmsDecoder->numSigners;
-       return errSecSuccess;
-}
-
-/*
- * Obtain the status of a CMS message's signature. A CMS message can
- * be signed my multiple signers; this function returns the status
- * associated with signer 'n' as indicated by the signerIndex parameter.
- */
-OSStatus CMSDecoderCopySignerStatus(
-                                    CMSDecoderRef              cmsDecoder,
-                                    size_t                             signerIndex,
-                                    CFTypeRef                  policyOrArray,
-                                    Boolean                            evaluateSecTrust,
-                                    CMSSignerStatus            *signerStatus,                  /* optional; RETURNED */
-                                    SecTrustRef                        *secTrust,                              /* optional; RETURNED */
-                                    OSStatus                   *certVerifyResultCode)  /* optional; RETURNED */
-{
-       if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final)) {
-               return errSecParam;
-       }
-       
-       /* initialize return values */
-       if(signerStatus) {
-               *signerStatus = kCMSSignerUnsigned;
-       }
-       if(secTrust) {
-               *secTrust = NULL;
-       }
-       if(certVerifyResultCode) {
-               *certVerifyResultCode = 0;
-       }
-       
-       if(cmsDecoder->signedData == NULL) {
-               *signerStatus = kCMSSignerUnsigned;     /* redundant, I know, but explicit */
-               return errSecSuccess;
-       }
-       ASSERT(cmsDecoder->numSigners > 0);
-       if(signerIndex >= cmsDecoder->numSigners) {
-               *signerStatus = kCMSSignerInvalidIndex;
-               return errSecSuccess;
-       }
-       if(!SecCmsSignedDataHasDigests(cmsDecoder->signedData)) {
-               *signerStatus = kCMSSignerNeedsDetachedContent;
-               return errSecSuccess;
-       }
-       
-       /*
-        * OK, we should be able to verify this signerInfo.
-        * I think we have to do the SecCmsSignedDataVerifySignerInfo first
-        * in order get all the cert pieces into place before returning them
-        * to the caller.
-        */
-       SecTrustRef theTrust = NULL;
-       OSStatus vfyRtn = SecCmsSignedDataVerifySignerInfo(cmsDecoder->signedData,
-                                                       (int)signerIndex,
-                                                       /*
-                                                        * FIXME this cast should not be necessary, but libsecurity_smime
-                                                        * declares this argument as a SecKeychainRef
-                                                        */
-                                                       (SecKeychainRef)cmsDecoder->keychainOrArray,
-                                                       policyOrArray,
-                                                       &theTrust);
-    /* Subsequent errors to errOut: */
-    
-       /*
-        * NOTE the smime lib did NOT evaluate that SecTrust - it only does
-        * SecTrustEvaluate() if we don't ask for a copy.
-        *
-        * FIXME deal with multitudes of status returns here...for now, proceed with
-        * obtaining components the caller wants and assume that a nonzero vfyRtn
-        * means "bad signature".
-        */
-       OSStatus ortn = errSecSuccess;
-       SecTrustResultType secTrustResult;
-       CSSM_RETURN tpVfyStatus = CSSM_OK;
-       OSStatus evalRtn;
-       
-       if(secTrust != NULL) {
-               *secTrust = theTrust;
-               /* we'll release our reference at the end */
-               if (theTrust)
-                       CFRetain(theTrust);
-       }
-       SecCmsSignerInfoRef signerInfo =
-    SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
-       if(signerInfo == NULL) {
-               /* should never happen */
-               ASSERT(0);
-               dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
-               ortn = errSecInternalComponent;
-               goto errOut;
-       }
-    
-       /* now do the actual cert verify */
-       if(evaluateSecTrust) {
-               evalRtn = SecTrustEvaluate(theTrust, &secTrustResult);
-               if(evalRtn) {
-                       /* should never happen */
-                       CSSM_PERROR("SecTrustEvaluate", evalRtn);
-                       dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
-                       ortn = errSecInternalComponent;
-                       goto errOut;
-               }
-               switch(secTrustResult) {
-                       case kSecTrustResultUnspecified:
-                               /* cert chain valid, no special UserTrust assignments */
-                       case kSecTrustResultProceed:
-                               /* cert chain valid AND user explicitly trusts this */
-                               break;
-                       case kSecTrustResultDeny:
-                               tpVfyStatus = CSSMERR_APPLETP_TRUST_SETTING_DENY;
-                               break;
-                       case kSecTrustResultConfirm:
-                               dprintf("SecTrustEvaluate reported confirm\n");
-                               tpVfyStatus = CSSMERR_TP_NOT_TRUSTED;
-                               break;
-                       default:
-                       {
-                               /* get low-level TP error */
-                               OSStatus tpStatus;
-                               ortn = SecTrustGetCssmResultCode(theTrust, &tpStatus);
-                               if(ortn) {
-                                       CSSM_PERROR("SecTrustGetCssmResultCode", ortn);
-                               }
-                               else {
-                                       tpVfyStatus = tpStatus;
-                               }
-                               CSSM_PERROR("TP status after SecTrustEvaluate", tpVfyStatus);
-                               break;
-                       }
-               }       /* switch(secTrustResult) */
-       }               /* evaluateSecTrust true */
-       if(certVerifyResultCode != NULL) {
-               *certVerifyResultCode = tpVfyStatus;
-       }
-       
-       /* cook up global status based on vfyRtn and tpVfyStatus */
-       if(signerStatus != NULL) {
-               if((vfyRtn == errSecSuccess) && (tpVfyStatus == CSSM_OK))  {
-                       *signerStatus = kCMSSignerValid;
-               }
-               else if(vfyRtn != errSecSuccess) {
-                       /* this could mean other things, but for now... */
-                       *signerStatus = kCMSSignerInvalidSignature;
-               }
-               else {
-                       *signerStatus = kCMSSignerInvalidCert;
-               }
-       }
-errOut:
-       CFRELEASE(theTrust);
-       return ortn;
-}
-
-/*
- * Obtain the email address of signer 'signerIndex' of a CMS message, if
- * present.
- *
- * This cannot be called until after CMSDecoderFinalizeMessage() is called.
- */
-OSStatus CMSDecoderCopySignerEmailAddress(
-                                          CMSDecoderRef                cmsDecoder,
-                                          size_t                               signerIndex,
-                                          CFStringRef                  *signerEmailAddress)    /* RETURNED */
-{
-       if((cmsDecoder == NULL) ||
-          (signerEmailAddress == NULL) ||
-          (cmsDecoder->signedData == NULL) ||                  /* not signed */
-          (signerIndex >= cmsDecoder->numSigners) ||   /* index out of range */
-          (cmsDecoder->decState != DS_Final)) {
-               return errSecParam;
-       }
-       
-       SecCmsSignerInfoRef signerInfo =
-    SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
-       if(signerInfo == NULL) {
-               /* should never happen */
-               ASSERT(0);
-               dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
-               return errSecInternalComponent;
-       }
-       
-       /*
-        * This is leaking memory in libsecurityKeychain per Radar 4412699.
-        */
-       *signerEmailAddress = SecCmsSignerInfoGetSignerEmailAddress(signerInfo);
-       return errSecSuccess;
-}
-
-/*
- * Obtain the certificate of signer 'signerIndex' of a CMS message, if
- * present.
- *
- * This cannot be called until after CMSDecoderFinalizeMessage() is called.
- */
-OSStatus CMSDecoderCopySignerCert(
-                                  CMSDecoderRef                cmsDecoder,
-                                  size_t                               signerIndex,
-                                  SecCertificateRef    *signerCert)                    /* RETURNED */
-{
-       if((cmsDecoder == NULL) ||
-          (signerCert == NULL) ||
-          (cmsDecoder->signedData == NULL) ||                  /* not signed */
-          (signerIndex >= cmsDecoder->numSigners) ||   /* index out of range */
-          (cmsDecoder->decState != DS_Final)) {
-               return errSecParam;
-       }
-    
-       SecCmsSignerInfoRef signerInfo =
-    SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
-       if(signerInfo == NULL) {
-               /* should never happen */
-               ASSERT(0);
-               dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
-               return errSecInternalComponent;
-       }
-       *signerCert = SecCmsSignerInfoGetSigningCertificate(signerInfo, NULL);
-       /* libsecurity_smime does NOT retain that */
-       if(*signerCert == NULL) {
-               /* should never happen */
-               ASSERT(0);
-               dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
-               return errSecInternalComponent;
-       }
-       CFRetain(*signerCert);
-       return errSecSuccess;
-}
-
-/*
- * Determine whether a CMS message was encrypted, and if so, whether we were
- * able to decrypt it.
- */
-OSStatus CMSDecoderIsContentEncrypted(
-                                      CMSDecoderRef    cmsDecoder,
-                                      Boolean                  *wasEncrypted)
-{
-       if((cmsDecoder == NULL) || (wasEncrypted == NULL)) {
-               return errSecParam;
-       }
-       if(cmsDecoder->decState != DS_Final) {
-               return errSecParam;
-       }
-       *wasEncrypted = cmsDecoder->wasEncrypted;
-       return errSecSuccess;
-}
-
-/*
- * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
- * present.
- */
-OSStatus CMSDecoderCopyEncapsulatedContentType(
-                                               CMSDecoderRef           cmsDecoder,
-                                               CFDataRef                       *eContentType)          /* RETURNED */
-{
-       if((cmsDecoder == NULL) || (eContentType == NULL)) {
-               return errSecParam;
-       }
-       if(cmsDecoder->decState != DS_Final) {
-               return errSecParam;
-       }
-       if(cmsDecoder->signedData == NULL) {
-               *eContentType = NULL;
-       }
-       else {
-               CSSM_OID *ecOid = cmsDecoder->eContentType;
-               *eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length);
-       }
-       return errSecSuccess;
-}
-
-/*
- * Obtain an array of all of the certificates in a message. Elements of the
- * returned array are SecCertificateRefs. The caller must CFRelease the returned
- * array.
- * This cannot be called until after CMSDecoderFinalizeMessage() is called.
- */
-OSStatus CMSDecoderCopyAllCerts(
-                                CMSDecoderRef          cmsDecoder,
-                                CFArrayRef                     *certs)                                 /* RETURNED */
-{
-       if((cmsDecoder == NULL) || (certs == NULL)) {
-               return errSecParam;
-       }
-       if(cmsDecoder->decState != DS_Final) {
-               return errSecParam;
-       }
-       if(cmsDecoder->signedData == NULL) {
-               /* message wasn't signed */
-               *certs = NULL;
-               return errSecSuccess;
-       }
-       
-       /* NULL_terminated array of CSSM_DATA ptrs */
-       CSSM_DATA_PTR *cssmCerts = SecCmsSignedDataGetCertificateList(cmsDecoder->signedData);
-       if((cssmCerts == NULL) || (*cssmCerts == NULL)) {
-               *certs = NULL;
-               return errSecSuccess;
-       }
-       
-       CFMutableArrayRef allCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       CSSM_DATA_PTR *cssmCert;
-       for(cssmCert=cssmCerts; *cssmCert!=NULL; cssmCert++) {
-               OSStatus ortn;
-               SecCertificateRef cfCert;
-               ortn = SecCertificateCreateFromData(*cssmCert,
-                                            CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
-                                            &cfCert);
-               if(ortn) {
-                       CFRelease(allCerts);
-                       return ortn;
-               }
-               CFArrayAppendValue(allCerts, cfCert);
-               /* the array holds the only needed refcount */
-               CFRelease(cfCert);
-       }
-       *certs = allCerts;
-       return errSecSuccess;
-}
-
-/*
- * Obtain the actual message content (payload), if any. If the message was
- * signed with detached content this will return NULL.
- * Caller must CFRelease the result.
- */
-OSStatus CMSDecoderCopyContent(
-                               CMSDecoderRef           cmsDecoder,
-                               CFDataRef                       *content)                               /* RETURNED */
-{
-       if((cmsDecoder == NULL) || (content == NULL)) {
-               return errSecParam;
-       }
-       if(cmsDecoder->decState != DS_Final) {
-               return errSecParam;
-       }
-       if(cmsDecoder->cmsMsg == NULL) {
-               /* Hmmm....looks like the finalize call failed */
-               return errSecParam;
-       }
-       CSSM_DATA_PTR odata = SecCmsMessageGetContent(cmsDecoder->cmsMsg);
-       if((odata == NULL) || (odata->Length == 0)) {
-               /* i.e., detached content */
-               *content = NULL;
-               return errSecSuccess;
-       }
-       *content = CFDataCreate(NULL, (const UInt8 *)odata->Data, odata->Length);
-       return errSecSuccess;
-}
-
-#pragma mark --- SPI declared in CMSPrivate.h ---
-
-/*
- * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
- * to be called after decoding the message (i.e., after
- * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
- * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
- * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
- * called.
- *
- * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
- */
-OSStatus CMSDecoderGetCmsMessage(
-                                 CMSDecoderRef         cmsDecoder,
-                                 SecCmsMessageRef      *cmsMessage)            /* RETURNED */
-{
-       if((cmsDecoder == NULL) || (cmsMessage == NULL)) {
-               return errSecParam;
-       }
-       /* any state, whether we have a msg or not is OK */
-       *cmsMessage = cmsDecoder->cmsMsg;
-       return errSecSuccess;
-}
-
-/*
- * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
- * If this is called, it must be called before the first call to
- * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
- * incoming SecCmsDecoderRef.
- */
-OSStatus CMSDecoderSetDecoder(
-                              CMSDecoderRef            cmsDecoder,
-                              SecCmsDecoderRef decoder)
-{
-       if((cmsDecoder == NULL) || (decoder == NULL)) {
-               return errSecParam;
-       }
-       switch(cmsDecoder->decState) {
-               case DS_Init:
-                       ASSERT(cmsDecoder->decoder == NULL);
-                       cmsDecoder->decoder = decoder;
-                       cmsDecoder->decState = DS_Updating;
-                       return errSecSuccess;
-               case DS_Updating:
-               case DS_Final:
-                       return errSecParam;
-       }
-       return errSecSuccess;
-}
-
-/*
- * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
- * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
- * CMSDecoderUpdateMessage() has been called.
- * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
- */
-OSStatus CMSDecoderGetDecoder(
-                              CMSDecoderRef            cmsDecoder,
-                              SecCmsDecoderRef *decoder)                       /* RETURNED */
-{
-       if((cmsDecoder == NULL) || (decoder == NULL)) {
-               return errSecParam;
-       }
-       /* any state, whether we have a decoder or not is OK */
-       *decoder = cmsDecoder->decoder;
-       return errSecSuccess;
-}
-
-/*
- * Obtain the signing time of signer 'signerIndex' of a CMS message, if
- * present. This is an unauthenticate time, although it is part of the
- * signed attributes of the message.
- *
- * Returns errSecParam if the CMS message was not signed or if signerIndex
- * is greater than the number of signers of the message minus one.
- *
- * This cannot be called until after CMSDecoderFinalizeMessage() is called.
- */
-OSStatus CMSDecoderCopySignerSigningTime(
-                                         CMSDecoderRef         cmsDecoder,
-                                         size_t                                signerIndex,            /* usually 0 */
-                                         CFAbsoluteTime      *signingTime)                     /* RETURNED */
-{
-    OSStatus status = errSecParam;
-       SecCmsMessageRef cmsg;
-       SecCmsSignedDataRef signedData = NULL;
-    int numContentInfos = 0;
-    
-    require(cmsDecoder && signingTime, xit);
-       require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
-    numContentInfos = SecCmsMessageContentLevelCount(cmsg);
-    for (int dex = 0; !signedData && dex < numContentInfos; dex++)
-    {
-        SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
-        SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
-        if (tag == SEC_OID_PKCS7_SIGNED_DATA)
-            if ((signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci))))
-                if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex))
-                {
-                    status = SecCmsSignerInfoGetSigningTime(signerInfo, signingTime);
-                    break;
-                }
-    }
-xit:
-    return status;
-}
-
-/*
- * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
- * present. This timestamp is an authenticated timestamp provided by
- * a timestamping authority.
- *
- * Returns errSecParam if the CMS message was not signed or if signerIndex
- * is greater than the number of signers of the message minus one.
- *
- * This cannot be called until after CMSDecoderFinalizeMessage() is called.
- */
-
-OSStatus CMSDecoderCopySignerTimestamp(
-                                       CMSDecoderRef           cmsDecoder,
-                                       size_t                          signerIndex,        /* usually 0 */
-                                       CFAbsoluteTime      *timestamp)                 /* RETURNED */
-{
-    return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder, NULL, signerIndex, timestamp);
-}
-
-OSStatus CMSDecoderCopySignerTimestampWithPolicy(
-                                       CMSDecoderRef           cmsDecoder,
-                                       CFTypeRef            timeStampPolicy,
-                                       size_t                          signerIndex,        /* usually 0 */
-                                       CFAbsoluteTime      *timestamp)                 /* RETURNED */
-{
-    OSStatus status = errSecParam;
-       SecCmsMessageRef cmsg;
-       SecCmsSignedDataRef signedData = NULL;
-    int numContentInfos = 0;
-    
-    require(cmsDecoder && timestamp, xit);
-       require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
-    numContentInfos = SecCmsMessageContentLevelCount(cmsg);
-    for (int dex = 0; !signedData && dex < numContentInfos; dex++)
-    {
-        SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
-        SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
-        if (tag == SEC_OID_PKCS7_SIGNED_DATA)
-            if ((signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci))))
-                if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex))
-                {
-                    status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp);
-                    break;
-                }
-    }
-    
-xit:
-    return status;
-}
-
-/*
- * Obtain an array of the certificates in a timestamp response. Elements of the
- * returned array are SecCertificateRefs. The caller must CFRelease the returned
- * array. This timestamp is an authenticated timestamp provided by
- * a timestamping authority.
- *
- * Returns errSecParam if the CMS message was not signed or if signerIndex
- * is greater than the number of signers of the message minus one. It returns
- * errSecItemNotFound if no certificates were found.
- *
- * This cannot be called until after CMSDecoderFinalizeMessage() is called. 
- */
-OSStatus CMSDecoderCopySignerTimestampCertificates(
-                                                   CMSDecoderRef               cmsDecoder,
-                                                   size_t                              signerIndex,            /* usually 0 */
-                                                   CFArrayRef          *certificateRefs)       /* RETURNED */
-{
-    OSStatus status = errSecParam;
-       SecCmsMessageRef cmsg = NULL;
-       SecCmsSignedDataRef signedData = NULL;
-    int numContentInfos = 0;
-    CFIndex tsn = 0;
-    bool good = false;
-    
-    require(cmsDecoder && certificateRefs, xit);
-       require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
-    numContentInfos = SecCmsMessageContentLevelCount(cmsg);
-    for (int dex = 0; !signedData && dex < numContentInfos; dex++)
-    {
-        SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
-        SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
-        if (tag == SEC_OID_PKCS7_SIGNED_DATA)
-            if ((signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci))))
-                if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex))
-                {
-                    CFArrayRef certList = SecCmsSignerInfoGetTimestampCertList(signerInfo);
-                    require_action(certList, xit, status = errSecItemNotFound);
-                    CFMutableArrayRef certs = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(certList), certList);
-                    
-                    if(certs){
-                        //reorder certificates:
-                        tsn = CFArrayGetCount(certs);
-                        good = tsn > 0 && Security::CodeSigning::isAppleCA(SecCertificateRef(CFArrayGetValueAtIndex(certs, tsn-1)));
-                        
-                        if ( good == false )
-                        {
-                            //change TS certificate ordering.
-                            for (CFIndex n = 0; n < tsn; n++)
-                            {
-                                if (SecCertificateRef tsRoot = SecCertificateRef(CFArrayGetValueAtIndex(certs, n)))
-                                    if ((good = Security::CodeSigning::isAppleCA(tsRoot))) {
-                                        CFArrayExchangeValuesAtIndices(certs, n, tsn-1);
-                                        break;
-                                    }
-                            }
-                        }
-                        
-                        *certificateRefs = CFArrayCreateCopy(kCFAllocatorDefault, certs);
-                        CFRelease(certs);
-                        status = errSecSuccess;
-                    }
-                    break;
-                }
-    }
-    
-    
-    xit:
-        return status;
-    }