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