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/SecKeychain.h>
25 #include <Security/SecKeychainPriv.h>
26 #include <security_keychain/KCCursor.h>
27 #include <security_cdsa_utilities/cssmdata.h>
28 #include <security_cdsa_client/wrapkey.h>
29 #include <security_keychain/KCExceptions.h>
30 #include <securityd_client/ssblob.h>
31 #include <Security/SecAccess.h>
32 #include <Security/SecTrustedApplicationPriv.h>
33 #include "SecBridge.h"
34 #include "CCallbackMgr.h"
35 #include <security_cdsa_utilities/Schema.h>
36 #include <security_cdsa_client/mdsclient.h>
40 SecKeychainMDSInstall()
44 Security::MDSClient::Directory d
;
51 SecKeychainGetTypeID(void)
55 return gTypes().KeychainImpl
.typeID
;
57 END_SECAPI1(_kCFRuntimeNotATypeID
)
62 SecKeychainGetVersion(UInt32
*returnVers
)
67 *returnVers
= 0x02028000;
73 SecKeychainOpen(const char *pathName
, SecKeychainRef
*keychainRef
)
77 RequiredParam(keychainRef
)=globals().storageManager
.make(pathName
, false)->handle();
84 SecKeychainOpenWithGuid(const CSSM_GUID
*guid
, uint32 subserviceId
, uint32 subserviceType
, const char* dbName
,
85 const CSSM_NET_ADDRESS
*dbLocation
, SecKeychainRef
*keychain
)
89 // range check parameters
91 RequiredParam (dbName
);
93 // create a DLDbIdentifier that describes what should be opened
94 const CSSM_VERSION
*version
= NULL
;
95 const CssmSubserviceUid
ssuid(*guid
, version
, subserviceId
, subserviceType
);
96 DLDbIdentifier
dLDbIdentifier(ssuid
, dbName
, dbLocation
);
98 // make a keychain from the supplied info
99 RequiredParam(keychain
) = globals().storageManager
.makeKeychain(dLDbIdentifier
, false)->handle ();
106 SecKeychainCreate(const char *pathName
, UInt32 passwordLength
, const void *password
,
107 Boolean promptUser
, SecAccessRef initialAccess
, SecKeychainRef
*keychainRef
)
111 KCThrowParamErrIf_(!pathName
);
112 Keychain keychain
= globals().storageManager
.make(pathName
);
114 // @@@ the call to StorageManager::make above leaves keychain the the cache.
115 // If the create below fails we should probably remove it.
120 KCThrowParamErrIf_(!password
);
121 keychain
->create(passwordLength
, password
);
124 RequiredParam(keychainRef
)=keychain
->handle();
131 SecKeychainDelete(SecKeychainRef keychainOrArray
)
135 KCThrowIf_(!keychainOrArray
, errSecInvalidKeychain
);
136 StorageManager::KeychainList keychains
;
137 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
139 globals().storageManager
.remove(keychains
, true);
146 SecKeychainSetSettings(SecKeychainRef keychainRef
, const SecKeychainSettings
*newSettings
)
150 Keychain keychain
= Keychain::optional(keychainRef
);
151 if (newSettings
->version
==SEC_KEYCHAIN_SETTINGS_VERS1
)
153 UInt32 lockInterval
=newSettings
->lockInterval
;
154 bool lockOnSleep
=newSettings
->lockOnSleep
;
155 keychain
->setSettings(lockInterval
, lockOnSleep
);
163 SecKeychainCopySettings(SecKeychainRef keychainRef
, SecKeychainSettings
*outSettings
)
167 Keychain keychain
= Keychain::optional(keychainRef
);
168 if (outSettings
->version
==SEC_KEYCHAIN_SETTINGS_VERS1
)
173 keychain
->getSettings(lockInterval
, lockOnSleep
);
174 outSettings
->lockInterval
=lockInterval
;
175 outSettings
->lockOnSleep
=lockOnSleep
;
183 SecKeychainUnlock(SecKeychainRef keychainRef
, UInt32 passwordLength
, const void *password
, Boolean usePassword
)
187 Keychain keychain
= Keychain::optional(keychainRef
);
190 keychain
->unlock(CssmData(const_cast<void *>(password
), passwordLength
));
199 SecKeychainLock(SecKeychainRef keychainRef
)
203 Keychain keychain
= Keychain::optional(keychainRef
);
211 SecKeychainLockAll(void)
215 globals().storageManager
.lockAll();
221 OSStatus
SecKeychainResetLogin(UInt32 passwordLength
, const void* password
, Boolean resetSearchList
)
225 // Get the current user (using fallback method if necessary)
227 char* uName
= getenv("USER");
228 string userName
= uName
? uName
: "";
229 if ( userName
.length() == 0 )
231 uid_t uid
= geteuid();
232 if (!uid
) uid
= getuid();
233 struct passwd
*pw
= getpwuid(uid
); // fallback case...
235 userName
= pw
->pw_name
;
238 if ( userName
.length() == 0 ) // did we ultimately get one?
239 MacOSError::throwMe(errAuthorizationInternal
);
241 SecurityServer::ClientSession().resetKeyStorePassphrase(password
? CssmData(const_cast<void *>(password
), passwordLength
) : CssmData());
245 // Clear the plist and move aside (rename) the existing login.keychain
246 globals().storageManager
.resetKeychain(resetSearchList
);
248 // Create the login keychain without UI
249 globals().storageManager
.login((UInt32
)userName
.length(), userName
.c_str(), passwordLength
, password
);
251 // Set it as the default
252 Keychain keychain
= globals().storageManager
.loginKeychain();
253 globals().storageManager
.defaultKeychain(keychain
);
257 // Create the login keychain, prompting for password
258 // (implicitly calls resetKeychain, login, and defaultKeychain)
259 globals().storageManager
.makeLoginAuthUI(NULL
);
262 // Post a "list changed" event after a reset, so apps can refresh their list.
263 // Make sure we are not holding mLock when we post this event.
264 KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent
);
270 SecKeychainCopyDefault(SecKeychainRef
*keychainRef
)
274 RequiredParam(keychainRef
)=globals().storageManager
.defaultKeychain()->handle();
281 SecKeychainSetDefault(SecKeychainRef keychainRef
)
285 globals().storageManager
.defaultKeychain(Keychain::optional(keychainRef
));
290 OSStatus
SecKeychainCopySearchList(CFArrayRef
*searchList
)
294 RequiredParam(searchList
);
295 StorageManager
&smr
= globals().storageManager
;
296 StorageManager::KeychainList keychainList
;
297 smr
.getSearchList(keychainList
);
298 *searchList
= smr
.convertFromKeychainList(keychainList
);
303 OSStatus
SecKeychainSetSearchList(CFArrayRef searchList
)
307 RequiredParam(searchList
);
308 StorageManager
&smr
= globals().storageManager
;
309 StorageManager::KeychainList keychainList
;
310 smr
.convertToKeychainList(searchList
, keychainList
);
311 smr
.setSearchList(keychainList
);
316 OSStatus
SecKeychainCopyDomainDefault(SecPreferencesDomain domain
, SecKeychainRef
*keychainRef
)
320 RequiredParam(keychainRef
)=globals().storageManager
.defaultKeychain(domain
)->handle();
325 OSStatus
SecKeychainSetDomainDefault(SecPreferencesDomain domain
, SecKeychainRef keychainRef
)
329 globals().storageManager
.defaultKeychain(domain
, Keychain::optional(keychainRef
));
334 OSStatus
SecKeychainCopyDomainSearchList(SecPreferencesDomain domain
, CFArrayRef
*searchList
)
338 RequiredParam(searchList
);
339 StorageManager
&smr
= globals().storageManager
;
340 StorageManager::KeychainList keychainList
;
341 smr
.getSearchList(domain
, keychainList
);
342 *searchList
= smr
.convertFromKeychainList(keychainList
);
347 OSStatus
SecKeychainSetDomainSearchList(SecPreferencesDomain domain
, CFArrayRef searchList
)
351 RequiredParam(searchList
);
352 StorageManager
&smr
= globals().storageManager
;
353 StorageManager::KeychainList keychainList
;
354 smr
.convertToKeychainList(searchList
, keychainList
);
355 smr
.setSearchList(domain
, keychainList
);
360 OSStatus
SecKeychainSetPreferenceDomain(SecPreferencesDomain domain
)
364 globals().storageManager
.domain(domain
);
369 OSStatus
SecKeychainGetPreferenceDomain(SecPreferencesDomain
*domain
)
373 *domain
= globals().storageManager
.domain();
380 SecKeychainGetStatus(SecKeychainRef keychainRef
, SecKeychainStatus
*keychainStatus
)
384 RequiredParam(keychainStatus
) = (SecKeychainStatus
)Keychain::optional(keychainRef
)->status();
391 SecKeychainGetPath(SecKeychainRef keychainRef
, UInt32
*ioPathLength
, char *pathName
)
395 RequiredParam(pathName
);
396 RequiredParam(ioPathLength
);
398 const char *name
= Keychain::optional(keychainRef
)->name();
399 UInt32 nameLen
= (UInt32
)strlen(name
);
400 UInt32 callersLen
= *ioPathLength
;
401 *ioPathLength
= nameLen
;
402 if (nameLen
+1 > callersLen
) // if the client's buffer is too small (including null-termination), throw
403 return errSecBufferTooSmall
;
404 strncpy(pathName
, name
, nameLen
);
405 pathName
[nameLen
] = 0;
406 *ioPathLength
= nameLen
; // set the length.
412 SecKeychainGetKeychainVersion(SecKeychainRef keychainRef
, UInt32
* version
)
416 RequiredParam(version
);
418 *version
= Keychain::optional(keychainRef
)->database()->dbBlobVersion();
426 SecKeychainListGetCount(void)
430 return globals().storageManager
.size();
438 SecKeychainListCopyKeychainAtIndex(UInt16 index
, SecKeychainRef
*keychainRef
)
442 KeychainCore::StorageManager
&smgr
=KeychainCore::globals().storageManager
;
443 RequiredParam(keychainRef
)=smgr
[index
]->handle();
451 SecKeychainListRemoveKeychain(SecKeychainRef
*keychainRef
)
455 Required(keychainRef
);
456 Keychain keychain
= Keychain::optional(*keychainRef
);
457 StorageManager::KeychainList keychainList
;
458 keychainList
.push_back(keychain
);
459 globals().storageManager
.remove(keychainList
);
467 SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef
, UInt32 itemID
, SecKeychainAttributeInfo
**info
)
471 Keychain keychain
= Keychain::optional(keychainRef
);
472 keychain
->getAttributeInfoForItemID(itemID
, info
);
479 SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo
*info
)
483 KeychainImpl::freeAttributeInfo(info
);
490 SecKeychainAddCallback(SecKeychainCallback callbackFunction
, SecKeychainEventMask eventMask
, void* userContext
)
494 RequiredParam(callbackFunction
);
495 CCallbackMgr::AddCallback(callbackFunction
,eventMask
,userContext
);
502 SecKeychainRemoveCallback(SecKeychainCallback callbackFunction
)
506 RequiredParam(callbackFunction
);
507 CCallbackMgr::RemoveCallback(callbackFunction
);
513 SecKeychainAddInternetPassword(SecKeychainRef keychainRef
, UInt32 serverNameLength
, const char *serverName
, UInt32 securityDomainLength
, const char *securityDomain
, UInt32 accountNameLength
, const char *accountName
, UInt32 pathLength
, const char *path
, UInt16 port
, SecProtocolType protocol
, SecAuthenticationType authenticationType
, UInt32 passwordLength
, const void *passwordData
, SecKeychainItemRef
*itemRef
)
517 KCThrowParamErrIf_(passwordLength
!=0 && passwordData
==NULL
);
518 // @@@ Get real itemClass
519 Item
item(kSecInternetPasswordItemClass
, 'aapl', passwordLength
, passwordData
, false);
521 if (serverName
&& serverNameLength
)
523 CssmData
server(const_cast<void *>(reinterpret_cast<const void *>(serverName
)), serverNameLength
);
524 item
->setAttribute(Schema::attributeInfo(kSecServerItemAttr
), server
);
525 // use server name as default label
526 item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), server
);
529 if (accountName
&& accountNameLength
)
531 CssmData
account(const_cast<void *>(reinterpret_cast<const void *>(accountName
)), accountNameLength
);
532 item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
);
535 if (securityDomain
&& securityDomainLength
)
536 item
->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr
),
537 CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain
)), securityDomainLength
));
539 item
->setAttribute(Schema::attributeInfo(kSecPortItemAttr
), UInt32(port
));
540 item
->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr
), protocol
);
541 item
->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr
), authenticationType
);
543 if (path
&& pathLength
)
544 item
->setAttribute(Schema::attributeInfo(kSecPathItemAttr
),
545 CssmData(const_cast<void *>(reinterpret_cast<const void *>(path
)), pathLength
));
547 Keychain keychain
= nil
;
550 keychain
= Keychain::optional(keychainRef
);
551 if ( !keychain
->exists() )
553 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
558 keychain
= globals().storageManager
.defaultKeychainUI(item
);
564 *itemRef
= item
->handle();
571 SecKeychainFindInternetPassword(CFTypeRef keychainOrArray
, UInt32 serverNameLength
, const char *serverName
, UInt32 securityDomainLength
, const char *securityDomain
, UInt32 accountNameLength
, const char *accountName
, UInt32 pathLength
, const char *path
, UInt16 port
, SecProtocolType protocol
, SecAuthenticationType authenticationType
, UInt32
*passwordLength
, void **passwordData
, SecKeychainItemRef
*itemRef
)
576 StorageManager::KeychainList keychains
;
577 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
578 KCCursor
cursor(keychains
, kSecInternetPasswordItemClass
, NULL
);
580 if (serverName
&& serverNameLength
)
582 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServerItemAttr
),
583 CssmData(const_cast<char *>(serverName
), serverNameLength
));
586 if (securityDomain
&& securityDomainLength
)
588 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecSecurityDomainItemAttr
),
589 CssmData (const_cast<char*>(securityDomain
), securityDomainLength
));
592 if (accountName
&& accountNameLength
)
594 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecAccountItemAttr
),
595 CssmData (const_cast<char*>(accountName
), accountNameLength
));
600 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecPortItemAttr
),
606 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecProtocolItemAttr
),
610 if (authenticationType
)
612 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecAuthenticationTypeItemAttr
),
616 if (path
&& pathLength
)
618 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecPathItemAttr
), path
);
622 if (!cursor
->next(item
))
623 return errSecItemNotFound
;
625 // Get its data (only if necessary)
626 if (passwordData
|| passwordLength
)
628 CssmDataContainer outData
;
629 item
->getData(outData
);
630 *passwordLength
=(UInt32
)outData
.length();
632 *passwordData
=outData
.data();
637 *itemRef
=item
->handle();
644 SecKeychainAddGenericPassword(SecKeychainRef keychainRef
, UInt32 serviceNameLength
, const char *serviceName
, UInt32 accountNameLength
, const char *accountName
, UInt32 passwordLength
, const void *passwordData
, SecKeychainItemRef
*itemRef
)
648 KCThrowParamErrIf_(passwordLength
!=0 && passwordData
==NULL
);
649 // @@@ Get real itemClass
651 Item
item(kSecGenericPasswordItemClass
, 'aapl', passwordLength
, passwordData
, false);
653 if (serviceName
&& serviceNameLength
)
655 CssmData
service(const_cast<void *>(reinterpret_cast<const void *>(serviceName
)), serviceNameLength
);
656 item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), service
);
657 // use service name as default label (UNLESS the service is iTools and we have an account name [3787371])
658 const char *iTools
= "iTools";
659 if (accountNameLength
&& serviceNameLength
==strlen(iTools
) && !memcmp(serviceName
, iTools
, serviceNameLength
))
661 CssmData
account(const_cast<void *>(reinterpret_cast<const void *>(accountName
)), accountNameLength
);
662 item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), account
);
666 item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), service
);
670 if (accountName
&& accountNameLength
)
672 CssmData
account(const_cast<void *>(reinterpret_cast<const void *>(accountName
)), accountNameLength
);
673 item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
);
676 Keychain keychain
= nil
;
679 keychain
= Keychain::optional(keychainRef
);
680 if ( !keychain
->exists() )
682 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
687 keychain
= globals().storageManager
.defaultKeychainUI(item
);
692 *itemRef
= item
->handle();
699 SecKeychainFindGenericPassword(CFTypeRef keychainOrArray
, UInt32 serviceNameLength
, const char *serviceName
, UInt32 accountNameLength
, const char *accountName
, UInt32
*passwordLength
, void **passwordData
, SecKeychainItemRef
*itemRef
)
704 StorageManager::KeychainList keychains
;
705 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
706 KCCursor
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
);
708 if (serviceName
&& serviceNameLength
)
710 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
),
711 CssmData(const_cast<char *>(serviceName
), serviceNameLength
));
714 if (accountName
&& accountNameLength
)
716 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecAccountItemAttr
),
717 CssmData(const_cast<char *>(accountName
), accountNameLength
));
721 if (!cursor
->next(item
))
722 return errSecItemNotFound
;
724 // Get its data (only if necessary)
725 if (passwordData
|| passwordLength
)
727 CssmDataContainer outData
;
728 item
->getData(outData
);
729 *passwordLength
=(UInt32
)outData
.length();
731 *passwordData
=outData
.data();
736 *itemRef
=item
->handle();
743 SecKeychainSetUserInteractionAllowed(Boolean state
)
747 globals().setUserInteractionAllowed(state
);
754 SecKeychainGetUserInteractionAllowed(Boolean
*state
)
758 Required(state
)=globals().getUserInteractionAllowed();
765 SecKeychainGetDLDBHandle(SecKeychainRef keychainRef
, CSSM_DL_DB_HANDLE
*dldbHandle
)
769 RequiredParam(dldbHandle
);
771 Keychain keychain
= Keychain::optional(keychainRef
);
772 *dldbHandle
= keychain
->database()->handle();
779 SecKeychainGetCSPHandle(SecKeychainRef keychainRef
, CSSM_CSP_HANDLE
*cspHandle
)
783 RequiredParam(cspHandle
);
785 Keychain keychain
= Keychain::optional(keychainRef
);
786 *cspHandle
= keychain
->csp()->handle();
793 SecKeychainCopyAccess(SecKeychainRef keychainRef
, SecAccessRef
*accessRef
)
797 MacOSError::throwMe(errSecUnimplemented
);//%%%for now
804 SecKeychainSetAccess(SecKeychainRef keychainRef
, SecAccessRef accessRef
)
808 MacOSError::throwMe(errSecUnimplemented
);//%%%for now
814 #pragma mark ---- Private API ----
818 SecKeychainChangePassword(SecKeychainRef keychainRef
, UInt32 oldPasswordLength
, const void *oldPassword
, UInt32 newPasswordLength
, const void *newPassword
)
822 Keychain keychain
= Keychain::optional(keychainRef
);
823 keychain
->changePassphrase (oldPasswordLength
, oldPassword
, newPasswordLength
, newPassword
);
830 SecKeychainCopyLogin(SecKeychainRef
*keychainRef
)
834 RequiredParam(keychainRef
)=globals().storageManager
.loginKeychain()->handle();
841 SecKeychainLogin(UInt32 nameLength
, const void* name
, UInt32 passwordLength
, const void* password
)
848 globals().storageManager
.login(nameLength
, name
, passwordLength
, password
);
850 globals().storageManager
.stashLogin();
853 catch (CommonError
&e
)
855 if (e
.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED
)
857 return errSecAuthFailed
;
868 OSStatus
SecKeychainStash()
874 globals().storageManager
.stashKeychain();
876 catch (CommonError
&e
)
878 if (e
.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED
)
880 return errSecAuthFailed
;
896 globals().storageManager
.logout();
901 /* (non-exported C utility routine) 'Makes' a keychain based on a full path
903 static Keychain
make(const char *name
)
905 return globals().storageManager
.make(name
);
908 /* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs.
909 Note this version doesn't take an accessRef or password.
910 The "KC" create API takes a keychainRef...
912 OSStatus
SecKeychainMakeFromFullPath(const char *fullPathName
, SecKeychainRef
*keychainRef
)
915 RequiredParam(fullPathName
);
916 RequiredParam(keychainRef
)=make(fullPathName
)->handle();
921 /* Determines if the keychainRef is a valid keychain.
923 OSStatus
SecKeychainIsValid(SecKeychainRef keychainRef
, Boolean
* isValid
)
927 if (KeychainImpl::optional(keychainRef
)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL
)
932 /* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs.
934 OSStatus
SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef
)
937 StorageManager::KeychainList singleton
;
938 singleton
.push_back(KeychainImpl::required(keychainRef
));
939 globals().storageManager
.remove(singleton
);
943 /* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs.
945 OSStatus
SecKeychainCreateNew(SecKeychainRef keychainRef
, UInt32 passwordLength
, const char* inPassword
)
948 RequiredParam(inPassword
);
949 KeychainImpl::required(keychainRef
)->create(passwordLength
, inPassword
);
953 /* Modify a keychain so that it can be synchronized.
955 OSStatus
SecKeychainRecodeKeychain(SecKeychainRef keychainRef
, CFArrayRef dbBlobArray
, CFDataRef extraData
)
959 // do error checking for required parameters
960 RequiredParam(dbBlobArray
);
961 RequiredParam(extraData
);
963 const CssmData
extraCssmData(const_cast<UInt8
*>(CFDataGetBytePtr(extraData
)),
964 CFDataGetLength(extraData
));
966 CFIndex dbBlobArrayCount
= CFArrayGetCount(dbBlobArray
);
967 size_t space
= sizeof(uint8
) + (dbBlobArrayCount
* sizeof(SecurityServer::DbHandle
));
968 void *dataPtr
= (void*)malloc(space
);
970 return errSecAllocate
;
972 // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with.
974 uint8
* sizePtr
= (uint8
*)dataPtr
;
975 *sizePtr
= dbBlobArrayCount
;
976 SecurityServer::DbHandle
*currDbHandle
= (SecurityServer::DbHandle
*)(sizePtr
+1);
978 SecurityServer::ClientSession
ss(Allocator::standard(), Allocator::standard());
979 for (index
=0; index
< dbBlobArrayCount
; index
++)
981 CFDataRef cfBlobData
= (CFDataRef
)CFArrayGetValueAtIndex(dbBlobArray
, index
);
982 const CssmData
thisKCData(const_cast<UInt8
*>(CFDataGetBytePtr(cfBlobData
)), CFDataGetLength(cfBlobData
));
984 // Since it's to a DbHandle that's not on our disk (it came from user's iDisk),
985 // it's OK to use the mIdentifier and access credentials of the keychain we're recoding.
987 Keychain kc
= KeychainImpl::required(keychainRef
);
988 *currDbHandle
= ss
.decodeDb(kc
->dlDbIdentifier(), kc
->defaultCredentials(), thisKCData
); /* returns a DbHandle (IPCDbHandle) */
993 Keychain keychain
= Keychain::optional(keychainRef
);
994 const CssmData
data(const_cast<UInt8
*>((uint8
*)dataPtr
), space
);
995 Boolean recodeFailed
= false;
997 int errCode
=errSecSuccess
;
1001 keychain
->recode(data
, extraCssmData
);
1003 catch (MacOSError e
)
1005 errCode
= e
.osStatus();
1006 recodeFailed
= true;
1008 catch (UnixError ue
)
1010 errCode
= ue
.unixError();
1013 currDbHandle
= (SecurityServer::DbHandle
*)(sizePtr
+1);
1014 for (index
=0; index
< dbBlobArrayCount
; index
++)
1016 ss
.releaseDb(*currDbHandle
);
1030 OSStatus
SecKeychainCopySignature(SecKeychainRef keychainRef
, CFDataRef
*keychainSignature
)
1034 // do error checking for required parameters
1035 RequiredParam(keychainSignature
);
1037 // make a keychain object "wrapper" for this keychain ref
1038 Keychain keychain
= Keychain::optional(keychainRef
);
1039 CssmAutoData
data(keychain
->database()->allocator());
1040 keychain
->copyBlob(data
.get());
1042 // get the cssmDBBlob
1043 const SecurityServer::DbBlob
*cssmDBBlob
=
1044 data
.get().interpretedAs
<const SecurityServer::DbBlob
>();
1046 // convert from CDSA standards to CF standards
1047 *keychainSignature
= CFDataCreate(kCFAllocatorDefault
,
1048 cssmDBBlob
->randomSignature
.bytes
,
1049 sizeof(SecurityServer::DbBlob::Signature
));
1054 OSStatus
SecKeychainCopyBlob(SecKeychainRef keychainRef
, CFDataRef
*dbBlob
)
1058 // do error checking for required parameters
1059 RequiredParam(dbBlob
);
1061 // make a keychain object "wrapper" for this keychain ref
1062 Keychain keychain
= Keychain::optional(keychainRef
);
1063 CssmAutoData
data(keychain
->database()->allocator());
1064 keychain
->copyBlob(data
.get());
1066 // convert from CDSA standards to CF standards
1067 *dbBlob
= CFDataCreate(kCFAllocatorDefault
, data
, data
.length());
1072 // make a new keychain with pre-existing secrets
1073 OSStatus
SecKeychainCreateWithBlob(const char* fullPathName
, CFDataRef dbBlob
, SecKeychainRef
*kcRef
)
1077 KCThrowParamErrIf_(!fullPathName
);
1078 KCThrowParamErrIf_(!dbBlob
);
1080 Keychain keychain
= globals().storageManager
.make(fullPathName
);
1082 CssmData
blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob
)), CFDataGetLength(dbBlob
));
1084 // @@@ the call to StorageManager::make above leaves keychain the the cache.
1085 // If the create below fails we should probably remove it.
1086 keychain
->createWithBlob(blob
);
1088 RequiredParam(kcRef
)=keychain
->handle();
1095 // add a non-file based DB to the keychain list
1096 OSStatus
SecKeychainAddDBToKeychainList (SecPreferencesDomain domain
, const char* dbName
,
1097 const CSSM_GUID
*guid
, uint32 subServiceType
)
1101 RequiredParam(dbName
);
1102 StorageManager
&smr
= globals().storageManager
;
1103 smr
.addToDomainList(domain
, dbName
, *guid
, subServiceType
);
1108 // determine if a non-file based DB is in the keychain list
1109 OSStatus
SecKeychainDBIsInKeychainList (SecPreferencesDomain domain
, const char* dbName
,
1110 const CSSM_GUID
*guid
, uint32 subServiceType
)
1113 RequiredParam(dbName
);
1114 StorageManager
&smr
= globals().storageManager
;
1115 smr
.isInDomainList(domain
, dbName
, *guid
, subServiceType
);
1119 // remove a non-file based DB from the keychain list
1120 OSStatus
SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain
, const char* dbName
,
1121 const CSSM_GUID
*guid
, uint32 subServiceType
)
1124 RequiredParam(dbName
);
1125 StorageManager
&smr
= globals().storageManager
;
1126 smr
.removeFromDomainList(domain
, dbName
, *guid
, subServiceType
);
1131 // set server mode -- must be called before any other Sec* etc. call
1132 void SecKeychainSetServerMode()
1139 OSStatus
SecKeychainSetBatchMode (SecKeychainRef kcRef
, Boolean mode
, Boolean rollback
)
1142 RequiredParam(kcRef
);
1143 Keychain keychain
= Keychain::optional(kcRef
);
1144 keychain
->setBatchMode(mode
, rollback
);
1150 OSStatus
SecKeychainCleanupHandles()
1153 END_SECAPI
// which causes the handle cache cleanup routine to run
1156 OSStatus
SecKeychainVerifyKeyStorePassphrase(uint32_t retries
)
1159 SecurityServer::ClientSession().verifyKeyStorePassphrase(retries
);
1163 OSStatus
SecKeychainChangeKeyStorePassphrase()
1166 SecurityServer::ClientSession().changeKeyStorePassphrase();
1170 static OSStatus
SecKeychainGetMasterKey(SecKeychainRef userKeychainRef
, CFDataRef
*masterKey
, CFStringRef password
)
1174 // make a keychain object "wrapper" for this keychain ref
1175 Keychain keychain
= Keychain::optional(userKeychainRef
);
1177 CssmClient::Db db
= keychain
->database();
1179 // create the keychain, using appropriate credentials
1180 Allocator
&alloc
= db
->allocator();
1181 AutoCredentials
cred(alloc
); // will leak, but we're quitting soon :-)
1183 char passphrase
[1024];
1184 CFStringGetCString(password
, passphrase
, sizeof(passphrase
), kCFStringEncodingUTF8
);
1186 // use this passphrase
1187 cred
+= TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
,
1188 new(alloc
) ListElement(CSSM_SAMPLE_TYPE_PASSWORD
),
1189 new(alloc
) ListElement(StringData(passphrase
)));
1190 db
->accessCredentials(&cred
);
1192 CSSM_DL_DB_HANDLE dlDb
= db
->handle();
1193 CssmData dlDbData
= CssmData::wrap(dlDb
);
1195 KeySpec
spec(CSSM_KEYUSE_ANY
,
1196 CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
);
1198 DeriveKey
derive(keychain
->csp(), CSSM_ALGID_KEYCHAIN_KEY
, CSSM_ALGID_3DES_3KEY
, 3 * 64);
1199 derive(&dlDbData
, spec
, refKey
);
1201 // now extract the raw keybits
1203 WrapKey
wrap(keychain
->csp(), CSSM_ALGID_NONE
);
1204 wrap(refKey
, rawKey
);
1206 *masterKey
= CFDataCreate(kCFAllocatorDefault
, rawKey
.keyData(), rawKey
.length());
1212 OSStatus
SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef
, SecKeychainRef systemKeychainRef
, CFStringRef username
, CFStringRef password
) {
1213 SecTrustedApplicationRef itemPath
;
1214 SecAccessRef ourAccessRef
= NULL
;
1216 OSStatus result
= errSecParam
;
1218 CFDataRef masterKey
= NULL
;
1219 result
= SecKeychainGetMasterKey(userKeychainRef
, &masterKey
, password
);
1220 if (errSecSuccess
!= result
) {
1224 result
= SecKeychainStash();
1225 if (errSecSuccess
!= result
) {
1226 if (NULL
!= masterKey
) CFRelease(masterKey
);
1230 CFMutableArrayRef trustedApplications
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1231 if ( noErr
== SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL
, &itemPath
) && itemPath
)
1232 CFArrayAppendValue(trustedApplications
, itemPath
);
1234 if ( trustedApplications
&& (CFArrayGetCount(trustedApplications
) > 0)) {
1235 if (errSecSuccess
== (result
= SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications
, &ourAccessRef
))) {
1236 if (NULL
== systemKeychainRef
) {
1237 SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem
, &systemKeychainRef
);
1240 const void *queryKeys
[] = { kSecClass
,
1245 const void *queryValues
[] = { kSecClassGenericPassword
,
1246 CFSTR("com.apple.loginwindow.auto-login"),
1251 const void *updateKeys
[] = { kSecAttrAccess
,
1254 const void *updateValues
[] = { ourAccessRef
,
1258 CFDictionaryRef query
= CFDictionaryCreate(kCFAllocatorDefault
, queryKeys
, queryValues
, sizeof(queryValues
)/sizeof(*queryValues
), &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1259 CFDictionaryRef update
= CFDictionaryCreate(kCFAllocatorDefault
, updateKeys
, updateValues
, sizeof(updateValues
)/sizeof(*updateValues
), &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1261 result
= SecItemUpdate(query
, update
);
1263 if (errSecSuccess
!= result
) {
1264 const void *addKeys
[] = { kSecClass
,
1271 const void *addValues
[] = { kSecClassGenericPassword
,
1272 CFSTR("com.apple.loginwindow.auto-login"),
1279 CFDictionaryRef add
= CFDictionaryCreate(kCFAllocatorDefault
, addKeys
, addValues
, sizeof(addValues
)/sizeof(*addValues
), &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1280 result
= SecItemAdd(add
, NULL
);
1281 if (NULL
!= add
) CFRelease(add
);
1284 if (NULL
!= query
) CFRelease(query
);
1285 if (NULL
!= update
) CFRelease(update
);
1289 if (NULL
!= masterKey
) CFRelease(masterKey
);
1290 if (NULL
!= trustedApplications
) CFRelease(trustedApplications
);
1291 if (NULL
!= ourAccessRef
) CFRelease(ourAccessRef
);
1292 if (NULL
!= systemKeychainRef
) CFRelease(systemKeychainRef
);