#include "ssblob.h"
#include <utilities/SecCFRelease.h>
namespace Security {
namespace SecurityServer {
uint32 CommonBlob::getCurrentVersion() {
uint32 ret = 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) {
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) {
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();
}
void CommonBlob::initialize(uint32 version)
{
magic = magicNumber;
secinfo("integrity", "creating a keychain with version %d", version);
this->blobVersion = version;
}
bool CommonBlob::isValid() const
{
return magic == magicNumber;
}
void CommonBlob::validate(CSSM_RETURN failureCode) const
{
if (!isValid())
CssmError::throwMe(failureCode);
}
static const char clearPubKeySig[] = "Cleartext public key";
bool KeyBlob::isClearText()
{
return (memcmp(blobSignature, clearPubKeySig,
sizeof(blobSignature)) == 0);
}
void KeyBlob::setClearTextSignature()
{
memmove(blobSignature, clearPubKeySig, sizeof(blobSignature));
}
SystemKeychainKey::SystemKeychainKey(const char *path)
: mPath(path), mValid(false)
{
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 (mValid && mUpdateThreshold > Time::now())
return mValid;
struct stat st;
if (::stat(mPath.c_str(), &st)) {
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;
}
}
}