X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_cms/lib/CMSDecoder.cpp?ds=inline diff --git a/Security/libsecurity_cms/lib/CMSDecoder.cpp b/Security/libsecurity_cms/lib/CMSDecoder.cpp deleted file mode 100644 index e4ed76ad..00000000 --- a/Security/libsecurity_cms/lib/CMSDecoder.cpp +++ /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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; dexcmsMsg, 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; - }