/* * SecCmsSignerInfoDestroy - destroy a SignerInfo data structure */ void SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si) { if (si->cert != NULL) { dprintfRC("SecCmsSignerInfoDestroy top: certp %p cert.rc %d\n", si->cert, (int)CFGetRetainCount(si->cert)); CERT_DestroyCertificate(si->cert); } if (si->certList != NULL) { dprintfRC("SecCmsSignerInfoDestroy top: certList.rc %d\n", (int)CFGetRetainCount(si->certList)); CFRelease(si->certList); } if (si->timestampCertList != NULL) { dprintfRC("SecCmsSignerInfoDestroy top: timestampCertList.rc %d\n", (int)CFGetRetainCount(si->timestampCertList)); CFRelease(si->timestampCertList); } if (si->hashAgilityAttrValue != NULL) { dprintfRC("SecCmsSignerInfoDestroy top: hashAgilityAttrValue.rc %d\n", (int)CFGetRetainCount(si->hashAgilityAttrValue)); CFRelease(si->hashAgilityAttrValue); } /* XXX storage ??? */ }
CFArrayRef SecCmsSignerInfoGetTimestampCertList(SecCmsSignerInfoRef signerinfo) { dprintfRC("SecCmsSignerInfoGetCertList: timestampCertList.rc %d\n", (int)CFGetRetainCount(signerinfo->timestampCertList)); return signerinfo->timestampCertList; }
int Plugin::unload() { if (module == NULL) return 1; #if defined(_WIN32) FreeLibrary((HMODULE)module); // FIXME - error checking return 1; #elif defined(__linux__) return dlclose(module) == 0 ? 1 : 0; #elif defined(__APPLE__) /* we must unload bundles but because bundles may be in use for other plug-in types it is important (and mandatory on certain plug-ins, e.g. Korg) to do a check on the retain count. */ CFIndex retainCount = CFGetRetainCount(module); if (retainCount == 1) { gLog("[plugin] retainCount == 1, can unload dlyb\n"); CFBundleUnloadExecutable(module); CFRelease(module); } else gLog("[plugin] retainCount > 1 (%d), leave dlyb alone\n", (int) retainCount); return 1; #endif }
/* * Return the signing cert of a CMS signerInfo. * * the certs in the enclosing SignedData must have been imported already */ SecCertificateRef SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray) { SecCertificateRef cert; SecCmsSignerIdentifier *sid; OSStatus ortn; CSSM_DATA_PTR *rawCerts; if (signerinfo->cert != NULL) { dprintfRC("SecCmsSignerInfoGetSigningCertificate top: cert %p cert.rc %d\n", signerinfo->cert, (int)CFGetRetainCount(signerinfo->cert)); return signerinfo->cert; } ortn = SecCmsSignedDataRawCerts(signerinfo->sigd, &rawCerts); if(ortn) { return NULL; } dprintf("SecCmsSignerInfoGetSigningCertificate: numRawCerts %d\n", SecCmsArrayCount((void **)rawCerts)); /* * This cert will also need to be freed, but since we save it * in signerinfo for later, we do not want to destroy it when * we leave this function -- we let the clean-up of the entire * cinfo structure later do the destroy of this cert. */ sid = &signerinfo->signerIdentifier; switch (sid->identifierType) { case SecCmsSignerIDIssuerSN: cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, signerinfo->cmsg->poolp, sid->id.issuerAndSN); break; case SecCmsSignerIDSubjectKeyID: cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, sid->id.subjectKeyID); break; default: cert = NULL; break; } /* cert can be NULL at that point */ signerinfo->cert = cert; /* earmark it */ dprintfRC("SecCmsSignerInfoGetSigningCertificate end: certp %p cert.rc %d\n", signerinfo->cert, (int)CFGetRetainCount(signerinfo->cert)); return cert; }
CFIndex Type::GetRetainCount( void ) const { if( this->GetCFObject() == NULL ) { return 0; } return CFGetRetainCount( this->GetCFObject() ); }
static void CheckForRelease(SecCFObject* ptr) { CFTypeRef tr = ptr->operator CFTypeRef(); CFIndex retainCount = CFGetRetainCount(tr); if (retainCount == 1 || retainCount == -1) { ptr->aboutToDestruct(); } }
static void tests(void) { SSLContextRef ctx = NULL; SecIdentityRef identity; CFArrayRef list = NULL; CFArrayRef trust_chain; AddIdentityToKeychain(); EAPSecIdentityListCreate(&list); identity = (SecIdentityRef)CFArrayGetValueAtIndex(list, 0); is(CFGetRetainCount(identity), 1, "identity rc = 1"); ok_status(EAPSecIdentityCreateIdentityTrustChain(identity, &trust_chain), "EAPSecIdentityCreateIdentityTrustChain"); ok(ctx=SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), "SSLNewContext"); ok_status(SSLSetCertificate(ctx, trust_chain), "SSLSetCertificate"); CFReleaseNull(ctx); DeleteIdentityFromKeychain(); CFRelease(trust_chain); CFReleaseNull(list); }
nsresult AppleVDADecoder::SubmitFrame(mp4_demuxer::MP4Sample* aSample) { AutoCFRelease<CFDataRef> block = CFDataCreate(kCFAllocatorDefault, aSample->data, aSample->size); if (!block) { NS_ERROR("Couldn't create CFData"); return NS_ERROR_FAILURE; } AutoCFRelease<CFNumberRef> pts = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &aSample->composition_timestamp); AutoCFRelease<CFNumberRef> dts = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &aSample->decode_timestamp); AutoCFRelease<CFNumberRef> duration = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &aSample->duration); AutoCFRelease<CFNumberRef> byte_offset = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &aSample->byte_offset); char keyframe = aSample->is_sync_point ? 1 : 0; AutoCFRelease<CFNumberRef> cfkeyframe = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &keyframe); const void* keys[] = { CFSTR("FRAME_PTS"), CFSTR("FRAME_DTS"), CFSTR("FRAME_DURATION"), CFSTR("FRAME_OFFSET"), CFSTR("FRAME_KEYFRAME") }; const void* values[] = { pts, dts, duration, byte_offset, cfkeyframe }; static_assert(ArrayLength(keys) == ArrayLength(values), "Non matching keys/values array size"); AutoCFRelease<CFDictionaryRef> frameInfo = CFDictionaryCreate(kCFAllocatorDefault, keys, values, ArrayLength(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); OSStatus rv = VDADecoderDecode(mDecoder, 0, block, frameInfo); LOG("[%s]: FrameInfo retain count = %ld", __func__, CFGetRetainCount(frameInfo)); MOZ_ASSERT(CFGetRetainCount(frameInfo) >= 2, "Bad retain count"); if (rv != noErr) { NS_WARNING("AppleVDADecoder: Couldn't pass frame to decoder"); return NS_ERROR_FAILURE; } if (mIs106) { // TN2267: // frameInfo: A CFDictionaryRef containing information to be returned in // the output callback for this frame. // This dictionary can contain client provided information associated with // the frame being decoded, for example presentation time. // The CFDictionaryRef will be retained by the framework. // In 10.6, it is released one too many. So retain it. CFRetain(frameInfo); } // Ask for more data. if (mTaskQueue->IsEmpty()) { LOG("AppleVDADecoder task queue empty; requesting more data"); mCallback->InputExhausted(); } return NS_OK; }
void tests(int dont_skip) { SecKeychainRef source, dest; ok_status(SecKeychainCreate("source", 4, "test", FALSE, NULL, &source), "create source keychain"); ok_status(SecKeychainCreate("dest", 4, "test", FALSE, NULL, &dest), "create dest keychain"); SecKeychainItemRef original = NULL; ok_status(SecKeychainAddInternetPassword(source, 19, "members.spamcop.net", 0, NULL, 5, "smith", 0, NULL, 80, kSecProtocolTypeHTTP, kSecAuthenticationTypeDefault, 4, "test", &original), "add internet password"); SecKeychainAttribute origAttrs[] = { { kSecCreationDateItemAttr }, { kSecModDateItemAttr } }; SecKeychainAttributeList origAttrList = { sizeof(origAttrs) / sizeof(*origAttrs), origAttrs }; ok_status(SecKeychainItemCopyContent(original, NULL, &origAttrList, NULL, NULL), "SecKeychainItemCopyContent"); /* Must sleep 1 second to trigger mod date bug. */ sleep(1); SecKeychainItemRef copy; ok_status(SecKeychainItemCreateCopy(original, dest, NULL, ©), "copy item"); SecKeychainAttribute copyAttrs[] = { { kSecCreationDateItemAttr }, { kSecModDateItemAttr } }; SecKeychainAttributeList copyAttrList = { sizeof(copyAttrs) / sizeof(*copyAttrs), copyAttrs }; ok_status(SecKeychainItemCopyContent(copy, NULL, ©AttrList, NULL, NULL), "SecKeychainItemCopyContent"); is(origAttrs[0].length, 16, "creation date length 16"); is(origAttrs[1].length, 16, "mod date length 16"); is(origAttrs[0].length, copyAttrs[0].length, "creation date length same"); is(origAttrs[1].length, copyAttrs[1].length, "mod date length same"); TODO: { todo("<rdar://problem/3731664> Moving/copying a keychain item " "between keychains erroneously updates dates"); diag("original creation: %.*s copy creation: %.*s", (int)origAttrs[0].length, (const char *)origAttrs[0].data, (int)copyAttrs[0].length, (const char *)copyAttrs[0].data); ok(!memcmp(origAttrs[0].data, copyAttrs[0].data, origAttrs[0].length), "creation date same"); diag("original mod: %.*s copy mod: %.*s", (int)origAttrs[1].length, (const char *)origAttrs[1].data, (int)copyAttrs[1].length, (const char *)copyAttrs[1].data); ok(!memcmp(origAttrs[1].data, copyAttrs[1].data, origAttrs[1].length), "mod date same"); } ok_status(SecKeychainItemFreeContent(&origAttrList, NULL), "SecKeychainItemCopyContent"); ok_status(SecKeychainItemFreeContent(©AttrList, NULL), "SecKeychainItemCopyContent"); is(CFGetRetainCount(original), 1, "original retaincount is 1"); CFRelease(original); is(CFGetRetainCount(copy), 1, "copy retaincount is 1"); CFRelease(copy); is(CFGetRetainCount(source), 1, "source retaincount is 1"); ok_status(SecKeychainDelete(source), "delete keychain source"); CFRelease(source); ok_status(SecKeychainDelete(dest), "delete keychain dest"); is(CFGetRetainCount(dest), 1, "dest retaincount is 1"); CFRelease(dest); ok(tests_end(1), "cleanup"); }
static pascal void RefCounter(CFTypeRef node, void *context) // A callback routine that adds node's reference count // to a global total. Used by TotalAllRefCounts. { (*((SInt32 *)context)) += CFGetRetainCount(node); }
/* * SecCmsSignerInfoSign - sign something * */ OSStatus SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType) { SecCertificateRef cert; SecPrivateKeyRef privkey = NULL; SECOidTag digestalgtag; SECOidTag pubkAlgTag; CSSM_DATA signature = { 0 }; OSStatus rv; PLArenaPool *poolp, *tmppoolp = NULL; const SECAlgorithmID *algID; SECAlgorithmID freeAlgID; //CERTSubjectPublicKeyInfo *spki; PORT_Assert (digest != NULL); poolp = signerinfo->cmsg->poolp; switch (signerinfo->signerIdentifier.identifierType) { case SecCmsSignerIDIssuerSN: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; cert = signerinfo->cert; if (SecCertificateGetAlgorithmID(cert,&algID)) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } break; case SecCmsSignerIDSubjectKeyID: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; #if 0 spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey); SECKEY_DestroyPublicKey(signerinfo->pubKey); signerinfo->pubKey = NULL; SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm); SECKEY_DestroySubjectPublicKeyInfo(spki); algID = &freeAlgID; #else #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) { #else /* TBD: Unify this code. Currently, iOS has an incompatible * SecKeyGetAlgorithmID implementation. */ if (true) { #endif PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } CFRelease(signerinfo->pubKey); signerinfo->pubKey = NULL; #endif break; default: PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE); goto loser; } digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo); /* * XXX I think there should be a cert-level interface for this, * so that I do not have to know about subjectPublicKeyInfo... */ pubkAlgTag = SECOID_GetAlgorithmTag(algID); if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) { SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE); } #if 0 // @@@ Not yet /* Fortezza MISSI have weird signature formats. * Map them to standard DSA formats */ pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag); #endif if (signerinfo->authAttr != NULL) { CSSM_DATA encoded_attrs; /* find and fill in the message digest attribute. */ rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE); if (rv != SECSuccess) goto loser; if (contentType != NULL) { /* if the caller wants us to, find and fill in the content type attribute. */ rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE); if (rv != SECSuccess) goto loser; } if ((tmppoolp = PORT_NewArena (1024)) == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } /* * Before encoding, reorder the attributes so that when they * are encoded, they will be conforming DER, which is required * to have a specific order and that is what must be used for * the hash/signature. We do this here, rather than building * it into EncodeAttributes, because we do not want to do * such reordering on incoming messages (which also uses * EncodeAttributes) or our old signatures (and other "broken" * implementations) will not verify. So, we want to guarantee * that we send out good DER encodings of attributes, but not * to expect to receive them. */ if (SecCmsAttributeArrayReorder(signerinfo->authAttr) != SECSuccess) goto loser; encoded_attrs.Data = NULL; encoded_attrs.Length = 0; if (SecCmsAttributeArrayEncode(tmppoolp, &(signerinfo->authAttr), &encoded_attrs) == NULL) goto loser; rv = SEC_SignData(&signature, encoded_attrs.Data, (int)encoded_attrs.Length, privkey, digestalgtag, pubkAlgTag); PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */ tmppoolp = 0; } else { rv = SGN_Digest(privkey, digestalgtag, pubkAlgTag, &signature, digest); } SECKEY_DestroyPrivateKey(privkey); privkey = NULL; if (rv != SECSuccess) goto loser; if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess) goto loser; SECITEM_FreeItem(&signature, PR_FALSE); if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY) { /* * RFC 3278 section section 2.1.1 states that the signatureAlgorithm * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey * as would appear in other forms of signed datas. However Microsoft doesn't * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there, * MS can't verify - presumably because it takes the digest of the digest * before feeding it to ECDSA. * We handle this with a preference; default if it's not there is * "Microsoft compatibility mode". */ if(!SecCmsMsEcdsaCompatMode()) { pubkAlgTag = SEC_OID_ECDSA_WithSHA1; } /* else violating the spec for compatibility */ } if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, NULL) != SECSuccess) goto loser; return SECSuccess; loser: if (signature.Length != 0) SECITEM_FreeItem (&signature, PR_FALSE); if (privkey) SECKEY_DestroyPrivateKey(privkey); if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); return SECFailure; } OSStatus SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray, CFTypeRef policies, SecTrustRef *trustRef) { SecCertificateRef cert; CFAbsoluteTime stime; OSStatus rv; CSSM_DATA_PTR *otherCerts; if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) { dprintf("SecCmsSignerInfoVerifyCertificate: no signing cert\n"); signerinfo->verificationStatus = SecCmsVSSigningCertNotFound; return SECFailure; } /* * Get and convert the signing time; if available, it will be used * both on the cert verification and for importing the sender * email profile. */ CFTypeRef timeStampPolicies=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies); if (SecCmsSignerInfoGetTimestampTimeWithPolicy(signerinfo, timeStampPolicies, &stime) != SECSuccess) if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess) stime = CFAbsoluteTimeGetCurrent(); CFReleaseSafe(timeStampPolicies); rv = SecCmsSignedDataRawCerts(signerinfo->sigd, &otherCerts); if(rv) { return rv; } rv = CERT_VerifyCert(keychainOrArray, cert, otherCerts, policies, stime, trustRef); dprintfRC("SecCmsSignerInfoVerifyCertificate after vfy: certp %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert)); if (rv || !trustRef) { if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT) { /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */ if (signerinfo->verificationStatus == SecCmsVSGoodSignature) signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted; } } /* FIXME isn't this leaking the cert? */ dprintf("SecCmsSignerInfoVerifyCertificate: CertVerify rtn %d\n", (int)rv); return rv; }
SecCmsSignerInfoRef nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag) { void *mark; SecCmsSignerInfoRef signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } signerinfo->cmsg = cmsg; switch(type) { case SecCmsSignerIDIssuerSN: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN; if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n", (int)CFGetRetainCount(signerinfo->cert)); break; case SecCmsSignerIDSubjectKeyID: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID; PORT_Assert(subjKeyID); if (!subjKeyID) goto loser; signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA); if (SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID, subjKeyID)) { goto loser; } signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey); if (!signerinfo->pubKey) goto loser; break; default: goto loser; } if (!signingKey) goto loser; signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey); if (!signerinfo->signingKey) goto loser; /* set version right now */ version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
}; //============================================================================ // Test case //---------------------------------------------------------------------------- TEST_NCFOBJECT("Retain", "[cf]") { // Perform the test cfArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); REQUIRE(CFGetRetainCount(cfArray) == 1); CFSafeRetain(cfArray); REQUIRE(CFGetRetainCount(cfArray) == 2); CFRelease(cfArray); REQUIRE(CFGetRetainCount(cfArray) == 1); CFSafeRelease(cfArray); REQUIRE(cfArray == NULL); }
static OSStatus CFQMutableDictionaryGetParentForPath(CFMutableDictionaryRef dict, const void *path[], CFIndex pathElementCount, CFMutableDictionaryRef *result) { OSStatus err; CFIndex thisElement; CFMutableDictionaryRef parent; CFDictionaryRef child; assert( dict != NULL); assert( path != NULL); assert( pathElementCount > 0 ); // 0 length paths aren't allowed assert( result != NULL); // Some subtleties in the following loop. // // o It's possible for dictionaries to contain NULL values, so we use // CFDictionaryGetValueIfPresent to test for the presence of the // child rather than CFDictionaryGetValue. // // o We use CFDictionaryGetValueIfPresent in place of the combination of // CFDictionaryContainsKey and CFDictionaryGetValue because it does // both operations in one hit. // // o Loop terminates in one of three ways: // i) we reach the last path element // ii) a path element isn't found (kCFQKeyNotFoundErr) // iii) we proceed to the next path element but the child we // found isn't valid (kCFQDataErr) // iv) we get an error when creating a mutable dictionary // // o Memory tracking is very tricky. Specifically, we have to be // very careful with the mutableChild variable. We create this // each time we progress through a dictionary in the loop. Each // time we create it we then immediately add it to the parent // dictionary, thus ensuring a continued reference count after // we release our reference count. err = noErr; thisElement = 0; parent = dict; while (true) { if (thisElement == (pathElementCount - 1)) { break; } if ( ! CFDictionaryGetValueIfPresent(parent, path[thisElement], (const void **) &child) ) { err = kCFQKeyNotFoundErr; break; } if ( (child == NULL) || (CFGetTypeID(child) != CFDictionaryGetTypeID()) ) { err = kCFQDataErr; break; } { CFMutableDictionaryRef mutableChild; mutableChild = CFDictionaryCreateMutableCopy(NULL, 0, child); if (mutableChild == NULL) { err = coreFoundationUnknownErr; } if (err == noErr) { CFDictionarySetValue(parent, path[thisElement], mutableChild); assert( CFGetRetainCount(mutableChild) >= 2 ); parent = mutableChild; thisElement += 1; } CFQRelease(mutableChild); } if (err != noErr) { break; } } if (err == noErr) { *result = parent; } assert( (err == noErr) == (*result != NULL) ); return err; }
/* Create and identity and try to retrieve it. */ static void tests(void) { SecCertificateRef cert = NULL; SecKeyRef privKey = NULL; SecIdentityRef identity = NULL; isnt(cert = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), NULL, "create certificate"); isnt(privKey = SecKeyCreateRSAPrivateKey(NULL, _k1, sizeof(_k1), kSecKeyEncodingPkcs1), NULL, "create private key"); const void *certkeys[] = { kSecValueRef }; const void *certvalues[] = { cert }; CFDictionaryRef certDict = CFDictionaryCreate(NULL, certkeys, certvalues, array_size(certkeys), NULL, NULL); ok_status(SecItemAdd(certDict, NULL), "add certificate"); CFReleaseNull(certDict); const void *privkeys[] = { kSecValueRef }; const void *privvalues[] = { privKey }; CFDictionaryRef privDict = CFDictionaryCreate(NULL, privkeys, privvalues, array_size(privkeys), NULL, NULL); ok_status(SecItemAdd(privDict, NULL), "add private key"); CFReleaseNull(privDict); isnt(identity = SecIdentityCreate(NULL, cert, privKey), NULL, "create identity"); /* Lookup the key and certificate using SecItemCopyMatching(). */ CFDataRef pk_digest = CFDataCreate(NULL, _k1_digest, sizeof(_k1_digest)); const void *q_keys[] = { kSecClass, kSecAttrApplicationLabel, kSecReturnRef }; const void *q_values[] = { kSecClassKey, pk_digest, kCFBooleanTrue }; CFDictionaryRef query = CFDictionaryCreate(NULL, q_keys, q_values, array_size(q_keys), NULL, NULL); CFTypeRef result_key; ok_status(SecItemCopyMatching(query, &result_key), "lookup key"); isnt(CFEqual(privKey, result_key), 0, "keys match"); CFReleaseNull(query); q_keys[1] = kSecAttrPublicKeyHash; q_values[0] = kSecClassCertificate; query = CFDictionaryCreate(NULL, q_keys, q_values, array_size(q_keys), NULL, NULL); CFTypeRef result_cert; ok_status(SecItemCopyMatching(query, &result_cert), "lookup certificate"); isnt(CFEqual(cert, result_cert), 0, "certificates match"); CFReleaseNull(query); /* Cleanup. */ CFReleaseNull(result_key); CFReleaseNull(result_cert); /* identity lookup */ const void *idnt_keys[] = { kSecClass, kSecAttrApplicationLabel, kSecReturnRef }; const void *idnt_values[] = { kSecClassIdentity, pk_digest, kCFBooleanTrue }; CFTypeRef result_idnt; SecCertificateRef result_cert2; query = CFDictionaryCreate(NULL, idnt_keys, idnt_values, array_size(idnt_keys), NULL, NULL); ok_status(SecItemCopyMatching(query, &result_idnt), "lookup identity"); isnt(result_idnt, NULL, "found identity?"); is(CFGetRetainCount(result_idnt), 1, "result_idnt rc = 1"); isnt(CFEqual(identity, result_idnt), 0, "identities match"); CFReleaseNull(identity); ok_status(SecIdentityCopyCertificate((SecIdentityRef)result_idnt, &result_cert2), "get cert from identity"); isnt(CFEqual(cert, result_cert2), 0, "certificates match"); CFRelease(query); CFRelease(pk_digest); CFReleaseNull(result_cert2); certDict = CFDictionaryCreate(NULL, certkeys, certvalues, array_size(certkeys), NULL, NULL); ok_status(SecItemDelete(certDict), "delete certificate via ref"); is_status(errSecItemNotFound, SecItemCopyMatching(certDict, NULL), "verify certificate is gone"); CFReleaseNull(certDict); privDict = CFDictionaryCreate(NULL, privkeys, privvalues, array_size(privkeys), NULL, NULL); ok_status(SecItemDelete(privDict), "delete key via ref"); is_status(errSecItemNotFound, SecItemCopyMatching(privDict, NULL), "verify key is gone"); CFReleaseNull(privDict); /* add certificate to offset cert row id from key row id */ SecCertificateRef apple_ca_cert = NULL; isnt(apple_ca_cert = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), NULL, "create apple ca certificate"); CFDictionaryRef appleCertDict = CFDictionaryCreate(NULL, (const void **)&kSecValueRef, (const void **)&apple_ca_cert, 1, NULL, NULL); ok_status(SecItemAdd(appleCertDict, NULL), "add apple ca certificate to offset key and cert rowid"); /* add identity, get persistent ref */ const void *keys_identity[] = { kSecValueRef, kSecReturnPersistentRef }; const void *values_identity[] = { result_idnt, kCFBooleanTrue }; CFDictionaryRef identity_add = CFDictionaryCreate(NULL, keys_identity, values_identity, array_size(keys_identity), NULL, NULL); CFTypeRef persist = NULL; ok_status(SecItemAdd(identity_add, &persist), "add identity ref"); ok(persist, "got back persistent ref"); /* <rdar://problem/6537195> SecItemAdd returns success when it shouldn't */ CFTypeRef persist_again = NULL; is_status(errSecDuplicateItem, SecItemAdd(identity_add, &persist_again), "fail to add identity ref again"); ok(!persist_again, "no persistent ref this time"); /* find by persistent ref */ const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef }; const void *values_persist[] = { kCFBooleanTrue, persist }; CFDictionaryRef persist_find = CFDictionaryCreate(NULL, keys_persist, values_persist, (array_size(keys_persist)), NULL, NULL); CFTypeRef results2 = NULL; ok_status(SecItemCopyMatching(persist_find, &results2), "find identity by persistent ref"); is(CFGetRetainCount(results2), 1, "results2 rc = 1"); // not implemented ok(CFEqual(result_idnt, results2), "same item (attributes)"); CFReleaseNull(results2); /* find identity, key and cert by ref and return persistent ref */ const void *keys_ref_to_persist[] = { kSecReturnPersistentRef, kSecValueRef }; const void *values_ref_to_persist[] = { kCFBooleanTrue, NULL }; CFTypeRef items[] = { result_idnt, privKey, cert, NULL }; CFTypeRef *item = items; while (*item) { values_ref_to_persist[1] = *item; CFDictionaryRef ref_to_persist_find = CFDictionaryCreate(NULL, keys_ref_to_persist, values_ref_to_persist, (array_size(keys_ref_to_persist)), NULL, NULL); results2 = NULL; ok_status(SecItemCopyMatching(ref_to_persist_find, &results2), "find persistent ref for identity ref"); ok(NULL != results2, "good persistent ref"); is(CFGetRetainCount(results2), 1, "results2 rc = 1"); CFReleaseNull(results2); CFReleaseNull(ref_to_persist_find); item++; } /* delete identity by identity ref */ ok_status(SecItemDelete(identity_add), "delete identity by identity ref"); is(SecItemCopyMatching(persist_find, &results2), errSecItemNotFound, "make sure identity by persistent ref is no longer there"); CFRelease(persist_find); CFReleaseNull(persist); ok_status(SecItemAdd(identity_add, &persist), "add identity ref back"); CFRelease(identity_add); /* delete identity by persistent ref */ CFDictionaryRef persist_delete = CFDictionaryCreate(NULL, &kSecValuePersistentRef, &persist, 1, NULL, NULL); ok_status(SecItemDelete(persist_delete), "delete identity by persistent ref"); is(SecItemCopyMatching(persist_delete, &results2), errSecItemNotFound, "make sure identity by persistent ref is no longer there"); CFRelease(persist_delete); CFReleaseNull(persist); /* add identity with a label set */ CFStringRef zomg_label = CFSTR("zomg"); CFMutableDictionaryRef lbl_idnt_query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(lbl_idnt_query, kSecValueRef, result_idnt); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); ok_status(SecItemAdd(lbl_idnt_query, NULL), "add identity ref"); /* find identity with label*/ CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); ok_status(SecItemCopyMatching(lbl_idnt_query, NULL), "find identity by label"); /* find certs with label */ CFTypeRef zomg_cert; CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassCertificate); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_cert), "find cert by label"); /* find keys with label */ CFTypeRef zomg_key; CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassKey); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_key), "find key by label"); /* update label on key */ CFStringRef new_label_value = CFSTR("zzzomg"); CFDictionaryRef new_label = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&kSecAttrLabel, (const void **)&new_label_value, 1, NULL, NULL); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecValueRef, zomg_key); ok_status(SecItemUpdate(lbl_idnt_query, new_label), "update label to zzzomg for key"); CFTypeRef zomg_idnt = NULL; CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_idnt), "still finding zomg ident"); CFReleaseNull(zomg_idnt); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecValueRef, zomg_cert); ok_status(SecItemUpdate(lbl_idnt_query, new_label), "update label to zzzomg for cert"); CFReleaseNull(new_label); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); is_status(errSecItemNotFound, SecItemCopyMatching(lbl_idnt_query, &zomg_idnt), "no longer find identity by label"); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, new_label_value); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_idnt), "finding ident with zzzomg label"); /* Find zomg identity with canonical issuer */ { unsigned char DN[] = { 0x30, 0x32, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x0f, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x40, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d }; unsigned int DN_len = 52; CFMutableDictionaryRef find_by_issuer = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); CFDataRef issuer = SecCertificateGetNormalizedIssuerContent(cert); CFTypeRef found_by_issuer = NULL; CFDictionarySetValue(find_by_issuer, kSecAttrIssuer, issuer); CFDictionarySetValue(find_by_issuer, kSecClass, kSecClassIdentity); CFDictionarySetValue(find_by_issuer, kSecReturnRef, kCFBooleanTrue); ok_status(SecItemCopyMatching(find_by_issuer, &found_by_issuer), "find identity by cert issuer"); ok(CFEqual(found_by_issuer, zomg_idnt), "should be same as zomg_idnt"); CFReleaseNull(found_by_issuer); issuer = CFDataCreate(kCFAllocatorDefault, DN, DN_len); CFDictionarySetValue(find_by_issuer, kSecAttrIssuer, issuer); ok_status(SecItemCopyMatching(find_by_issuer, &found_by_issuer), "find identity by cert issuer"); CFReleaseNull(issuer); ok(CFEqual(found_by_issuer, zomg_idnt), "should be same as zomg_idnt"); CFReleaseNull(found_by_issuer); CFReleaseNull(find_by_issuer); } ok_status(SecItemDelete(lbl_idnt_query), "delete ident with zzzomg label"); /* Delete the apple cert last */ ok_status(SecItemDelete(appleCertDict), "delete apple ca certificate"); CFReleaseNull(appleCertDict); CFReleaseNull(apple_ca_cert); CFRelease(zomg_key); CFRelease(zomg_cert); CFRelease(zomg_idnt); CFRelease(zomg_label); CFRelease(new_label_value); CFRelease(lbl_idnt_query); CFReleaseNull(result_idnt); CFReleaseNull(privKey); CFReleaseNull(cert); }
OSStatus SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType) { SecPublicKeyRef publickey = NULL; SecCmsAttribute *attr; CSSM_DATA encoded_attrs; SecCertificateRef cert; SecCmsVerificationStatus vs = SecCmsVSUnverified; PLArenaPool *poolp; SECOidTag digestAlgTag, digestEncAlgTag; if (signerinfo == NULL) return SECFailure; /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */ /* cert has not been verified */ if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, NULL)) == NULL) { dprintf("SecCmsSignerInfoVerify: no signing cert\n"); vs = SecCmsVSSigningCertNotFound; goto loser; } dprintfRC("SecCmsSignerInfoVerify top: cert %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert)); debugShowSigningCertificate(signerinfo); OSStatus status; if ((status = SecCertificateCopyPublicKey(cert, &publickey))) { syslog(LOG_ERR, "SecCmsSignerInfoVerifyWithPolicy: copy public key failed %d", (int)status); vs = SecCmsVSProcessingError; goto loser; } digestAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg)); digestEncAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)); /* * Gross hack necessitated by RFC 3278 section 2.1.1, which states * that the signature algorithm (here, digestEncAlg) contains ecdsa_with-SHA1, * *not* (as in all other algorithms) the raw signature algorithm, e.g. * pkcs1RSAEncryption. */ if(digestEncAlgTag == SEC_OID_ECDSA_WithSHA1) { digestEncAlgTag = SEC_OID_EC_PUBLIC_KEY; } if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) { if (contentType) { /* * Check content type * * RFC2630 sez that if there are any authenticated attributes, * then there must be one for content type which matches the * content type of the content being signed, and there must * be one for message digest which matches our message digest. * So check these things first. */ if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL) { vs = SecCmsVSMalformedSignature; goto loser; } if (SecCmsAttributeCompareValue(attr, contentType) == PR_FALSE) { vs = SecCmsVSMalformedSignature; goto loser; } } /* * Check digest */ if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL) { vs = SecCmsVSMalformedSignature; goto loser; } if (SecCmsAttributeCompareValue(attr, digest) == PR_FALSE) { vs = SecCmsVSDigestMismatch; goto loser; } if ((poolp = PORT_NewArena (1024)) == NULL) { vs = SecCmsVSProcessingError; goto loser; } /* * Check signature * * The signature is based on a digest of the DER-encoded authenticated * attributes. So, first we encode and then we digest/verify. * we trust the decoder to have the attributes in the right (sorted) order */ encoded_attrs.Data = NULL; encoded_attrs.Length = 0; if (SecCmsAttributeArrayEncode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL || encoded_attrs.Data == NULL || encoded_attrs.Length == 0) { vs = SecCmsVSProcessingError; goto loser; } vs = (VFY_VerifyData (encoded_attrs.Data, (int)encoded_attrs.Length, publickey, &(signerinfo->encDigest), digestAlgTag, digestEncAlgTag, signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature; dprintf("VFY_VerifyData (authenticated attributes): %s\n", (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature"); PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */ } else { CSSM_DATA_PTR sig; /* No authenticated attributes. The signature is based on the plain message digest. */ sig = &(signerinfo->encDigest); if (sig->Length == 0) goto loser; vs = (VFY_VerifyDigest(digest, publickey, sig, digestAlgTag, digestEncAlgTag, signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature; dprintf("VFY_VerifyData (plain message digest): %s\n", (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature"); } if (!SecCmsArrayIsEmpty((void **)signerinfo->unAuthAttr)) { dprintf("found an unAuthAttr\n"); OSStatus rux = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo,timeStampPolicy); dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux); if (rux) { goto loser; } } if (vs == SecCmsVSBadSignature) { /* * XXX Change the generic error into our specific one, because * in that case we get a better explanation out of the Security * Advisor. This is really a bug in our error strings (the * "generic" error has a lousy/wrong message associated with it * which assumes the signature verification was done for the * purposes of checking the issuer signature on a certificate) * but this is at least an easy workaround and/or in the * Security Advisor, which specifically checks for the error * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation * in that case but does not similarly check for * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would * probably say the wrong thing in the case that it *was* the * certificate signature check that failed during the cert * verification done above. Our error handling is really a mess. */ if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); } if (publickey != NULL) CFRelease(publickey); signerinfo->verificationStatus = vs; dprintfRC("SecCmsSignerInfoVerify end: cerp %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert)); dprintf("verificationStatus: %d\n", vs); return (vs == SecCmsVSGoodSignature) ? SECSuccess : SECFailure; loser: if (publickey != NULL) SECKEY_DestroyPublicKey (publickey); dprintf("verificationStatus2: %d\n", vs); signerinfo->verificationStatus = vs; PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); return SECFailure; }
// Callback passed to the VideoToolbox decoder for returning data. // This needs to be static because the API takes a C-style pair of // function and userdata pointers. This validates parameters and // forwards the decoded image back to an object method. static void PlatformCallback(void* decompressionOutputRefCon, CFDictionaryRef frameInfo, OSStatus status, VDADecodeInfoFlags infoFlags, CVImageBufferRef image) { LOG("AppleVDADecoder[%s] status %d flags %d retainCount %ld", __func__, status, infoFlags, CFGetRetainCount(frameInfo)); // Validate our arguments. // According to Apple's TN2267 // The output callback is still called for all flushed frames, // but no image buffers will be returned. // FIXME: Distinguish between errors and empty flushed frames. if (status != noErr || !image) { NS_WARNING("AppleVDADecoder decoder returned no data"); return; } MOZ_ASSERT(CFGetTypeID(image) == CVPixelBufferGetTypeID(), "AppleVDADecoder returned an unexpected image type"); if (infoFlags & kVDADecodeInfo_FrameDropped) { NS_WARNING(" ...frame dropped..."); return; } AppleVDADecoder* decoder = static_cast<AppleVDADecoder*>(decompressionOutputRefCon); AutoCFRelease<CFNumberRef> ptsref = (CFNumberRef)CFDictionaryGetValue(frameInfo, CFSTR("FRAME_PTS")); AutoCFRelease<CFNumberRef> dtsref = (CFNumberRef)CFDictionaryGetValue(frameInfo, CFSTR("FRAME_DTS")); AutoCFRelease<CFNumberRef> durref = (CFNumberRef)CFDictionaryGetValue(frameInfo, CFSTR("FRAME_DURATION")); AutoCFRelease<CFNumberRef> boref = (CFNumberRef)CFDictionaryGetValue(frameInfo, CFSTR("FRAME_OFFSET")); AutoCFRelease<CFNumberRef> kfref = (CFNumberRef)CFDictionaryGetValue(frameInfo, CFSTR("FRAME_KEYFRAME")); Microseconds dts; Microseconds pts; Microseconds duration; int64_t byte_offset; char is_sync_point; CFNumberGetValue(ptsref, kCFNumberSInt64Type, &pts); CFNumberGetValue(dtsref, kCFNumberSInt64Type, &dts); CFNumberGetValue(durref, kCFNumberSInt64Type, &duration); CFNumberGetValue(boref, kCFNumberSInt64Type, &byte_offset); CFNumberGetValue(kfref, kCFNumberSInt8Type, &is_sync_point); nsAutoPtr<AppleVDADecoder::AppleFrameRef> frameRef( new AppleVDADecoder::AppleFrameRef(dts, pts, duration, byte_offset, is_sync_point == 1)); // Forward the data back to an object method which can access // the correct MP4Reader callback. decoder->OutputFrame(image, frameRef); }
static pascal void PrintPropertyListCallback(CFTypeRef key, CFTypeRef node, void *context) // A callback routine used by PrintPropertyList to print // a property list in a nicely formatted way. { #pragma unused(key) int i; int depth; depth = (int)context; for (i = 0; i < depth; i++) { fprintf(stderr, " "); } { CFStringRef fullDesc; CFStringRef typeDesc; CFStringRef valueDesc; fullDesc = NULL; typeDesc = CFCopyTypeIDDescription(CFGetTypeID(node)); valueDesc = NULL; if ( CFQPropertyListIsLeaf(node) ) { if ( CFGetTypeID(node) == CFStringGetTypeID() ) { valueDesc = (CFStringRef) CFRetain(node); } else if ( CFGetTypeID(node) == CFNumberGetTypeID() ) { valueDesc = (CFStringRef) CFRetain(node); } else { valueDesc = CFCopyDescription(node); } fullDesc = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ : %@ [%d] = %@"), key, typeDesc, CFGetRetainCount(node), valueDesc); } else { fullDesc = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ : %@ [%d]"), key, typeDesc, CFGetRetainCount(node)); } CFShow(fullDesc); CFQRelease(fullDesc); CFQRelease(valueDesc); CFQRelease(typeDesc); } if ( ! CFQPropertyListIsLeaf(node) ) { CFQPropertyListShallowApplyFunction(node, PrintPropertyListCallback, (void *) (depth + 1) ); } }