]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_keychain/lib/SecKeychainItem.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_keychain / lib / SecKeychainItem.cpp
1 /*
2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <Security/SecBase.h>
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>
31 #include <security_keychain/Certificate.h>
32 #include <security_keychain/Identity.h>
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 //
50 static
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 );
181
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);
188 if(ortn == errSecSuccess) {
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 }
196
197 /* now delete the item */
198 keychain->deleteItem( item );
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 }
213
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
248 #if 0
249 static
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 */
263 static
264 OSStatus SecAccessModifyObject(SecAccessRef accessRef, CFTypeRef sourceRef)
265 {
266 BEGIN_SECAPI
267 Access::required(accessRef)->setAccess(*aclBearer(sourceRef), true);
268 END_SECAPI
269 }
270 #endif
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);
293
294 END_SECAPI
295 }
296
297 /* Sets an item's data for legacy "KC" CoreServices APIs.
298 Note this version sets the data, but doesn't update the item
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))
316 MacOSError::throwMe(errSecParam);
317
318 CssmDataContainer aData;
319 ItemImpl::required(itemRef)->getData(aData);
320 if (actualLength)
321 *actualLength = (UInt32)aData.length();
322
323 if (data)
324 {
325 // Make sure the buffer is big enough
326 if (aData.length() > maxLength)
327 MacOSError::throwMe(errSecBufferTooSmall);
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.
392 Note: This version doesn't take a SecItemClass because
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);
404
405 Item item;
406 if (!cursor->next(item))
407 return errSecItemNotFound;
408
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);
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);
430 END_SECAPI
431 }
432
433 OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef)
434 {
435 BEGIN_SECAPI
436 KCThrowParamErrIf_(!persistentItemRef || !itemRef);
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();
451 }
452 *itemRef = (SecKeychainItemRef) result;
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);
479
480 Db db(keychain->database());
481
482 // make a raw database call to get the data
483 CSSM_DL_DB_HANDLE dbHandle = db.handle ();
484 CSSM_DB_UNIQUE_RECORD uniqueRecord;
485
486 // according to source, we should be able to reconsitute the uniqueRecord
487 // from the data we earlier retained
488
489 // prepare the record id
490 memset (&uniqueRecord, 0, sizeof (uniqueRecord));
491 uniqueRecord.RecordIdentifier.Data = (uint8*) CFDataGetBytePtr (recordIdentifier);
492 uniqueRecord.RecordIdentifier.Length = CFDataGetLength (recordIdentifier);
493
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);
499
500 // from this, get the record type
501 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData;
502 memset (&attributeData, 0, sizeof (attributeData));
503
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);
531
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);
570
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();
583
584 CSSM_DATA recordID;
585 item->copyRecordIdentifier (recordID);
586
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 }