X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..ee5f17c73ddf6cea151be3383378b7972c71f538:/OSX/libsecurityd/lib/ssblob.cpp diff --git a/OSX/libsecurityd/lib/ssblob.cpp b/OSX/libsecurityd/lib/ssblob.cpp index 2a47bd26..da56d9d4 100644 --- a/OSX/libsecurityd/lib/ssblob.cpp +++ b/OSX/libsecurityd/lib/ssblob.cpp @@ -26,11 +26,72 @@ // ssclient - SecurityServer client interface library // #include "ssblob.h" - +#include namespace Security { namespace SecurityServer { +uint32 CommonBlob::getCurrentVersion() { + uint32 ret = version_MacOS_10_0; + // If the integrity protections are turned on, use version_partition. + // else, use version_MacOS_10_0. + CFTypeRef integrity = (CFNumberRef)CFPreferencesCopyValue(CFSTR("KeychainIntegrity"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (integrity && CFGetTypeID(integrity) == CFBooleanGetTypeID()) { + bool integrityProtections = CFBooleanGetValue((CFBooleanRef)integrity); + + if(integrityProtections) { + secnotice("integrity", "creating a partition keychain; global is on"); + ret = version_partition; + } else { + secnotice("integrity", "creating a old-style keychain; global is off"); + ret = version_MacOS_10_0; + } + } else { + secnotice("integrity", "global integrity not set, defaulting to on"); + ret = version_partition; + } + CFReleaseSafe(integrity); + + return ret; +} + +uint32 CommonBlob::getCurrentVersionForDb(const char* dbName) { + // Currently, the scheme is as follows: + // in ~/Library/Keychains: + // version_partition + // Elsewhere: + // version_MacOS_10_0` + + if(pathInHomeLibraryKeychains(dbName)) { + return CommonBlob::getCurrentVersion(); + } + + secnotice("integrity", "outside ~/Library/Keychains/; creating a old-style keychain"); + return version_MacOS_10_0; +} + +bool CommonBlob::pathInHomeLibraryKeychains(const string& path) { + // We need to check if this path is in Some User's ~/Library/Keychains directory. + // At this level, there's no great way of discovering what's actually a + // user's home directory, so instead let's look for anything under + // ./Library/Keychains/ that isn't /Library/Keychains or /System/Library/Keychains. + + string libraryKeychains = "/Library/Keychains"; + string systemLibraryKeychains = "/System/Library/Keychains"; + + bool inALibraryKeychains = (string::npos != path.find(libraryKeychains)); + bool inRootLibraryKeychains = (0 == path.find(libraryKeychains)); + bool inSystemLibraryKeychains = (0 == path.find(systemLibraryKeychains)); + + return (inALibraryKeychains && !inRootLibraryKeychains && !inSystemLibraryKeychains); +} + +void CommonBlob::initialize() +{ + magic = magicNumber; + + this->blobVersion = getCurrentVersion(); +} // // Initialize the blob header for a given version @@ -38,6 +99,8 @@ namespace SecurityServer { void CommonBlob::initialize(uint32 version) { magic = magicNumber; + + secinfo("integrity", "creating a keychain with version %d", version); this->blobVersion = version; } @@ -72,7 +135,79 @@ void KeyBlob::setClearTextSignature() { memmove(blobSignature, clearPubKeySig, sizeof(blobSignature)); } - + +// +// Implementation of a "system keychain unlock key store" +// +SystemKeychainKey::SystemKeychainKey(const char *path) +: mPath(path), mValid(false) +{ + // explicitly set up a key header for a raw 3DES key + CssmKey::Header &hdr = mKey.header(); + hdr.blobType(CSSM_KEYBLOB_RAW); + hdr.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING); + hdr.keyClass(CSSM_KEYCLASS_SESSION_KEY); + hdr.algorithm(CSSM_ALGID_3DES_3KEY_EDE); + hdr.KeyAttr = 0; + hdr.KeyUsage = CSSM_KEYUSE_ANY; + mKey = CssmData::wrap(mBlob.masterKey); +} + +SystemKeychainKey::~SystemKeychainKey() +{ +} + +bool SystemKeychainKey::matches(const DbBlob::Signature &signature) +{ + return update() && signature == mBlob.signature; +} + +CssmKey& SystemKeychainKey::key() +{ + if(!mValid) { + update(); + } + return mKey; +} + +bool SystemKeychainKey::update() +{ + // if we checked recently, just assume it's okay + if (mValid && mUpdateThreshold > Time::now()) + return mValid; + + // check the file + struct stat st; + if (::stat(mPath.c_str(), &st)) { + // something wrong with the file; can't use it + mUpdateThreshold = Time::now() + Time::Interval(checkDelay); + return mValid = false; + } + if (mValid && Time::Absolute(st.st_mtimespec) == mCachedDate) + return true; + mUpdateThreshold = Time::now() + Time::Interval(checkDelay); + + try { + secnotice("syskc", "reading system unlock record from %s", mPath.c_str()); + UnixPlusPlus::AutoFileDesc fd(mPath, O_RDONLY); + if (fd.read(mBlob) != sizeof(mBlob)) + return false; + if (mBlob.isValid()) { + mCachedDate = st.st_mtimespec; + return mValid = true; + } else + return mValid = false; + } catch (...) { + secnotice("syskc", "system unlock record not available"); + return false; + } +} + +bool SystemKeychainKey::valid() +{ + update(); + return mValid; +} } // end namespace SecurityServer