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
10extern "C" {
11OSStatus SecTrustedApplicationCopyRequirement(
12    SecTrustedApplicationRef application,
13    SecRequirementRef* requirement);
14}  // extern "C"
15
16namespace chrome {
17
18ScopedSecKeychainSetUserInteractionAllowed::
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
32ScopedSecKeychainSetUserInteractionAllowed::
33    ~ScopedSecKeychainSetUserInteractionAllowed() {
34  OSStatus status = SecKeychainSetUserInteractionAllowed(old_allowed_);
35  if (status != errSecSuccess) {
36    OSSTATUS_LOG(ERROR, status);
37  }
38}
39
40CrSKeychainItemAndAccess::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
56CrSKeychainItemAndAccess::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
65CrSKeychainItemAndAccess::~CrSKeychainItemAndAccess() {
66}
67
68void 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
77CrSACLSimpleContents::CrSACLSimpleContents() {
78}
79
80CrSACLSimpleContents::~CrSACLSimpleContents() {
81}
82
83ScopedSecKeychainAttributeInfo::ScopedSecKeychainAttributeInfo(
84    SecKeychainAttributeInfo* attribute_info)
85    : attribute_info_(attribute_info) {
86}
87
88ScopedSecKeychainAttributeInfo::~ScopedSecKeychainAttributeInfo() {
89  OSStatus status = SecKeychainFreeAttributeInfo(attribute_info_);
90  if (status != errSecSuccess) {
91    OSSTATUS_LOG(ERROR, status);
92  }
93}
94
95ScopedCrSKeychainItemAttributesAndData::ScopedCrSKeychainItemAttributesAndData(
96    CrSKeychainItemAttributesAndData* attributes_and_data)
97    : attributes_and_data_(attributes_and_data) {
98}
99
100ScopedCrSKeychainItemAttributesAndData::
101    ~ScopedCrSKeychainItemAttributesAndData() {
102  if (attributes_and_data_.get()) {
103    CrSKeychainItemFreeAttributesAndData(
104        attributes_and_data_->attribute_list, attributes_and_data_->data);
105  }
106}
107
108SecKeychainSearchRef 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
125SecKeychainItemRef 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
142void 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
151bool 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
172SecAccessRef 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
185CFArrayRef 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
200CrSACLSimpleContents* 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
227SecRequirementRef 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
244CFStringRef 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
262SecTrustedApplicationRef 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
273bool 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
288SecKeychainRef 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
299SecKeychainAttributeInfo* 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
314CrSKeychainItemAttributesAndData* 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
379bool 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
389SecKeychainItemRef 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