]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
5c19dc3a | 2 | * Copyright (c) 2000-2004,2011-2015 Apple Inc. All Rights Reserved. |
427c49bc | 3 | * |
b1ab9ed8 | 4 | * @APPLE_LICENSE_HEADER_START@ |
5c19dc3a | 5 | * |
b1ab9ed8 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
5c19dc3a | 12 | * |
b1ab9ed8 A |
13 | * The Original Code and all software distributed under the License are |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
5c19dc3a | 20 | * |
b1ab9ed8 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
427c49bc | 24 | #include <Security/SecBase.h> |
b1ab9ed8 A |
25 | #include <Security/SecKeychainItem.h> |
26 | #include <Security/SecKeychainItemPriv.h> | |
5c19dc3a | 27 | #include <Security/SecCertificatePriv.h> |
b1ab9ed8 A |
28 | |
29 | #include <security_keychain/Keychains.h> | |
30 | #include <security_keychain/KeyItem.h> | |
31 | #include <security_keychain/Item.h> | |
427c49bc A |
32 | #include <security_keychain/Certificate.h> |
33 | #include <security_keychain/Identity.h> | |
b1ab9ed8 A |
34 | #include <security_keychain/KCCursor.h> // @@@ Remove this when SecKeychainItemFindFirst moves to SecKeychainSearch |
35 | ||
36 | #include <securityd_client/dictionary.h> | |
37 | #include <security_cdsa_utilities/Schema.h> | |
38 | #include <Security/cssmapplePriv.h> | |
5c19dc3a | 39 | #include <syslog.h> |
b1ab9ed8 A |
40 | |
41 | #include "SecBridge.h" | |
42 | #include "KCExceptions.h" | |
43 | #include "Access.h" | |
44 | #include "SecKeychainItemExtendedAttributes.h" | |
45 | ||
5c19dc3a | 46 | |
b1ab9ed8 A |
47 | // |
48 | // Given a polymorphic Sec type object, return | |
49 | // its AclBearer component. | |
50 | // Note: Login ACLs are not hooked into this layer; | |
51 | // modules or attachments have no Sec* layer representation. | |
52 | // | |
427c49bc | 53 | static |
b1ab9ed8 A |
54 | RefPointer<AclBearer> aclBearer(CFTypeRef itemRef) |
55 | { | |
56 | // well, exactly what kind of something are you? | |
57 | CFTypeID id = CFGetTypeID(itemRef); | |
58 | if (id == gTypes().ItemImpl.typeID) { | |
59 | // keychain item. If it's in a protected group, return the group key | |
60 | if (SSGroup group = ItemImpl::required(SecKeychainItemRef(itemRef))->group()) | |
61 | return &*group; | |
62 | } else if (id == gTypes().KeyItem.typeID) { | |
63 | // key item, return the key itself. | |
64 | if (CssmClient::Key key = KeyItem::required(SecKeyRef(itemRef))->key()) | |
65 | return &*key; | |
66 | } else if (id == gTypes().KeychainImpl.typeID) { | |
67 | // keychain (this yields the database ACL) | |
68 | //@@@ not hooked up yet | |
69 | } | |
70 | // Guess not. Bummer | |
71 | MacOSError::throwMe(errSecNoAccessForItem); | |
72 | } | |
73 | ||
74 | ||
75 | CFTypeID | |
76 | SecKeychainItemGetTypeID(void) | |
77 | { | |
78 | BEGIN_SECAPI | |
79 | ||
80 | return gTypes().ItemImpl.typeID; | |
81 | ||
82 | END_SECAPI1(_kCFRuntimeNotATypeID) | |
83 | } | |
84 | ||
85 | ||
86 | OSStatus | |
87 | SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeList *attrList, | |
88 | UInt32 length, const void *data, SecKeychainRef keychainRef, | |
89 | SecAccessRef initialAccess, SecKeychainItemRef *itemRef) | |
90 | { | |
91 | BEGIN_SECAPI | |
92 | KCThrowParamErrIf_(length!=0 && data==NULL); | |
93 | Item item(itemClass, attrList, length, data); | |
94 | if (initialAccess) | |
95 | item->setAccess(Access::required(initialAccess)); | |
96 | ||
97 | Keychain keychain = nil; | |
98 | try | |
99 | { | |
100 | keychain = Keychain::optional(keychainRef); | |
101 | if ( !keychain->exists() ) | |
102 | { | |
103 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
104 | } | |
105 | } | |
106 | catch(...) | |
107 | { | |
108 | keychain = globals().storageManager.defaultKeychainUI(item); | |
109 | } | |
110 | ||
111 | keychain->add(item); | |
112 | if (itemRef) | |
113 | *itemRef = item->handle(); | |
114 | END_SECAPI | |
115 | } | |
116 | ||
117 | ||
118 | OSStatus | |
119 | SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) | |
120 | { | |
121 | BEGIN_SECAPI | |
122 | Item item = ItemImpl::required(itemRef); | |
123 | item->modifyContent(attrList, length, data); | |
124 | END_SECAPI | |
125 | } | |
126 | ||
127 | ||
128 | OSStatus | |
129 | SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData) | |
130 | { | |
5c19dc3a | 131 | #if !SECTRUST_OSX |
b1ab9ed8 A |
132 | BEGIN_SECAPI |
133 | Item item = ItemImpl::required(itemRef); | |
134 | item->getContent(itemClass, attrList, length, outData); | |
135 | END_SECAPI | |
5c19dc3a A |
136 | #else |
137 | OSStatus __secapiresult; | |
138 | bool isCertificate = false; | |
139 | SecKeychainItemRef itemImplRef; | |
140 | if (itemRef && CFGetTypeID(itemRef) == SecCertificateGetTypeID()) { | |
141 | // TODO: determine whether we need to actually look up the cert in a keychain here | |
142 | itemImplRef = (SecKeychainItemRef) SecCertificateCopyKeychainItem((SecCertificateRef)itemRef); | |
143 | if (!itemImplRef) { | |
144 | itemImplRef = (SecKeychainItemRef) SecCertificateCreateItemImplInstance((SecCertificateRef)itemRef); | |
145 | } | |
146 | isCertificate = true; | |
147 | } | |
148 | else { | |
149 | itemImplRef = (SecKeychainItemRef)((itemRef) ? CFRetain(itemRef) : NULL); | |
150 | } | |
151 | ||
152 | try | |
153 | { | |
154 | Item item = ItemImpl::required(itemImplRef); | |
155 | item->getContent(itemClass, attrList, (isCertificate) ? NULL : length, (isCertificate) ? NULL : outData); | |
156 | __secapiresult=0; | |
157 | } | |
158 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
159 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
160 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
161 | catch (...) { __secapiresult=errSecInternalComponent; } | |
162 | ||
163 | if (isCertificate && outData && *outData == NULL) { | |
164 | // copy the data here | |
165 | __secapiresult = errSecAllocate; | |
166 | CFDataRef dataRef = SecCertificateCopyData((SecCertificateRef)itemRef); | |
167 | if (dataRef) { | |
168 | CFIndex dataLen = CFDataGetLength(dataRef); | |
169 | const UInt8 *bytePtr = CFDataGetBytePtr(dataRef); | |
170 | if ((bytePtr != NULL) && (dataLen > 0)) { | |
171 | *outData = malloc(dataLen); | |
172 | memcpy(*outData, bytePtr, dataLen); | |
173 | *length = (UInt32)dataLen; | |
174 | __secapiresult = errSecSuccess; | |
175 | } | |
176 | CFRelease(dataRef); | |
177 | } | |
178 | } | |
179 | if (itemImplRef) { | |
180 | CFRelease(itemImplRef); | |
181 | } | |
182 | return __secapiresult; | |
183 | #endif | |
b1ab9ed8 A |
184 | } |
185 | ||
186 | ||
187 | OSStatus | |
188 | SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data) | |
189 | { | |
190 | BEGIN_SECAPI | |
191 | ItemImpl::freeContent(attrList, data); | |
192 | END_SECAPI | |
193 | } | |
194 | ||
195 | ||
196 | OSStatus | |
197 | SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) | |
198 | { | |
199 | BEGIN_SECAPI | |
200 | Item item = ItemImpl::required(itemRef); | |
201 | item->modifyAttributesAndData(attrList, length, data); | |
202 | END_SECAPI | |
203 | } | |
204 | ||
205 | ||
206 | OSStatus | |
207 | SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, SecItemClass *itemClass, SecKeychainAttributeList **attrList, UInt32 *length, void **outData) | |
208 | { | |
5c19dc3a | 209 | #if !SECTRUST_OSX |
b1ab9ed8 A |
210 | BEGIN_SECAPI |
211 | Item item = ItemImpl::required(itemRef); | |
212 | item->getAttributesAndData(info, itemClass, attrList, length, outData); | |
213 | END_SECAPI | |
5c19dc3a A |
214 | #else |
215 | // if the item is a SecCertificateRef, must convert to an ItemImpl-based instance | |
216 | // TODO: determine whether we need to actually look up the cert in a keychain here | |
217 | OSStatus __secapiresult; | |
218 | SecKeychainItemRef itemImplRef; | |
219 | if (itemRef && CFGetTypeID(itemRef) == SecCertificateGetTypeID()) { | |
220 | itemImplRef = (SecKeychainItemRef) SecCertificateCopyKeychainItem((SecCertificateRef)itemRef); | |
221 | if (!itemImplRef) { | |
222 | itemImplRef = (SecKeychainItemRef) SecCertificateCreateItemImplInstance((SecCertificateRef)itemRef); | |
223 | } | |
224 | } | |
225 | else { | |
226 | itemImplRef = (SecKeychainItemRef)((itemRef) ? CFRetain(itemRef) : NULL); | |
227 | } | |
228 | ||
229 | try | |
230 | { | |
231 | Item item = ItemImpl::required(itemImplRef); | |
232 | item->getAttributesAndData(info, itemClass, attrList, length, outData); | |
233 | __secapiresult=0; | |
234 | } | |
235 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
236 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
237 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
238 | catch (...) { __secapiresult=errSecInternalComponent; } | |
239 | ||
240 | if (itemImplRef) { | |
241 | CFRelease(itemImplRef); | |
242 | } | |
243 | return __secapiresult; | |
244 | #endif | |
b1ab9ed8 A |
245 | } |
246 | ||
247 | ||
248 | OSStatus | |
249 | SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList *attrList, void *data) | |
250 | { | |
251 | BEGIN_SECAPI | |
252 | ItemImpl::freeAttributesAndData(attrList, data); | |
253 | END_SECAPI | |
254 | } | |
255 | ||
256 | ||
257 | OSStatus | |
258 | SecKeychainItemDelete(SecKeychainItemRef itemRef) | |
259 | { | |
5c19dc3a | 260 | #if !SECTRUST_OSX |
b1ab9ed8 A |
261 | BEGIN_SECAPI |
262 | Item item = ItemImpl::required( itemRef ); | |
263 | Keychain keychain = item->keychain(); | |
264 | // item must be persistent. | |
265 | KCThrowIf_( !keychain, errSecInvalidItemRef ); | |
427c49bc | 266 | |
b1ab9ed8 A |
267 | /* |
268 | * Before deleting the item, delete any existing Extended Attributes. | |
269 | */ | |
270 | OSStatus ortn; | |
271 | CFArrayRef attrNames = NULL; | |
272 | ortn = SecKeychainItemCopyAllExtendedAttributes(itemRef, &attrNames, NULL); | |
427c49bc | 273 | if(ortn == errSecSuccess) { |
b1ab9ed8 A |
274 | CFIndex numAttrs = CFArrayGetCount(attrNames); |
275 | for(CFIndex dex=0; dex<numAttrs; dex++) { | |
276 | CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(attrNames, dex); | |
277 | /* setting value to NULL ==> delete */ | |
278 | SecKeychainItemSetExtendedAttribute(itemRef, attrName, NULL); | |
279 | } | |
280 | } | |
427c49bc | 281 | |
b1ab9ed8 | 282 | /* now delete the item */ |
427c49bc | 283 | keychain->deleteItem( item ); |
b1ab9ed8 | 284 | END_SECAPI |
5c19dc3a A |
285 | #else |
286 | // if the item is a SecCertificateRef, must convert to an ItemImpl-based instance | |
287 | // TODO: determine whether we need to actually look up the cert in a keychain here | |
288 | OSStatus __secapiresult; | |
289 | SecKeychainItemRef itemImplRef; | |
290 | if (itemRef && CFGetTypeID(itemRef) == SecCertificateGetTypeID()) { | |
291 | itemImplRef = (SecKeychainItemRef) SecCertificateCopyKeychainItem((SecCertificateRef)itemRef); | |
292 | if (!itemImplRef) { | |
293 | itemImplRef = (SecKeychainItemRef) SecCertificateCreateItemImplInstance((SecCertificateRef)itemRef); | |
294 | } | |
295 | } | |
296 | else { | |
297 | itemImplRef = (SecKeychainItemRef)((itemRef) ? CFRetain(itemRef) : NULL); | |
298 | } | |
299 | ||
300 | try | |
301 | { | |
302 | Item item = ItemImpl::required( itemImplRef ); | |
303 | Keychain keychain = item->keychain(); | |
304 | // item must be persistent. | |
305 | KCThrowIf_( !keychain, errSecInvalidItemRef ); | |
306 | ||
307 | /* | |
308 | * Before deleting the item, delete any existing Extended Attributes. | |
309 | */ | |
310 | OSStatus ortn; | |
311 | CFArrayRef attrNames = NULL; | |
312 | ortn = SecKeychainItemCopyAllExtendedAttributes(itemImplRef, &attrNames, NULL); | |
313 | if(ortn == errSecSuccess) { | |
314 | CFIndex numAttrs = CFArrayGetCount(attrNames); | |
315 | for(CFIndex dex=0; dex<numAttrs; dex++) { | |
316 | CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(attrNames, dex); | |
317 | /* setting value to NULL ==> delete */ | |
318 | SecKeychainItemSetExtendedAttribute(itemImplRef, attrName, NULL); | |
319 | } | |
320 | } | |
321 | ||
322 | /* now delete the item */ | |
323 | keychain->deleteItem( item ); | |
324 | __secapiresult=0; | |
325 | } | |
326 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
327 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
328 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
329 | catch (...) { __secapiresult=errSecInternalComponent; } | |
330 | ||
331 | if (itemImplRef) { | |
332 | CFRelease(itemImplRef); | |
333 | } | |
334 | return __secapiresult; | |
335 | #endif | |
b1ab9ed8 A |
336 | } |
337 | ||
338 | ||
339 | OSStatus | |
340 | SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef* keychainRef) | |
341 | { | |
5c19dc3a A |
342 | #if !SECTRUST_OSX |
343 | BEGIN_SECAPI | |
b1ab9ed8 A |
344 | // make sure this item has a keychain |
345 | Keychain kc = ItemImpl::required(itemRef)->keychain (); | |
346 | if (kc == NULL) | |
347 | { | |
348 | MacOSError::throwMe(errSecNoSuchKeychain); | |
349 | } | |
427c49bc | 350 | |
b1ab9ed8 A |
351 | Required(keychainRef) = kc->handle(); |
352 | END_SECAPI | |
5c19dc3a A |
353 | #else |
354 | // if the item is a SecCertificateRef, must convert to an ItemImpl-based instance | |
355 | // TODO: determine whether we need to actually look up the cert in a keychain here | |
356 | OSStatus __secapiresult; | |
357 | SecKeychainItemRef itemImplRef; | |
358 | if (itemRef && CFGetTypeID(itemRef) == SecCertificateGetTypeID()) { | |
359 | itemImplRef = (SecKeychainItemRef) SecCertificateCopyKeychainItem((SecCertificateRef)itemRef); | |
360 | if (!itemImplRef) { | |
361 | itemImplRef = (SecKeychainItemRef) SecCertificateCreateItemImplInstance((SecCertificateRef)itemRef); | |
362 | } | |
363 | } | |
364 | else { | |
365 | itemImplRef = (SecKeychainItemRef)((itemRef) ? CFRetain(itemRef) : NULL); | |
366 | } | |
367 | ||
368 | try | |
369 | { | |
370 | // make sure this item has a keychain | |
371 | Keychain kc = ItemImpl::required(itemImplRef)->keychain(); | |
372 | if (kc == NULL) | |
373 | { | |
374 | MacOSError::throwMe(errSecNoSuchKeychain); | |
375 | } | |
376 | ||
377 | Required(keychainRef) = kc->handle(); | |
378 | __secapiresult=0; | |
379 | } | |
380 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
381 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
382 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
383 | catch (...) { __secapiresult=errSecInternalComponent; } | |
384 | ||
385 | if (itemImplRef) { | |
386 | CFRelease(itemImplRef); | |
387 | } | |
388 | return __secapiresult; | |
389 | #endif | |
b1ab9ed8 A |
390 | } |
391 | ||
392 | ||
393 | OSStatus | |
394 | SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef destKeychainRef, | |
395 | SecAccessRef initialAccess, SecKeychainItemRef *itemCopy) | |
396 | { | |
5c19dc3a A |
397 | #if SECTRUST_OSX |
398 | // bridge code for certificate items | |
399 | if (itemRef && CFGetTypeID(itemRef) == SecCertificateGetTypeID()) { | |
400 | return SecCertificateAddToKeychain((SecCertificateRef)itemRef, destKeychainRef); | |
401 | } | |
402 | #endif | |
403 | ||
404 | BEGIN_SECAPI | |
b1ab9ed8 A |
405 | Item copy = ItemImpl::required(itemRef)->copyTo(Keychain::optional(destKeychainRef), Access::optional(initialAccess)); |
406 | if (itemCopy) | |
407 | *itemCopy = copy->handle(); | |
408 | END_SECAPI | |
409 | } | |
410 | ||
411 | ||
412 | OSStatus | |
413 | SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef, const CSSM_DB_UNIQUE_RECORD **uniqueRecordID) | |
414 | { | |
5c19dc3a A |
415 | BEGIN_SECAPI |
416 | Required(uniqueRecordID) = ItemImpl::required(itemRef)->dbUniqueRecord(); | |
b1ab9ed8 A |
417 | END_SECAPI |
418 | } | |
419 | ||
420 | ||
421 | OSStatus | |
422 | SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef, CSSM_DL_DB_HANDLE* dldbHandle) | |
423 | { | |
5c19dc3a A |
424 | BEGIN_SECAPI |
425 | *dldbHandle = ItemImpl::required(itemRef)->keychain()->database()->handle(); | |
b1ab9ed8 A |
426 | END_SECAPI |
427 | } | |
428 | ||
427c49bc A |
429 | #if 0 |
430 | static | |
b1ab9ed8 A |
431 | OSStatus SecAccessCreateFromObject(CFTypeRef sourceRef, |
432 | SecAccessRef *accessRef) | |
433 | { | |
434 | BEGIN_SECAPI | |
435 | Required(accessRef); // preflight | |
436 | SecPointer<Access> access = new Access(*aclBearer(sourceRef)); | |
437 | *accessRef = access->handle(); | |
438 | END_SECAPI | |
439 | } | |
440 | ||
441 | ||
442 | /*! | |
443 | */ | |
427c49bc | 444 | static |
b1ab9ed8 A |
445 | OSStatus SecAccessModifyObject(SecAccessRef accessRef, CFTypeRef sourceRef) |
446 | { | |
447 | BEGIN_SECAPI | |
448 | Access::required(accessRef)->setAccess(*aclBearer(sourceRef), true); | |
449 | END_SECAPI | |
450 | } | |
427c49bc | 451 | #endif |
b1ab9ed8 A |
452 | |
453 | OSStatus | |
454 | SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef) | |
455 | { | |
456 | BEGIN_SECAPI | |
457 | ||
458 | Required(accessRef); // preflight | |
459 | SecPointer<Access> access = new Access(*aclBearer(reinterpret_cast<CFTypeRef>(itemRef))); | |
460 | *accessRef = access->handle(); | |
461 | ||
462 | END_SECAPI | |
463 | } | |
464 | ||
465 | ||
466 | OSStatus | |
467 | SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef accessRef) | |
468 | { | |
469 | BEGIN_SECAPI | |
470 | ||
471 | Access::required(accessRef)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef>(itemRef)), true); | |
472 | ||
473 | ItemImpl::required(itemRef)->postItemEvent (kSecUpdateEvent); | |
427c49bc | 474 | |
b1ab9ed8 A |
475 | END_SECAPI |
476 | } | |
477 | ||
e3d460c9 A |
478 | OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAccessRef accessRef, UInt32 passwordLength, const void * password) { |
479 | BEGIN_SECAPI | |
480 | ||
481 | OSStatus result; | |
482 | ||
483 | // try to unlock the keychain with this password first | |
484 | SecKeychainRef kc = NULL; | |
485 | result = SecKeychainItemCopyKeychain(itemRef, &kc); | |
486 | if(!result) { | |
487 | SecKeychainUnlock(kc, passwordLength, password, true); | |
488 | if(kc) { | |
489 | CFRelease(kc); | |
490 | } | |
491 | } | |
492 | ||
493 | // Create some credentials with this password | |
494 | CssmAutoData data(Allocator::standard(), password, passwordLength); | |
495 | AclFactory::PassphraseUnlockCredentials cred(data, Allocator::standard()); | |
496 | ||
497 | Access::required(accessRef)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef>(itemRef)), true, cred.getAccessCredentials()); | |
498 | ItemImpl::required(itemRef)->postItemEvent (kSecUpdateEvent); | |
499 | ||
500 | END_SECAPI | |
501 | } | |
502 | ||
503 | ||
b1ab9ed8 | 504 | /* Sets an item's data for legacy "KC" CoreServices APIs. |
427c49bc | 505 | Note this version sets the data, but doesn't update the item |
b1ab9ed8 A |
506 | as the KC behavior dictates. |
507 | */ | |
508 | OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data) | |
509 | { | |
510 | BEGIN_SECAPI | |
511 | ItemImpl::required(itemRef)->setData(length, data); | |
512 | END_SECAPI | |
513 | } | |
514 | ||
515 | /* Gets an item's data for legacy "KC" CoreServices APIs. | |
516 | Note this version doesn't take a SecItemClass parameter. | |
517 | */ | |
518 | OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength) | |
519 | { | |
520 | BEGIN_SECAPI | |
521 | /* The caller either needs to specify data and maxLength or an actualLength, so we return either the data itself or the actual length of the data or both. */ | |
522 | if (!((data && maxLength) || actualLength)) | |
427c49bc | 523 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
524 | |
525 | CssmDataContainer aData; | |
526 | ItemImpl::required(itemRef)->getData(aData); | |
527 | if (actualLength) | |
427c49bc A |
528 | *actualLength = (UInt32)aData.length(); |
529 | ||
b1ab9ed8 A |
530 | if (data) |
531 | { | |
532 | // Make sure the buffer is big enough | |
533 | if (aData.length() > maxLength) | |
427c49bc | 534 | MacOSError::throwMe(errSecBufferTooSmall); |
b1ab9ed8 A |
535 | memcpy(data, aData.data(), aData.length()); |
536 | } | |
537 | END_SECAPI | |
538 | } | |
539 | ||
540 | /* Update a keychain item for legacy "KC" CoreServices APIs. | |
541 | The "KC" API's do a 'set attribute', then an 'update'. | |
542 | */ | |
543 | OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef) | |
544 | { | |
545 | BEGIN_SECAPI | |
546 | ItemImpl::required(itemRef)->update(); | |
547 | END_SECAPI | |
548 | } | |
549 | ||
550 | /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs. | |
551 | */ | |
552 | OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef) | |
553 | { | |
554 | BEGIN_SECAPI | |
555 | Item item = ItemImpl::required(itemRef); | |
556 | Keychain::optional(keychainRef)->add(item); | |
557 | END_SECAPI | |
558 | } | |
559 | ||
560 | /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs. | |
561 | */ | |
562 | OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef) | |
563 | { | |
564 | BEGIN_SECAPI | |
565 | Item item = ItemImpl::required(itemRef); | |
566 | Keychain defaultKeychain = globals().storageManager.defaultKeychainUI(item); | |
567 | defaultKeychain->add(item); | |
568 | END_SECAPI | |
569 | } | |
570 | ||
571 | /* Creates a floating keychain item for legacy "KC" CoreServices APIs | |
572 | */ | |
573 | OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef) | |
574 | { | |
575 | BEGIN_SECAPI | |
576 | RequiredParam(itemRef) = Item(itemClass, itemCreator, length, data, false)->handle(); | |
577 | END_SECAPI | |
578 | } | |
579 | ||
580 | /* Gets an individual attribute for legacy "KC" CoreServices APIs | |
581 | */ | |
582 | OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength) | |
583 | { | |
584 | BEGIN_SECAPI | |
585 | ItemImpl::required(itemRef)->getAttribute(RequiredParam(attribute), actualLength); | |
586 | END_SECAPI | |
587 | } | |
588 | ||
589 | /* Sets an individual attribute for legacy "KC" CoreServices APIs | |
590 | */ | |
591 | OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute) | |
592 | { | |
593 | BEGIN_SECAPI | |
594 | ItemImpl::required(itemRef)->setAttribute(RequiredParam(attribute)); | |
595 | END_SECAPI | |
596 | } | |
597 | ||
598 | /* Finds a keychain item for legacy "KC" CoreServices APIs. | |
427c49bc | 599 | Note: This version doesn't take a SecItemClass because |
b1ab9ed8 A |
600 | SecKeychainSearchCreateFromAttributes() requires it. |
601 | @@@ This should move to SecKeychainSearch.cpp | |
602 | */ | |
603 | OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef) | |
604 | { | |
605 | BEGIN_SECAPI | |
606 | KCCursor cursor; | |
607 | if (keychainRef) | |
608 | cursor = KeychainImpl::required(keychainRef)->createCursor(attrList); | |
609 | else | |
610 | cursor = globals().storageManager.createCursor(attrList); | |
427c49bc | 611 | |
b1ab9ed8 A |
612 | Item item; |
613 | if (!cursor->next(item)) | |
427c49bc A |
614 | return errSecItemNotFound; |
615 | ||
b1ab9ed8 A |
616 | *itemRef=item->handle(); |
617 | if (searchRef) | |
618 | *searchRef=cursor->handle(); | |
619 | END_SECAPI | |
620 | } | |
621 | ||
5c19dc3a A |
622 | #if SECTRUST_OSX |
623 | static OSStatus SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef, | |
624 | CFDataRef *persistentItemRef) | |
b1ab9ed8 | 625 | { |
5c19dc3a A |
626 | if (!certRef || !persistentItemRef) |
627 | return errSecParam; | |
628 | ||
629 | OSStatus __secapiresult; | |
630 | CFErrorRef errorRef = NULL; | |
631 | CFDataRef serialData = SecCertificateCopySerialNumber(certRef, &errorRef); | |
632 | if (errorRef) { | |
633 | CFIndex err = CFErrorGetCode(errorRef); | |
634 | CFRelease(errorRef); | |
635 | if (serialData) { CFRelease(serialData); } | |
636 | return (OSStatus)err; | |
637 | } | |
638 | CFDataRef issuerData = SecCertificateCopyNormalizedIssuerContent(certRef, &errorRef); | |
639 | if (errorRef) { | |
640 | CFIndex err = CFErrorGetCode(errorRef); | |
641 | CFRelease(errorRef); | |
642 | if (serialData) { CFRelease(serialData); } | |
643 | if (issuerData) { CFRelease(issuerData); } | |
644 | return (OSStatus)err; | |
645 | } | |
646 | ||
647 | try { | |
648 | // look up ItemImpl cert in keychain by normalized issuer and serial number | |
649 | StorageManager::KeychainList keychains; | |
650 | globals().storageManager.optionalSearchList(NULL, keychains); | |
651 | KCCursor cursor(Certificate::cursorForIssuerAndSN_CF(keychains, issuerData, serialData)); | |
427c49bc | 652 | Item item; |
5c19dc3a A |
653 | if (!cursor->next(item)) { |
654 | MacOSError::throwMe(errSecItemNotFound); | |
427c49bc | 655 | } |
5c19dc3a A |
656 | item->copyPersistentReference(*persistentItemRef, false); |
657 | __secapiresult = errSecSuccess; | |
658 | } | |
659 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
660 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
661 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
662 | catch (...) { __secapiresult=errSecInternalComponent; } | |
663 | ||
664 | if (serialData) | |
665 | CFRelease(serialData); | |
666 | if (issuerData) | |
667 | CFRelease(issuerData); | |
668 | ||
669 | return __secapiresult; | |
670 | } | |
671 | #endif | |
672 | ||
673 | OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef *persistentItemRef) | |
674 | { | |
675 | #if !SECTRUST_OSX | |
676 | BEGIN_SECAPI | |
677 | ||
678 | KCThrowParamErrIf_(!itemRef || !persistentItemRef); | |
679 | Item item; | |
680 | bool isIdentityRef = (CFGetTypeID(itemRef) == SecIdentityGetTypeID()) ? true : false; | |
681 | bool isCertificateRef = (CFGetTypeID(itemRef) == SecCertificateGetTypeID()) ? true : false; | |
682 | if (isIdentityRef) { | |
683 | SecPointer<Certificate> certificatePtr(Identity::required((SecIdentityRef)itemRef)->certificate()); | |
684 | SecCertificateRef certificateRef = certificatePtr->handle(false); | |
685 | item = ItemImpl::required((SecKeychainItemRef)certificateRef); | |
686 | item->copyPersistentReference(*persistentItemRef, true); | |
687 | } | |
688 | else if (isCertificateRef) { | |
689 | item = ItemImpl::required(itemRef); | |
690 | item->copyPersistentReference(*persistentItemRef, false); | |
691 | } | |
692 | else { | |
693 | item = ItemImpl::required(itemRef); | |
694 | item->copyPersistentReference(*persistentItemRef, false); | |
695 | } | |
696 | ||
b1ab9ed8 | 697 | END_SECAPI |
5c19dc3a A |
698 | #else |
699 | /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */ | |
700 | if (!itemRef || !persistentItemRef) { | |
701 | return errSecParam; | |
702 | } | |
703 | bool isIdentityRef = (CFGetTypeID(itemRef) == SecIdentityGetTypeID()) ? true : false; | |
704 | bool isCertificateRef = (CFGetTypeID(itemRef) == SecCertificateGetTypeID()) ? true : false; | |
705 | SecCertificateRef certRef = NULL; | |
706 | if (isIdentityRef) { | |
707 | SecIdentityCopyCertificate((SecIdentityRef)itemRef, &certRef); | |
708 | } | |
709 | else if (isCertificateRef) { | |
710 | certRef = (SecCertificateRef) CFRetain(itemRef); | |
711 | } | |
712 | if (certRef) { | |
713 | OSStatus status = SecKeychainItemCreatePersistentReferenceFromCertificate(certRef, persistentItemRef); | |
714 | CFRelease(certRef); | |
715 | return status; | |
716 | } | |
717 | // otherwise, not a certificate, so proceed as usual for keychain item | |
718 | ||
719 | BEGIN_SECAPI | |
720 | Item item = ItemImpl::required(itemRef); | |
721 | item->copyPersistentReference(*persistentItemRef, false); | |
722 | END_SECAPI | |
723 | ||
724 | #endif | |
b1ab9ed8 A |
725 | } |
726 | ||
727 | OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef) | |
728 | { | |
729 | BEGIN_SECAPI | |
5c19dc3a A |
730 | |
731 | KCThrowParamErrIf_(!persistentItemRef || !itemRef); | |
732 | CFTypeRef result = NULL; | |
733 | bool isIdentityRef = false; | |
734 | Item item = ItemImpl::makeFromPersistentReference(persistentItemRef, &isIdentityRef); | |
735 | if (isIdentityRef) { | |
736 | // item was stored as an identity, attempt to reconstitute it | |
737 | SecPointer<Certificate> certificatePtr(static_cast<Certificate *>(item.get())); | |
738 | StorageManager::KeychainList keychains; | |
739 | globals().storageManager.optionalSearchList(NULL, keychains); | |
740 | SecPointer<Identity> identityPtr(new Identity(keychains, certificatePtr)); | |
741 | result = identityPtr->handle(); | |
742 | KCThrowIf_( !result, errSecItemNotFound ); | |
743 | } | |
744 | if (!result) { | |
745 | result = item->handle(); | |
746 | } | |
747 | *itemRef = (SecKeychainItemRef) result; | |
748 | ||
749 | #if SECTRUST_OSX | |
750 | /* see if we should convert outgoing item to a unified SecCertificateRef */ | |
751 | SecItemClass tmpItemClass = Schema::itemClassFor(item->recordType()); | |
752 | if (tmpItemClass == kSecCertificateItemClass) { | |
753 | SecPointer<Certificate> certificate(static_cast<Certificate *>(&*item)); | |
754 | CssmData certData = certificate->data(); | |
755 | CFDataRef data = NULL; | |
756 | if (certData.Data && certData.Length) { | |
757 | data = CFDataCreate(NULL, certData.Data, certData.Length); | |
758 | } | |
759 | if (!data) { | |
760 | *itemRef = NULL; | |
761 | if (certData.Data && !certData.Length) { | |
762 | syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)", | |
763 | (uintptr_t)certData.Data); | |
764 | return errSecDataNotAvailable; | |
765 | } | |
766 | else { | |
767 | syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)", | |
768 | (long)certData.Length, (uintptr_t)certData.Data); | |
769 | return errSecInternal; | |
770 | } | |
771 | } | |
772 | SecKeychainItemRef tmpRef = *itemRef; | |
773 | *itemRef = (SecKeychainItemRef) SecCertificateCreateWithKeychainItem(NULL, data, tmpRef); | |
774 | if (data) | |
775 | CFRelease(data); | |
776 | if (tmpRef) | |
777 | CFRelease(tmpRef); | |
778 | } | |
779 | #endif | |
780 | ||
b1ab9ed8 A |
781 | END_SECAPI |
782 | } | |
783 | ||
784 | OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier) | |
785 | { | |
786 | BEGIN_SECAPI | |
787 | CSSM_DATA data; | |
788 | RequiredParam (recordIdentifier); | |
789 | Item item = ItemImpl::required(itemRef); | |
790 | item->copyRecordIdentifier (data); | |
791 | *recordIdentifier = ::CFDataCreate(kCFAllocatorDefault, (UInt8*) data.Data, data.Length); | |
792 | free (data.Data); | |
793 | END_SECAPI | |
794 | } | |
795 | ||
796 | OSStatus | |
797 | SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef, | |
798 | SecKeychainItemRef *itemRef, | |
799 | CFDataRef recordIdentifier) | |
800 | { | |
801 | BEGIN_SECAPI | |
802 | // make a local Keychain reference | |
803 | RequiredParam (keychainRef); | |
804 | Keychain keychain = KeychainImpl::optional (keychainRef); | |
805 | RequiredParam (itemRef); | |
806 | RequiredParam (recordIdentifier); | |
427c49bc | 807 | |
b1ab9ed8 | 808 | Db db(keychain->database()); |
427c49bc | 809 | |
b1ab9ed8 A |
810 | // make a raw database call to get the data |
811 | CSSM_DL_DB_HANDLE dbHandle = db.handle (); | |
812 | CSSM_DB_UNIQUE_RECORD uniqueRecord; | |
427c49bc | 813 | |
b1ab9ed8 A |
814 | // according to source, we should be able to reconsitute the uniqueRecord |
815 | // from the data we earlier retained | |
427c49bc | 816 | |
b1ab9ed8 A |
817 | // prepare the record id |
818 | memset (&uniqueRecord, 0, sizeof (uniqueRecord)); | |
819 | uniqueRecord.RecordIdentifier.Data = (uint8*) CFDataGetBytePtr (recordIdentifier); | |
820 | uniqueRecord.RecordIdentifier.Length = CFDataGetLength (recordIdentifier); | |
427c49bc | 821 | |
b1ab9ed8 A |
822 | // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL |
823 | CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr; | |
824 | CSSM_RETURN result; | |
825 | result = CSSM_DL_PassThrough (dbHandle, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER, &uniqueRecord, (void**) &outputUniqueRecordPtr); | |
826 | KCThrowIf_(result != 0, errSecItemNotFound); | |
427c49bc | 827 | |
b1ab9ed8 A |
828 | // from this, get the record type |
829 | CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData; | |
830 | memset (&attributeData, 0, sizeof (attributeData)); | |
427c49bc | 831 | |
b1ab9ed8 A |
832 | result = CSSM_DL_DataGetFromUniqueRecordId (dbHandle, outputUniqueRecordPtr, &attributeData, NULL); |
833 | KCThrowIf_(result != 0, errSecItemNotFound); | |
834 | CSSM_DB_RECORDTYPE recordType = attributeData.DataRecordType; | |
835 | ||
836 | // make the unique record item -- precursor to creation of a SecKeychainItemRef | |
837 | DbUniqueRecord unique(db); | |
838 | CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = unique; | |
839 | *uniquePtr = outputUniqueRecordPtr; | |
840 | ||
841 | unique->activate (); | |
842 | Item item = keychain->item (recordType, unique); | |
843 | if (itemRef) | |
844 | { | |
845 | *itemRef = item->handle(); | |
846 | } | |
847 | END_SECAPI | |
848 | } | |
849 | ||
850 | OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass, | |
851 | UInt32 length, const void *data, SecKeychainRef keychainRef, | |
852 | SecAccessRef initialAccess, SecKeychainItemRef *itemRef, CFDataRef *localID) | |
853 | { | |
854 | BEGIN_SECAPI | |
855 | KCThrowParamErrIf_(length!=0 && data==NULL); | |
856 | ||
857 | RequiredParam (localID); | |
858 | RequiredParam (keychainRef); | |
427c49bc | 859 | |
b1ab9ed8 A |
860 | Item item(itemClass, (uint32) 0, length, data, true); |
861 | if (initialAccess) | |
862 | item->setAccess(Access::required(initialAccess)); | |
863 | ||
864 | Keychain keychain = Keychain::optional(keychainRef); | |
865 | if (!keychain->exists()) | |
866 | { | |
867 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
868 | } | |
869 | ||
870 | item->doNotEncrypt (); | |
871 | try | |
872 | { | |
873 | keychain->add(item); | |
874 | } | |
875 | catch (const CommonError &err) | |
876 | { | |
877 | if (err.osStatus () == errSecNoSuchClass) | |
878 | { | |
879 | // the only time this should happen is if the item is a certificate (for keychain syncing) | |
880 | if (itemClass == CSSM_DL_DB_RECORD_X509_CERTIFICATE) | |
881 | { | |
882 | // create the certificate relation | |
883 | Db db(keychain->database()); | |
884 | ||
885 | db->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE, | |
886 | "CSSM_DL_DB_RECORD_X509_CERTIFICATE", | |
887 | Schema::X509CertificateSchemaAttributeCount, | |
888 | Schema::X509CertificateSchemaAttributeList, | |
889 | Schema::X509CertificateSchemaIndexCount, | |
890 | Schema::X509CertificateSchemaIndexList); | |
891 | keychain->keychainSchema()->didCreateRelation( | |
892 | CSSM_DL_DB_RECORD_X509_CERTIFICATE, | |
893 | "CSSM_DL_DB_RECORD_X509_CERTIFICATE", | |
894 | Schema::X509CertificateSchemaAttributeCount, | |
895 | Schema::X509CertificateSchemaAttributeList, | |
896 | Schema::X509CertificateSchemaIndexCount, | |
897 | Schema::X509CertificateSchemaIndexList); | |
427c49bc | 898 | |
b1ab9ed8 A |
899 | // add the item again |
900 | keychain->add(item); | |
901 | } | |
902 | } | |
903 | else | |
904 | { | |
905 | throw; | |
906 | } | |
907 | } | |
908 | ||
909 | if (itemRef) | |
910 | *itemRef = item->handle(); | |
427c49bc | 911 | |
b1ab9ed8 A |
912 | CSSM_DATA recordID; |
913 | item->copyRecordIdentifier (recordID); | |
427c49bc | 914 | |
b1ab9ed8 A |
915 | *localID = CFDataCreate(kCFAllocatorDefault, (UInt8*) recordID.Data, recordID.Length); |
916 | free (recordID.Data); | |
917 | END_SECAPI | |
918 | } | |
919 | ||
920 | OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, | |
921 | SecItemClass *itemClass, SecKeychainAttributeList **attrList, | |
922 | UInt32 *length, void **outData) | |
923 | { | |
924 | BEGIN_SECAPI | |
925 | Item item = ItemImpl::required(itemRef); | |
926 | item->doNotEncrypt (); | |
927 | item->getAttributesAndData(info, itemClass, attrList, length, outData); | |
928 | END_SECAPI | |
929 | } | |
930 | ||
931 | OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data) | |
932 | { | |
933 | BEGIN_SECAPI | |
934 | Item item = ItemImpl::required(itemRef); | |
935 | item->doNotEncrypt (); | |
936 | item->modifyAttributesAndData(NULL, length, data); | |
937 | END_SECAPI | |
938 | } |