// // Second stage of keychain synchronization: overwrite the original keychain's // (this KeychainDatabase's) operational secrets // void KeychainDatabase::commitSecretsForSync(KeychainDatabase &cloneDb) { StLock<Mutex> _(common()); // try to detect spoofing if (cloneDb.mRecodingSource != this) CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE); // in case we autolocked since starting the sync makeUnlocked(); // call this because we already own the lock cloneDb.unlockDb(); // we may not own the lock here, so calling unlockDb will lock the cloneDb's common lock // Decode all keys whose handles refer to this on-disk keychain so that // if the holding client commits the key back to disk, it's encoded with // the new operational secrets. The recoding client *must* hold a write // lock for the on-disk keychain from the moment it starts recoding key // items until after this call. // // @@@ This specific implementation is a workaround for 4003540. std::vector<U32HandleObject::Handle> handleList; U32HandleObject::findAllRefs<KeychainKey>(handleList); size_t count = handleList.size(); if (count > 0) { for (unsigned int n = 0; n < count; ++n) { RefPointer<KeychainKey> kckey = U32HandleObject::findRefAndLock<KeychainKey>(handleList[n], CSSMERR_CSP_INVALID_KEY_REFERENCE); StLock<Mutex> _(*kckey/*, true*/); if (kckey->database().global().identifier() == identifier()) { kckey->key(); // force decode kckey->invalidateBlob(); secdebug("kcrecode", "changed extant key %p (proc %d)", &*kckey, kckey->process().pid()); } } } // it is now safe to replace the old op secrets common().importSecrets(cloneDb.common()); common().invalidateBlob(); }
// // Given a (truncated) Database credentials TypedList specifying a master key, // locate the key and return a reference to it. // CssmClient::Key KeychainDatabase::keyFromCreds(const TypedList &sample, unsigned int requiredLength) { // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY) assert(sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY || sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY); if (sample.length() != requiredLength || sample[1].type() != CSSM_LIST_ELEMENT_DATUM || sample[2].type() != CSSM_LIST_ELEMENT_DATUM || (requiredLength == 4 && sample[3].type() != CSSM_LIST_ELEMENT_DATUM)) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); KeyHandle &handle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); // We used to be able to check the length but supporting multiple client // architectures dishes that (sizeof(CSSM_KEY) varies due to alignment and // field-size differences). The decoding in the transition layer should // serve as a sufficient garbling check anyway. if (sample[2].data().data() == NULL) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); CssmKey &key = *sample[2].data().interpretedAs<CssmKey>(); if (key.header().cspGuid() == gGuidAppleCSPDL) { // handleOrKey is a SecurityServer KeyHandle; ignore key argument return safer_cast<LocalKey &>(*Server::key(handle)); } else if (sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY) { /* Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp) sample[0] sample type sample[1] csp handle for master or wrapping key; is really a keyhandle sample[2] masterKey [not used since securityd cannot interpret; use sample[1] handle instead] sample[3] UnlockReferralRecord data, in this case the flattened symmetric key */ // RefPointer<Key> Server::key(KeyHandle key) KeyHandle keyhandle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); CssmData &flattenedKey = sample[3].data(); RefPointer<Key> unwrappingKey = Server::key(keyhandle); Database &db=unwrappingKey->database(); CssmKey rawWrappedKey; unflattenKey(flattenedKey, rawWrappedKey); RefPointer<Key> masterKey; CssmData emptyDescriptiveData; const AccessCredentials *cred = NULL; const AclEntryPrototype *owner = NULL; CSSM_KEYUSE usage = CSSM_KEYUSE_ANY; CSSM_KEYATTR_FLAGS attrs = CSSM_KEYATTR_EXTRACTABLE; //CSSM_KEYATTR_RETURN_REF | // Get default credentials for unwrappingKey (the one on the token) // Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp // Following KeyItem::getCredentials, one sees that the "operation" parameter // e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored Allocator &alloc = Allocator::standard(); AutoCredentials promptCred(alloc, 3);// enable interactive prompting // promptCred: a credential permitting user prompt confirmations // contains: // a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD // a PROMPTED_PASSWORD sample promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT); promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD, new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT))); promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, new(alloc) ListElement(alloc, CssmData())); // This unwrap object is here just to provide a context CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); //ok to lie about csp here unwrap.mode(CSSM_ALGMODE_NONE); unwrap.padding(CSSM_PADDING_PKCS1); unwrap.cred(promptCred); unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7)); Security::Context *tmpContext; CSSM_CC_HANDLE CCHandle = unwrap.handle(); /*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle, (CSSM_CONTEXT_PTR *)&tmpContext); // OK, this is skanky but necessary. We overwrite fields in the context struct tmpContext->ContextType = CSSM_ALGCLASS_ASYMMETRIC; tmpContext->AlgorithmType = CSSM_ALGID_RSA; db.unwrapKey(*tmpContext, cred, owner, unwrappingKey, NULL, usage, attrs, rawWrappedKey, masterKey, emptyDescriptiveData); Allocator::standard().free(rawWrappedKey.KeyData.Data); return safer_cast<LocalKey &>(*masterKey).key(); } else { // not a KeyHandle reference; use key as a raw key if (key.header().blobType() != CSSM_KEYBLOB_RAW) CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE); if (key.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY) CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); return CssmClient::Key(Server::csp(), key, true); } }