Home | History | Annotate | Download | only in mac
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/mac/security_wrappers.h"
      6 
      7 #include "base/mac/foundation_util.h"
      8 #include "base/mac/mac_logging.h"
      9 
     10 extern "C" {
     11 OSStatus SecTrustedApplicationCopyRequirement(
     12     SecTrustedApplicationRef application,
     13     SecRequirementRef* requirement);
     14 }  // extern "C"
     15 
     16 namespace chrome {
     17 
     18 ScopedSecKeychainSetUserInteractionAllowed::
     19     ScopedSecKeychainSetUserInteractionAllowed(Boolean allowed) {
     20   OSStatus status = SecKeychainGetUserInteractionAllowed(&old_allowed_);
     21   if (status != errSecSuccess) {
     22     OSSTATUS_LOG(ERROR, status);
     23     old_allowed_ = TRUE;
     24   }
     25 
     26   status = SecKeychainSetUserInteractionAllowed(allowed);
     27   if (status != errSecSuccess) {
     28     OSSTATUS_LOG(ERROR, status);
     29   }
     30 }
     31 
     32 ScopedSecKeychainSetUserInteractionAllowed::
     33     ~ScopedSecKeychainSetUserInteractionAllowed() {
     34   OSStatus status = SecKeychainSetUserInteractionAllowed(old_allowed_);
     35   if (status != errSecSuccess) {
     36     OSSTATUS_LOG(ERROR, status);
     37   }
     38 }
     39 
     40 CrSKeychainItemAndAccess::CrSKeychainItemAndAccess(SecKeychainItemRef item,
     41                                                    SecAccessRef access)
     42     : item_(item),
     43       access_(access) {
     44   // These CFRetain calls aren't leaks. They're balanced by an implicit
     45   // CFRelease at destruction because the fields are of type ScopedCFTypeRef.
     46   // These fields are retained on construction (unlike the typical
     47   // ScopedCFTypeRef pattern) because this class is intended for use as an STL
     48   // type adapter to keep two related objects together, and thus must
     49   // implement proper reference counting in the methods required for STL
     50   // container use. This class and is not intended to act as a scoper for the
     51   // underlying objects in user code. For that, just use ScopedCFTypeRef.
     52   CFRetain(item_);
     53   CFRetain(access_);
     54 }
     55 
     56 CrSKeychainItemAndAccess::CrSKeychainItemAndAccess(
     57     const CrSKeychainItemAndAccess& that)
     58     : item_(that.item_.get()),
     59       access_(that.access_.get()) {
     60   // See the comment above in the two-argument constructor.
     61   CFRetain(item_);
     62   CFRetain(access_);
     63 }
     64 
     65 CrSKeychainItemAndAccess::~CrSKeychainItemAndAccess() {
     66 }
     67 
     68 void CrSKeychainItemAndAccess::operator=(const CrSKeychainItemAndAccess& that) {
     69   // See the comment above in the two-argument constructor.
     70   CFRetain(that.item_);
     71   item_.reset(that.item_);
     72 
     73   CFRetain(that.access_);
     74   access_.reset(that.access_);
     75 }
     76 
     77 CrSACLSimpleContents::CrSACLSimpleContents() {
     78 }
     79 
     80 CrSACLSimpleContents::~CrSACLSimpleContents() {
     81 }
     82 
     83 ScopedSecKeychainAttributeInfo::ScopedSecKeychainAttributeInfo(
     84     SecKeychainAttributeInfo* attribute_info)
     85     : attribute_info_(attribute_info) {
     86 }
     87 
     88 ScopedSecKeychainAttributeInfo::~ScopedSecKeychainAttributeInfo() {
     89   OSStatus status = SecKeychainFreeAttributeInfo(attribute_info_);
     90   if (status != errSecSuccess) {
     91     OSSTATUS_LOG(ERROR, status);
     92   }
     93 }
     94 
     95 ScopedCrSKeychainItemAttributesAndData::ScopedCrSKeychainItemAttributesAndData(
     96     CrSKeychainItemAttributesAndData* attributes_and_data)
     97     : attributes_and_data_(attributes_and_data) {
     98 }
     99 
    100 ScopedCrSKeychainItemAttributesAndData::
    101     ~ScopedCrSKeychainItemAttributesAndData() {
    102   if (attributes_and_data_.get()) {
    103     CrSKeychainItemFreeAttributesAndData(
    104         attributes_and_data_->attribute_list, attributes_and_data_->data);
    105   }
    106 }
    107 
    108 SecKeychainSearchRef CrSKeychainSearchCreateFromAttributes(
    109     CFTypeRef keychain_or_array,
    110     SecItemClass item_class,
    111     const SecKeychainAttributeList* attribute_list) {
    112   SecKeychainSearchRef search;
    113   OSStatus status = SecKeychainSearchCreateFromAttributes(keychain_or_array,
    114                                                           item_class,
    115                                                           attribute_list,
    116                                                           &search);
    117   if (status != errSecSuccess) {
    118     OSSTATUS_LOG(ERROR, status);
    119     return NULL;
    120   }
    121 
    122   return search;
    123 }
    124 
    125 SecKeychainItemRef CrSKeychainSearchCopyNext(SecKeychainSearchRef search) {
    126   if (!search) {
    127     return NULL;
    128   }
    129 
    130   SecKeychainItemRef item;
    131   OSStatus status = SecKeychainSearchCopyNext(search, &item);
    132   if (status != errSecSuccess) {
    133     if (status != errSecItemNotFound) {
    134       OSSTATUS_LOG(ERROR, status);
    135     }
    136     return NULL;
    137   }
    138 
    139   return item;
    140 }
    141 
    142 void CrSKeychainItemFreeAttributesAndData(
    143     SecKeychainAttributeList* attribute_list,
    144     void* data) {
    145   OSStatus status = SecKeychainItemFreeAttributesAndData(attribute_list, data);
    146   if (status != errSecSuccess) {
    147     OSSTATUS_LOG(ERROR, status);
    148   }
    149 }
    150 
    151 bool CrSKeychainItemTestAccess(SecKeychainItemRef item) {
    152   UInt32 length;
    153   void* data;
    154   OSStatus status = SecKeychainItemCopyAttributesAndData(item,
    155                                                          NULL,
    156                                                          NULL,
    157                                                          NULL,
    158                                                          &length,
    159                                                          &data);
    160   if (status != errSecSuccess) {
    161     if (status != errSecAuthFailed) {
    162       OSSTATUS_LOG(ERROR, status);
    163     }
    164     return false;
    165   }
    166 
    167   CrSKeychainItemFreeAttributesAndData(NULL, data);
    168 
    169   return true;
    170 }
    171 
    172 SecAccessRef CrSKeychainItemCopyAccess(SecKeychainItemRef item) {
    173   SecAccessRef access;
    174   OSStatus status = SecKeychainItemCopyAccess(item, &access);
    175   if (status != errSecSuccess) {
    176     if (status != errSecNoAccessForItem && status != errSecAuthFailed) {
    177       OSSTATUS_LOG(ERROR, status);
    178     }
    179     return NULL;
    180   }
    181 
    182   return access;
    183 }
    184 
    185 CFArrayRef CrSAccessCopyACLList(SecAccessRef access) {
    186   if (!access) {
    187     return NULL;
    188   }
    189 
    190   CFArrayRef acl_list;
    191   OSStatus status = SecAccessCopyACLList(access, &acl_list);
    192   if (status != errSecSuccess) {
    193     OSSTATUS_LOG(ERROR, status);
    194     return NULL;
    195   }
    196 
    197   return acl_list;
    198 }
    199 
    200 CrSACLSimpleContents* CrSACLCopySimpleContents(SecACLRef acl) {
    201   if (!acl) {
    202     return NULL;
    203   }
    204 
    205   scoped_ptr<CrSACLSimpleContents> acl_simple_contents(
    206       new CrSACLSimpleContents());
    207   CFArrayRef application_list;
    208   CFStringRef description;
    209   OSStatus status =
    210       SecACLCopySimpleContents(acl,
    211                                &application_list,
    212                                &description,
    213                                &acl_simple_contents->prompt_selector);
    214   if (status != errSecSuccess) {
    215     if (status != errSecACLNotSimple) {
    216       OSSTATUS_LOG(ERROR, status);
    217     }
    218     return NULL;
    219   }
    220 
    221   acl_simple_contents->application_list.reset(application_list);
    222   acl_simple_contents->description.reset(description);
    223 
    224   return acl_simple_contents.release();
    225 }
    226 
    227 SecRequirementRef CrSTrustedApplicationCopyRequirement(
    228     SecTrustedApplicationRef application) {
    229   if (!application) {
    230     return NULL;
    231   }
    232 
    233   SecRequirementRef requirement;
    234   OSStatus status = SecTrustedApplicationCopyRequirement(application,
    235                                                          &requirement);
    236   if (status != errSecSuccess) {
    237     OSSTATUS_LOG(ERROR, status);
    238     return NULL;
    239   }
    240 
    241   return requirement;
    242 }
    243 
    244 CFStringRef CrSRequirementCopyString(SecRequirementRef requirement,
    245                                      SecCSFlags flags) {
    246   if (!requirement) {
    247     return NULL;
    248   }
    249 
    250   CFStringRef requirement_string;
    251   OSStatus status = SecRequirementCopyString(requirement,
    252                                              flags,
    253                                              &requirement_string);
    254   if (status != errSecSuccess) {
    255     OSSTATUS_LOG(ERROR, status);
    256     return NULL;
    257   }
    258 
    259   return requirement_string;
    260 }
    261 
    262 SecTrustedApplicationRef CrSTrustedApplicationCreateFromPath(const char* path) {
    263   SecTrustedApplicationRef application;
    264   OSStatus status = SecTrustedApplicationCreateFromPath(path, &application);
    265   if (status != errSecSuccess) {
    266     OSSTATUS_LOG(ERROR, status);
    267     return NULL;
    268   }
    269 
    270   return application;
    271 }
    272 
    273 bool CrSACLSetSimpleContents(SecACLRef acl,
    274                              const CrSACLSimpleContents& acl_simple_contents) {
    275   OSStatus status =
    276       SecACLSetSimpleContents(acl,
    277                               acl_simple_contents.application_list,
    278                               acl_simple_contents.description,
    279                               &acl_simple_contents.prompt_selector);
    280   if (status != errSecSuccess) {
    281     OSSTATUS_LOG(ERROR, status);
    282     return false;
    283   }
    284 
    285   return true;
    286 }
    287 
    288 SecKeychainRef CrSKeychainItemCopyKeychain(SecKeychainItemRef item) {
    289   SecKeychainRef keychain;
    290   OSStatus status = SecKeychainItemCopyKeychain(item, &keychain);
    291   if (status != errSecSuccess) {
    292     OSSTATUS_LOG(ERROR, status);
    293     return NULL;
    294   }
    295 
    296   return keychain;
    297 }
    298 
    299 SecKeychainAttributeInfo* CrSKeychainAttributeInfoForItemID(
    300     SecKeychainRef keychain,
    301     UInt32 item_id) {
    302   SecKeychainAttributeInfo* attribute_info;
    303   OSStatus status = SecKeychainAttributeInfoForItemID(keychain,
    304                                                       item_id,
    305                                                       &attribute_info);
    306   if (status != errSecSuccess) {
    307     OSSTATUS_LOG(ERROR, status);
    308     return NULL;
    309   }
    310 
    311   return attribute_info;
    312 }
    313 
    314 CrSKeychainItemAttributesAndData* CrSKeychainItemCopyAttributesAndData(
    315     SecKeychainRef keychain,
    316     SecKeychainItemRef item) {
    317   ScopedCrSKeychainItemAttributesAndData attributes_and_data(
    318       new CrSKeychainItemAttributesAndData());
    319   OSStatus status =
    320       SecKeychainItemCopyAttributesAndData(item,
    321                                            NULL,
    322                                            attributes_and_data.item_class_ptr(),
    323                                            NULL,
    324                                            NULL,
    325                                            NULL);
    326   if (status != errSecSuccess) {
    327     OSSTATUS_LOG(ERROR, status);
    328     return NULL;
    329   }
    330 
    331   // This looks really weird, but it's right. See 10.7.3
    332   // libsecurity_keychain-55044 lib/SecItem.cpp
    333   // _CreateAttributesDictionaryFromKeyItem and 10.7.3 SecurityTool-55002
    334   // keychain_utilities.c print_keychain_item_attributes.
    335   UInt32 item_id;
    336   switch (attributes_and_data.item_class()) {
    337     case kSecInternetPasswordItemClass:
    338       item_id = CSSM_DL_DB_RECORD_INTERNET_PASSWORD;
    339       break;
    340     case kSecGenericPasswordItemClass:
    341       item_id = CSSM_DL_DB_RECORD_GENERIC_PASSWORD;
    342       break;
    343     // kSecInternetPasswordItemClass is marked as deprecated in the 10.9 sdk,
    344     // but the files in libsecurity_keychain from 10.7 referenced above still
    345     // use it. Also see rdar://14281375 /
    346     // http://openradar.appspot.com/radar?id=3143412 .
    347 #pragma clang diagnostic push
    348 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
    349     case kSecAppleSharePasswordItemClass:
    350 #pragma clang diagnostic pop
    351       item_id = CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD;
    352       break;
    353     default:
    354       item_id = attributes_and_data.item_class();
    355       break;
    356   }
    357 
    358   ScopedSecKeychainAttributeInfo attribute_info(
    359       CrSKeychainAttributeInfoForItemID(keychain, item_id));
    360   if (!attribute_info) {
    361     return NULL;
    362   }
    363 
    364   status = SecKeychainItemCopyAttributesAndData(
    365       item,
    366       attribute_info,
    367       attributes_and_data.item_class_ptr(),
    368       attributes_and_data.attribute_list_ptr(),
    369       attributes_and_data.length_ptr(),
    370       attributes_and_data.data_ptr());
    371   if (status != errSecSuccess) {
    372     OSSTATUS_LOG(ERROR, status);
    373     return NULL;
    374   }
    375 
    376   return attributes_and_data.release();
    377 }
    378 
    379 bool CrSKeychainItemDelete(SecKeychainItemRef item) {
    380   OSStatus status = SecKeychainItemDelete(item);
    381   if (status != errSecSuccess) {
    382     OSSTATUS_LOG(ERROR, status);
    383     return false;
    384   }
    385 
    386   return true;
    387 }
    388 
    389 SecKeychainItemRef CrSKeychainItemCreateFromContent(
    390     const CrSKeychainItemAttributesAndData& attributes_and_data,
    391     SecKeychainRef keychain,
    392     SecAccessRef access) {
    393   SecKeychainItemRef item;
    394   OSStatus status =
    395       SecKeychainItemCreateFromContent(attributes_and_data.item_class,
    396                                        attributes_and_data.attribute_list,
    397                                        attributes_and_data.length,
    398                                        attributes_and_data.data,
    399                                        keychain,
    400                                        access,
    401                                        &item);
    402   if (status != errSecSuccess) {
    403     OSSTATUS_LOG(ERROR, status);
    404     return NULL;
    405   }
    406 
    407   return item;
    408 }
    409 
    410 }  // namespace chrome
    411