/******************************************************** *********** SecItemCertificateSource object ************ ********************************************************/ static bool SecItemCertificateSourceCopyParents( SecCertificateSourceRef source, SecCertificateRef certificate, void *context, SecCertificateSourceParents callback) { /* FIXME: Search for things other than just subject of our issuer if we have a subjectID or authorityKeyIdentifier. */ CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit, kSecAttrSubject }, *values[] = { kSecClassCertificate, kCFBooleanTrue, kSecMatchLimitAll, normalizedIssuer }; CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL); CFTypeRef results = NULL; /* We can make this async or run this on a queue now easily. */ OSStatus status = SecItemCopyMatching(query, &results); CFRelease(query); if (status) { secdebug("trust", "SecItemCopyMatching status: %lu", status); } callback(context, results); CFReleaseSafe(results); return true; }
/* Releases parent unconditionally, and return a CFArrayRef containing parent if the normalized subject of parent matches the normalized issuer of certificate. */ static CFArrayRef SecCAIssuerConvertToParents(SecCertificateRef certificate, SecCertificateRef parent) { CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate); CFArrayRef parents = NULL; if (parent) { CFDataRef parent_nic = SecCertificateGetNormalizedSubjectContent(parent); if (parent_nic && CFEqual(nic, parent_nic)) { const void *ventry = parent; parents = CFArrayCreate(NULL, &ventry, 1, &kCFTypeArrayCallBacks); } CFRelease(parent); } return parents; }
static bool SecMemoryCertificateSourceCopyParents( SecCertificateSourceRef source, SecCertificateRef certificate, void *context, SecCertificateSourceParents callback) { SecMemoryCertificateSourceRef msource = (SecMemoryCertificateSourceRef)source; CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); CFArrayRef parents = CFDictionaryGetValue(msource->subjects, normalizedIssuer); /* FIXME filter parents by subjectID if certificate has an authorityKeyIdentifier. */ secdebug("trust", "%@ parents -> %@", certificate, parents); callback(context, parents); return true; }
int check_comodo_blacklist(SecCertificateRefP cert) { int i; //check if issuer is UTNB CFDataRef issuer = SecCertificateGetNormalizedIssuerContent(cert); //CFDataGetLength() == 0x97 if (issuer == NULL || CFDataGetLength(issuer) != sizeof(comodo_utnb_issuer)) return 0; if(memcmp(CFDataGetBytePtr(issuer), comodo_utnb_issuer, sizeof(comodo_utnb_issuer))) return 0; CFDataRef serial = SecCertificateCopySerialNumber(cert); if (serial == NULL) //should not happen but whatever return 0; int sl = CFDataGetLength(serial); const UInt8* p = CFDataGetBytePtr(serial); if( p == NULL) return 0; //skip leading null bytes while(sl > 0 && *p == 0) { p++; sl--; } if (sl == SERIALSIZE) { for(i=0; i < N_COMODO_SERIALS; i++) { //XXX apple only memcmp 4 bytes ? false positives ? if(!memcmp(p, comodo_serials[i], SERIALSIZE)) { syslog(LOG_WARNING, "iSSLFix: blocking blacklisted Comodo certificate"); CFRelease(serial); return 1; } } } CFRelease(serial); return 0; }
/******************************************************** *********** SecSystemAnchorSource object ************ ********************************************************/ static bool SecSystemAnchorSourceCopyParents( SecCertificateSourceRef source, SecCertificateRef certificate, void *context, SecCertificateSourceParents callback) { #ifndef SECITEM_SHIM_OSX CFMutableArrayRef parents = NULL; CFDataRef nic = SecCertificateGetNormalizedIssuerContent(certificate); /* 64 bits cast: the worst that can happen here is we truncate the length and match an actual anchor. It does not matter since we would be returning the wrong anchors */ assert((unsigned long)CFDataGetLength(nic)<UINT_MAX); /* Debug check. correct as long as CFIndex is signed long */ const struct subject_to_ix_t *i2x = subject_to_anchor_ix((const char *)CFDataGetBytePtr(nic), (unsigned int)CFDataGetLength(nic)); require_quiet(i2x, errOut); int anchor_ix = i2x->anchor_ix; CFIndex capacity = 0; do { ++capacity; } while ((anchor_ix = anchorslist[anchor_ix].next_same_subject)); parents = CFArrayCreateMutable(kCFAllocatorDefault, capacity, &kCFTypeArrayCallBacks); anchor_ix = i2x->anchor_ix; do { const void *anchor = NULL; CFDataRef anchor_data = NULL; require_quiet(anchor_data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, (const UInt8 *)anchorslist[anchor_ix].data, anchorslist[anchor_ix].length, kCFAllocatorNull), errOut); anchor = SecCertificateCreateWithData(kCFAllocatorDefault, anchor_data); CFRelease(anchor_data); if (anchor) { CFArrayAppendValue(parents, anchor); CFRelease(anchor); } } while ((anchor_ix = anchorslist[anchor_ix].next_same_subject)); errOut: callback(context, parents); CFReleaseSafe(parents); #endif return true; }
/* 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); }