Ejemplo n.º 1
0
Archivo: main.c Proyecto: pnc/splitring
CFArrayRef SRCopyItems(CFArrayRef keychains, CFArrayRef classes) {
  CFMutableArrayRef allItems = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);

  CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0,
                                                           &kCFTypeDictionaryKeyCallBacks,
                                                           &kCFTypeDictionaryValueCallBacks);
  CFDictionarySetValue(query, kSecMatchSearchList, keychains);
  CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
  CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
  CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);

  for (int i = 0; i < CFArrayGetCount(classes); i++) {
    CFTypeRef class = CFArrayGetValueAtIndex(classes, i);
    CFDictionarySetValue(query, kSecClass, class);

    CFArrayRef items = NULL;
    OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)&items);
    // If there are not results, that's fine; this class is just empty
    if (errSecItemNotFound != status) {
      SRHandleError(status, true);
      for (int j = 0; j < CFArrayGetCount(items); j++) {
        CFDictionaryRef properties = CFArrayGetValueAtIndex(items, j);
        CFMutableDictionaryRef newProperties = CFDictionaryCreateMutableCopy(NULL, 0, properties);
        CFDictionarySetValue(newProperties, kSRAttrClass, class);
        CFArrayAppendValue(allItems, newProperties);
        CFRelease(newProperties);
      }
      CFRelease(items);
    }
  }
Ejemplo n.º 2
0
// static
bool OTKeyring::IOS_RetrieveSecret(const OTString& strUser,
                                   OTPassword& thePassword,
                                   const std::string& str_display)
{
    OT_ASSERT(strUser.Exists());

    CFStringRef service_name = CFSTR("opentxs");
    CFStringRef account_name = CFStringCreateWithCString(nullptr, strUser.Get(),
                                                         kCFStringEncodingUTF8);
    CFDataRef vData = nullptr;

    const void* keys[] = {kSecClass, kSecAttrService, kSecAttrAccount,
                          kSecReturnData};
    const void* values[] = {kSecClassGenericPassword, service_name,
                            account_name, kCFBooleanTrue};
    CFDictionaryRef query =
        CFDictionaryCreate(nullptr, keys, values, 4, nullptr, nullptr);

    OSStatus theError = SecItemCopyMatching(query, (CFTypeRef*)&vData);

    CFRelease(query);
    CFRelease(account_name);

    if (theError != noErr) {
        otErr
            << "OTKeyring::IOS_RetrieveSecret: Error in SecItemCopyMatching.\n";
        return false;
    }

    thePassword.setMemory(CFDataGetBytePtr(vData), CFDataGetLength(vData));
    CFRelease(vData);

    return true;
}
Ejemplo n.º 3
0
static OSStatus
EAPSecIdentityListCreate(CFArrayRef * ret_array)
{
    const void *		keys[] = {
	kSecClass,
	kSecReturnRef,
	kSecMatchLimit
    };
    CFDictionaryRef		query;
    CFTypeRef			results = NULL;
    OSStatus			status = errSecSuccess;
    const void *		values[] = {
	kSecClassIdentity,
	kCFBooleanTrue,
	kSecMatchLimitAll
    };

    query = CFDictionaryCreate(NULL, keys, values,
			       array_size(keys),
			       &kCFTypeDictionaryKeyCallBacks,
			       &kCFTypeDictionaryValueCallBacks);
    ok_status(status = SecItemCopyMatching(query, &results), "SecItemCopyMatching");
    CFReleaseNull(query);
    if (status == errSecSuccess) {
	*ret_array = results;
    }
    return (status);
}
Ejemplo n.º 4
0
CFArrayRef CreateKeychainItems(const std::set<std::string>& paths,
                               const CFTypeRef& item_type) {
  auto keychains = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
  for (const auto& path : paths) {
    genKeychains(path, keychains);
  }

  CFMutableDictionaryRef query;
  query = CFDictionaryCreateMutable(nullptr,
                                    0,
                                    &kCFTypeDictionaryKeyCallBacks,
                                    &kCFTypeDictionaryValueCallBacks);
  CFDictionaryAddValue(query, kSecClass, item_type);
  CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
  // This can be added to restrict results to x509v3
  // CFDictionaryAddValue(query, kSecAttrCertificateType, 0x03);
  CFDictionaryAddValue(query, kSecMatchSearchList, keychains);
  CFDictionaryAddValue(query, kSecAttrCanVerify, kCFBooleanTrue);
  CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll);

  CFArrayRef keychain_certs;
  auto status = SecItemCopyMatching(query, (CFTypeRef*)&keychain_certs);
  CFRelease(query);

  if (status != errSecSuccess) {
    return nullptr;
  }

  // Release each keychain search path.
  CFRelease(keychains);

  return keychain_certs;
}
static void ensureKeychainExists(void) {
    CFDictionaryRef query = CFDictionaryCreate(0, &kSecClass, &kSecClassInternetPassword, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFTypeRef results = NULL;
    is_status(SecItemCopyMatching(query, &results), errSecItemNotFound, "expected nothing got %@", results);
    CFReleaseNull(query);
    CFReleaseNull(results);
}
Ejemplo n.º 6
0
/********************************************************
 *********** 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;
}
Ejemplo n.º 7
0
static bool SecItemCertificateSourceContains(SecCertificateSourceRef source,
	SecCertificateRef certificate) {
    /* Lookup a certificate by issuer and serial number. */
    CFDataRef normalizedSubject =
        SecCertificateGetNormalizedSubjectContent(certificate);
    CFDataRef serialNumber =
        SecCertificateCopySerialNumber(certificate);
    const void *keys[] = {
        kSecClass,
        kSecReturnRef,
        kSecMatchLimit,
        kSecAttrIssuer,
		kSecAttrSerialNumber
    },
    *values[] = {
        kSecClassCertificate,
        kCFBooleanTrue,
        kSecMatchLimitOne,
        normalizedSubject,
		serialNumber
    };
    CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 5,
        NULL, NULL);
    OSStatus status = SecItemCopyMatching(query, NULL);
    CFRelease(query);
    CFRelease(serialNumber);

    if (status) {
		if (status != errSecItemNotFound) {
			secdebug("trust", "SecItemCopyMatching returned %d", status);
		}
		return false;
    }
    return true;
}
CFArrayRef
CUICertificateCredentialProvider::copyMatchingIdentities(CFDictionaryRef attributes, CFTypeRef targetName, CFErrorRef *error)
{
    CFMutableDictionaryRef query = NULL;
    CFArrayRef result = NULL;
    CFStringRef name;
    
    query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                                      &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    if (query == NULL)
        return NULL;

    if (attributes &&
        (name = (CFStringRef)CFDictionaryGetValue(attributes, kCUIAttrName))) {
        CFDictionarySetValue(query, kSecMatchSubjectContains, name);
    }

    CFDictionarySetValue(query, kSecClass,      kSecClassIdentity);
    CFDictionarySetValue(query, kSecReturnRef,  kCFBooleanTrue);
    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);

    SecItemCopyMatching(query, (CFTypeRef *)&result);
    
    CFRelease(query);
    
    return result;
}
Ejemplo n.º 9
0
CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) {
    CFTypeRef persistentRef = NULL;
    CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true);

    require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error ,
                           CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail);
fail:
    CFReleaseNull(query);
    return (CFDataRef)persistentRef;
}
static void persistentRefIs(CFDataRef pref, CFDataRef data) {
    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
    CFTypeRef result = NULL;
    CFDictionaryAddValue(dict, kSecValuePersistentRef, pref);
    CFDictionaryAddValue(dict, kSecReturnData, kCFBooleanTrue);
    ok_status(SecItemCopyMatching(dict, &result), "lookup item data by persistent ref");
    ok(CFEqual(data, result), "result %@ equals expected data %@", result, data);
    CFReleaseNull(result);
    CFReleaseNull(dict);
}
Ejemplo n.º 11
0
SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) {
    CFTypeRef private_key = NULL;
    
    CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, false);    
    
    require_quiet(SecError(SecItemCopyMatching(query, &private_key), error,
                           CFSTR("Error finding private key from public: %@"), publicKey), fail);
fail:
    CFReleaseNull(query);
    return (SecKeyRef)private_key;
}
static void test_persistent2(struct test_persistent_s *p)
{
    CFTypeRef results = NULL;
    CFTypeRef results2 = NULL;

    ok_status(!SecItemCopyMatching(p->query, &results),
        "don't find internet password by attributes");
    ok(!results, "no results");

    ok_status(!SecItemCopyMatching(p->query2, &results2),
        "don't find internet password by persistent ref anymore");
    ok(!results2, "no results");

    SKIP:{
        ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref");
        skip("non updated internet password by persistent ref NOT FOUND!", 2, results2);
        ok(results2, "non updated internet password not found");
        CFStringRef server = CFDictionaryGetValue(results2, kSecAttrServer);
        ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update");
        CFReleaseNull(results2);
    }

    is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound,
        "don't find deleted internet password by persistent ref");
    CFReleaseNull(results2);
    ok_status(SecItemCopyMatching(p->query4, &results2),
        "find non deleted internet password by persistent ref");
    CFReleaseNull(results2);

    ok_status(SecItemDelete(p->query4),"Deleted internet password by persistent ref");

    CFRelease(p->query);
    CFRelease(p->query2);
    CFRelease(p->query3);
    CFRelease(p->query4);
    CFReleaseNull(p->persist[0]);
    CFReleaseNull(p->persist[1]);
}
/* Create an empty keychain file that can't be read or written and make sure
   securityd can deal with it. */
static void tests(void)
{
#ifndef NO_SERVER
    plan_skip_all("No testing against server.");
#else
    const char *home_dir = getenv("HOME");
    char keychain_dir[1000];
    char keychain_name[1000];
    sprintf(keychain_dir, "%s/Library/Keychains", home_dir);
    sprintf(keychain_name, "%s/keychain-2-debug.db", keychain_dir);

    ensureKeychainExists();
    int fd;
    ok_unix(fd = open(keychain_name, O_RDWR | O_CREAT | O_TRUNC, 0644),
        "create keychain file '%s'", keychain_name);
    ok_unix(fchmod(fd, 0), " keychain file '%s'", keychain_name);
    ok_unix(close(fd), "close keychain file '%s'", keychain_name);

    kc_dbhandle_reset();

    int v_eighty = 80;
    CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty);
    const char *v_data = "test";
    CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
    CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
    CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net"));
    CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith"));
    CFDictionaryAddValue(query, kSecAttrPort, eighty);
    CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP);
    CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault);
    CFDictionaryAddValue(query, kSecValueData, pwdata);
    ok_status(SecItemAdd(query, NULL), "add internet password");
    is_status(SecItemAdd(query, NULL), errSecDuplicateItem,
	"add internet password again");

    ok_status(SecItemCopyMatching(query, NULL), "Found the item we added");

    ok_status(SecItemDelete(query),"Deleted the item we added");

    CFReleaseSafe(eighty);
    CFReleaseSafe(pwdata);
    CFReleaseSafe(query);
#endif
}
Ejemplo n.º 14
0
      /**
       * Searches certificates in all opened system keychains. Takes an optional
       * \p query that defines filter attributes to be searched for. That query
       * is amended by generic attributes for "certificate filtering".
       *
       * \param query  a list of key-value pairs used for filtering
       * \returns      an array with the resulting certificates or nullptr if
       *               no matching certificate was found
       */
      scoped_CFType<CFArrayRef> search(Query query = Query()) const
         {
         scoped_CFType<CFDictionaryRef> fullQuery(
            prepareQuery(std::move(query)));
         check_notnull(fullQuery, "create search query");

         scoped_CFType<CFArrayRef> result(nullptr);
         auto status = SecItemCopyMatching(fullQuery.get(),
                                           (CFTypeRef*)&result.get());
         if(errSecItemNotFound == status)
            {
            return scoped_CFType<CFArrayRef>(nullptr);  // no matches
            }

         check_success(status, "look up certificate");
         check_notnull(result, "look up certificate (invalid result value)");

         return result;
         }
static OSStatus do_query(void)
{
    /* querying a password */
    const void *keys[] = {
        kSecClass,
        kSecAttrServer,
        kSecReturnAttributes,
    };
    const void *values[] = {
        kSecClassInternetPassword,
        CFSTR("corrupt.spamcop.net"),
        kCFBooleanTrue,
    };
    CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values,
                                              array_size(keys), NULL, NULL);
    CFTypeRef results = NULL;

    OSStatus err = SecItemCopyMatching(query, &results);
    CFReleaseNull(query);
    return err;
}
Ejemplo n.º 16
0
std::vector<char> metadata_realm_encryption_key()
{
    const size_t key_size = 64;
    const std::string service = "io.realm.sync.keychain";
    const std::string account = "metadata";

    auto search_dictionary = build_search_dictionary(account, service, none);
    CFDataRef retained_key_data;
    if (OSStatus status = SecItemCopyMatching(search_dictionary.get(), (CFTypeRef *)&retained_key_data)) {
        if (status != errSecItemNotFound) {
            throw KeychainAccessException(status);
        }

        // Key was not found. Generate a new key, store it, and return it.
        std::vector<char> key(key_size);
        arc4random_buf(key.data(), key_size);
        auto key_data = adoptCF(CFDataCreate(nullptr, reinterpret_cast<const UInt8 *>(key.data()), key_size));
        if (!key_data) {
            throw std::bad_alloc();
        }

        CFDictionaryAddValue(search_dictionary.get(), kSecValueData, key_data.get());
        if (OSStatus status = SecItemAdd(search_dictionary.get(), nullptr)) {
            throw KeychainAccessException(status);
        }

        return key;
    }
    CFPtr<CFDataRef> key_data = adoptCF(retained_key_data);

    // Key was previously stored. Extract it.
    if (key_size != CFDataGetLength(key_data.get())) {
        throw std::runtime_error("Password stored in keychain was not expected size.");
    }

    auto key_bytes = reinterpret_cast<const char *>(CFDataGetBytePtr(key_data.get()));
    return std::vector<char>(key_bytes, key_bytes + key_size);
}
Ejemplo n.º 17
0
static VALUE rb_keychain_item_reload(VALUE self){
  SecKeychainItemRef keychainItem=NULL;
  Data_Get_Struct(self, struct OpaqueSecKeychainItemRef, keychainItem);

  CFMutableDictionaryRef query = sec_query_identifying_item(keychainItem);

  CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
  CFStringRef cfclass = rb_copy_item_class(keychainItem);
  CFDictionarySetValue(query, kSecClass, cfclass);
  CFRelease(cfclass);

  CFDictionaryRef attributes;
  OSStatus result = SecItemCopyMatching(query, (CFTypeRef*)&attributes);
  CFRelease(query);
  CheckOSStatusOrRaise(result);
  VALUE new_attributes = rb_hash_new();
  CFDictionaryApplyFunction(attributes, cf_hash_to_rb_hash, (void*)new_attributes);
  rb_ivar_set(self, rb_intern("@attributes"), new_attributes);
  rb_ivar_set(self, rb_intern("unsaved_password"), Qnil);
  CFRelease(attributes);

  return self;
}
CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error)
{
    CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true);

    CFDataRef result = NULL;

    OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result);

    CFReleaseNull(query);

    if (copyResult != noErr) {
        SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service);
        CFReleaseNull(result);
        return NULL;
    }

    if (!isData(result)) {
        SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service);
        CFReleaseNull(result);
        return NULL;
    }

    return result;
}
Ejemplo n.º 19
0
static VALUE rb_keychain_find(int argc, VALUE *argv, VALUE self){

  VALUE kind;
  VALUE attributes;
  VALUE first_or_all;
  rb_scan_args(argc, argv, "2:", &first_or_all, &kind, &attributes);

  Check_Type(first_or_all, T_SYMBOL);
  Check_Type(kind, T_STRING);
  
  CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

  CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue);
  CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
  

  if(rb_to_id(first_or_all) == rb_intern("all")){
    CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
  }

  rb_add_value_to_cf_dictionary(query, kSecClass, kind);


  if(!NIL_P(attributes)){
    Check_Type(attributes, T_HASH);
    VALUE rb_keychains = rb_hash_aref(attributes, ID2SYM(rb_intern("keychains")));
    if(!NIL_P(rb_keychains)){
      Check_Type(rb_keychains, T_ARRAY);
      CFMutableArrayRef searchArray = CFArrayCreateMutable(NULL, RARRAY_LEN(rb_keychains), &kCFTypeArrayCallBacks);
      for(int index=0; index < RARRAY_LEN(rb_keychains); index++){
        SecKeychainRef keychain = NULL;
        Data_Get_Struct(RARRAY_PTR(rb_keychains)[index], struct OpaqueSecKeychainRef, keychain);
        CFArrayAppendValue(searchArray, keychain);
      }
      CFDictionarySetValue(query, kSecMatchSearchList,searchArray);
      CFRelease(searchArray);
    }  

    VALUE limit = rb_hash_aref(attributes, ID2SYM(rb_intern("limit")));
    if(!NIL_P(limit)){
      Check_Type(limit, T_FIXNUM);
      long c_limit = FIX2LONG(limit);
      CFNumberRef cf_limit = CFNumberCreate(NULL, kCFNumberLongType, &c_limit);
      CFDictionarySetValue(query, kSecMatchLimit, cf_limit);
      CFRelease(cf_limit);
    }

    VALUE conditions = rb_hash_aref(attributes, ID2SYM(rb_intern("conditions")));
    
    if(!NIL_P(conditions)){
      Check_Type(conditions, T_HASH);
      VALUE rQuery = Data_Wrap_Struct(rb_cPointerWrapper, NULL, NULL, query);
      rb_block_call(conditions, rb_intern("each"), 0, NULL, RUBY_METHOD_FUNC(add_conditions_to_query), rQuery);
    }
  }

  CFDictionaryRef result;

  OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&result);
  CFRelease(query);

  VALUE rb_item = rb_ary_new2(0);

  switch(status){
    case errSecItemNotFound: 
      break;
    default:
    CheckOSStatusOrRaise(status);
    if(CFArrayGetTypeID() == CFGetTypeID(result)){
      CFArrayRef result_array = (CFArrayRef)result;
      for(CFIndex i = 0; i < CFArrayGetCount(result_array); i++){
        rb_ary_push(rb_item,rb_keychain_item_from_sec_dictionary(CFArrayGetValueAtIndex(result_array,i)));
      }
    }
    else{
      rb_ary_push(rb_item, rb_keychain_item_from_sec_dictionary(result));
    }
    CFRelease(result);
  }

  if(rb_to_id(first_or_all) == rb_intern("first")){
    return rb_ary_entry(rb_item,0);
  }
  else{
    return rb_item;
  }
}
Ejemplo n.º 20
0
static CFArrayRef				/* O - Array of certificates */
copy_cdsa_certificate(
    cupsd_client_t *con)			/* I - Client connection */
{
  OSStatus		err;		/* Error info */
  SecKeychainRef	keychain = NULL;/* Keychain reference */
  SecIdentitySearchRef	search = NULL;	/* Search reference */
  SecIdentityRef	identity = NULL;/* Identity */
  CFArrayRef		certificates = NULL;
					/* Certificate array */
  SecPolicyRef		policy = NULL;	/* Policy ref */
  CFStringRef		servername = NULL;
					/* Server name */
  CFMutableDictionaryRef query = NULL;	/* Query qualifiers */
  CFArrayRef		list = NULL;	/* Keychain list */
#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  char			localname[1024];/* Local hostname */
#    endif /* HAVE_DNSSD || HAVE_AVAHI */


  cupsdLogMessage(CUPSD_LOG_DEBUG,
                  "copy_cdsa_certificate: Looking for certs for \"%s\".",
		  con->servername);

  if ((err = SecKeychainOpen(ServerCertificate, &keychain)))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)",
	            ServerCertificate, cssmErrorString(err), (int)err);
    goto cleanup;
  }

  servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername,
					 kCFStringEncodingUTF8);

  policy = SecPolicyCreateSSL(1, servername);

  if (servername)
    CFRelease(servername);

  if (!policy)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
    goto cleanup;
  }

  if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
					  &kCFTypeDictionaryKeyCallBacks,
					  &kCFTypeDictionaryValueCallBacks)))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary");
    goto cleanup;
  }

  list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1,
                       &kCFTypeArrayCallBacks);

  CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
  CFDictionaryAddValue(query, kSecMatchPolicy, policy);
  CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
  CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
  CFDictionaryAddValue(query, kSecMatchSearchList, list);

  CFRelease(list);

  err = SecItemCopyMatching(query, (CFTypeRef *)&identity);

#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  if (err && DNSSDHostName)
  {
   /*
    * Search for the connection server name failed; try the DNS-SD .local
    * hostname instead...
    */

    snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);

    cupsdLogMessage(CUPSD_LOG_DEBUG,
		    "copy_cdsa_certificate: Looking for certs for \"%s\".",
		    localname);

    servername = CFStringCreateWithCString(kCFAllocatorDefault, localname,
					   kCFStringEncodingUTF8);

    CFRelease(policy);

    policy = SecPolicyCreateSSL(1, servername);

    if (servername)
      CFRelease(servername);

    if (!policy)
    {
      cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
      goto cleanup;
    }

    CFDictionarySetValue(query, kSecMatchPolicy, policy);

    err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
  }
#    endif /* HAVE_DNSSD || HAVE_AVAHI */

  if (err)
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG,
		    "Cannot find signing key in keychain \"%s\": %s (%d)",
		    ServerCertificate, cssmErrorString(err), (int)err);
    goto cleanup;
  }

  if (CFGetTypeID(identity) != SecIdentityGetTypeID())
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure.");
    goto cleanup;
  }

  if ((certificates = CFArrayCreate(NULL, (const void **)&identity,
				  1, &kCFTypeArrayCallBacks)) == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array");
    goto cleanup;
  }

  cleanup :

  if (keychain)
    CFRelease(keychain);
  if (search)
    CFRelease(search);
  if (identity)
    CFRelease(identity);

  if (policy)
    CFRelease(policy);
  if (query)
    CFRelease(query);

  return (certificates);
}
Ejemplo n.º 21
0
static value cert_load_defaults(){
#if defined(NEKO_WINDOWS)
	value v;
	HCERTSTORE store;
	PCCERT_CONTEXT cert;
	mbedtls_x509_crt *chain = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt));
	mbedtls_x509_crt_init( chain );
	if( store = CertOpenSystemStore(0, (LPCSTR)"Root") ){
		cert = NULL;
		while( cert = CertEnumCertificatesInStore(store, cert) )
			mbedtls_x509_crt_parse_der( chain, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded );
		CertCloseStore(store, 0);
	}
	v = alloc_abstract(k_cert, chain);
	val_gc(v,free_cert);
	return v;
#elif defined(NEKO_MAC)
	CFMutableDictionaryRef search;
	CFArrayRef result;
	SecKeychainRef keychain;
	SecCertificateRef item;
	CFDataRef dat;
	value v;
	mbedtls_x509_crt *chain = NULL;

	// Load keychain
	if( SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain",&keychain) != errSecSuccess )
		return val_null;

	// Search for certificates
	search = CFDictionaryCreateMutable( NULL, 0, NULL, NULL );
	CFDictionarySetValue( search, kSecClass, kSecClassCertificate );
	CFDictionarySetValue( search, kSecMatchLimit, kSecMatchLimitAll );
	CFDictionarySetValue( search, kSecReturnRef, kCFBooleanTrue );
	CFDictionarySetValue( search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL) );
	if( SecItemCopyMatching( search, (CFTypeRef *)&result ) == errSecSuccess ){
		CFIndex n = CFArrayGetCount( result );
		for( CFIndex i = 0; i < n; i++ ){
			item = (SecCertificateRef)CFArrayGetValueAtIndex( result, i );

			// Get certificate in DER format
			dat = SecCertificateCopyData( item );
			if( dat ){
				if( chain == NULL ){
					chain = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt));
					mbedtls_x509_crt_init( chain );
				}
				mbedtls_x509_crt_parse_der( chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat) );
				CFRelease( dat );
			}
		}
	}
	CFRelease(keychain);
	if( chain != NULL ){
		v = alloc_abstract(k_cert, chain);
		val_gc(v,free_cert);
		return v;
	}else{
		return val_null;
	}
#else
	return val_null;
#endif
}
/* Test low level keychain migration from device to device interface. */
static void tests(void)
{
    int v_eighty = 80;
    CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty);
    const char *v_data = "test";
    CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
    CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
    CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
    CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net"));
    CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith"));
    CFDictionaryAddValue(query, kSecAttrPort, eighty);
    CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP);
    CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault);
    CFDictionaryAddValue(query, kSecValueData, pwdata);
    // NUKE anything we might have left around from a previous test run so we don't crash.
    SecItemDelete(query);
    ok_status(SecItemAdd(query, NULL), "add internet password");
    is_status(SecItemAdd(query, NULL), errSecDuplicateItem,
	"add internet password again");

    ok_status(SecItemCopyMatching(query, NULL), "Found the item we added");

    struct test_persistent_s p = {};
    test_persistent(&p);

    CFDataRef backup = NULL, keybag = NULL, password = NULL;

    test_add_lockdown_identity_items();

#if USE_KEYSTORE
    keybag = create_keybag(kAppleKeyStoreBackupBag, password);
#else
    keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0);
#endif

    ok(backup = _SecKeychainCopyBackup(keybag, password),
        "_SecKeychainCopyBackup");

    test_add_managedconfiguration_item();
    test_remove_lockdown_identity_items();

    ok_status(_SecKeychainRestoreBackup(backup, keybag, password),
        "_SecKeychainRestoreBackup");
    CFReleaseSafe(backup);

    test_no_find_lockdown_identity_item();
    test_find_managedconfiguration_item();

    ok_status(SecItemCopyMatching(query, NULL),
        "Found the item we added after restore");

    test_persistent2(&p);

#if USE_KEYSTORE
    CFReleaseNull(keybag);
    keybag = create_keybag(kAppleKeyStoreOTABackupBag, password);
#endif

    ok(backup = _SecKeychainCopyBackup(keybag, password),
       "_SecKeychainCopyBackup");
    ok_status(_SecKeychainRestoreBackup(backup, keybag, password),
              "_SecKeychainRestoreBackup");
    ok_status(SecItemCopyMatching(query, NULL),
              "Found the item we added after restore");
    CFReleaseNull(backup);

    // force tombstone to be added, since it's not the default behavior per rdar://14680869
    CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanTrue);

    ok_status(SecItemDelete(query), "Deleted item we added");

#if USE_KEYSTORE
    CFReleaseNull(keybag);
    keybag = create_keybag(kAppleKeyStoreOTABackupBag /* use truthiness bag once it's there */, password);
#endif

    // add syncable item
    CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue);
    ok_status(SecItemAdd(query, NULL), "add internet password");

    // and non-syncable item
    test_add_managedconfiguration_item();

    CFDictionaryRef syncableBackup = NULL;

    CFErrorRef error = NULL;
    CFDictionaryRef scratch = NULL;
    SKIP: {
        skip("skipping syncable backup tests", 7,
             ok_status(_SecKeychainBackupSyncable(keybag, password, NULL, &syncableBackup), "export items"));

        // TODO: add item, call SecServerCopyTruthInTheCloud again

        // CFShow(syncableBackup);

        // find and delete
        skip("skipping syncable backup tests", 6,
             ok_status(SecItemCopyMatching(query, NULL), "find item we are about to destroy"));

        skip("skipping syncable backup tests", 5,
             ok_status(SecItemDelete(query), "delete item we backed up"));

        // ensure we added a tombstone
        CFDictionaryAddValue(query, kSecAttrTombstone, kCFBooleanTrue);
        skip("skipping syncable backup tests", 4,
             ok_status(SecItemCopyMatching(query, NULL), "find tombstone for item we deleted"));
        CFDictionaryRemoveValue(query, kSecAttrTombstone);

        test_find_managedconfiguration_item(); // <- 2 tests here

        // TODO: add a different new item - delete what's not in the syncableBackup?

        // Do another backup after some changes
        skip("skipping syncable backup tests", 1,
             ok_status(_SecKeychainBackupSyncable(keybag, password, syncableBackup, &scratch), "export items after changes"));

        skip("skipping syncable backup tests", 0,
             ok_status(_SecKeychainRestoreSyncable(keybag, password, syncableBackup), "import items"));
    }
    CFReleaseNull(scratch);
    CFReleaseNull(error);

    // non-syncable item should (still) be gone -> add should work
    test_add_managedconfiguration_item();
    test_find_managedconfiguration_item();

    // syncable item should have not been restored, because the tombstone was newer than the item in the backup -> copy matching should fail
    is_status(errSecItemNotFound, SecItemCopyMatching(query, NULL),
              "find restored item");
    is_status(errSecItemNotFound, SecItemDelete(query), "delete restored item");

    CFReleaseSafe(syncableBackup);
    CFReleaseSafe(keybag);
    CFReleaseSafe(eighty);
    CFReleaseSafe(pwdata);
    CFReleaseSafe(query);
}
static void test_persistent(struct test_persistent_s *p)
{
    int v_eighty = 80;
    CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty);
    const char *v_data = "test";
    CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data));
    const void *keys[] = {
		kSecClass,
		kSecAttrServer,
		kSecAttrAccount,
		kSecAttrPort,
		kSecAttrProtocol,
		kSecAttrAuthenticationType,
		kSecReturnPersistentRef,
		kSecValueData
    };
    const void *values[] = {
		kSecClassInternetPassword,
		CFSTR("zuigt.nl"),
		CFSTR("frtnbf"),
		eighty,
		CFSTR("http"),
		CFSTR("dflt"),
		kCFBooleanTrue,
		pwdata
    };
    CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values,
        array_size(keys), &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);

    p->persist[0] = NULL;
    // NUKE anything we might have left around from a previous test run so we don't crash.
    SecItemDelete(item);
    ok_status(SecItemAdd(item, &p->persist[0]), "add internet password");
    CFTypeRef results = NULL;
    CFTypeRef results2 = NULL;
    SKIP: {
        skip("no persistent ref", 6, ok(p->persist[0], "got back persistent ref"));

        /* Create a dict with all attrs except the data. */
        keys[(array_size(keys)) - 2] = kSecReturnAttributes;
        p->query = CFDictionaryCreate(NULL, keys, values,
                                      (array_size(keys)) - 1, &kCFTypeDictionaryKeyCallBacks,
                                      &kCFTypeDictionaryValueCallBacks);
        ok_status(SecItemCopyMatching(p->query, &results), "find internet password by attr");

        const void *keys_persist[] = {
            kSecReturnAttributes,
            kSecValuePersistentRef
        };
        const void *values_persist[] = {
            kCFBooleanTrue,
            p->persist[0]
        };
        p->query2 = CFDictionaryCreate(NULL, keys_persist, values_persist,
                                       (array_size(keys_persist)), &kCFTypeDictionaryKeyCallBacks,
                                       &kCFTypeDictionaryValueCallBacks);
        ok_status(SecItemCopyMatching(p->query2, &results2), "find internet password by persistent ref");
        ok(CFEqual(results, results2 ? results2 : CFSTR("")), "same item (attributes)");

        CFReleaseNull(results);
        CFReleaseNull(results2);

        ok_status(SecItemDelete(p->query), "delete internet password");

        ok_status(!SecItemCopyMatching(p->query, &results),
                  "don't find internet password by attributes");
        ok(!results, "no results");
    }

    /* clean up left over from aborted run */
    if (results) {
        CFDictionaryRef cleanup = CFDictionaryCreate(NULL, &kSecValuePersistentRef,
            &results, 1, &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);
        SecItemDelete(cleanup);
        CFRelease(results);
        CFRelease(cleanup);
    }

    ok_status(!SecItemCopyMatching(p->query2, &results2),
        "don't find internet password by persistent ref anymore");
    ok(!results2, "no results");

    CFReleaseNull(p->persist[0]);

    /* Add a new item and get it's persitant ref. */
    ok_status(SecItemAdd(item, &p->persist[0]), "add internet password");
    p->persist[1] = NULL;
    CFMutableDictionaryRef item2 = CFDictionaryCreateMutableCopy(NULL, 0, item);
    CFDictionarySetValue(item2, kSecAttrAccount, CFSTR("johndoe-bu"));
    // NUKE anything we might have left around from a previous test run so we don't crash.
    SecItemDelete(item2);
    ok_status(SecItemAdd(item2, &p->persist[1]), "add second internet password");
    CFMutableDictionaryRef update = NULL;
    CFStringRef server = NULL;
SKIP: {
    skip("no persistent ref", 3, ok(p->persist[0], "got back persistent ref from first internet password"));

    is(CFGetTypeID(p->persist[0]), CFDataGetTypeID(), "result is a CFData");
    p->query3 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);
    CFDictionaryAddValue(p->query3, kSecValuePersistentRef, p->persist[0]);
    update = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
    CFDictionaryAddValue(update, kSecAttrServer, CFSTR("zuigt.com"));
    ok_status(SecItemUpdate(p->query3, update), "update via persitant ref");

    /* Verify that the update really worked. */
    CFDictionaryAddValue(p->query3, kSecReturnAttributes, kCFBooleanTrue);
    ok_status(SecItemCopyMatching(p->query3, &results2), "find updated internet password by persistent ref");
    server = CFDictionaryGetValue(results2, kSecAttrServer);
    ok(CFEqual(server, CFSTR("zuigt.com")), "verify attribute was modified by update");
    CFReleaseNull(results2);
    CFDictionaryRemoveValue(p->query3, kSecReturnAttributes);
}

SKIP: {
    skip("no persistent ref", 2, ok(p->persist[1], "got back persistent ref"));

    /* Verify that item2 wasn't affected by the update. */
    p->query4 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
                                          &kCFTypeDictionaryValueCallBacks);
    CFDictionaryAddValue(p->query4, kSecValuePersistentRef, p->persist[1]);
    CFDictionaryAddValue(p->query4, kSecReturnAttributes, kCFBooleanTrue);
    ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref");
    server = CFDictionaryGetValue(results2, kSecAttrServer);
    ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update");
    CFReleaseNull(results2);
}

    /* Delete the item via persitant ref. */
    ok_status(SecItemDelete(p->query3), "delete via persitant ref");
    is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound,
        "don't find deleted internet password by persistent ref");
    CFReleaseNull(results2);
    ok_status(SecItemCopyMatching(p->query4, &results2),
        "find non deleted internet password by persistent ref");
    CFReleaseNull(results2);

    CFReleaseNull(update);
    CFReleaseNull(item);
    CFReleaseNull(item2);
    CFReleaseNull(eighty);
    CFReleaseNull(pwdata);
}
/* 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);
}
static void test_find_managedconfiguration_item(void) {
    CFMutableDictionaryRef query = test_create_managedconfiguration_query();
    ok_status(SecItemCopyMatching(query, NULL), "test_find_managedconfiguration_item");
    ok_status(SecItemDelete(query), "test_find_managedconfiguration_item (deleted)");
    CFReleaseSafe(query);
}
static void testkeygen2(size_t keySizeInBits) {
	SecKeyRef pubKey = NULL, privKey = NULL;
	size_t keySizeInBytes = (keySizeInBits + 7) / 8;
	CFNumberRef kzib;
    int32_t keysz32 = (int32_t)keySizeInBits;

    CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault);
    CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID);
    CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);
    CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString);

    CFReleaseNull(ourUUID);
    CFReleaseNull(uuidString);

    CFStringAppend(publicName, CFSTR("-Public-41"));
    CFStringAppend(privateName, CFSTR("-Private-41"));

    CFMutableDictionaryRef pubd = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
                                                                          kSecAttrLabel, publicName,
                                                                          NULL);
    CFMutableDictionaryRef privd = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
                                                                           kSecAttrLabel, privateName,
                                                                           NULL);

	kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
    CFDictionaryRef kgp = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
                                                       kSecAttrKeyType, kSecAttrKeyTypeEC,
                                                       kSecAttrKeySizeInBits, kzib,
                                                       kSecAttrIsPermanent, kCFBooleanTrue,
                                                       kSecPublicKeyAttrs, pubd,
                                                       kSecPrivateKeyAttrs, privd,
                                                       NULL);

    CFReleaseNull(kzib);

	OSStatus status;
	ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey),
              "Generate %ld bit (%ld byte) persistent RSA keypair",
              keySizeInBits, keySizeInBytes);

    CFReleaseNull(kgp);

SKIP: {
    skip("keygen failed", 8, status == errSecSuccess);
    ok(pubKey, "pubkey returned");
    ok(privKey, "privKey returned");
    is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok");
    is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok");

    SecKeyRef pubKey2, privKey2;
    CFDictionaryAddValue(pubd, kSecClass, kSecClassKey);
    CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue);
    CFDictionaryAddValue(privd, kSecClass, kSecClassKey);
    CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue);
    CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue);
    ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2),
              "retrieve pub key by label");
    ok(pubKey2, "got valid object");
    ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2),
              "retrieve priv key by label and kSecAttrCanSign");
    ok(privKey2, "got valid object");

    /* Sign something. */
    uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
    size_t sigLen = SecKeyGetSize(privKey2, kSecKeySignatureSize);
    uint8_t sig[sigLen];
    ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1,
                            something, sizeof(something), sig, &sigLen), "sign something");
    ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1,
                              something, sizeof(something), sig, sigLen), "verify sig on something");

    /* Cleanup. */
    CFReleaseNull(pubKey2);
    CFReleaseNull(privKey2);
}

    /* delete from keychain - note: do it before releasing publicName and privateName
       because pubd and privd have no retain/release callbacks */
    ok_status(SecItemDelete(pubd), "delete generated pub key");
    ok_status(SecItemDelete(privd), "delete generated priv key");

	/* Cleanup. */
	CFReleaseNull(pubKey);
	CFReleaseNull(privKey);

    CFReleaseNull(publicName);
    CFReleaseNull(privateName);

	CFReleaseNull(pubd);
	CFReleaseNull(privd);
}
static int
keychain_query(hx509_context context,
	       hx509_certs certs,
	       void *data,
	       const hx509_query *query,
	       hx509_cert *retcert)
{
    CFArrayRef identities = NULL;
    hx509_cert cert = NULL;
    CFIndex n, count;
    int ret;
    int kdcLookupHack = 0;

    /*
     * First to course filtering using security framework ....
     */

#define FASTER_FLAGS (HX509_QUERY_MATCH_PERSISTENT|HX509_QUERY_PRIVATE_KEY)

    if ((query->match & FASTER_FLAGS) == 0)
	return HX509_UNIMPLEMENTED_OPERATION;

    CFMutableDictionaryRef secQuery = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,  &kCFTypeDictionaryValueCallBacks);

    /*
     * XXX this is so broken, SecItem doesn't find the kdc certificte,
     * and kdc certificates happend to be searched by friendly name,
     * so find that and mundge on the structure.
     */

    if ((query->match & HX509_QUERY_MATCH_FRIENDLY_NAME) &&
	(query->match & HX509_QUERY_PRIVATE_KEY) && 
	strcmp(query->friendlyname, "O=System Identity,CN=com.apple.kerberos.kdc") == 0)
    {
	((hx509_query *)query)->match &= ~HX509_QUERY_PRIVATE_KEY;
	kdcLookupHack = 1;
    }

    if (kdcLookupHack || (query->match & HX509_QUERY_MATCH_PERSISTENT)) {
	CFDictionaryAddValue(secQuery, kSecClass, kSecClassCertificate);
    } else
	CFDictionaryAddValue(secQuery, kSecClass, kSecClassIdentity);

    CFDictionaryAddValue(secQuery, kSecReturnRef, kCFBooleanTrue);
    CFDictionaryAddValue(secQuery, kSecMatchLimit, kSecMatchLimitAll);

    if (query->match & HX509_QUERY_MATCH_PERSISTENT) {
	CFDataRef refdata = CFDataCreateWithBytesNoCopy(NULL, query->persistent->data, query->persistent->length, kCFAllocatorNull);
	CFDictionaryAddValue(secQuery, kSecValuePersistentRef, refdata);
	CFRelease(refdata);
    }


    OSStatus status = SecItemCopyMatching(secQuery, (CFTypeRef *)&identities);
    CFRelease(secQuery);
    if (status || identities == NULL) {
	hx509_clear_error_string(context);
	return HX509_CERT_NOT_FOUND;
    }
    
    heim_assert(CFArrayGetTypeID() == CFGetTypeID(identities), "return value not an array");

    /*
     * ... now do hx509 filtering
     */

    count = CFArrayGetCount(identities);
    for (n = 0; n < count; n++) {
	CFTypeRef secitem = (CFTypeRef)CFArrayGetValueAtIndex(identities, n);

#ifndef __APPLE_TARGET_EMBEDDED__

	if (query->match & HX509_QUERY_MATCH_PERSISTENT) {
	    SecIdentityRef other = NULL;
	    OSStatus osret;

	    osret = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)secitem, &other);
	    if (osret == noErr) {
		ret = hx509_cert_init_SecFramework(context, (void *)other, &cert);
		CFRelease(other);
		if (ret)
		    continue;
	    } else {
		ret = hx509_cert_init_SecFramework(context, (void *)secitem, &cert);
		if (ret)
		    continue;
	    }
	} else
#endif
        {

	    ret = hx509_cert_init_SecFramework(context, (void *)secitem, &cert);
	    if (ret)
		continue;
	}

	if (_hx509_query_match_cert(context, query, cert)) {

#ifndef __APPLE_TARGET_EMBEDDED__
	    /* certtool/keychain doesn't glue togheter the cert with keys for system keys */
	    if (kdcLookupHack) {
		SecIdentityRef other = NULL;
		OSStatus osret;

		osret = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)secitem, &other);
		if (osret == noErr) {
		    hx509_cert_free(cert);
		    ret = hx509_cert_init_SecFramework(context, other, &cert);
		    CFRelease(other);
		    if (ret)
			continue;
		}
	    }	    
#endif
	    *retcert = cert;
	    break;
	}
	hx509_cert_free(cert);
    }

    if (kdcLookupHack)
	((hx509_query *)query)->match |= HX509_QUERY_PRIVATE_KEY;

    CFRelease(identities);

    if (*retcert == NULL) {
	hx509_clear_error_string(context);
	return HX509_CERT_NOT_FOUND;
    }

    return 0;
}
static int
keychain_iter_start(hx509_context context,
		    hx509_certs certs, void *data, void **cursor)
{
#ifndef __APPLE_TARGET_EMBEDDED__
    struct ks_keychain *ctx = data;
#endif
    struct iter *iter;

    iter = calloc(1, sizeof(*iter));
    if (iter == NULL) {
	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
	return ENOMEM;
    }

#ifndef __APPLE_TARGET_EMBEDDED__
    if (ctx->anchors) {
        CFArrayRef anchors;
	int ret;
	int i;

	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
			       0, NULL, &iter->certs);
	if (ret) {
	    free(iter);
	    return ret;
	}

	ret = SecTrustCopyAnchorCertificates(&anchors);
	if (ret != 0) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    hx509_set_error_string(context, 0, ENOMEM,
				   "Can't get trust anchors from Keychain");
	    return ENOMEM;
	}
	for (i = 0; i < CFArrayGetCount(anchors); i++) {
	    SecCertificateRef cr;
	    hx509_cert cert;
	    CFDataRef dataref;

	    cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);

	    dataref = SecCertificateCopyData(cr);
	    if (dataref == NULL)
		continue;

	    ret = hx509_cert_init_data(context, CFDataGetBytePtr(dataref), CFDataGetLength(dataref), &cert);
	    CFRelease(dataref);
	    if (ret)
		continue;

	    ret = hx509_certs_add(context, iter->certs, cert);
	    hx509_cert_free(cert);
	}
	CFRelease(anchors);
	if (ret != 0) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    hx509_set_error_string(context, 0, ret,
				   "Failed to add cert");
	    return ret;
	}
    }

    if (iter->certs) {
	int ret;
	ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
	if (ret) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    return ret;
	}
    } else
#endif
    {
	OSStatus ret;
	const void *keys[] = {
	    kSecClass,
	    kSecReturnRef,
	    kSecMatchLimit
	};
	const void *values[] = {
	    kSecClassCertificate,
	    kCFBooleanTrue,
	    kSecMatchLimitAll
	};

	CFDictionaryRef secQuery;

	secQuery = CFDictionaryCreate(NULL, keys, values,
				      sizeof(keys) / sizeof(*keys),
				      &kCFTypeDictionaryKeyCallBacks,
				      &kCFTypeDictionaryValueCallBacks);
	
	ret = SecItemCopyMatching(secQuery, (CFTypeRef *)&iter->search);
	CFRelease(secQuery);
	if (ret) {
	    free(iter);
	    return ENOMEM;
	}
    }

    *cursor = iter;
    return 0;
}
Ejemplo n.º 29
0
extern "C" int32_t AppleCryptoNative_X509CopyWithPrivateKey(SecCertificateRef cert,
                                                            SecKeyRef privateKey,
                                                            SecKeychainRef targetKeychain,
                                                            SecIdentityRef* pIdentityOut,
                                                            int32_t* pOSStatus)
{
    if (pIdentityOut != nullptr)
        *pIdentityOut = nullptr;
    if (pOSStatus != nullptr)
        *pOSStatus = noErr;

    if (cert == nullptr || privateKey == nullptr || targetKeychain == nullptr || pIdentityOut == nullptr ||
        pOSStatus == nullptr)
    {
        return -1;
    }

    SecKeychainRef keyKeychain = nullptr;

    OSStatus status = SecKeychainItemCopyKeychain(reinterpret_cast<SecKeychainItemRef>(privateKey), &keyKeychain);
    SecKeychainItemRef itemCopy = nullptr;

    // This only happens with an ephemeral key, so the keychain we're adding it to is temporary.
    if (status == errSecNoSuchKeychain)
    {
        status = AddKeyToKeychain(privateKey, targetKeychain);
    }

    if (itemCopy != nullptr)
    {
        CFRelease(itemCopy);
    }

    CFMutableDictionaryRef query = nullptr;

    if (status == noErr)
    {
        query = CFDictionaryCreateMutable(
            kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

        if (query == nullptr)
        {
            status = errSecAllocate;
        }
    }

    CFArrayRef searchList = nullptr;

    if (status == noErr)
    {
        searchList = CFArrayCreate(
            nullptr, const_cast<const void**>(reinterpret_cast<void**>(&targetKeychain)), 1, &kCFTypeArrayCallBacks);

        if (searchList == nullptr)
        {
            status = errSecAllocate;
        }
    }

    CFArrayRef itemMatch = nullptr;

    if (status == noErr)
    {
        itemMatch = CFArrayCreate(
            nullptr, const_cast<const void**>(reinterpret_cast<void**>(&cert)), 1, &kCFTypeArrayCallBacks);

        if (itemMatch == nullptr)
        {
            status = errSecAllocate;
        }
    }

    CFTypeRef result = nullptr;

    if (status == noErr)
    {
        CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
        CFDictionarySetValue(query, kSecMatchSearchList, searchList);
        CFDictionarySetValue(query, kSecMatchItemList, itemMatch);
        CFDictionarySetValue(query, kSecClass, kSecClassIdentity);

        status = SecItemCopyMatching(query, &result);

        if (status != noErr && result != nullptr)
        {
            CFRelease(result);
            result = nullptr;
        }

        bool added = false;

        if (status == errSecItemNotFound)
        {
            status = SecCertificateAddToKeychain(cert, targetKeychain);

            added = (status == noErr);
        }

        if (result == nullptr && status == noErr)
        {
            status = SecItemCopyMatching(query, &result);
        }

        if (result != nullptr && status == noErr)
        {

            if (CFGetTypeID(result) != SecIdentityGetTypeID())
            {
                status = errSecItemNotFound;
            }
            else
            {
                SecIdentityRef identity = reinterpret_cast<SecIdentityRef>(const_cast<void*>(result));
                CFRetain(identity);
                *pIdentityOut = identity;
            }
        }

        if (added)
        {
            // The same query that was used to find the identity can be used
            // to find/delete the certificate, as long as we fix the class to just the cert.
            CFDictionarySetValue(query, kSecClass, kSecClassCertificate);

            // Ignore the output status, there's no point in telling the user
            // that the cleanup failed, since that just makes them have a dirty keychain
            // AND their program didn't work.
            SecItemDelete(query);
        }
    }

    if (result != nullptr)
        CFRelease(result);

    if (itemMatch != nullptr)
        CFRelease(itemMatch);

    if (searchList != nullptr)
        CFRelease(searchList);

    if (query != nullptr)
        CFRelease(query);

    if (keyKeychain != nullptr)
        CFRelease(keyKeychain);

    *pOSStatus = status;
    return status == noErr;
}
/*
 * Convert a keychain name (which may be NULL) into the CFArrayRef required
 * by SSLSetCertificate. This is a bare-bones example of this operation,
 * since it requires and assumes that there is exactly one SecIdentity
 * in the keychain - i.e., there is exactly one matching cert/private key 
 * pair. A real world server would probably search a keychain for a SecIdentity 
 * matching some specific criteria. 
 */
CFArrayRef getSslCerts( 
	const char			*kcName,				// may be NULL, i.e., use default
	bool                encryptOnly,
	bool                completeCertChain,
	const char			*anchorFile,			// optional trusted anchor
	SecKeychainRef		*pKcRef)				// RETURNED
{
#if 0
	SecKeychainRef 		kcRef = nil;
	OSStatus			ortn;
	
	*pKcRef = nil;
	
	/* pick a keychain */
	if(kcName) {
		ortn = SecKeychainOpen(kcName, &kcRef);
		if(ortn) {
			printf("SecKeychainOpen returned %d.\n", (int)ortn);
			printf("Cannot open keychain at %s. Aborting.\n", kcName);
			return NULL;
		}
	}
	else {
		/* use default keychain */
		ortn = SecKeychainCopyDefault(&kcRef);
		if(ortn) {
			printf("SecKeychainCopyDefault returned %d; aborting.\n", (int)ortn);
			return nil;
		}
	}
	*pKcRef = kcRef;
	return sslKcRefToCertArray(kcRef, encryptOnly, completeCertChain, anchorFile);
#else
	SecCertificateRef cert = NULL;
	SecIdentityRef identity = NULL;
	CFMutableArrayRef certificates = NULL, result = NULL;
	CFMutableDictionaryRef certQuery = NULL, keyQuery = NULL, keyResult = NULL;
	SecTrustRef trust = NULL;
	SecKeyRef key = NULL;
	CFTypeRef pkdigest = NULL;

	// Find the first private key in the keychain and return both it's
	// attributes and a ref to it.
	require(keyQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
	CFDictionaryAddValue(keyQuery, kSecClass, kSecClassKey);
	CFDictionaryAddValue(keyQuery, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
	CFDictionaryAddValue(keyQuery, kSecReturnRef, kCFBooleanTrue);
	CFDictionaryAddValue(keyQuery, kSecReturnAttributes, kCFBooleanTrue);
	require_noerr(SecItemCopyMatching(keyQuery, (CFTypeRef *)&keyResult),
		errOut);
	require(key = (SecKeyRef)CFDictionaryGetValue(keyResult, kSecValueRef),
		errOut);
	require(pkdigest = CFDictionaryGetValue(keyResult, kSecAttrApplicationLabel),
		errOut);

	// Find the first certificate that has the same public key hash as the
	// returned private key and return it as a ref.
	require(certQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
	CFDictionaryAddValue(certQuery, kSecClass, kSecClassCertificate);
	CFDictionaryAddValue(certQuery, kSecAttrPublicKeyHash, pkdigest);
	CFDictionaryAddValue(certQuery, kSecReturnRef, kCFBooleanTrue);
	require_noerr(SecItemCopyMatching(certQuery, (CFTypeRef *)&cert), errOut);

	// Create an identity from the key and certificate.
	require(identity = SecIdentityCreate(NULL, cert, key), errOut);

	// Build a (partial) certificate chain from cert
	require(certificates = CFArrayCreateMutable(NULL, 0,
		&kCFTypeArrayCallBacks), errOut);
	CFArrayAppendValue(certificates, cert);
	require_noerr(SecTrustCreateWithCertificates(certificates, NULL, &trust),
		errOut);
	SecTrustResultType tresult;
	require_noerr(SecTrustEvaluate(trust, &tresult), errOut);

	CFIndex certCount, ix;
	// We need at least 1 certificate
	require(certCount = SecTrustGetCertificateCount(trust), errOut);

	// Build a result where element 0 is the identity and the other elements
	// are the certs in the chain starting at the first intermediate up to the
	// anchor, if we found one, or as far as we were able to build the chain
	// if not.
	require(result = CFArrayCreateMutable(NULL, certCount, &kCFTypeArrayCallBacks),
		errOut);

	// We are commited to returning a result now, so do not use require below
	// this line without setting result to NULL again.
	CFArrayAppendValue(result, identity);
	for (ix = 1; ix < certCount; ++ix) {
		CFArrayAppendValue(result, SecTrustGetCertificateAtIndex(trust, ix));
	}

errOut:
	CFReleaseSafe(trust);
	CFReleaseSafe(certificates);
	CFReleaseSafe(identity);
	CFReleaseSafe(cert);
	CFReleaseSafe(certQuery);
	CFReleaseSafe(keyResult);
	CFReleaseSafe(keyQuery);

    return result;
#endif
}