X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/822b670c6f91d089ccb51b77e24b6ac80406b337..07691282a056c4efea71e1e505527601e8cc166b:/OSX/libsecurity_keychain/lib/SecKeychain.cpp diff --git a/OSX/libsecurity_keychain/lib/SecKeychain.cpp b/OSX/libsecurity_keychain/lib/SecKeychain.cpp index 8a48d3f2..b13c0357 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychain.cpp +++ b/OSX/libsecurity_keychain/lib/SecKeychain.cpp @@ -35,11 +35,18 @@ #include #include #include +#include +#include +#include +#include "TokenLogin.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(); @@ -73,6 +80,9 @@ OSStatus SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef) { 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); RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle(); @@ -85,6 +95,9 @@ SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subse const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainOpenWithGuid", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); // range check parameters RequiredParam (guid); @@ -96,7 +109,7 @@ SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subse DLDbIdentifier dLDbIdentifier(ssuid, dbName, dbLocation); // make a keychain from the supplied info - RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false)->handle (); + RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false, false)->handle (); END_SECAPI } @@ -107,9 +120,12 @@ SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *passw 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. @@ -131,6 +147,9 @@ OSStatus 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; @@ -146,6 +165,9 @@ OSStatus SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings) { 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) @@ -163,6 +185,9 @@ OSStatus SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings) { 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) @@ -183,6 +208,9 @@ OSStatus SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword) { 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); @@ -199,6 +227,9 @@ OSStatus 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(); @@ -211,6 +242,9 @@ OSStatus 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(); @@ -221,6 +255,9 @@ 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 +273,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 +295,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 } @@ -281,6 +322,9 @@ OSStatus 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)); @@ -290,6 +334,9 @@ SecKeychainSetDefault(SecKeychainRef keychainRef) 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; @@ -303,6 +350,9 @@ OSStatus SecKeychainCopySearchList(CFArrayRef *searchList) 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; @@ -316,6 +366,9 @@ OSStatus SecKeychainSetSearchList(CFArrayRef searchList) OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef) { 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(); @@ -325,6 +378,9 @@ OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRe OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef) { 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)); @@ -347,6 +403,9 @@ OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList) { 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; @@ -360,6 +419,9 @@ OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef 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); @@ -369,6 +431,9 @@ 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 +473,50 @@ 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 @@ -478,6 +587,9 @@ pascal OSStatus SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext) { 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); @@ -490,6 +602,9 @@ OSStatus 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); @@ -501,6 +616,9 @@ OSStatus 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) { 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 @@ -560,6 +678,9 @@ 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); @@ -615,9 +736,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; } @@ -632,6 +757,9 @@ OSStatus SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) { 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 +770,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) @@ -688,6 +806,9 @@ 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); @@ -714,9 +835,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; } @@ -753,6 +878,9 @@ OSStatus SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle) { 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); @@ -762,6 +890,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 +901,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 } @@ -806,6 +944,9 @@ OSStatus SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword) { 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); @@ -818,6 +959,9 @@ OSStatus 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(); @@ -829,17 +973,21 @@ OSStatus SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password) { 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 +997,21 @@ 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 { @@ -880,6 +1036,9 @@ OSStatus 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(); @@ -922,6 +1081,9 @@ 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 +1095,9 @@ 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 @@ -943,6 +1108,9 @@ OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData) { 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); @@ -1018,6 +1186,9 @@ OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlob OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) { 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); @@ -1042,6 +1213,9 @@ OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychai 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 +1235,9 @@ 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); @@ -1085,6 +1262,9 @@ OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char const CSSM_GUID *guid, uint32 subServiceType) { 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; @@ -1109,6 +1289,9 @@ 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 +1310,9 @@ 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); @@ -1144,6 +1330,9 @@ OSStatus SecKeychainCleanupHandles() 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 +1340,9 @@ 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 } @@ -1158,6 +1350,9 @@ OSStatus SecKeychainChangeKeyStorePassphrase() static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password) { 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 +1370,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,6 +1391,81 @@ 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) { SecTrustedApplicationRef itemPath; @@ -1203,6 +1473,14 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe 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 +1489,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 +1514,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 +1540,7 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe const void *addValues[] = { kSecClassGenericPassword, CFSTR("com.apple.loginwindow.auto-login"), username, - systemKeychainRef, + internalSystemKeychainRef, ourAccessRef, masterKey, }; @@ -1271,13 +1552,127 @@ 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) +{ + 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}; + AuthorizationRights *authorizedRights = NULL; + + 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, &authorizedRights); + if (authorizedRights) + AuthorizationFreeItemSet(authorizedRights); + + if (result == errAuthorizationSuccess) { + AuthorizationItemSet *items; + result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items); + if (result == errAuthorizationSuccess) { + if (items->count > 0) { + pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8); + } + 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); + return result; +} + +OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash) +{ + OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash); + if (result != errSecSuccess) { + secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result); + } + return result; +} +