/* * 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); } }
/* * Parse a ContentInfo as best we can. All return fields are optional. * If signer_cert_status is NULL on entry, NO signature or cert evaluation * will be performed. */ krb5_error_code krb5int_pkinit_parse_cms_msg( const krb5_data *content_info, krb5_pkinit_cert_db_t cert_db, /* may be required for SignedData */ krb5_boolean is_client_msg, /* TRUE : msg is from client */ krb5_boolean *is_signed, /* RETURNED */ krb5_boolean *is_encrypted, /* RETURNED */ krb5_data *raw_data, /* RETURNED */ krb5int_cms_content_type *inner_content_type,/* Returned, ContentType of */ /* EncapsulatedData */ krb5_data *signer_cert, /* RETURNED */ krb5int_cert_sig_status *signer_cert_status,/* RETURNED */ unsigned *num_all_certs, /* size of *all_certs RETURNED */ krb5_data **all_certs) /* entire cert chain RETURNED */ { SecPolicySearchRef policy_search = NULL; SecPolicyRef policy = NULL; OSStatus ortn; krb5_error_code krtn = 0; CMSDecoderRef decoder = NULL; size_t num_signers; CMSSignerStatus signer_status; OSStatus cert_verify_status; CFArrayRef cf_all_certs = NULL; int msg_is_signed = 0; if(content_info == NULL) { pkiDebug("krb5int_pkinit_parse_cms_msg: no ContentInfo\n"); return KRB5_CRYPTO_INTERNAL; } ortn = CMSDecoderCreate(&decoder); if(ortn) { return ENOMEM; } ortn = CMSDecoderUpdateMessage(decoder, content_info->data, content_info->length); if(ortn) { /* no verify yet, must be bad message */ krtn = KRB5_PARSE_MALFORMED; goto errOut; } ortn = CMSDecoderFinalizeMessage(decoder); if(ortn) { pkiCssmErr("CMSDecoderFinalizeMessage", ortn); krtn = KRB5_PARSE_MALFORMED; goto errOut; } /* expect zero or one signers */ ortn = CMSDecoderGetNumSigners(decoder, &num_signers); switch(num_signers) { case 0: msg_is_signed = 0; break; case 1: msg_is_signed = 1; break; default: krtn = KRB5_PARSE_MALFORMED; goto errOut; } /* * We need a cert verify policy even if we're not actually evaluating * the cert due to requirements in libsecurity_smime. */ ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, is_client_msg ? &CSSMOID_APPLE_TP_PKINIT_CLIENT : &CSSMOID_APPLE_TP_PKINIT_SERVER, NULL, &policy_search); if(ortn) { pkiCssmErr("SecPolicySearchCreate", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } ortn = SecPolicySearchCopyNext(policy_search, &policy); if(ortn) { pkiCssmErr("SecPolicySearchCopyNext", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } /* get some basic status that doesn't need heavyweight evaluation */ if(msg_is_signed) { if(is_signed) { *is_signed = TRUE; } if(inner_content_type) { CSSM_OID ec_oid = {0, NULL}; CFDataRef ec_data = NULL; krb5int_cms_content_type ctype; ortn = CMSDecoderCopyEncapsulatedContentType(decoder, &ec_data); if(ortn || (ec_data == NULL)) { pkiCssmErr("CMSDecoderCopyEncapsulatedContentType", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } ec_oid.Data = (uint8 *)CFDataGetBytePtr(ec_data); ec_oid.Length = CFDataGetLength(ec_data); if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_Data)) { ctype = ECT_Data; } else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_SignedData)) { ctype = ECT_SignedData; } else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EnvelopedData)) { ctype = ECT_EnvelopedData; } else if(pkiCompareCssmData(&ec_oid, &CSSMOID_PKCS7_EncryptedData)) { ctype = ECT_EncryptedData; } else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_AUTH_DATA)) { ctype = ECT_PkAuthData; } else if(pkiCompareCssmData(&ec_oid, &_CSSMOID_PKINIT_RKEY_DATA)) { ctype = ECT_PkReplyKeyKata; } else { ctype = ECT_Other; } *inner_content_type = ctype; CFRelease(ec_data); } /* * Get SignedData's certs if the caller wants them */ if(all_certs) { ortn = CMSDecoderCopyAllCerts(decoder, &cf_all_certs); if(ortn) { pkiCssmErr("CMSDecoderCopyAllCerts", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } krtn = pkiCertArrayToKrb5Data(cf_all_certs, num_all_certs, all_certs); if(krtn) { goto errOut; } } /* optional signer cert */ if(signer_cert) { SecCertificateRef sec_signer_cert = NULL; CSSM_DATA cert_data; ortn = CMSDecoderCopySignerCert(decoder, 0, &sec_signer_cert); if(ortn) { /* should never happen if it's signed */ pkiCssmErr("CMSDecoderCopySignerStatus", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } ortn = SecCertificateGetData(sec_signer_cert, &cert_data); if(ortn) { pkiCssmErr("SecCertificateGetData", ortn); CFRelease(sec_signer_cert); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } krtn = pkiDataToKrb5Data(cert_data.Data, cert_data.Length, signer_cert); CFRelease(sec_signer_cert); if(krtn) { goto errOut; } } } else { /* not signed */ if(is_signed) { *is_signed = FALSE; } if(inner_content_type) { *inner_content_type = ECT_Other; } if(signer_cert) { signer_cert->data = NULL; signer_cert->length = 0; } if(signer_cert_status) { *signer_cert_status = pki_not_signed; } if(num_all_certs) { *num_all_certs = 0; } if(all_certs) { *all_certs = NULL; } } if(is_encrypted) { Boolean bencr; ortn = CMSDecoderIsContentEncrypted(decoder, &bencr); if(ortn) { pkiCssmErr("CMSDecoderCopySignerStatus", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } *is_encrypted = bencr ? TRUE : FALSE; } /* * Verify signature and cert. The actual verify operation is optional, * per our signer_cert_status argument, but we do this anyway if we need * to get the signer cert. */ if((signer_cert_status != NULL) || (signer_cert != NULL)) { ortn = CMSDecoderCopySignerStatus(decoder, 0, /* signerIndex */ policy, signer_cert_status ? TRUE : FALSE, /* evaluateSecTrust */ &signer_status, NULL, /* secTrust - not needed */ &cert_verify_status); if(ortn) { /* gross error - subsequent processing impossible */ pkiCssmErr("CMSDecoderCopySignerStatus", ortn); krtn = KRB5_PARSE_MALFORMED; goto errOut; } } /* obtain & return status */ if(signer_cert_status) { *signer_cert_status = pkiInferSigStatus(signer_status, cert_verify_status); } /* finally, the payload */ if(raw_data) { CFDataRef cf_content = NULL; ortn = CMSDecoderCopyContent(decoder, &cf_content); if(ortn) { pkiCssmErr("CMSDecoderCopyContent", ortn); krtn = KRB5_PARSE_MALFORMED; goto errOut; } krtn = pkiCfDataToKrb5Data(cf_content, raw_data); CFRELEASE(cf_content); } errOut: CFRELEASE(policy_search); CFRELEASE(policy); CFRELEASE(cf_all_certs); CFRELEASE(decoder); return krtn; }
/* * Create a CMS message: either encrypted (EnvelopedData), signed * (SignedData), or both (EnvelopedData(SignedData(content)). * * The message is signed iff signing_cert is non-NULL. * The message is encrypted iff recip_cert is non-NULL. * * The content_type argument specifies to the eContentType * for a SignedData's EncapsulatedContentInfo. */ krb5_error_code krb5int_pkinit_create_cms_msg( const krb5_data *content, /* Content */ krb5_pkinit_signing_cert_t signing_cert, /* optional: signed by this cert */ const krb5_data *recip_cert, /* optional: encrypted with this cert */ krb5int_cms_content_type content_type, /* OID for EncapsulatedData */ krb5_ui_4 num_cms_types, /* optional, unused here */ const krb5int_algorithm_id *cms_types, /* optional, unused here */ krb5_data *content_info) /* contents mallocd and RETURNED */ { krb5_error_code krtn; OSStatus ortn; SecCertificateRef sec_recip = NULL; CFDataRef cf_content = NULL; const CSSM_OID *eContentOid = NULL; if((signing_cert == NULL) && (recip_cert == NULL)) { /* must have one or the other */ pkiDebug("krb5int_pkinit_create_cms_msg: no signer or recipient\n"); return KRB5_CRYPTO_INTERNAL; } /* * Optional signer cert. Note signing_cert, if present, is * a SecIdentityRef. */ if(recip_cert) { if(pkiKrb5DataToSecCert(recip_cert, &sec_recip)) { krtn = ASN1_BAD_FORMAT; goto errOut; } } /* optional eContentType */ if(signing_cert) { switch(content_type) { case ECT_PkAuthData: eContentOid = &_CSSMOID_PKINIT_AUTH_DATA; break; case ECT_PkReplyKeyKata: eContentOid = &_CSSMOID_PKINIT_RKEY_DATA; break; case ECT_Data: /* the only standard/default case we allow */ break; default: /* others: no can do */ pkiDebug("krb5int_pkinit_create_cms_msg: bad contentType\n"); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } } /* GO */ ortn = CMSEncode((SecIdentityRef)signing_cert, sec_recip, eContentOid, FALSE, /* detachedContent */ kCMSAttrNone, /* no signed attributes that I know of */ content->data, content->length, &cf_content); if(ortn) { pkiCssmErr("CMSEncode", ortn); krtn = KRB5_CRYPTO_INTERNAL; goto errOut; } krtn = pkiCfDataToKrb5Data(cf_content, content_info); errOut: CFRELEASE(sec_recip); CFRELEASE(cf_content); return krtn; }
/* * Returns true if we are to allow/trust the specified * cert as a PKINIT-only anchor. */ static bool tpCheckPkinitServerCert( TPCertGroup &certGroup) { /* * Basic requirement: exactly one cert, self-signed. * The numCerts == 1 requirement might change... */ unsigned numCerts = certGroup.numCerts(); if(numCerts != 1) { tpDebug("tpCheckPkinitServerCert: too many certs"); return false; } /* end of chain... */ TPCertInfo *theCert = certGroup.certAtIndex(numCerts - 1); if(!theCert->isSelfSigned()) { tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed"); return false; } const CSSM_DATA *subjectName = theCert->subjectName(); /* * Open the magic keychain. * We're going up and over the Sec layer here, not generally * kosher, but this is a temp hack. */ OSStatus ortn; SecKeychainRef kcRef = NULL; string fullPathName; const char *homeDir = getenv("HOME"); if (homeDir == NULL) { // If $HOME is unset get the current user's home directory // from the passwd file. uid_t uid = geteuid(); if (!uid) uid = getuid(); struct passwd *pw = getpwuid(uid); if (!pw) { return false; } homeDir = pw->pw_dir; } fullPathName = homeDir; fullPathName += "/Library/Application Support/PKINIT/TrustedServers.keychain"; ortn = SecKeychainOpen(fullPathName.c_str(), &kcRef); if(ortn) { tpDebug("tpCheckPkinitServerCert: keychain not found (1)"); return false; } /* subsequent errors to errOut: */ bool ourRtn = false; SecKeychainStatus kcStatus; CSSM_DATA_PTR subjSerial = NULL; CSSM_RETURN crtn; SecKeychainSearchRef srchRef = NULL; SecKeychainAttributeList attrList; SecKeychainAttribute attrs[2]; SecKeychainItemRef foundItem = NULL; ortn = SecKeychainGetStatus(kcRef, &kcStatus); if(ortn) { tpDebug("tpCheckPkinitServerCert: keychain not found (2)"); goto errOut; } /* * We already have this cert's normalized name; get its * serial number. */ crtn = theCert->fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial); if(crtn) { /* should never happen */ tpDebug("tpCheckPkinitServerCert: error fetching serial number"); goto errOut; } attrs[0].tag = kSecSubjectItemAttr; attrs[0].length = subjectName->Length; attrs[0].data = subjectName->Data; attrs[1].tag = kSecSerialNumberItemAttr; attrs[1].length = subjSerial->Length; attrs[1].data = subjSerial->Data; attrList.count = 2; attrList.attr = attrs; ortn = SecKeychainSearchCreateFromAttributes(kcRef, kSecCertificateItemClass, &attrList, &srchRef); if(ortn) { tpDebug("tpCheckPkinitServerCert: search failure"); goto errOut; } for(;;) { ortn = SecKeychainSearchCopyNext(srchRef, &foundItem); if(ortn) { tpDebug("tpCheckPkinitServerCert: end search"); break; } /* found a matching cert; do byte-for-byte compare */ CSSM_DATA certData; ortn = SecCertificateGetData((SecCertificateRef)foundItem, &certData); if(ortn) { tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure"); continue; } if(tpCompareCssmData(&certData, theCert->itemData())){ tpDebug("tpCheckPkinitServerCert: FOUND CERT"); ourRtn = true; break; } tpDebug("tpCheckPkinitServerCert: skipping matching cert"); CFRelease(foundItem); foundItem = NULL; } errOut: CFRELEASE(kcRef); CFRELEASE(srchRef); CFRELEASE(foundItem); if(subjSerial != NULL) { theCert->freeField(&CSSMOID_X509V1SerialNumber, subjSerial); } return ourRtn; }
/* * 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; }
/* write image file */ int BIWriteFile( const char *fileName, BIFileType fileType, const BIImageInfo *imageInfo, const unsigned char *bitmap) { int ourRtn = 0; CGImageAlphaInfo alpha; CGBitmapInfo bitmapInfo = 0; CGContextRef bitmapContextRef = NULL; CGImageRef imageRef = NULL; CFURLRef fileURL = NULL; CGImageDestinationRef imageDestRef = NULL; CGColorSpaceRef rgbColorSpaceRef = NULL; CFStringRef uti = NULL; CFDictionaryRef propDict = NULL; if(imageInfo->bitsPerPixel == 8) { /* grayscale image */ rgbColorSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); alpha = kCGImageAlphaNone; bitmapInfo = 0; } else { /* RGB no alpha */ rgbColorSpaceRef = CGColorSpaceCreateDeviceRGB(); alpha = kCGImageAlphaNoneSkipLast; bitmapInfo = kCGBitmapByteOrder32Big | alpha; } if(rgbColorSpaceRef == NULL) { fprintf(stderr, "***BIWriteFile: Error on CGColorSpaceCreateWithName\n"); ourRtn = 1; goto errOut; } /* A bitmap-oriented CGContextRef based on bitmap data */ bitmapContextRef = CGBitmapContextCreate((void *)bitmap, imageInfo->imageWidth, imageInfo->imageHeight, imageInfo->bitsPerComponent, imageInfo->bytesPerRow, rgbColorSpaceRef, bitmapInfo); if(bitmapContextRef == NULL) { fprintf(stderr, "***BIWriteFile: Error creating CGBitmapContext\n"); ourRtn = 1; goto errOut; } /* CGContextRef --> CGImageRef */ imageRef = CGBitmapContextCreateImage(bitmapContextRef); fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (unsigned char*)fileName, strlen(fileName), FALSE); if(fileURL == NULL) { fprintf(stderr, "***BIWriteFile: Error on CFURLCreateFromFileSystemRepresentation\n"); ourRtn = 1; goto errOut; } uti = BIGetUTI(fileURL, fileType); if(uti == NULL) { ourRtn = 1; goto errOut; } imageDestRef = CGImageDestinationCreateWithURL(fileURL, uti, 1, NULL ); if(imageDestRef == NULL) { fprintf(stderr, "***BIWriteFile: Error on CGImageDestinationCreateWithURL\n"); ourRtn = 1; goto errOut; } /* Some BIFileTypes require the specification of a "Lossless" property */ switch(fileType) { case BI_FT_JPEG2000_Lossless: case BI_FT_JPEG_Lossless: { CFStringRef key = kCGImageDestinationLossyCompressionQuality; float valf = 1.0; CFNumberRef val = CFNumberCreate(NULL, kCFNumberFloatType, &valf); propDict = CFDictionaryCreate(NULL, (const void **)&key, (const void **)&val, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); /* * The docs say we should be able to set these properties like this, * but that has no effect. We need to pass it as the 'properties' argument * to CGImageDestinationAddImage(), below. * See <rdar://problem/5670614> */ //CGImageDestinationSetProperties(imageDestRef, propDict); CFRelease(val); break; } default: break; } CGImageDestinationAddImage(imageDestRef, imageRef, propDict); /* Write the image to disk */ if(!CGImageDestinationFinalize(imageDestRef)) { fprintf(stderr, "***BIWriteFile: Error on CGImageDestinationFinalize\n"); ourRtn = 1; } if(propDict != NULL) { CFRelease(propDict); } errOut: CFRELEASE(bitmapContextRef); CFRELEASE(imageRef); CFRELEASE(fileURL); CFRELEASE(imageDestRef); CFRELEASE(rgbColorSpaceRef); return ourRtn; }
/* read image file */ int BIReadFile( const char *fileName, BIFileType fileType, BIPadMode padMode, unsigned padSize, BIImageInfo *imageInfo, /* RETURNED */ unsigned char **bitmap) /* mallocd and RETURNED; caller must free */ { CFURLRef fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (unsigned char*)fileName, strlen(fileName), FALSE); if(fileURL == NULL) { fprintf(stderr, "***BIReadFile: Error on CFURLCreateFromFileSystemRepresentation\n"); return -1; } CFStringRef keys[1] = {kCGImageSourceTypeIdentifierHint}; CFStringRef values[1] = {BIGetUTI(fileURL, fileType)}; if(values[0] == NULL) { return -1; } CFDictionaryRef optionsDict = NULL; CGImageSourceRef imageSourceRef = NULL; CGImageRef imageRef = NULL; CGColorSpaceRef rgbColorSpaceRef = NULL; CGContextRef bitmapContextRef = NULL; CGBitmapInfo bitmapInfo = 0; CGImageAlphaInfo alpha; unsigned bytesPerPixel = 4; optionsDict = CFDictionaryCreate( kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); /* subsequent errors to errOut: */ int ourRtn = 0; /* source file --> CGImageRef */ imageSourceRef = CGImageSourceCreateWithURL(fileURL, optionsDict); if(imageSourceRef == NULL) { fprintf(stderr, "***BIReadFile: Error on CGImageSourceCreateWithURL\n"); ourRtn = 1; goto errOut; } CFRELEASE(fileURL); imageRef = CGImageSourceCreateImageAtIndex(imageSourceRef, 0, optionsDict ); if(imageRef == NULL) { fprintf(stderr, "***BIReadFile: Error on CGImageSourceCreateImageAtIndex\n"); ourRtn = 1; goto errOut; } imageInfo->imageWidth = CGImageGetWidth(imageRef); imageInfo->imageHeight = CGImageGetHeight(imageRef); imageInfo->bitsPerComponent = CGImageGetBitsPerComponent(imageRef); imageInfo->bitsPerPixel = CGImageGetBitsPerPixel(imageRef); if(imageInfo->bitsPerPixel == 8) { /* the image is gray */ rgbColorSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); imageInfo->bytesPerRow = imageInfo->imageWidth; alpha = kCGImageAlphaNone; bitmapInfo = CGImageGetBitmapInfo(imageRef); bytesPerPixel = 1; } else { rgbColorSpaceRef = CGColorSpaceCreateDeviceRGB(); imageInfo->bytesPerRow = imageInfo->imageWidth * 4; alpha = kCGImageAlphaPremultipliedLast; bitmapInfo = kCGBitmapByteOrder32Big | alpha; } if(rgbColorSpaceRef == NULL) { fprintf(stderr, "***BIReadFile: Error on CGColorSpaceCreateWithName\n"); ourRtn = 1; goto errOut; } /* optionally pad */ imageInfo->effectHeight = imageInfo->imageHeight; if(padMode != PM_None) { if(padSize == 0) { fprintf(stderr, "***Pad size of 0 invalid\n"); ourRtn = 1; goto errOut; } unsigned padSizeBytes = padSize; if(padMode == PM_Pixels) { padSizeBytes *= bytesPerPixel; } imageInfo->bytesPerRow = ROUND_TO(imageInfo->bytesPerRow, padSizeBytes); /* also round up row count */ imageInfo->effectHeight = ROUND_TO(imageInfo->imageHeight, padSize); } *bitmap = (unsigned char *)malloc(imageInfo->bytesPerRow * imageInfo->effectHeight); bitmapContextRef = CGBitmapContextCreate(*bitmap, imageInfo->imageWidth, imageInfo->imageHeight, imageInfo->bitsPerComponent, imageInfo->bytesPerRow, rgbColorSpaceRef, bitmapInfo); if(bitmapContextRef == NULL) { fprintf(stderr, "***BIReadFile: Error creating CGBitmapContext\n"); ourRtn = 1; goto errOut; } /* enable high quality interpolation */ CGContextSetInterpolationQuality(bitmapContextRef, kCGInterpolationHigh); /* Draw into the context */ CGContextDrawImage(bitmapContextRef, CGRectMake(0, 0, imageInfo->imageWidth, imageInfo->imageHeight), imageRef); errOut: CFRELEASE(optionsDict); CFRELEASE(imageSourceRef); CFRELEASE(imageRef); CFRELEASE(rgbColorSpaceRef); CFRELEASE(bitmapContextRef); if(ourRtn) { if(*bitmap) { free(*bitmap); *bitmap = NULL; } } return ourRtn; }
/* * 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; }