* CMSDecoder.cpp - Interface for decoding CMS messages.
*/
-#include "CMSDecoder.h"
-#include "CMSPrivate.h"
+#include <Security/CMSDecoder.h>
+#include <Security/CMSPrivate.h>
#include "CMSUtils.h"
#include <../libsecurity_codesigning/lib/csutilities.h>
#include <Security/oidsattr.h>
#include <Security/SecTrustPriv.h>
#include <CoreFoundation/CFRuntime.h>
+#include <utilities/SecCFWrappers.h>
#include <pthread.h>
#include <syslog.h>
#include <AssertMacros.h>
SecArenaPoolRef arena; /* the decoder's arena */
SecCmsDecoderRef decoder;
CFDataRef detachedContent;
- CFTypeRef keychainOrArray; /* from CMSDecoderSetSearchKeychain() */
+ CFTypeRef keychainOrArray; /* unused */
/*
* The following are valid (and quiescent) after CMSDecoderFinalizeMessage().
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...
+ * an error case. Unlike Finish, this calls SecCmsMessageDestroy.
*/
SecCmsDecoderDestroy(cmsDecoder->decoder);
+ cmsDecoder->cmsMsg = NULL;
}
CFRELEASE(cmsDecoder->detachedContent);
CFRELEASE(cmsDecoder->keychainOrArray);
if(cmsDecoder->cmsMsg != NULL) {
SecCmsMessageDestroy(cmsDecoder->cmsMsg);
+ cmsDecoder->cmsMsg = NULL;
}
if(cmsDecoder->arena != NULL) {
SecArenaPoolFree(cmsDecoder->arena, false);
+ cmsDecoder->arena = NULL;
}
}
(SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci);
/* dig down one more layer for eContentType */
ci = SecCmsSignedDataGetContentInfo(cmsDecoder->signedData);
- cmsDecoder->eContentType = SecCmsContentInfoGetContentTypeOID(ci);
+ if (ci) {
+ cmsDecoder->eContentType = SecCmsContentInfoGetContentTypeOID(ci);
+ }
break;
default:
break;
}
/*
- * 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().
+ * Beginning in 10.12, this function stopped affecting the behavior of the
+ * CMS Decoder. Its only use was in SecTrustSetKeychains which is a no-op.
+ * Please discontinue use.
*/
OSStatus CMSDecoderSetSearchKeychain(
CMSDecoderRef cmsDecoder,
CFTypeRef keychainOrArray)
{
- if(cmsDecoder == NULL) {
- return errSecParam;
- }
- cmsDecoder->keychainOrArray = keychainOrArray;
- if(keychainOrArray) {
- CFRetain(keychainOrArray);
- }
return errSecSuccess;
}
SecTrustRef *secTrust, /* optional; RETURNED */
OSStatus *certVerifyResultCode) /* optional; RETURNED */
{
- if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final)) {
+ if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final) || (!policyOrArray) || !signerStatus) {
return errSecParam;
}
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,
+ NULL,
policyOrArray,
&theTrust);
if(secTrust != NULL) {
*secTrust = theTrust;
/* we'll release our reference at the end */
- if (theTrust)
- CFRetain(theTrust);
+ CFRetainSafe(theTrust);
}
SecCmsSignerInfoRef signerInfo =
SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
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 */
xit:
return status;
}
+
+/*
+ * Obtain the Hash Agility attribute value of signer 'signerIndex'
+ * of a CMS message, if present.
+ *
+ * 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 CMSDecoderCopySignerAppleCodesigningHashAgility(
+ CMSDecoderRef cmsDecoder,
+ size_t signerIndex, /* usually 0 */
+ CFDataRef CF_RETURNS_RETAINED *hashAgilityAttrValue) /* RETURNED */
+{
+ OSStatus status = errSecParam;
+ SecCmsMessageRef cmsg;
+ SecCmsSignedDataRef signedData = NULL;
+ int numContentInfos = 0;
+ CFDataRef returnedValue = NULL;
+
+ require(cmsDecoder && hashAgilityAttrValue, exit);
+ require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), exit);
+ 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 = SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo, &returnedValue);
+ break;
+ }
+ }
+exit:
+ if (status == errSecSuccess && returnedValue) {
+ *hashAgilityAttrValue = (CFDataRef) CFRetain(returnedValue);
+ } else {
+ *hashAgilityAttrValue = NULL;
+ }
+ return status;
+}
+
+/*
+ * Obtain the Hash Agility V2 attribute value of signer 'signerIndex'
+ * of a CMS message, if present.
+ *
+ * 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 CMSDecoderCopySignerAppleCodesigningHashAgilityV2(
+ CMSDecoderRef cmsDecoder,
+ size_t signerIndex, /* usually 0 */
+ CFDictionaryRef CF_RETURNS_RETAINED *hashAgilityV2AttrValues) /* RETURNED */
+{
+ OSStatus status = errSecParam;
+ SecCmsMessageRef cmsg;
+ SecCmsSignedDataRef signedData = NULL;
+ int numContentInfos = 0;
+ CFDictionaryRef returnedValue = NULL;
+
+ require(cmsDecoder && hashAgilityV2AttrValues, exit);
+ require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), exit);
+ 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))) {
+ SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
+ if (signerInfo)
+ {
+ status = SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(signerInfo, &returnedValue);
+ break;
+ }
+ }
+ }
+exit:
+ if (status == errSecSuccess && returnedValue) {
+ *hashAgilityV2AttrValues = (CFDictionaryRef) CFRetain(returnedValue);
+ } else {
+ *hashAgilityV2AttrValues = NULL;
+ }
+ return status;
+}
+
+/*
+ * Obtain the expiration time of signer 'signerIndex' of a CMS message, if
+ * present. This 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 CMSDecoderCopySignerAppleExpirationTime(
+ CMSDecoderRef cmsDecoder,
+ size_t signerIndex,
+ CFAbsoluteTime *expirationTime) /* RETURNED */
+{
+ OSStatus status = errSecParam;
+ SecCmsMessageRef cmsg = NULL;
+ int numContentInfos = 0;
+ SecCmsSignedDataRef signedData = NULL;
+
+ require(cmsDecoder && expirationTime, 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))) {
+ SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
+ if (signerInfo) {
+ status = SecCmsSignerInfoGetAppleExpirationTime(signerInfo, expirationTime);
+ break;
+ }
+ }
+ }
+ }
+xit:
+ return status;
+}