X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/822b670c6f91d089ccb51b77e24b6ac80406b337..02b2aca600d4a0fe6fb259262bd6808ef889acde:/OSX/libsecurity_keychain/lib/SecKeychain.cpp diff --git a/OSX/libsecurity_keychain/lib/SecKeychain.cpp b/OSX/libsecurity_keychain/lib/SecKeychain.cpp index 8a48d3f2..ca80c80b 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychain.cpp +++ b/OSX/libsecurity_keychain/lib/SecKeychain.cpp @@ -35,11 +35,24 @@ #include #include #include +#include +#include +#include +#include "TokenLogin.h" +#include "LegacyAPICounts.h" + +extern "C" { +#include "ctkloginhelper.h" +} OSStatus SecKeychainMDSInstall() { - BEGIN_SECAPI + BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Security::MDSClient::Directory d; d.install(); @@ -61,6 +74,7 @@ SecKeychainGetTypeID(void) OSStatus SecKeychainGetVersion(UInt32 *returnVers) { + COUNTLEGACYAPI if (!returnVers) return errSecSuccess; @@ -74,42 +88,27 @@ SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef) { BEGIN_SECAPI - RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle(); - - END_SECAPI -} - - -OSStatus -SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subserviceType, const char* dbName, - const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain) -{ - BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); - // range check parameters - RequiredParam (guid); - RequiredParam (dbName); - - // create a DLDbIdentifier that describes what should be opened - const CSSM_VERSION *version = NULL; - const CssmSubserviceUid ssuid(*guid, version, subserviceId, subserviceType); - DLDbIdentifier dLDbIdentifier(ssuid, dbName, dbLocation); - - // make a keychain from the supplied info - RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false)->handle (); + RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle(); END_SECAPI } - OSStatus SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password, Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); KCThrowParamErrIf_(!pathName); - Keychain keychain = globals().storageManager.make(pathName); + Keychain keychain = globals().storageManager.make(pathName, true, true); // @@@ the call to StorageManager::make above leaves keychain the the cache. // If the create below fails we should probably remove it. @@ -132,6 +131,10 @@ SecKeychainDelete(SecKeychainRef keychainOrArray) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + KCThrowIf_(!keychainOrArray, errSecInvalidKeychain); StorageManager::KeychainList keychains; globals().storageManager.optionalSearchList(keychainOrArray, keychains); @@ -147,6 +150,10 @@ SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *ne { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + Keychain keychain = Keychain::optional(keychainRef); if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) { @@ -164,6 +171,10 @@ SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSett { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + Keychain keychain = Keychain::optional(keychainRef); if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) { @@ -184,6 +195,10 @@ SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + Keychain keychain = Keychain::optional(keychainRef); if (usePassword) @@ -200,6 +215,10 @@ SecKeychainLock(SecKeychainRef keychainRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + Keychain keychain = Keychain::optional(keychainRef); keychain->lock(); @@ -212,6 +231,10 @@ SecKeychainLockAll(void) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + globals().storageManager.lockAll(); END_SECAPI @@ -221,6 +244,10 @@ SecKeychainLockAll(void) OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); // // Get the current user (using fallback method if necessary) // @@ -236,17 +263,19 @@ OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Bool endpwent(); } if ( userName.length() == 0 ) // did we ultimately get one? + { MacOSError::throwMe(errAuthorizationInternal); + } SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast(password), passwordLength) : CssmData()); - + secwarning("SecKeychainResetLogin: reset AKS passphrase"); if (password) { // Clear the plist and move aside (rename) the existing login.keychain globals().storageManager.resetKeychain(resetSearchList); // Create the login keychain without UI - globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password); + globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password, true); // Set it as the default Keychain keychain = globals().storageManager.loginKeychain(); @@ -256,13 +285,15 @@ OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Bool { // Create the login keychain, prompting for password // (implicitly calls resetKeychain, login, and defaultKeychain) - globals().storageManager.makeLoginAuthUI(NULL); + globals().storageManager.makeLoginAuthUI(NULL, true); } + secwarning("SecKeychainResetLogin: reset osx keychain"); // Post a "list changed" event after a reset, so apps can refresh their list. // Make sure we are not holding mLock when we post this event. KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); + END_SECAPI } @@ -282,6 +313,10 @@ SecKeychainSetDefault(SecKeychainRef keychainRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + globals().storageManager.defaultKeychain(Keychain::optional(keychainRef)); END_SECAPI @@ -291,6 +326,10 @@ OSStatus SecKeychainCopySearchList(CFArrayRef *searchList) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(searchList); StorageManager &smr = globals().storageManager; StorageManager::KeychainList keychainList; @@ -304,6 +343,10 @@ OSStatus SecKeychainSetSearchList(CFArrayRef searchList) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(searchList); StorageManager &smr = globals().storageManager; StorageManager::KeychainList keychainList; @@ -317,6 +360,10 @@ OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRe { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle(); END_SECAPI @@ -326,6 +373,10 @@ OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef)); END_SECAPI @@ -348,6 +399,10 @@ OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(searchList); StorageManager &smr = globals().storageManager; StorageManager::KeychainList keychainList; @@ -361,6 +416,10 @@ OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + globals().storageManager.domain(domain); END_SECAPI @@ -369,6 +428,10 @@ OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain) OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); *domain = globals().storageManager.domain(); @@ -408,6 +471,51 @@ SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathN END_SECAPI } +OSStatus +SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version) +{ + BEGIN_SECAPI + + RequiredParam(version); + + *version = Keychain::optional(keychainRef)->database()->dbBlobVersion(); + + END_SECAPI +} + +OSStatus +SecKeychainAttemptMigrationWithMasterKey(SecKeychainRef keychain, UInt32 version, const char* masterKeyFilename) +{ + BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + + RequiredParam(masterKeyFilename); + Keychain kc = Keychain::optional(keychain); + + SecurityServer::SystemKeychainKey keychainKey(masterKeyFilename); + if(keychainKey.valid()) { + // We've managed to read the key; now, create credentials using it + string path = kc->name(); + + CssmClient::Key keychainMasterKey(kc->csp(), keychainKey.key(), true); + CssmClient::AclFactory::MasterKeyUnlockCredentials creds(keychainMasterKey, Allocator::standard(Allocator::sensitive)); + + // Attempt the migrate, using our master key as the ACL override + bool result = kc->keychainMigration(path, kc->database()->dbBlobVersion(), path, version, creds.getAccessCredentials()); + if(!result) { + return errSecBadReq; + } + return (kc->database()->dbBlobVersion() == version ? errSecSuccess : errSecBadReq); + } else { + return errSecBadReq; + } + + END_SECAPI +} + // @@@ Deprecated UInt16 @@ -479,6 +587,10 @@ SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMas { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(callbackFunction); CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext); @@ -491,6 +603,10 @@ SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(callbackFunction); CCallbackMgr::RemoveCallback(callbackFunction); @@ -502,6 +618,10 @@ SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLeng { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); // @@@ Get real itemClass Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false); @@ -561,6 +681,10 @@ SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLeng { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + StorageManager::KeychainList keychains; globals().storageManager.optionalSearchList(keychainOrArray, keychains); KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL); @@ -615,9 +739,13 @@ SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLeng { CssmDataContainer outData; item->getData(outData); - *passwordLength=(UInt32)outData.length(); + if (passwordLength) { + *passwordLength=(UInt32)outData.length(); + } outData.Length=0; - *passwordData=outData.data(); + if (passwordData) { + *passwordData=outData.data(); + } outData.Data=NULL; } @@ -633,6 +761,10 @@ SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLeng { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); // @@@ Get real itemClass @@ -642,17 +774,7 @@ SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLeng { CssmData service(const_cast(reinterpret_cast(serviceName)), serviceNameLength); item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); - // use service name as default label (UNLESS the service is iTools and we have an account name [3787371]) - const char *iTools = "iTools"; - if (accountNameLength && serviceNameLength==strlen(iTools) && !memcmp(serviceName, iTools, serviceNameLength)) - { - CssmData account(const_cast(reinterpret_cast(accountName)), accountNameLength); - item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), account); - } - else - { - item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); - } + item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); } if (accountName && accountNameLength) @@ -689,6 +811,10 @@ SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLeng { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + StorageManager::KeychainList keychains; globals().storageManager.optionalSearchList(keychainOrArray, keychains); KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); @@ -714,9 +840,13 @@ SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLeng { CssmDataContainer outData; item->getData(outData); - *passwordLength=(UInt32)outData.length(); + if (passwordLength) { + *passwordLength=(UInt32)outData.length(); + } outData.Length=0; - *passwordData=outData.data(); + if (passwordData) { + *passwordData=outData.data(); + } outData.Data=NULL; } @@ -754,6 +884,10 @@ SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHand { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(dldbHandle); Keychain keychain = Keychain::optional(keychainRef); @@ -762,6 +896,8 @@ SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHand END_SECAPI } +static ModuleNexus gSecReturnedKeychainCSPsMutex; +static ModuleNexus> gSecReturnedKeychainCSPs; OSStatus SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) @@ -771,7 +907,15 @@ SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) RequiredParam(cspHandle); Keychain keychain = Keychain::optional(keychainRef); - *cspHandle = keychain->csp()->handle(); + + // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). + // Keep a global pointer to it to force the CSP to stay live forever. + CssmClient::CSP returnedKeychainCSP = keychain->csp(); + { + StLock _(gSecReturnedKeychainCSPsMutex()); + gSecReturnedKeychainCSPs().insert(returnedKeychainCSP); + } + *cspHandle = returnedKeychainCSP->handle(); END_SECAPI } @@ -807,6 +951,10 @@ SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + Keychain keychain = Keychain::optional(keychainRef); keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword); @@ -819,6 +967,10 @@ SecKeychainCopyLogin(SecKeychainRef *keychainRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle(); END_SECAPI @@ -830,16 +982,21 @@ SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, con { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + try { if (password) { - globals().storageManager.login(nameLength, name, passwordLength, password); + globals().storageManager.login(nameLength, name, passwordLength, password, false); } else { globals().storageManager.stashLogin(); } } catch (CommonError &e) { + secnotice("KCLogin", "SecKeychainLogin failed: %d, password was%s supplied", (int)e.osStatus(), password?"":" not"); if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) { return errSecAuthFailed; @@ -849,13 +1006,22 @@ SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, con return e.osStatus(); } } - + + catch (...) { + __secapiresult=errSecInternalComponent; + } + secnotice("KCLogin", "SecKeychainLogin result: %d, password was%s supplied", (int)__secapiresult, password?"":" not"); + END_SECAPI } OSStatus SecKeychainStash() { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); try { @@ -881,6 +1047,10 @@ SecKeychainLogout() { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + globals().storageManager.logout(); END_SECAPI @@ -900,7 +1070,8 @@ static Keychain make(const char *name) OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef) { BEGIN_SECAPI - RequiredParam(fullPathName); + + RequiredParam(fullPathName); RequiredParam(keychainRef)=make(fullPathName)->handle(); END_SECAPI } @@ -911,7 +1082,8 @@ OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *k OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid) { BEGIN_SECAPI - *isValid = false; + + *isValid = false; if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL) *isValid = true; END_SECAPI @@ -922,6 +1094,10 @@ OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid) OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); StorageManager::KeychainList singleton; singleton.push_back(KeychainImpl::required(keychainRef)); globals().storageManager.remove(singleton); @@ -933,6 +1109,10 @@ OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef) OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); RequiredParam(inPassword); KeychainImpl::required(keychainRef)->create(passwordLength, inPassword); END_SECAPI @@ -944,6 +1124,10 @@ OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlob { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + // do error checking for required parameters RequiredParam(dbBlobArray); RequiredParam(extraData); @@ -1019,6 +1203,10 @@ OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychai { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + // do error checking for required parameters RequiredParam(keychainSignature); @@ -1043,6 +1231,10 @@ OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + // do error checking for required parameters RequiredParam(dbBlob); @@ -1061,6 +1253,10 @@ OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob) OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); KCThrowParamErrIf_(!fullPathName); KCThrowParamErrIf_(!dbBlob); @@ -1086,6 +1282,10 @@ OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + RequiredParam(dbName); StorageManager &smr = globals().storageManager; smr.addToDomainList(domain, dbName, *guid, subServiceType); @@ -1098,7 +1298,8 @@ OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* const CSSM_GUID *guid, uint32 subServiceType) { BEGIN_SECAPI - RequiredParam(dbName); + + RequiredParam(dbName); StorageManager &smr = globals().storageManager; smr.isInDomainList(domain, dbName, *guid, subServiceType); END_SECAPI @@ -1109,6 +1310,10 @@ OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const const CSSM_GUID *guid, uint32 subServiceType) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); RequiredParam(dbName); StorageManager &smr = globals().storageManager; smr.removeFromDomainList(domain, dbName, *guid, subServiceType); @@ -1127,6 +1332,10 @@ void SecKeychainSetServerMode() OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); RequiredParam(kcRef); Keychain keychain = Keychain::optional(kcRef); keychain->setBatchMode(mode, rollback); @@ -1138,12 +1347,17 @@ OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean ro OSStatus SecKeychainCleanupHandles() { BEGIN_SECAPI - END_SECAPI // which causes the handle cache cleanup routine to run + + END_SECAPI // which causes the handle cache cleanup routine to run } OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries) { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); SecurityServer::ClientSession().verifyKeyStorePassphrase(retries); END_SECAPI } @@ -1151,6 +1365,10 @@ OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries) OSStatus SecKeychainChangeKeyStorePassphrase() { BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); SecurityServer::ClientSession().changeKeyStorePassphrase(); END_SECAPI } @@ -1159,6 +1377,10 @@ static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRe { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + // make a keychain object "wrapper" for this keychain ref Keychain keychain = Keychain::optional(userKeychainRef); @@ -1175,9 +1397,9 @@ static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRe cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD), new(alloc) ListElement(StringData(passphrase))); - db->accessCredentials(&cred); - - CSSM_DL_DB_HANDLE dlDb = db->handle(); + db->authenticate(CSSM_DB_ACCESS_READ, &cred); + + CSSM_DL_DB_HANDLE dlDb = db->handle(); CssmData dlDbData = CssmData::wrap(dlDb); CssmKey refKey; KeySpec spec(CSSM_KEYUSE_ANY, @@ -1196,13 +1418,97 @@ static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRe END_SECAPI } +static const char *kAutologinPWFilePath = "/etc/kcpassword"; +static const uint32_t kObfuscatedPasswordSizeMultiple = 12; +static const uint32_t buffer_size = 512; +static const uint8_t kObfuscationKey[] = {0x7d, 0x89, 0x52, 0x23, 0xd2, 0xbc, 0xdd, 0xea, 0xa3, 0xb9, 0x1f}; + +static void obfuscate(void *buffer, size_t bufferLength) +{ + uint8_t *pBuf = (uint8_t *) buffer; + const uint8_t *pKey = kObfuscationKey, *eKey = pKey + sizeof( kObfuscationKey ); + + while (bufferLength--) { + *pBuf = *pBuf ^ *pKey; + ++pKey; + ++pBuf; + if (pKey == eKey) + pKey = kObfuscationKey; + } +} + +static bool _SASetAutologinPW(CFStringRef inAutologinPW) +{ + bool result = false; + struct stat sb; + + // Delete the kcpassword file if it exists already + if (stat(kAutologinPWFilePath, &sb) == 0) + unlink( kAutologinPWFilePath ); + + // NIL incoming password ==> clear auto login password (above) without setting a new one. In other words: turn auto login off. + if (inAutologinPW != NULL) { + char buffer[buffer_size]; + const char *pwAsUTF8String = CFStringGetCStringPtr(inAutologinPW, kCFStringEncodingUTF8); + if (pwAsUTF8String == NULL) { + if (CFStringGetCString(inAutologinPW, buffer, buffer_size, kCFStringEncodingUTF8)) pwAsUTF8String = buffer; + } + + if (pwAsUTF8String != NULL) { + size_t pwLength = strlen(pwAsUTF8String) + 1; + size_t obfuscatedPWLength; + char *obfuscatedPWBuffer; + + // The size of the obfuscated password should be the smallest multiple of + // kObfuscatedPasswordSizeMultiple greater than or equal to pwLength. + obfuscatedPWLength = (((pwLength - 1) / kObfuscatedPasswordSizeMultiple) + 1) * kObfuscatedPasswordSizeMultiple; + obfuscatedPWBuffer = (char *) malloc(obfuscatedPWLength); + + // Copy the password (including null terminator) to beginning of obfuscatedPWBuffer + bcopy(pwAsUTF8String, obfuscatedPWBuffer, pwLength); + + // Pad remainder of obfuscatedPWBuffer with random bytes + { + char *p; + char *endOfBuffer = obfuscatedPWBuffer + obfuscatedPWLength; + + for (p = obfuscatedPWBuffer + pwLength; p < endOfBuffer; ++p) + *p = random() & 0x000000FF; + } + + obfuscate(obfuscatedPWBuffer, obfuscatedPWLength); + + int pwFile = open(kAutologinPWFilePath, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR); + if (pwFile >= 0) { + size_t wrote = write(pwFile, obfuscatedPWBuffer, obfuscatedPWLength); + if (wrote == obfuscatedPWLength) + result = true; + close(pwFile); + } + + chmod(kAutologinPWFilePath, S_IRUSR | S_IWUSR); + free(obfuscatedPWBuffer); + } + } + + return result; +} OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) { + COUNTLEGACYAPI SecTrustedApplicationRef itemPath; SecAccessRef ourAccessRef = NULL; OSStatus result = errSecParam; + if (userKeychainRef == NULL) { + // We don't have a specific user keychain, fall back + if (_SASetAutologinPW(password)) + result = errSecSuccess; + + return result; + } + CFDataRef masterKey = NULL; result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password); if (errSecSuccess != result) { @@ -1211,18 +1517,21 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe result = SecKeychainStash(); if (errSecSuccess != result) { - if (NULL != masterKey) CFRelease(masterKey); + if (masterKey != NULL) CFRelease(masterKey); return result; } CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if ( noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath ) + if (noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath) CFArrayAppendValue(trustedApplications, itemPath); - if ( trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) { + if (trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) { if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) { + SecKeychainRef internalSystemKeychainRef = NULL; if (NULL == systemKeychainRef) { - SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &systemKeychainRef); + SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &internalSystemKeychainRef); + } else { + internalSystemKeychainRef = systemKeychainRef; } const void *queryKeys[] = { kSecClass, @@ -1233,7 +1542,7 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe const void *queryValues[] = { kSecClassGenericPassword, CFSTR("com.apple.loginwindow.auto-login"), username, - systemKeychainRef, + internalSystemKeychainRef, }; const void *updateKeys[] = { kSecAttrAccess, @@ -1259,7 +1568,7 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe const void *addValues[] = { kSecClassGenericPassword, CFSTR("com.apple.loginwindow.auto-login"), username, - systemKeychainRef, + internalSystemKeychainRef, ourAccessRef, masterKey, }; @@ -1271,13 +1580,149 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe if (NULL != query) CFRelease(query); if (NULL != update) CFRelease(update); + + // If the caller wanted us to locate the system keychain reference, it's okay to go ahead and free our magically created one + if (systemKeychainRef == NULL) CFRelease(internalSystemKeychainRef); } } if (NULL != masterKey) CFRelease(masterKey); if (NULL != trustedApplications) CFRelease(trustedApplications); if (NULL != ourAccessRef) CFRelease(ourAccessRef); - if (NULL != systemKeychainRef) CFRelease(systemKeychainRef); return result; } + +OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts) +{ + BEGIN_SECAPI + + os_activity_t activity = os_activity_create("SecKeychainGetUserPromptAttempts", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + + if(attempts) { + SecurityServer::ClientSession().getUserPromptAttempts(*attempts); + } + + END_SECAPI +} + +OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash, + SecKeychainRef userKeychain, CFStringRef password) +{ + COUNTLEGACYAPI + CFRef pwd; + OSStatus result; + + if (password == NULL || CFStringGetLength(password) == 0) { + AuthorizationRef authorizationRef; + result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef); + if (result != errAuthorizationSuccess) { + secnotice("SecKeychain", "failed to create authorization"); + return result; + } + + AuthorizationItem myItems = {"com.apple.ctk.pair", 0, NULL, 0}; + AuthorizationRights myRights = {1, &myItems}; + + char pathName[PATH_MAX]; + UInt32 pathLength = PATH_MAX; + result = SecKeychainGetPath(userKeychain, &pathLength, pathName); + if (result != errSecSuccess) { + secnotice("SecKeychain", "failed to create authorization"); + return result; + } + + Boolean checkPwd = TRUE; + Boolean ignoreSession = TRUE; + AuthorizationItem envItems[] = { + {AGENT_HINT_KEYCHAIN_PATH, pathLength, pathName, 0}, + {AGENT_HINT_KEYCHAIN_CHECK, sizeof(checkPwd), &checkPwd}, + {AGENT_HINT_IGNORE_SESSION, sizeof(ignoreSession), &ignoreSession} + }; + + AuthorizationEnvironment environment = {3, envItems}; + AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; + result = AuthorizationCopyRights(authorizationRef, &myRights, &environment, flags, NULL); + secnotice("SecKeychain", "Authorization result: %d", (int)result); + + if (result == errAuthorizationSuccess) { + AuthorizationItemSet *items; + result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items); + secnotice("SecKeychain", "Items copy result: %d", (int)result); + if (result == errAuthorizationSuccess) { + secnotice("SecKeychain", "Items count: %d", items->count); + if (items->count > 0) { + pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8); + if (pwd) { + secnotice("SecKeychain", "Got kcpass"); + } + } + AuthorizationFreeItemSet(items); + } + } + AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); + if (result != errAuthorizationSuccess) { + secnotice("SecKeychain", "did not get authorization to pair the card"); + return result; + } + } else { + pwd.take(password); + } + + if (!pwd) { + secnotice("SecKeychain", "did not get kcpass"); + return errSecInternalComponent; + } + + CFRef masterKey; + result = SecKeychainGetMasterKey(userKeychain, masterKey.take(), pwd); + if (result != errSecSuccess) { + secnotice("SecKeychain", "Failed to get master key: %d", (int) result); + return result; + } + + CFRef scBlob; + result = TokenLoginGetScBlob(wrapPubKeyHash, tokenID, pwd, scBlob.take()); + if (result != errSecSuccess) { + secnotice("SecKeychain", "Failed to get stash: %d", (int) result); + return result; + } + + result = TokenLoginCreateLoginData(tokenID, pubKeyHash, wrapPubKeyHash, masterKey, scBlob); + if (result != errSecSuccess) { + secnotice("SecKeychain", "Failed to create login data: %d", (int) result); + return result; + } + + secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result); + + // create SC KEK + // this might fail if KC password is different from user's password + uid_t uid = geteuid(); + if (!uid) { + uid = getuid(); + } + struct passwd *passwd = getpwuid(uid); + if (passwd) { + CFRef username = CFStringCreateWithCString(kCFAllocatorDefault, passwd->pw_name, kCFStringEncodingUTF8); + OSStatus kekRes = TKAddSecureToken(username, pwd, tokenID, wrapPubKeyHash); + if (kekRes != noErr) { + secnotice("SecKeychain", "Failed to register SC token: %d", (int) kekRes); // do not fail because KC functionality be still OK + } + } else { + secnotice("SecKeychain", "Unable to get name for uid %d", uid); + } + return result; +} + +OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash) +{ + COUNTLEGACYAPI + OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash); + if (result != errSecSuccess) { + secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result); + } + return result; +}