2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <Security/SecBase.h>
25 #include <Security/SecKeychainItem.h>
26 #include <Security/SecKeychainItemPriv.h>
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
35 #include <securityd_client/dictionary.h>
36 #include <security_cdsa_utilities/Schema.h>
37 #include <Security/cssmapplePriv.h>
39 #include "SecBridge.h"
40 #include "KCExceptions.h"
42 #include "SecKeychainItemExtendedAttributes.h"
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.
51 RefPointer
<AclBearer
> aclBearer(CFTypeRef itemRef
)
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())
59 } else if (id
== gTypes().KeyItem
.typeID
) {
60 // key item, return the key itself.
61 if (CssmClient::Key key
= KeyItem::required(SecKeyRef(itemRef
))->key())
63 } else if (id
== gTypes().KeychainImpl
.typeID
) {
64 // keychain (this yields the database ACL)
65 //@@@ not hooked up yet
68 MacOSError::throwMe(errSecNoAccessForItem
);
73 SecKeychainItemGetTypeID(void)
77 return gTypes().ItemImpl
.typeID
;
79 END_SECAPI1(_kCFRuntimeNotATypeID
)
84 SecKeychainItemCreateFromContent(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
,
85 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
86 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
)
89 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
90 Item
item(itemClass
, attrList
, length
, data
);
92 item
->setAccess(Access::required(initialAccess
));
94 Keychain keychain
= nil
;
97 keychain
= Keychain::optional(keychainRef
);
98 if ( !keychain
->exists() )
100 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
105 keychain
= globals().storageManager
.defaultKeychainUI(item
);
110 *itemRef
= item
->handle();
116 SecKeychainItemModifyContent(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
119 Item item
= ItemImpl::required(itemRef
);
120 item
->modifyContent(attrList
, length
, data
);
126 SecKeychainItemCopyContent(SecKeychainItemRef itemRef
, SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
129 Item item
= ItemImpl::required(itemRef
);
130 item
->getContent(itemClass
, attrList
, length
, outData
);
136 SecKeychainItemFreeContent(SecKeychainAttributeList
*attrList
, void *data
)
139 ItemImpl::freeContent(attrList
, data
);
145 SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
148 Item item
= ItemImpl::required(itemRef
);
149 item
->modifyAttributesAndData(attrList
, length
, data
);
155 SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
158 Item item
= ItemImpl::required(itemRef
);
159 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
165 SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
168 ItemImpl::freeAttributesAndData(attrList
, data
);
174 SecKeychainItemDelete(SecKeychainItemRef itemRef
)
177 Item item
= ItemImpl::required( itemRef
);
178 Keychain keychain
= item
->keychain();
179 // item must be persistent.
180 KCThrowIf_( !keychain
, errSecInvalidItemRef
);
183 * Before deleting the item, delete any existing Extended Attributes.
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
);
197 /* now delete the item */
198 keychain
->deleteItem( item
);
204 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef
, SecKeychainRef
* keychainRef
)
207 // make sure this item has a keychain
208 Keychain kc
= ItemImpl::required(itemRef
)->keychain ();
211 MacOSError::throwMe(errSecNoSuchKeychain
);
214 Required(keychainRef
) = kc
->handle();
220 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef
, SecKeychainRef destKeychainRef
,
221 SecAccessRef initialAccess
, SecKeychainItemRef
*itemCopy
)
224 Item copy
= ItemImpl::required(itemRef
)->copyTo(Keychain::optional(destKeychainRef
), Access::optional(initialAccess
));
226 *itemCopy
= copy
->handle();
232 SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef
, const CSSM_DB_UNIQUE_RECORD
**uniqueRecordID
)
235 Required(uniqueRecordID
) = ItemImpl::required(itemRef
)->dbUniqueRecord();
241 SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef
, CSSM_DL_DB_HANDLE
* dldbHandle
)
244 *dldbHandle
= ItemImpl::required(itemRef
)->keychain()->database()->handle();
250 OSStatus
SecAccessCreateFromObject(CFTypeRef sourceRef
,
251 SecAccessRef
*accessRef
)
254 Required(accessRef
); // preflight
255 SecPointer
<Access
> access
= new Access(*aclBearer(sourceRef
));
256 *accessRef
= access
->handle();
264 OSStatus
SecAccessModifyObject(SecAccessRef accessRef
, CFTypeRef sourceRef
)
267 Access::required(accessRef
)->setAccess(*aclBearer(sourceRef
), true);
273 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef
, SecAccessRef
* accessRef
)
277 Required(accessRef
); // preflight
278 SecPointer
<Access
> access
= new Access(*aclBearer(reinterpret_cast<CFTypeRef
>(itemRef
)));
279 *accessRef
= access
->handle();
286 SecKeychainItemSetAccess(SecKeychainItemRef itemRef
, SecAccessRef accessRef
)
290 Access::required(accessRef
)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(itemRef
)), true);
292 ItemImpl::required(itemRef
)->postItemEvent (kSecUpdateEvent
);
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.
301 OSStatus
SecKeychainItemSetData(SecKeychainItemRef itemRef
, UInt32 length
, const void* data
)
304 ItemImpl::required(itemRef
)->setData(length
, data
);
308 /* Gets an item's data for legacy "KC" CoreServices APIs.
309 Note this version doesn't take a SecItemClass parameter.
311 OSStatus
SecKeychainItemGetData(SecKeychainItemRef itemRef
, UInt32 maxLength
, void* data
, UInt32
* actualLength
)
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
);
318 CssmDataContainer aData
;
319 ItemImpl::required(itemRef
)->getData(aData
);
321 *actualLength
= (UInt32
)aData
.length();
325 // Make sure the buffer is big enough
326 if (aData
.length() > maxLength
)
327 MacOSError::throwMe(errSecBufferTooSmall
);
328 memcpy(data
, aData
.data(), aData
.length());
333 /* Update a keychain item for legacy "KC" CoreServices APIs.
334 The "KC" API's do a 'set attribute', then an 'update'.
336 OSStatus
SecKeychainItemUpdate(SecKeychainItemRef itemRef
)
339 ItemImpl::required(itemRef
)->update();
343 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs.
345 OSStatus
SecKeychainItemAddNoUI(SecKeychainRef keychainRef
, SecKeychainItemRef itemRef
)
348 Item item
= ItemImpl::required(itemRef
);
349 Keychain::optional(keychainRef
)->add(item
);
353 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs.
355 OSStatus
SecKeychainItemAdd(SecKeychainItemRef itemRef
)
358 Item item
= ItemImpl::required(itemRef
);
359 Keychain defaultKeychain
= globals().storageManager
.defaultKeychainUI(item
);
360 defaultKeychain
->add(item
);
364 /* Creates a floating keychain item for legacy "KC" CoreServices APIs
366 OSStatus
SecKeychainItemCreateNew(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, SecKeychainItemRef
* itemRef
)
369 RequiredParam(itemRef
) = Item(itemClass
, itemCreator
, length
, data
, false)->handle();
373 /* Gets an individual attribute for legacy "KC" CoreServices APIs
375 OSStatus
SecKeychainItemGetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
, UInt32
* actualLength
)
378 ItemImpl::required(itemRef
)->getAttribute(RequiredParam(attribute
), actualLength
);
382 /* Sets an individual attribute for legacy "KC" CoreServices APIs
384 OSStatus
SecKeychainItemSetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
)
387 ItemImpl::required(itemRef
)->setAttribute(RequiredParam(attribute
));
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
396 OSStatus
SecKeychainItemFindFirst(SecKeychainRef keychainRef
, const SecKeychainAttributeList
*attrList
, SecKeychainSearchRef
*searchRef
, SecKeychainItemRef
*itemRef
)
401 cursor
= KeychainImpl::required(keychainRef
)->createCursor(attrList
);
403 cursor
= globals().storageManager
.createCursor(attrList
);
406 if (!cursor
->next(item
))
407 return errSecItemNotFound
;
409 *itemRef
=item
->handle();
411 *searchRef
=cursor
->handle();
415 OSStatus
SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef
, CFDataRef
*persistentItemRef
)
418 KCThrowParamErrIf_(!itemRef
|| !persistentItemRef
);
420 bool isIdentityRef
= (CFGetTypeID(itemRef
) == SecIdentityGetTypeID()) ? true : false;
422 SecPointer
<Certificate
> certificatePtr(Identity::required((SecIdentityRef
)itemRef
)->certificate());
423 SecCertificateRef certificateRef
= certificatePtr
->handle(false);
424 item
= ItemImpl::required((SecKeychainItemRef
)certificateRef
);
427 item
= ItemImpl::required(itemRef
);
429 item
->copyPersistentReference(*persistentItemRef
, isIdentityRef
);
433 OSStatus
SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef
, SecKeychainItemRef
*itemRef
)
436 KCThrowParamErrIf_(!persistentItemRef
|| !itemRef
);
437 CFTypeRef result
= NULL
;
438 bool isIdentityRef
= false;
439 Item item
= ItemImpl::makeFromPersistentReference(persistentItemRef
, &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
);
450 result
= item
->handle();
452 *itemRef
= (SecKeychainItemRef
) result
;
456 OSStatus
SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef
, CFDataRef
*recordIdentifier
)
460 RequiredParam (recordIdentifier
);
461 Item item
= ItemImpl::required(itemRef
);
462 item
->copyRecordIdentifier (data
);
463 *recordIdentifier
= ::CFDataCreate(kCFAllocatorDefault
, (UInt8
*) data
.Data
, data
.Length
);
469 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef
,
470 SecKeychainItemRef
*itemRef
,
471 CFDataRef recordIdentifier
)
474 // make a local Keychain reference
475 RequiredParam (keychainRef
);
476 Keychain keychain
= KeychainImpl::optional (keychainRef
);
477 RequiredParam (itemRef
);
478 RequiredParam (recordIdentifier
);
480 Db
db(keychain
->database());
482 // make a raw database call to get the data
483 CSSM_DL_DB_HANDLE dbHandle
= db
.handle ();
484 CSSM_DB_UNIQUE_RECORD uniqueRecord
;
486 // according to source, we should be able to reconsitute the uniqueRecord
487 // from the data we earlier retained
489 // prepare the record id
490 memset (&uniqueRecord
, 0, sizeof (uniqueRecord
));
491 uniqueRecord
.RecordIdentifier
.Data
= (uint8
*) CFDataGetBytePtr (recordIdentifier
);
492 uniqueRecord
.RecordIdentifier
.Length
= CFDataGetLength (recordIdentifier
);
494 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL
495 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr
;
497 result
= CSSM_DL_PassThrough (dbHandle
, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER
, &uniqueRecord
, (void**) &outputUniqueRecordPtr
);
498 KCThrowIf_(result
!= 0, errSecItemNotFound
);
500 // from this, get the record type
501 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData
;
502 memset (&attributeData
, 0, sizeof (attributeData
));
504 result
= CSSM_DL_DataGetFromUniqueRecordId (dbHandle
, outputUniqueRecordPtr
, &attributeData
, NULL
);
505 KCThrowIf_(result
!= 0, errSecItemNotFound
);
506 CSSM_DB_RECORDTYPE recordType
= attributeData
.DataRecordType
;
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
;
514 Item item
= keychain
->item (recordType
, unique
);
517 *itemRef
= item
->handle();
522 OSStatus
SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass
,
523 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
524 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
, CFDataRef
*localID
)
527 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
529 RequiredParam (localID
);
530 RequiredParam (keychainRef
);
532 Item
item(itemClass
, (uint32
) 0, length
, data
, true);
534 item
->setAccess(Access::required(initialAccess
));
536 Keychain keychain
= Keychain::optional(keychainRef
);
537 if (!keychain
->exists())
539 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
542 item
->doNotEncrypt ();
547 catch (const CommonError
&err
)
549 if (err
.osStatus () == errSecNoSuchClass
)
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
)
554 // create the certificate relation
555 Db
db(keychain
->database());
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
);
571 // add the item again
582 *itemRef
= item
->handle();
585 item
->copyRecordIdentifier (recordID
);
587 *localID
= CFDataCreate(kCFAllocatorDefault
, (UInt8
*) recordID
.Data
, recordID
.Length
);
588 free (recordID
.Data
);
592 OSStatus
SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
,
593 SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
,
594 UInt32
*length
, void **outData
)
597 Item item
= ItemImpl::required(itemRef
);
598 item
->doNotEncrypt ();
599 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
603 OSStatus
SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef
, UInt32 length
, const void *data
)
606 Item item
= ItemImpl::required(itemRef
);
607 item
->doNotEncrypt ();
608 item
->modifyAttributesAndData(NULL
, length
, data
);