// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/mac/security_wrappers.h" #include "base/mac/foundation_util.h" #include "base/mac/mac_logging.h" #if !defined(MAC_OS_X_VERSION_10_5) || \ MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 enum { // New Security.framework code uses errSecSuccess instead of noErr, but the // constant is new in 10.6. errSecSuccess = 0 }; // This exists on 10.5 for linking, but but because // did not ship in the SDK in that version, no // declaration is present. This declaration is correct on 10.5, see // 10.5.0 libsecurity_codesigning-32568/lib/SecRequirement.h. extern "C" { OSStatus SecRequirementCopyString(SecRequirementRef requirement, SecCSFlags flags, CFStringRef* text); } // extern "C" #endif extern "C" { OSStatus SecTrustedApplicationCopyRequirement( SecTrustedApplicationRef application, SecRequirementRef* requirement); } // extern "C" namespace chrome { namespace browser { namespace mac { ScopedSecKeychainSetUserInteractionAllowed:: ScopedSecKeychainSetUserInteractionAllowed(Boolean allowed) { OSStatus status = SecKeychainGetUserInteractionAllowed(&old_allowed_); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); old_allowed_ = TRUE; } status = SecKeychainSetUserInteractionAllowed(allowed); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); } } ScopedSecKeychainSetUserInteractionAllowed:: ~ScopedSecKeychainSetUserInteractionAllowed() { OSStatus status = SecKeychainSetUserInteractionAllowed(old_allowed_); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); } } CrSKeychainItemAndAccess::CrSKeychainItemAndAccess(SecKeychainItemRef item, SecAccessRef access) : item_(item), access_(access) { // These CFRetain calls aren't leaks. They're balanced by an implicit // CFRelease at destruction because the fields are of type ScopedCFTypeRef. // These fields are retained on construction (unlike the typical // ScopedCFTypeRef pattern) because this class is intended for use as an STL // type adapter to keep two related objects together, and thus must // implement proper reference counting in the methods required for STL // container use. This class and is not intended to act as a scoper for the // underlying objects in user code. For that, just use ScopedCFTypeRef. CFRetain(item_); CFRetain(access_); } CrSKeychainItemAndAccess::CrSKeychainItemAndAccess( const CrSKeychainItemAndAccess& that) : item_(that.item_.get()), access_(that.access_.get()) { // See the comment above in the two-argument constructor. CFRetain(item_); CFRetain(access_); } CrSKeychainItemAndAccess::~CrSKeychainItemAndAccess() { } void CrSKeychainItemAndAccess::operator=(const CrSKeychainItemAndAccess& that) { // See the comment above in the two-argument constructor. CFRetain(that.item_); item_.reset(that.item_); CFRetain(that.access_); access_.reset(that.access_); } CrSACLSimpleContents::CrSACLSimpleContents() { } CrSACLSimpleContents::~CrSACLSimpleContents() { } ScopedSecKeychainAttributeInfo::ScopedSecKeychainAttributeInfo( SecKeychainAttributeInfo* attribute_info) : attribute_info_(attribute_info) { } ScopedSecKeychainAttributeInfo::~ScopedSecKeychainAttributeInfo() { OSStatus status = SecKeychainFreeAttributeInfo(attribute_info_); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); } } ScopedCrSKeychainItemAttributesAndData::ScopedCrSKeychainItemAttributesAndData( CrSKeychainItemAttributesAndData* attributes_and_data) : attributes_and_data_(attributes_and_data) { } ScopedCrSKeychainItemAttributesAndData:: ~ScopedCrSKeychainItemAttributesAndData() { if (attributes_and_data_.get()) { CrSKeychainItemFreeAttributesAndData( attributes_and_data_->attribute_list, attributes_and_data_->data); } } SecKeychainSearchRef CrSKeychainSearchCreateFromAttributes( CFTypeRef keychain_or_array, SecItemClass item_class, const SecKeychainAttributeList* attribute_list) { SecKeychainSearchRef search; OSStatus status = SecKeychainSearchCreateFromAttributes(keychain_or_array, item_class, attribute_list, &search); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return search; } SecKeychainItemRef CrSKeychainSearchCopyNext(SecKeychainSearchRef search) { if (!search) { return NULL; } SecKeychainItemRef item; OSStatus status = SecKeychainSearchCopyNext(search, &item); if (status != errSecSuccess) { if (status != errSecItemNotFound) { OSSTATUS_LOG(ERROR, status); } return NULL; } return item; } void CrSKeychainItemFreeAttributesAndData( SecKeychainAttributeList* attribute_list, void* data) { OSStatus status = SecKeychainItemFreeAttributesAndData(attribute_list, data); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); } } bool CrSKeychainItemTestAccess(SecKeychainItemRef item) { UInt32 length; void* data; OSStatus status = SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL, &length, &data); if (status != errSecSuccess) { if (status != errSecAuthFailed) { OSSTATUS_LOG(ERROR, status); } return false; } CrSKeychainItemFreeAttributesAndData(NULL, data); return true; } SecAccessRef CrSKeychainItemCopyAccess(SecKeychainItemRef item) { SecAccessRef access; OSStatus status = SecKeychainItemCopyAccess(item, &access); if (status != errSecSuccess) { if (status != errSecNoAccessForItem && status != errSecAuthFailed) { OSSTATUS_LOG(ERROR, status); } return NULL; } return access; } CFArrayRef CrSAccessCopyACLList(SecAccessRef access) { if (!access) { return NULL; } CFArrayRef acl_list; OSStatus status = SecAccessCopyACLList(access, &acl_list); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return acl_list; } CrSACLSimpleContents* CrSACLCopySimpleContents(SecACLRef acl) { if (!acl) { return NULL; } scoped_ptr acl_simple_contents( new CrSACLSimpleContents()); CFArrayRef application_list; CFStringRef description; OSStatus status = SecACLCopySimpleContents(acl, &application_list, &description, &acl_simple_contents->prompt_selector); if (status != errSecSuccess) { if (status != errSecACLNotSimple) { OSSTATUS_LOG(ERROR, status); } return NULL; } acl_simple_contents->application_list.reset(application_list); acl_simple_contents->description.reset(description); return acl_simple_contents.release(); } SecRequirementRef CrSTrustedApplicationCopyRequirement( SecTrustedApplicationRef application) { if (!application) { return NULL; } SecRequirementRef requirement; OSStatus status = SecTrustedApplicationCopyRequirement(application, &requirement); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return requirement; } CFStringRef CrSRequirementCopyString(SecRequirementRef requirement, SecCSFlags flags) { if (!requirement) { return NULL; } CFStringRef requirement_string; OSStatus status = SecRequirementCopyString(requirement, flags, &requirement_string); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return requirement_string; } SecTrustedApplicationRef CrSTrustedApplicationCreateFromPath(const char* path) { SecTrustedApplicationRef application; OSStatus status = SecTrustedApplicationCreateFromPath(path, &application); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return application; } bool CrSACLSetSimpleContents(SecACLRef acl, const CrSACLSimpleContents& acl_simple_contents) { OSStatus status = SecACLSetSimpleContents(acl, acl_simple_contents.application_list, acl_simple_contents.description, &acl_simple_contents.prompt_selector); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return false; } return true; } SecKeychainRef CrSKeychainItemCopyKeychain(SecKeychainItemRef item) { SecKeychainRef keychain; OSStatus status = SecKeychainItemCopyKeychain(item, &keychain); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return keychain; } SecKeychainAttributeInfo* CrSKeychainAttributeInfoForItemID( SecKeychainRef keychain, UInt32 item_id) { SecKeychainAttributeInfo* attribute_info; OSStatus status = SecKeychainAttributeInfoForItemID(keychain, item_id, &attribute_info); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return attribute_info; } CrSKeychainItemAttributesAndData* CrSKeychainItemCopyAttributesAndData( SecKeychainRef keychain, SecKeychainItemRef item) { ScopedCrSKeychainItemAttributesAndData attributes_and_data( new CrSKeychainItemAttributesAndData()); OSStatus status = SecKeychainItemCopyAttributesAndData(item, NULL, attributes_and_data.item_class_ptr(), NULL, NULL, NULL); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } // This looks really weird, but it's right. See 10.7.3 // libsecurity_keychain-55044 lib/SecItem.cpp // _CreateAttributesDictionaryFromKeyItem and 10.7.3 SecurityTool-55002 // keychain_utilities.c print_keychain_item_attributes. UInt32 item_id; switch (attributes_and_data.item_class()) { case kSecInternetPasswordItemClass: item_id = CSSM_DL_DB_RECORD_INTERNET_PASSWORD; break; case kSecGenericPasswordItemClass: item_id = CSSM_DL_DB_RECORD_GENERIC_PASSWORD; break; case kSecAppleSharePasswordItemClass: item_id = CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD; break; default: item_id = attributes_and_data.item_class(); break; } ScopedSecKeychainAttributeInfo attribute_info( CrSKeychainAttributeInfoForItemID(keychain, item_id)); if (!attribute_info) { return NULL; } status = SecKeychainItemCopyAttributesAndData( item, attribute_info, attributes_and_data.item_class_ptr(), attributes_and_data.attribute_list_ptr(), attributes_and_data.length_ptr(), attributes_and_data.data_ptr()); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return attributes_and_data.release(); } bool CrSKeychainItemDelete(SecKeychainItemRef item) { OSStatus status = SecKeychainItemDelete(item); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return false; } return true; } SecKeychainItemRef CrSKeychainItemCreateFromContent( const CrSKeychainItemAttributesAndData& attributes_and_data, SecKeychainRef keychain, SecAccessRef access) { SecKeychainItemRef item; OSStatus status = SecKeychainItemCreateFromContent(attributes_and_data.item_class, attributes_and_data.attribute_list, attributes_and_data.length, attributes_and_data.data, keychain, access, &item); if (status != errSecSuccess) { OSSTATUS_LOG(ERROR, status); return NULL; } return item; } } // namespace mac } // namespace browser } // namespace chrome