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