]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
427c49bc A |
2 | * Copyright (c) 2000-2004,2012-2013 Apple Inc. All Rights Reserved. |
3 | * | |
b1ab9ed8 | 4 | * @APPLE_LICENSE_HEADER_START@ |
427c49bc | 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. | |
427c49bc | 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. | |
427c49bc | 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> | |
27 | ||
28 | #include <security_keychain/Keychains.h> | |
29 | #include <security_keychain/KeyItem.h> | |
30 | #include <security_keychain/Item.h> | |
427c49bc A |
31 | #include <security_keychain/Certificate.h> |
32 | #include <security_keychain/Identity.h> | |
b1ab9ed8 A |
33 | #include <security_keychain/KCCursor.h> // @@@ Remove this when SecKeychainItemFindFirst moves to SecKeychainSearch |
34 | ||
35 | #include <securityd_client/dictionary.h> | |
36 | #include <security_cdsa_utilities/Schema.h> | |
37 | #include <Security/cssmapplePriv.h> | |
38 | ||
39 | #include "SecBridge.h" | |
40 | #include "KCExceptions.h" | |
41 | #include "Access.h" | |
42 | #include "SecKeychainItemExtendedAttributes.h" | |
43 | ||
44 | // | |
45 | // Given a polymorphic Sec type object, return | |
46 | // its AclBearer component. | |
47 | // Note: Login ACLs are not hooked into this layer; | |
48 | // modules or attachments have no Sec* layer representation. | |
49 | // | |
427c49bc | 50 | static |
b1ab9ed8 A |
51 | RefPointer<AclBearer> aclBearer(CFTypeRef itemRef) |
52 | { | |
53 | // well, exactly what kind of something are you? | |
54 | CFTypeID id = CFGetTypeID(itemRef); | |
55 | if (id == gTypes().ItemImpl.typeID) { | |
56 | // keychain item. If it's in a protected group, return the group key | |
57 | if (SSGroup group = ItemImpl::required(SecKeychainItemRef(itemRef))->group()) | |
58 | return &*group; | |
59 | } else if (id == gTypes().KeyItem.typeID) { | |
60 | // key item, return the key itself. | |
61 | if (CssmClient::Key key = KeyItem::required(SecKeyRef(itemRef))->key()) | |
62 | return &*key; | |
63 | } else if (id == gTypes().KeychainImpl.typeID) { | |
64 | // keychain (this yields the database ACL) | |
65 | //@@@ not hooked up yet | |
66 | } | |
67 | // Guess not. Bummer | |
68 | MacOSError::throwMe(errSecNoAccessForItem); | |
69 | } | |
70 | ||
71 | ||
72 | CFTypeID | |
73 | SecKeychainItemGetTypeID(void) | |
74 | { | |
75 | BEGIN_SECAPI | |
76 | ||
77 | return gTypes().ItemImpl.typeID; | |
78 | ||
79 | END_SECAPI1(_kCFRuntimeNotATypeID) | |
80 | } | |
81 | ||
82 | ||
83 | OSStatus | |
84 | SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeList *attrList, | |
85 | UInt32 length, const void *data, SecKeychainRef keychainRef, | |
86 | SecAccessRef initialAccess, SecKeychainItemRef *itemRef) | |
87 | { | |
88 | BEGIN_SECAPI | |
89 | KCThrowParamErrIf_(length!=0 && data==NULL); | |
90 | Item item(itemClass, attrList, length, data); | |
91 | if (initialAccess) | |
92 | item->setAccess(Access::required(initialAccess)); | |
93 | ||
94 | Keychain keychain = nil; | |
95 | try | |
96 | { | |
97 | keychain = Keychain::optional(keychainRef); | |
98 | if ( !keychain->exists() ) | |
99 | { | |
100 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
101 | } | |
102 | } | |
103 | catch(...) | |
104 | { | |
105 | keychain = globals().storageManager.defaultKeychainUI(item); | |
106 | } | |
107 | ||
108 | keychain->add(item); | |
109 | if (itemRef) | |
110 | *itemRef = item->handle(); | |
111 | END_SECAPI | |
112 | } | |
113 | ||
114 | ||
115 | OSStatus | |
116 | SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) | |
117 | { | |
118 | BEGIN_SECAPI | |
119 | Item item = ItemImpl::required(itemRef); | |
120 | item->modifyContent(attrList, length, data); | |
121 | END_SECAPI | |
122 | } | |
123 | ||
124 | ||
125 | OSStatus | |
126 | SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData) | |
127 | { | |
128 | BEGIN_SECAPI | |
129 | Item item = ItemImpl::required(itemRef); | |
130 | item->getContent(itemClass, attrList, length, outData); | |
131 | END_SECAPI | |
132 | } | |
133 | ||
134 | ||
135 | OSStatus | |
136 | SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data) | |
137 | { | |
138 | BEGIN_SECAPI | |
139 | ItemImpl::freeContent(attrList, data); | |
140 | END_SECAPI | |
141 | } | |
142 | ||
143 | ||
144 | OSStatus | |
145 | SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) | |
146 | { | |
147 | BEGIN_SECAPI | |
148 | Item item = ItemImpl::required(itemRef); | |
149 | item->modifyAttributesAndData(attrList, length, data); | |
150 | END_SECAPI | |
151 | } | |
152 | ||
153 | ||
154 | OSStatus | |
155 | SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, SecItemClass *itemClass, SecKeychainAttributeList **attrList, UInt32 *length, void **outData) | |
156 | { | |
157 | BEGIN_SECAPI | |
158 | Item item = ItemImpl::required(itemRef); | |
159 | item->getAttributesAndData(info, itemClass, attrList, length, outData); | |
160 | END_SECAPI | |
161 | } | |
162 | ||
163 | ||
164 | OSStatus | |
165 | SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList *attrList, void *data) | |
166 | { | |
167 | BEGIN_SECAPI | |
168 | ItemImpl::freeAttributesAndData(attrList, data); | |
169 | END_SECAPI | |
170 | } | |
171 | ||
172 | ||
173 | OSStatus | |
174 | SecKeychainItemDelete(SecKeychainItemRef itemRef) | |
175 | { | |
176 | BEGIN_SECAPI | |
177 | Item item = ItemImpl::required( itemRef ); | |
178 | Keychain keychain = item->keychain(); | |
179 | // item must be persistent. | |
180 | KCThrowIf_( !keychain, errSecInvalidItemRef ); | |
427c49bc | 181 | |
b1ab9ed8 A |
182 | /* |
183 | * Before deleting the item, delete any existing Extended Attributes. | |
184 | */ | |
185 | OSStatus ortn; | |
186 | CFArrayRef attrNames = NULL; | |
187 | ortn = SecKeychainItemCopyAllExtendedAttributes(itemRef, &attrNames, NULL); | |
427c49bc | 188 | if(ortn == errSecSuccess) { |
b1ab9ed8 A |
189 | CFIndex numAttrs = CFArrayGetCount(attrNames); |
190 | for(CFIndex dex=0; dex<numAttrs; dex++) { | |
191 | CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(attrNames, dex); | |
192 | /* setting value to NULL ==> delete */ | |
193 | SecKeychainItemSetExtendedAttribute(itemRef, attrName, NULL); | |
194 | } | |
195 | } | |
427c49bc | 196 | |
b1ab9ed8 | 197 | /* now delete the item */ |
427c49bc | 198 | keychain->deleteItem( item ); |
b1ab9ed8 A |
199 | END_SECAPI |
200 | } | |
201 | ||
202 | ||
203 | OSStatus | |
204 | SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef* keychainRef) | |
205 | { | |
206 | BEGIN_SECAPI | |
207 | // make sure this item has a keychain | |
208 | Keychain kc = ItemImpl::required(itemRef)->keychain (); | |
209 | if (kc == NULL) | |
210 | { | |
211 | MacOSError::throwMe(errSecNoSuchKeychain); | |
212 | } | |
427c49bc | 213 | |
b1ab9ed8 A |
214 | Required(keychainRef) = kc->handle(); |
215 | END_SECAPI | |
216 | } | |
217 | ||
218 | ||
219 | OSStatus | |
220 | SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef destKeychainRef, | |
221 | SecAccessRef initialAccess, SecKeychainItemRef *itemCopy) | |
222 | { | |
223 | BEGIN_SECAPI | |
224 | Item copy = ItemImpl::required(itemRef)->copyTo(Keychain::optional(destKeychainRef), Access::optional(initialAccess)); | |
225 | if (itemCopy) | |
226 | *itemCopy = copy->handle(); | |
227 | END_SECAPI | |
228 | } | |
229 | ||
230 | ||
231 | OSStatus | |
232 | SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef, const CSSM_DB_UNIQUE_RECORD **uniqueRecordID) | |
233 | { | |
234 | BEGIN_SECAPI | |
235 | Required(uniqueRecordID) = ItemImpl::required(itemRef)->dbUniqueRecord(); | |
236 | END_SECAPI | |
237 | } | |
238 | ||
239 | ||
240 | OSStatus | |
241 | SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef, CSSM_DL_DB_HANDLE* dldbHandle) | |
242 | { | |
243 | BEGIN_SECAPI | |
244 | *dldbHandle = ItemImpl::required(itemRef)->keychain()->database()->handle(); | |
245 | END_SECAPI | |
246 | } | |
247 | ||
427c49bc A |
248 | #if 0 |
249 | static | |
b1ab9ed8 A |
250 | OSStatus SecAccessCreateFromObject(CFTypeRef sourceRef, |
251 | SecAccessRef *accessRef) | |
252 | { | |
253 | BEGIN_SECAPI | |
254 | Required(accessRef); // preflight | |
255 | SecPointer<Access> access = new Access(*aclBearer(sourceRef)); | |
256 | *accessRef = access->handle(); | |
257 | END_SECAPI | |
258 | } | |
259 | ||
260 | ||
261 | /*! | |
262 | */ | |
427c49bc | 263 | static |
b1ab9ed8 A |
264 | OSStatus SecAccessModifyObject(SecAccessRef accessRef, CFTypeRef sourceRef) |
265 | { | |
266 | BEGIN_SECAPI | |
267 | Access::required(accessRef)->setAccess(*aclBearer(sourceRef), true); | |
268 | END_SECAPI | |
269 | } | |
427c49bc | 270 | #endif |
b1ab9ed8 A |
271 | |
272 | OSStatus | |
273 | SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef) | |
274 | { | |
275 | BEGIN_SECAPI | |
276 | ||
277 | Required(accessRef); // preflight | |
278 | SecPointer<Access> access = new Access(*aclBearer(reinterpret_cast<CFTypeRef>(itemRef))); | |
279 | *accessRef = access->handle(); | |
280 | ||
281 | END_SECAPI | |
282 | } | |
283 | ||
284 | ||
285 | OSStatus | |
286 | SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef accessRef) | |
287 | { | |
288 | BEGIN_SECAPI | |
289 | ||
290 | Access::required(accessRef)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef>(itemRef)), true); | |
291 | ||
292 | ItemImpl::required(itemRef)->postItemEvent (kSecUpdateEvent); | |
427c49bc | 293 | |
b1ab9ed8 A |
294 | END_SECAPI |
295 | } | |
296 | ||
297 | /* Sets an item's data for legacy "KC" CoreServices APIs. | |
427c49bc | 298 | Note this version sets the data, but doesn't update the item |
b1ab9ed8 A |
299 | as the KC behavior dictates. |
300 | */ | |
301 | OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data) | |
302 | { | |
303 | BEGIN_SECAPI | |
304 | ItemImpl::required(itemRef)->setData(length, data); | |
305 | END_SECAPI | |
306 | } | |
307 | ||
308 | /* Gets an item's data for legacy "KC" CoreServices APIs. | |
309 | Note this version doesn't take a SecItemClass parameter. | |
310 | */ | |
311 | OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength) | |
312 | { | |
313 | BEGIN_SECAPI | |
314 | /* 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. */ | |
315 | if (!((data && maxLength) || actualLength)) | |
427c49bc | 316 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
317 | |
318 | CssmDataContainer aData; | |
319 | ItemImpl::required(itemRef)->getData(aData); | |
320 | if (actualLength) | |
427c49bc A |
321 | *actualLength = (UInt32)aData.length(); |
322 | ||
b1ab9ed8 A |
323 | if (data) |
324 | { | |
325 | // Make sure the buffer is big enough | |
326 | if (aData.length() > maxLength) | |
427c49bc | 327 | MacOSError::throwMe(errSecBufferTooSmall); |
b1ab9ed8 A |
328 | memcpy(data, aData.data(), aData.length()); |
329 | } | |
330 | END_SECAPI | |
331 | } | |
332 | ||
333 | /* Update a keychain item for legacy "KC" CoreServices APIs. | |
334 | The "KC" API's do a 'set attribute', then an 'update'. | |
335 | */ | |
336 | OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef) | |
337 | { | |
338 | BEGIN_SECAPI | |
339 | ItemImpl::required(itemRef)->update(); | |
340 | END_SECAPI | |
341 | } | |
342 | ||
343 | /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs. | |
344 | */ | |
345 | OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef) | |
346 | { | |
347 | BEGIN_SECAPI | |
348 | Item item = ItemImpl::required(itemRef); | |
349 | Keychain::optional(keychainRef)->add(item); | |
350 | END_SECAPI | |
351 | } | |
352 | ||
353 | /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs. | |
354 | */ | |
355 | OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef) | |
356 | { | |
357 | BEGIN_SECAPI | |
358 | Item item = ItemImpl::required(itemRef); | |
359 | Keychain defaultKeychain = globals().storageManager.defaultKeychainUI(item); | |
360 | defaultKeychain->add(item); | |
361 | END_SECAPI | |
362 | } | |
363 | ||
364 | /* Creates a floating keychain item for legacy "KC" CoreServices APIs | |
365 | */ | |
366 | OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef) | |
367 | { | |
368 | BEGIN_SECAPI | |
369 | RequiredParam(itemRef) = Item(itemClass, itemCreator, length, data, false)->handle(); | |
370 | END_SECAPI | |
371 | } | |
372 | ||
373 | /* Gets an individual attribute for legacy "KC" CoreServices APIs | |
374 | */ | |
375 | OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength) | |
376 | { | |
377 | BEGIN_SECAPI | |
378 | ItemImpl::required(itemRef)->getAttribute(RequiredParam(attribute), actualLength); | |
379 | END_SECAPI | |
380 | } | |
381 | ||
382 | /* Sets an individual attribute for legacy "KC" CoreServices APIs | |
383 | */ | |
384 | OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute) | |
385 | { | |
386 | BEGIN_SECAPI | |
387 | ItemImpl::required(itemRef)->setAttribute(RequiredParam(attribute)); | |
388 | END_SECAPI | |
389 | } | |
390 | ||
391 | /* Finds a keychain item for legacy "KC" CoreServices APIs. | |
427c49bc | 392 | Note: This version doesn't take a SecItemClass because |
b1ab9ed8 A |
393 | SecKeychainSearchCreateFromAttributes() requires it. |
394 | @@@ This should move to SecKeychainSearch.cpp | |
395 | */ | |
396 | OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef) | |
397 | { | |
398 | BEGIN_SECAPI | |
399 | KCCursor cursor; | |
400 | if (keychainRef) | |
401 | cursor = KeychainImpl::required(keychainRef)->createCursor(attrList); | |
402 | else | |
403 | cursor = globals().storageManager.createCursor(attrList); | |
427c49bc | 404 | |
b1ab9ed8 A |
405 | Item item; |
406 | if (!cursor->next(item)) | |
427c49bc A |
407 | return errSecItemNotFound; |
408 | ||
b1ab9ed8 A |
409 | *itemRef=item->handle(); |
410 | if (searchRef) | |
411 | *searchRef=cursor->handle(); | |
412 | END_SECAPI | |
413 | } | |
414 | ||
415 | OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef *persistentItemRef) | |
416 | { | |
417 | BEGIN_SECAPI | |
418 | KCThrowParamErrIf_(!itemRef || !persistentItemRef); | |
427c49bc A |
419 | Item item; |
420 | bool isIdentityRef = (CFGetTypeID(itemRef) == SecIdentityGetTypeID()) ? true : false; | |
421 | if (isIdentityRef) { | |
422 | SecPointer<Certificate> certificatePtr(Identity::required((SecIdentityRef)itemRef)->certificate()); | |
423 | SecCertificateRef certificateRef = certificatePtr->handle(false); | |
424 | item = ItemImpl::required((SecKeychainItemRef)certificateRef); | |
425 | } | |
426 | else { | |
427 | item = ItemImpl::required(itemRef); | |
428 | } | |
429 | item->copyPersistentReference(*persistentItemRef, isIdentityRef); | |
b1ab9ed8 A |
430 | END_SECAPI |
431 | } | |
432 | ||
433 | OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef) | |
434 | { | |
435 | BEGIN_SECAPI | |
436 | KCThrowParamErrIf_(!persistentItemRef || !itemRef); | |
427c49bc A |
437 | CFTypeRef result = NULL; |
438 | bool isIdentityRef = false; | |
439 | Item item = ItemImpl::makeFromPersistentReference(persistentItemRef, &isIdentityRef); | |
440 | if (isIdentityRef) { | |
441 | // item was stored as an identity, attempt to reconstitute it | |
442 | SecPointer<Certificate> certificatePtr(static_cast<Certificate *>(item.get())); | |
443 | StorageManager::KeychainList keychains; | |
444 | globals().storageManager.optionalSearchList(NULL, keychains); | |
445 | SecPointer<Identity> identityPtr(new Identity(keychains, certificatePtr)); | |
446 | result = identityPtr->handle(); | |
447 | KCThrowIf_( !result, errSecItemNotFound ); | |
448 | } | |
449 | if (!result) { | |
450 | result = item->handle(); | |
b1ab9ed8 | 451 | } |
427c49bc | 452 | *itemRef = (SecKeychainItemRef) result; |
b1ab9ed8 A |
453 | END_SECAPI |
454 | } | |
455 | ||
456 | OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier) | |
457 | { | |
458 | BEGIN_SECAPI | |
459 | CSSM_DATA data; | |
460 | RequiredParam (recordIdentifier); | |
461 | Item item = ItemImpl::required(itemRef); | |
462 | item->copyRecordIdentifier (data); | |
463 | *recordIdentifier = ::CFDataCreate(kCFAllocatorDefault, (UInt8*) data.Data, data.Length); | |
464 | free (data.Data); | |
465 | END_SECAPI | |
466 | } | |
467 | ||
468 | OSStatus | |
469 | SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef, | |
470 | SecKeychainItemRef *itemRef, | |
471 | CFDataRef recordIdentifier) | |
472 | { | |
473 | BEGIN_SECAPI | |
474 | // make a local Keychain reference | |
475 | RequiredParam (keychainRef); | |
476 | Keychain keychain = KeychainImpl::optional (keychainRef); | |
477 | RequiredParam (itemRef); | |
478 | RequiredParam (recordIdentifier); | |
427c49bc | 479 | |
b1ab9ed8 | 480 | Db db(keychain->database()); |
427c49bc | 481 | |
b1ab9ed8 A |
482 | // make a raw database call to get the data |
483 | CSSM_DL_DB_HANDLE dbHandle = db.handle (); | |
484 | CSSM_DB_UNIQUE_RECORD uniqueRecord; | |
427c49bc | 485 | |
b1ab9ed8 A |
486 | // according to source, we should be able to reconsitute the uniqueRecord |
487 | // from the data we earlier retained | |
427c49bc | 488 | |
b1ab9ed8 A |
489 | // prepare the record id |
490 | memset (&uniqueRecord, 0, sizeof (uniqueRecord)); | |
491 | uniqueRecord.RecordIdentifier.Data = (uint8*) CFDataGetBytePtr (recordIdentifier); | |
492 | uniqueRecord.RecordIdentifier.Length = CFDataGetLength (recordIdentifier); | |
427c49bc | 493 | |
b1ab9ed8 A |
494 | // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL |
495 | CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr; | |
496 | CSSM_RETURN result; | |
497 | result = CSSM_DL_PassThrough (dbHandle, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER, &uniqueRecord, (void**) &outputUniqueRecordPtr); | |
498 | KCThrowIf_(result != 0, errSecItemNotFound); | |
427c49bc | 499 | |
b1ab9ed8 A |
500 | // from this, get the record type |
501 | CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData; | |
502 | memset (&attributeData, 0, sizeof (attributeData)); | |
427c49bc | 503 | |
b1ab9ed8 A |
504 | result = CSSM_DL_DataGetFromUniqueRecordId (dbHandle, outputUniqueRecordPtr, &attributeData, NULL); |
505 | KCThrowIf_(result != 0, errSecItemNotFound); | |
506 | CSSM_DB_RECORDTYPE recordType = attributeData.DataRecordType; | |
507 | ||
508 | // make the unique record item -- precursor to creation of a SecKeychainItemRef | |
509 | DbUniqueRecord unique(db); | |
510 | CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = unique; | |
511 | *uniquePtr = outputUniqueRecordPtr; | |
512 | ||
513 | unique->activate (); | |
514 | Item item = keychain->item (recordType, unique); | |
515 | if (itemRef) | |
516 | { | |
517 | *itemRef = item->handle(); | |
518 | } | |
519 | END_SECAPI | |
520 | } | |
521 | ||
522 | OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass, | |
523 | UInt32 length, const void *data, SecKeychainRef keychainRef, | |
524 | SecAccessRef initialAccess, SecKeychainItemRef *itemRef, CFDataRef *localID) | |
525 | { | |
526 | BEGIN_SECAPI | |
527 | KCThrowParamErrIf_(length!=0 && data==NULL); | |
528 | ||
529 | RequiredParam (localID); | |
530 | RequiredParam (keychainRef); | |
427c49bc | 531 | |
b1ab9ed8 A |
532 | Item item(itemClass, (uint32) 0, length, data, true); |
533 | if (initialAccess) | |
534 | item->setAccess(Access::required(initialAccess)); | |
535 | ||
536 | Keychain keychain = Keychain::optional(keychainRef); | |
537 | if (!keychain->exists()) | |
538 | { | |
539 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
540 | } | |
541 | ||
542 | item->doNotEncrypt (); | |
543 | try | |
544 | { | |
545 | keychain->add(item); | |
546 | } | |
547 | catch (const CommonError &err) | |
548 | { | |
549 | if (err.osStatus () == errSecNoSuchClass) | |
550 | { | |
551 | // the only time this should happen is if the item is a certificate (for keychain syncing) | |
552 | if (itemClass == CSSM_DL_DB_RECORD_X509_CERTIFICATE) | |
553 | { | |
554 | // create the certificate relation | |
555 | Db db(keychain->database()); | |
556 | ||
557 | db->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE, | |
558 | "CSSM_DL_DB_RECORD_X509_CERTIFICATE", | |
559 | Schema::X509CertificateSchemaAttributeCount, | |
560 | Schema::X509CertificateSchemaAttributeList, | |
561 | Schema::X509CertificateSchemaIndexCount, | |
562 | Schema::X509CertificateSchemaIndexList); | |
563 | keychain->keychainSchema()->didCreateRelation( | |
564 | CSSM_DL_DB_RECORD_X509_CERTIFICATE, | |
565 | "CSSM_DL_DB_RECORD_X509_CERTIFICATE", | |
566 | Schema::X509CertificateSchemaAttributeCount, | |
567 | Schema::X509CertificateSchemaAttributeList, | |
568 | Schema::X509CertificateSchemaIndexCount, | |
569 | Schema::X509CertificateSchemaIndexList); | |
427c49bc | 570 | |
b1ab9ed8 A |
571 | // add the item again |
572 | keychain->add(item); | |
573 | } | |
574 | } | |
575 | else | |
576 | { | |
577 | throw; | |
578 | } | |
579 | } | |
580 | ||
581 | if (itemRef) | |
582 | *itemRef = item->handle(); | |
427c49bc | 583 | |
b1ab9ed8 A |
584 | CSSM_DATA recordID; |
585 | item->copyRecordIdentifier (recordID); | |
427c49bc | 586 | |
b1ab9ed8 A |
587 | *localID = CFDataCreate(kCFAllocatorDefault, (UInt8*) recordID.Data, recordID.Length); |
588 | free (recordID.Data); | |
589 | END_SECAPI | |
590 | } | |
591 | ||
592 | OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, | |
593 | SecItemClass *itemClass, SecKeychainAttributeList **attrList, | |
594 | UInt32 *length, void **outData) | |
595 | { | |
596 | BEGIN_SECAPI | |
597 | Item item = ItemImpl::required(itemRef); | |
598 | item->doNotEncrypt (); | |
599 | item->getAttributesAndData(info, itemClass, attrList, length, outData); | |
600 | END_SECAPI | |
601 | } | |
602 | ||
603 | OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data) | |
604 | { | |
605 | BEGIN_SECAPI | |
606 | Item item = ItemImpl::required(itemRef); | |
607 | item->doNotEncrypt (); | |
608 | item->modifyAttributesAndData(NULL, length, data); | |
609 | END_SECAPI | |
610 | } |