| // 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" |
| |
| extern "C" { |
| OSStatus SecTrustedApplicationCopyRequirement( |
| SecTrustedApplicationRef application, |
| SecRequirementRef* requirement); |
| } // extern "C" |
| |
| namespace chrome { |
| |
| 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<CrSACLSimpleContents> 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; |
| // kSecInternetPasswordItemClass is marked as deprecated in the 10.9 sdk, |
| // but the files in libsecurity_keychain from 10.7 referenced above still |
| // use it. Also see rdar://14281375 / |
| // http://openradar.appspot.com/radar?id=3143412 . |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| case kSecAppleSharePasswordItemClass: |
| #pragma clang diagnostic pop |
| 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 chrome |