kcdatabase.h
1 /* 2 * Copyright (c) 2000-2008,2012-2013 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25 // 26 // kcdatabase - software database container implementation. 27 // 28 // A KeychainDatabase is a software storage container, 29 // implemented in cooperation by the AppleCSLDP CDSA plugin and this daemon. 30 // 31 #ifndef _H_KCDATABASE 32 #define _H_KCDATABASE 33 34 #include "localdatabase.h" 35 #include <securityd_client/ss_types.h> 36 #include "agentclient.h" 37 38 class KeychainDatabase; 39 class KeychainDbCommon; 40 class KeychainKey; 41 42 43 // 44 // We identify KeychainDatabases uniquely by a combination of 45 // a DLDbIdentifier and a database (blob) identifier. Equivalence 46 // by DbIdentifier is the criterion for parent-side merging. 47 // 48 class DbIdentifier { 49 public: 50 DbIdentifier(const DLDbIdentifier &id, DbBlob::Signature sig) 51 : mIdent(id), mSig(sig) { } 52 53 const DLDbIdentifier &dlDbIdentifier() const { return mIdent; } 54 const DbBlob::Signature &signature() const { return mSig; } 55 operator const DLDbIdentifier &() const { return dlDbIdentifier(); } 56 operator const DbBlob::Signature &() const { return signature(); } 57 const char *dbName() const { return mIdent.dbName(); } 58 59 bool operator < (const DbIdentifier &id) const // simple lexicographic 60 { 61 if (mIdent < id.mIdent) return true; 62 if (id.mIdent < mIdent) return false; 63 return mSig < id.mSig; 64 } 65 66 bool operator == (const DbIdentifier &id) const 67 { return mIdent == id.mIdent && mSig == id.mSig; } 68 69 private: 70 DLDbIdentifier mIdent; 71 DbBlob::Signature mSig; 72 }; 73 74 75 // 76 // A vestigal system-global database instance 77 // We don't (yet) use it for anything. Perhaps it should carry our ACL... 78 // 79 class KeychainDbGlobal : public PerGlobal { 80 public: 81 KeychainDbGlobal(const DbIdentifier &id); 82 ~KeychainDbGlobal(); 83 84 const DbIdentifier &identifier() const { return mIdentifier; } 85 86 private: 87 DbIdentifier mIdentifier; // database external identifier [const] 88 }; 89 90 91 // 92 // KeychainDatabase DbCommons 93 // 94 class KeychainDbCommon : public LocalDbCommon, 95 public DatabaseCryptoCore, public MachServer::Timer { 96 public: 97 KeychainDbCommon(Session &ssn, const DbIdentifier &id, uint32 requestedVersion = CommonBlob::version_none); 98 KeychainDbCommon(Session &ssn, const DbIdentifier &id, KeychainDbCommon& toClone); 99 ~KeychainDbCommon(); 100 101 // If you have an existing KeychainDbCommon, and want to make it look a lot like that one 102 void cloneFrom(KeychainDbCommon& toClone, uint32 requestedVersion = CommonBlob::version_none); 103 104 // finishes the initialization of this KeychainDbCommon. Do not call this 105 // while holding the mCommon lock, or you may get a multiprocess deadlock. 106 void initializeKeybag(); 107 108 void kill(); // remove from commonSet 109 110 KeychainDbGlobal &global() const; 111 112 bool unlockDb(DbBlob *blob, void **privateAclBlob = NULL); 113 void lockDb(); // make locked (if currently unlocked) 114 bool isLocked() { return mIsLocked; } // lock status 115 void setUnlocked(); 116 void invalidateBlob() { version++; } 117 118 void activity(); // reset lock timeout 119 120 void makeNewSecrets(); 121 122 const DbIdentifier &identifier() const {return mIdentifier; } 123 const DLDbIdentifier &dlDbIdent() const { return identifier(); } 124 const char *dbName() const { return dlDbIdent().dbName(); } 125 uint32 dbVersion() { return DatabaseCryptoCore::mBlobVersion; } 126 bool isLoginKeychain() const { return mLoginKeychain; } 127 128 DbBlob *encode(KeychainDatabase &db); 129 130 void notify(NotificationEvent event) { DbCommon::notify(event, identifier()); } 131 132 void sleepProcessing(); 133 void lockProcessing(); 134 135 bool belongsToSystem() const; 136 bool isDefaultSystemKeychain() const; 137 138 public: 139 // debugging 140 IFDUMP(void dumpNode()); 141 142 protected: 143 void action(); // timer queue action to lock keychain 144 145 // lifetime management for our Timer personality 146 void select(); 147 void unselect(); 148 149 public: 150 // all following data locked with object lock 151 uint32 sequence; // change sequence number 152 DBParameters mParams; // database parameters (arbitrated copy) 153 154 uint32 version; // version stamp for change tracking 155 156 private: 157 DbIdentifier mIdentifier; // database external identifier [const] 158 // all following data protected by object lock 159 bool mIsLocked; // logically locked 160 bool mValidParams; // mParams has been set 161 bool mLoginKeychain; 162 163 public: 164 void insert(); // insert into commonSet 165 static bool find(const DbIdentifier &ident, Session &session, RefPointer<KeychainDbCommon> &common, 166 uint32 requestedVersion = CommonBlob::version_none, KeychainDbCommon* cloneFrom = NULL); // find in commonSet 167 168 private: 169 void insertHoldingLock(); // Does the guts of insert(); you must hold a write lock on mRWCommonLock when calling this 170 171 // global set of KeychainDbCommons for name unification 172 typedef std::set<KeychainDbCommon *> CommonSet; 173 static CommonSet mCommonSet; 174 static ReadWriteLock mRWCommonLock; //protects only mCommonSet 175 }; 176 177 178 // 179 // A Database object represents an Apple CSP/DL open database (DL/DB) object. 180 // It maintains its protected semantic state (including keys) and provides controlled 181 // access. 182 // 183 class KeychainDatabase : public LocalDatabase, private virtual SecurityServerAcl { 184 friend class KeychainDbCommon; 185 public: 186 KeychainDatabase(const DLDbIdentifier &id, const DBParameters ¶ms, Process &proc, 187 const AccessCredentials *cred, const AclEntryPrototype *owner); 188 KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc, 189 const AccessCredentials *cred); 190 191 // keychain synchronization recode to a specfic blob: 192 KeychainDatabase(KeychainDatabase &src, Process &proc, DbHandle dbToClone); 193 194 // Clone another database, but to a new DLDb identifier 195 KeychainDatabase(const DLDbIdentifier &id, KeychainDatabase &src, Process &proc); 196 197 // Copy another database, but with new secrets. 198 // To use this, you must provide the version you want to end up with. 199 KeychainDatabase(uint32 requestedVersion, KeychainDatabase &src, Process &proc); 200 virtual ~KeychainDatabase(); 201 202 KeychainDbCommon &common() const; 203 const char *dbName() const; 204 bool transient() const; 205 206 KeychainDbGlobal &global() const { return common().global(); } 207 208 public: 209 static const int maxUnlockTryCount = 3; 210 211 public: 212 const DbIdentifier &identifier() const { return common().identifier(); } 213 214 public: 215 // encoding/decoding databases 216 DbBlob *blob(); 217 218 void authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred); 219 bool checkCredentials(const AccessCredentials* creds); 220 void changePassphrase(const AccessCredentials *cred); 221 RefPointer<Key> extractMasterKey(Database &db, const AccessCredentials *cred, 222 const AclEntryPrototype *owner, uint32 usage, uint32 attrs); 223 void commitSecretsForSync(KeychainDatabase &cloneDb); 224 225 // lock/unlock processing 226 void lockDb(); // unconditional lock 227 void unlockDb(bool unlockKeybag); // full-feature unlock 228 void unlockDb(const CssmData &passphrase, bool unlockKeybag); // unlock with passphrase 229 230 void stashDbCheck(); // check AppleKeyStore for master key 231 void stashDb(); // stash master key in AppleKeyStore 232 233 bool decode(); // unlock given established master key 234 bool decode(const CssmData &passphrase); // set master key from PP, try unlock 235 236 bool validatePassphrase(const CssmData &passphrase) const; // nonthrowing validation 237 bool isLocked() { return common().isLocked(); } // lock status 238 void notify(NotificationEvent event) { return common().notify(event); } 239 void activity() const { common().activity(); } // reset timeout clock 240 241 // encoding/decoding keys 242 void decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl); 243 KeyBlob *encodeKey(const CssmKey &key, const CssmData &pubAcl, const CssmData &privAcl); 244 KeyBlob *recodeKey(KeychainKey &oldKey); 245 bool validBlob() const { return mBlob && version == common().version; } 246 247 // manage database parameters 248 void setParameters(const DBParameters ¶ms); 249 void getParameters(DBParameters ¶ms); 250 251 // where's my (database) ACL? 252 SecurityServerAcl &acl(); 253 254 AclKind aclKind() const; 255 Database *relatedDatabase(); 256 257 // ACL state management hooks 258 void instantiateAcl(); 259 void changedAcl(); 260 261 // miscellaneous utilities 262 static void validateBlob(const DbBlob *blob); 263 264 bool isRecoding(); 265 266 // Notify ourselves that the keychain recode/migration has finished 267 void recodeFinished(); 268 269 // debugging 270 IFDUMP(void dumpNode()); 271 272 protected: 273 RefPointer<Key> makeKey(const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner); 274 RefPointer<Key> makeKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner); 275 276 void makeUnlocked(bool unlockKeybag); // interior version of unlock() 277 void makeUnlocked(const AccessCredentials *cred, bool unlockKeybag); // like () with explicit cred 278 void makeUnlocked(const CssmData &passphrase, bool unlockKeybag); // interior version of unlock(CssmData) 279 280 void establishOldSecrets(const AccessCredentials *creds); 281 bool establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason, bool change); 282 283 bool interactiveUnlock(); 284 285 CssmClient::Key keyFromCreds(const TypedList &sample, unsigned int requiredLength); 286 CssmClient::Key keyFromKeybag(const TypedList &sample); 287 CssmClient::Key makeRawKey(void *data, size_t length, CSSM_ALGORITHMS algid, CSSM_KEYUSE usage); 288 289 void encode(); // (re)generate mBlob if needed 290 291 // Counts the number of total interactive unlocks attempted by securityd 292 static uint32_t interactiveUnlockAttempts; 293 294 public: 295 static uint32_t getInteractiveUnlockAttempts(); 296 297 private: 298 // all following data is locked by the common lock 299 bool mValidData; // valid ACL and params (blob decoded) 300 CssmAutoData mSecret; 301 bool mSaveSecret; 302 303 uint32 version; // version stamp for blob validity 304 DbBlob *mBlob; // database blob (encoded) 305 306 AccessCredentials *mCred; // local access credentials (always valid) 307 308 RefPointer<KeychainDatabase> mRecodingSource; // keychain synchronization ONLY; should not require accessors 309 bool mRecoded; // true once a recode completes, until recodeFinished is called 310 }; 311 312 #endif //_H_KCDATABASE