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