/* * 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); } }
/* * Dispose of a CMSEncoder. Called out from CFRelease(). */ static void cmsEncoderFinalize( CFTypeRef enc) { CMSEncoderRef cmsEncoder = (CMSEncoderRef)enc; if(cmsEncoder == NULL) { return; } if(cmsEncoder->eContentType.Data != NULL) { free(cmsEncoder->eContentType.Data); } CFRELEASE(cmsEncoder->signers); CFRELEASE(cmsEncoder->recipients); CFRELEASE(cmsEncoder->otherCerts); if(cmsEncoder->cmsMsg != NULL) { SecCmsMessageDestroy(cmsEncoder->cmsMsg); cmsEncoder->cmsMsg = NULL; } if(cmsEncoder->arena != NULL) { SecArenaPoolFree(cmsEncoder->arena, false); } if(cmsEncoder->encoder != NULL) { /* * Normally this gets freed in SecCmsEncoderFinish - this is * an error case. */ SecCmsEncoderDestroy(cmsEncoder->encoder); } }
void Download::Initialize (CFDataRef ticket, SecureDownloadTrustSetupCallback setup, void* setupContext, SecureDownloadTrustEvaluateCallback evaluate, void* evaluateContext) { // decode the ticket SecCmsMessageRef cmsMessage = GetCmsMessageFromData (ticket); // get a policy SecPolicyRef policy = GetPolicy (); // parse the CMS message int contentLevelCount = SecCmsMessageContentLevelCount (cmsMessage); SecCmsSignedDataRef signedData; OSStatus result; int i = 0; while (i < contentLevelCount) { SecCmsContentInfoRef contentInfo = SecCmsMessageContentLevel (cmsMessage, i++); SECOidTag contentTypeTag = SecCmsContentInfoGetContentTypeTag (contentInfo); if (contentTypeTag != SEC_OID_PKCS7_SIGNED_DATA) { continue; } signedData = (SecCmsSignedDataRef) SecCmsContentInfoGetContent (contentInfo); if (signedData == NULL) { MacOSError::throwMe (errSecureDownloadInvalidTicket); } // import the certificates found in the cms message result = SecCmsSignedDataImportCerts (signedData, NULL, certUsageObjectSigner, true); if (result != 0) { MacOSError::throwMe (errSecureDownloadInvalidTicket); } int numberOfSigners = SecCmsSignedDataSignerInfoCount (signedData); int j; if (numberOfSigners == 0) // no signers? This is a possible attack { MacOSError::throwMe (errSecureDownloadInvalidTicket); } for (j = 0; j < numberOfSigners; ++j) { SecTrustResultType resultType; // do basic verification of the message SecTrustRef trustRef; result = SecCmsSignedDataVerifySignerInfo (signedData, j, NULL, policy, &trustRef); // notify the user of the new trust ref if (setup != NULL) { SecureDownloadTrustCallbackResult tcResult = setup (trustRef, setupContext); switch (tcResult) { case kSecureDownloadDoNotEvaluateSigner: continue; case kSecureDownloadFailEvaluation: MacOSError::throwMe (errSecureDownloadInvalidTicket); case kSecureDownloadEvaluateSigner: break; } } if (result != 0) { MacOSError::throwMe (errSecureDownloadInvalidTicket); } result = SecTrustEvaluate (trustRef, &resultType); if (result != noErr) { MacOSError::throwMe (errSecureDownloadInvalidTicket); } if (evaluate != NULL) { resultType = evaluate (trustRef, resultType, evaluateContext); } GoOrNoGo (resultType); } } // extract the message CSSM_DATA_PTR message = SecCmsMessageGetContent (cmsMessage); CFDataRef ticketData = CFDataCreateWithBytesNoCopy (NULL, message->Data, message->Length, kCFAllocatorNull); CheckCFThingForNULL (ticketData); ParseTicket (ticketData); // setup for hashing CC_SHA256_Init (&mSHA256Context); // clean up CFRelease (ticketData); SecCmsMessageDestroy (cmsMessage); }
/* * Set up a SecCmsMessageRef for a EnvelopedData creation. */ static OSStatus cmsSetupForEnvelopedData( CMSEncoderRef cmsEncoder) { ASSERT(cmsEncoder->op == EO_Encrypt); ASSERT(cmsEncoder->recipients != NULL); SecCmsContentInfoRef contentInfo = NULL; SecCmsEnvelopedDataRef envelopedData = NULL; SECOidTag algorithmTag; int keySize; OSStatus ortn; /* * Find encryption algorithm...unfortunately we need a NULL-terminated array * of SecCertificateRefs for this. */ CFIndex numCerts = CFArrayGetCount(cmsEncoder->recipients); CFIndex dex; SecCertificateRef *certArray = (SecCertificateRef *)malloc( (numCerts+1) * sizeof(SecCertificateRef)); for(dex=0; dex<numCerts; dex++) { certArray[dex] = (SecCertificateRef)CFArrayGetValueAtIndex( cmsEncoder->recipients, dex); } certArray[numCerts] = NULL; ortn = SecSMIMEFindBulkAlgForRecipients(certArray, &algorithmTag, &keySize); free(certArray); if(ortn) { CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn); return ortn; } /* build chain of objects: message->envelopedData->data */ if(cmsEncoder->cmsMsg != NULL) { SecCmsMessageDestroy(cmsEncoder->cmsMsg); } cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL); if(cmsEncoder->cmsMsg == NULL) { return errSecInternalComponent; } envelopedData = SecCmsEnvelopedDataCreate(cmsEncoder->cmsMsg, algorithmTag, keySize); if(envelopedData == NULL) { return errSecInternalComponent; } contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg); ortn = SecCmsContentInfoSetContentEnvelopedData(cmsEncoder->cmsMsg, contentInfo, envelopedData); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn); return ortn; } contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData); if(cmsEncoder->eContentType.Data != NULL) { /* Override the default ContentType of id-data */ ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg, contentInfo, NULL, /* data - provided to encoder, not here */ FALSE, /* detachedContent */ &cmsEncoder->eContentType); } else { ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg, contentInfo, NULL /* data - provided to encoder, not here */, cmsEncoder->detachedContent); } if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn); return ortn; } /* * create & attach recipient information, one for each recipient */ for(dex=0; dex<numCerts; dex++) { SecCmsRecipientInfoRef recipientInfo = NULL; SecCertificateRef thisRecip = (SecCertificateRef)CFArrayGetValueAtIndex( cmsEncoder->recipients, dex); recipientInfo = SecCmsRecipientInfoCreate(cmsEncoder->cmsMsg, thisRecip); ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn); return ortn; } } return errSecSuccess; }
/* * Set up a SecCmsMessageRef for a SignedData creation. */ static OSStatus cmsSetupForSignedData( CMSEncoderRef cmsEncoder) { ASSERT((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL)); SecCmsContentInfoRef contentInfo = NULL; SecCmsSignedDataRef signedData = NULL; OSStatus ortn; /* build chain of objects: message->signedData->data */ if(cmsEncoder->cmsMsg != NULL) { SecCmsMessageDestroy(cmsEncoder->cmsMsg); } cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL); if(cmsEncoder->cmsMsg == NULL) { return errSecInternalComponent; } signedData = SecCmsSignedDataCreate(cmsEncoder->cmsMsg); if(signedData == NULL) { return errSecInternalComponent; } contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg); ortn = SecCmsContentInfoSetContentSignedData(cmsEncoder->cmsMsg, contentInfo, signedData); if(ortn) { return cmsRtnToOSStatus(ortn); } contentInfo = SecCmsSignedDataGetContentInfo(signedData); if(cmsEncoder->eContentType.Data != NULL) { /* Override the default eContentType of id-data */ ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg, contentInfo, NULL, /* data - provided to encoder, not here */ cmsEncoder->detachedContent, &cmsEncoder->eContentType); } else { ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg, contentInfo, NULL, /* data - provided to encoder, not here */ cmsEncoder->detachedContent); } if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsContentInfoSetContent*", ortn); return ortn; } /* optional 'global' (per-SignedData) certs */ if(cmsEncoder->otherCerts != NULL) { ortn = SecCmsSignedDataAddCertList(signedData, cmsEncoder->otherCerts); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignedDataAddCertList", ortn); return ortn; } } /* SignerInfos, one per signer */ CFIndex numSigners = 0; if(cmsEncoder->signers != NULL) { /* this is optional...in case we're just creating a cert bundle */ numSigners = CFArrayGetCount(cmsEncoder->signers); } CFIndex dex; SecCertificateRef ourCert = NULL; SecCmsCertChainMode chainMode = SecCmsCMCertChain; switch(cmsEncoder->chainMode) { case kCMSCertificateNone: chainMode = SecCmsCMNone; break; case kCMSCertificateSignerOnly: chainMode = SecCmsCMCertOnly; break; case kCMSCertificateChainWithRoot: chainMode = SecCmsCMCertChainWithRoot; break; default: break; } for(dex=0; dex<numSigners; dex++) { SecCmsSignerInfoRef signerInfo; SecIdentityRef ourId = (SecIdentityRef)CFArrayGetValueAtIndex(cmsEncoder->signers, dex); ortn = SecIdentityCopyCertificate(ourId, &ourCert); if(ortn) { CSSM_PERROR("SecIdentityCopyCertificate", ortn); break; } signerInfo = SecCmsSignerInfoCreate(cmsEncoder->cmsMsg, ourId, cmsEncoder->digestalgtag); if (signerInfo == NULL) { ortn = errSecInternalComponent; break; } /* we want the cert chain included for this one */ /* NOTE the usage parameter is currently unused by the SMIME lib */ ortn = SecCmsSignerInfoIncludeCerts(signerInfo, chainMode, certUsageEmailSigner); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignerInfoIncludeCerts", ortn); break; } /* other options */ if(cmsEncoder->signedAttributes & kCMSAttrSmimeCapabilities) { ortn = SecCmsSignerInfoAddSMIMECaps(signerInfo); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn); break; } } if(cmsEncoder->signedAttributes & kCMSAttrSmimeEncryptionKeyPrefs) { ortn = SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo, ourCert, NULL); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn); break; } } if(cmsEncoder->signedAttributes & kCMSAttrSmimeMSEncryptionKeyPrefs) { ortn = SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerInfo, ourCert, NULL); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignerInfoAddMSSMIMEEncKeyPrefs", ortn); break; } } if(cmsEncoder->signedAttributes & kCMSAttrSigningTime) { if (cmsEncoder->signingTime == 0) cmsEncoder->signingTime = CFAbsoluteTimeGetCurrent(); ortn = SecCmsSignerInfoAddSigningTime(signerInfo, cmsEncoder->signingTime); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignerInfoAddSigningTime", ortn); break; } } if(cmsEncoder->signedAttributes & kCMSAttrAppleCodesigningHashAgility) { ortn = SecCmsSignerInfoAddAppleCodesigningHashAgility(signerInfo, cmsEncoder->hashAgilityAttrValue); /* libsecurity_smime made a copy of the attribute value. We don't need it anymore. */ CFReleaseNull(cmsEncoder->hashAgilityAttrValue); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignerInfoAddAppleCodesigningHashAgility", ortn); break; } } ortn = SecCmsSignedDataAddSignerInfo(signedData, signerInfo); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsSignedDataAddSignerInfo", ortn); break; } CFRELEASE(ourCert); ourCert = NULL; } if(ortn) { CFRELEASE(ourCert); } return ortn; }