/* * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "EAPKeychainUtil.h" OSStatus EAPSecKeychainPasswordItemRemove(SecKeychainRef keychain, CFStringRef unique_id_str) { SecKeychainItemRef item; OSStatus status; CFDataRef unique_id; unique_id = CFStringCreateExternalRepresentation(NULL, unique_id_str, kCFStringEncodingUTF8, 0); status = SecKeychainFindGenericPassword(keychain, CFDataGetLength(unique_id), (const char *)CFDataGetBytePtr(unique_id), 0, NULL, NULL, NULL, &item); CFRelease(unique_id); if (status != noErr) { fprintf(stderr, "SecKeychainFindGenericPassword failed: %s (%ld)\n", EAPSecurityErrorString(status), status); goto done; } status = SecKeychainItemDelete(item); CFRelease(item); if (status != noErr) { fprintf(stderr, "SecKeychainItemDelete() failed: %s (%ld)\n", EAPSecurityErrorString(status), status); } done: return (status); } OSStatus EAPSecKeychainPasswordItemCopy(SecKeychainRef keychain, CFStringRef unique_id_str, CFDataRef * ret_password) { void * password; UInt32 password_length; OSStatus status; CFDataRef unique_id; unique_id = CFStringCreateExternalRepresentation(NULL, unique_id_str, kCFStringEncodingUTF8, 0); status = SecKeychainFindGenericPassword(keychain, CFDataGetLength(unique_id), (const char *)CFDataGetBytePtr(unique_id), 0, NULL, &password_length, &password, NULL); CFRelease(unique_id); if (status == noErr) { *ret_password = CFDataCreate(NULL, password, password_length); SecKeychainItemFreeContent(NULL, password); } return (status); } OSStatus EAPSecKeychainPasswordItemCreateWithAccess(SecKeychainRef keychain, SecAccessRef access, CFStringRef unique_id_str, CFDataRef label, CFDataRef description, CFDataRef user, CFDataRef password) { SecKeychainAttribute attributes[4]; SecKeychainAttributeList attributeList = { 0, attributes }; int i; OSStatus status; CFDataRef unique_id; unique_id = CFStringCreateExternalRepresentation(NULL, unique_id_str, kCFStringEncodingUTF8, 0); attributes[0].tag = kSecServiceItemAttr; attributes[0].length = CFDataGetLength(unique_id); attributes[0].data = (void *)CFDataGetBytePtr(unique_id); i = 1; if (label != NULL) { attributes[i].tag = kSecLabelItemAttr; attributes[i].length = CFDataGetLength(label); attributes[i].data = (void *)CFDataGetBytePtr(label); i++; } if (description != NULL) { attributes[i].tag = kSecDescriptionItemAttr; attributes[i].length = CFDataGetLength(description); attributes[i].data = (void *)CFDataGetBytePtr(description); i++; } if (user != NULL) { attributes[i].tag = kSecAccountItemAttr; attributes[i].length = CFDataGetLength(user); attributes[i].data = (void *)CFDataGetBytePtr(user); i++; } attributeList.count = i; status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributeList, CFDataGetLength(password), CFDataGetBytePtr(password), keychain, access, NULL); CFRelease(unique_id); return (status); } static CFStringRef EAPCFUUIDStringCreate(CFAllocatorRef alloc) { CFUUIDRef uuid; CFStringRef uuid_str; uuid = CFUUIDCreate(alloc); uuid_str = CFUUIDCreateString(alloc, uuid); CFRelease(uuid); return (uuid_str); } OSStatus EAPSecKeychainPasswordItemCreateUniqueWithAccess(SecKeychainRef keychain, SecAccessRef access, CFDataRef label, CFDataRef description, CFDataRef user, CFDataRef password, CFStringRef * ret_unique_id) { OSStatus status; CFStringRef unique_id_str; if (ret_unique_id != NULL) { *ret_unique_id = NULL; } unique_id_str = EAPCFUUIDStringCreate(NULL); status = EAPSecKeychainPasswordItemCreateWithAccess(keychain, access, unique_id_str, label, description, user, password); if (status == noErr && ret_unique_id != NULL) { *ret_unique_id = unique_id_str; } else { CFRelease(unique_id_str); } return (status); } OSStatus EAPSecKeychainPasswordItemSet(SecKeychainRef keychain, CFStringRef unique_id_str, CFDataRef password) { void * existing_password; UInt32 existing_password_length; SecKeychainItemRef item; OSStatus status; CFDataRef unique_id; unique_id = CFStringCreateExternalRepresentation(NULL, unique_id_str, kCFStringEncodingUTF8, 0); status = SecKeychainFindGenericPassword(keychain, CFDataGetLength(unique_id), (const char *)CFDataGetBytePtr(unique_id), 0, NULL, &existing_password_length, &existing_password, &item); CFRelease(unique_id); if (status != noErr) { return (status); } if (CFDataGetLength(password) == existing_password_length && bcmp(CFDataGetBytePtr(password), existing_password, existing_password_length) == 0) { goto done; } status = SecKeychainItemModifyAttributesAndData(item, NULL, CFDataGetLength(password), CFDataGetBytePtr(password)); done: SecKeychainItemFreeContent(NULL, existing_password); CFRelease(item); return (status); } #ifdef TEST_EAPKEYCHAINUTIL /* * Create a SecAccessRef with a custom form. * Both the owner and the ACL set allow free access to root, * but nothing to anyone else. * NOTE: This is not the easiest way to build up CSSM data structures. * But it's a way that does not depend on any outside software layers * (other than CSSM and Security's Sec* layer, of course). */ static OSStatus EAPSecAccessCreateWithUid(uid_t uid, SecAccessRef * ret_access) { /* make the "uid/gid" ACL subject, this is a CSSM_LIST_ELEMENT chain */ CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = { CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, CSSM_ACL_MATCH_UID, /* active fields mask: match uids (only) */ uid, /* effective user id to match */ 0 /* effective group id to match */ }; CSSM_LIST_ELEMENT subject2 = { NULL, /* NextElement */ 0, /* WordID */ CSSM_LIST_ELEMENT_DATUM /* ElementType */ }; CSSM_LIST_ELEMENT subject1 = { &subject2, /* NextElement */ CSSM_ACL_SUBJECT_TYPE_PROCESS, /* WordID */ CSSM_LIST_ELEMENT_WORDID /* ElementType */ }; /* rights granted (replace with individual list if desired) */ CSSM_ACL_AUTHORIZATION_TAG rights[] = { CSSM_ACL_AUTHORIZATION_ANY }; /* owner component (right to change ACL) */ CSSM_ACL_OWNER_PROTOTYPE owner = { { // TypedSubject CSSM_LIST_TYPE_UNKNOWN, /* type of this list */ &subject1, /* head of the list */ &subject2 /* tail of the list */ }, FALSE /* Delegate */ }; /* ACL entry */ CSSM_ACL_ENTRY_INFO acls[] = { { { /* EntryPublicInfo */ { /* TypedSubject */ CSSM_LIST_TYPE_UNKNOWN, /* type of this list */ &subject1, /* head of the list */ &subject2 /* tail of the list */ }, FALSE, /* Delegate */ { /* Authorization */ sizeof(rights) / sizeof(rights[0]), /* NumberOfAuthTags */ rights /* AuthTags */ }, { /* TimeRange */ }, { /* EntryTag */ } }, 0 /* EntryHandle */ } }; subject2.Element.Word.Data = (UInt8 *)&selector; subject2.Element.Word.Length = sizeof(selector); return (SecAccessCreateFromOwnerAndACL(&owner, sizeof(acls) / sizeof(acls[0]), acls, ret_access)); } static OSStatus SecKeychainCopySystemKeychain(SecKeychainRef * ret_keychain) { SecKeychainRef keychain = NULL; OSStatus status; status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); if (status != noErr) { goto done; } status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain); done: if (status != noErr && keychain != NULL) { CFRelease(keychain); keychain = NULL; } *ret_keychain = keychain; return (status); } static void usage(const char * progname) { fprintf(stderr, "%s [system] create