/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ // // key - representation of SecurityServer key objects // #include "key.h" #include "server.h" #include "xdatabase.h" #include // // Create a Key object from a database-encoded blob. // Note that this doesn't decode the blob (yet). // Key::Key(Database &db, const KeyBlob *blob) : SecurityServerAcl(keyAcl, CssmAllocator::standard()), mDigest(Server::csp().allocator()) { // perform basic validation on the incoming blob assert(blob); blob->validate(CSSMERR_APPLEDL_INVALID_KEY_BLOB); switch (blob->version()) { #if defined(COMPAT_OSX_10_0) case blob->version_MacOS_10_0: break; #endif case blob->version_MacOS_10_1: break; default: CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_KEY_BLOB); } // set it up mDatabase = &db; mBlob = blob->copy(CssmAllocator::standard()); mAttributes = 0; mValidBlob = true; mValidKey = false; mValidUID = false; secdebug("SSkey", "%p (handle 0x%lx) created from blob version %lx", this, handle(), blob->version()); } // // Create a Key from an explicit CssmKey. // Key::Key(Database *db, const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner) : SecurityServerAcl(keyAcl, CssmAllocator::standard()), mDigest(Server::csp().allocator()) { if (moreAttributes & CSSM_KEYATTR_PERMANENT) { // better have a database to make it permanent in... if (!db) CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE); } else { // non-permanent; ignore database db = NULL; } mDatabase = db; mValidKey = true; mBlob = NULL; mValidBlob = false; mValidUID = false; setup(newKey, moreAttributes); // establish initial ACL; reinterpret empty (null-list) owner as NULL for resilence's sake if (owner && !owner->subject().empty()) cssmSetInitial(*owner); // specified else cssmSetInitial(new AnyAclSubject()); // defaulted secdebug("SSkey", "%p (handle 0x%lx) created from key alg=%ld use=0x%lx attr=0x%lx db=%p", this, handle(), mKey.header().algorithm(), mKey.header().usage(), mAttributes, db); } // // Set up the CssmKey part of this Key according to instructions. // void Key::setup(const CssmKey &newKey, uint32 moreAttributes) { mKey = CssmClient::Key(Server::csp(), newKey, false); CssmKey::Header &header = mKey->header(); // copy key header header = newKey.header(); mAttributes = (header.attributes() & ~forcedAttributes) | moreAttributes; // apply initial values of derived attributes (these are all in managedAttributes) if (!(mAttributes & CSSM_KEYATTR_EXTRACTABLE)) mAttributes |= CSSM_KEYATTR_NEVER_EXTRACTABLE; if (mAttributes & CSSM_KEYATTR_SENSITIVE) mAttributes |= CSSM_KEYATTR_ALWAYS_SENSITIVE; // verify internal/external attribute separation assert((header.attributes() & managedAttributes) == forcedAttributes); } Key::~Key() { CssmAllocator::standard().free(mBlob); secdebug("SSkey", "%p destroyed", this); } // // Form a KeySpec with checking and masking // Key::KeySpec::KeySpec(uint32 usage, uint32 attrs) : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes) { if (attrs & generatedAttributes) CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } Key::KeySpec::KeySpec(uint32 usage, uint32 attrs, const CssmData &label) : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes, label) { if (attrs & generatedAttributes) CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } // // Retrieve the actual CssmKey value for the key object. // This will decode its blob if needed (and appropriate). // CssmClient::Key Key::keyValue() { decode(); return mKey; } // // Ensure that a key is fully decoded. // This makes the mKey key value available for use, as well as its ACL. // void Key::decode() { if (!mValidKey) { assert(mDatabase); // have to have a database (to decode the blob) assert(mValidBlob); // must have a blob to decode // decode the key void *publicAcl, *privateAcl; CssmKey key; database()->decodeKey(mBlob, key, publicAcl, privateAcl); mKey = CssmClient::Key(Server::csp(), key); importBlob(publicAcl, privateAcl); // publicAcl points into the blob; privateAcl was allocated for us CssmAllocator::standard().free(privateAcl); // extract managed attribute bits mAttributes = mKey.header().attributes() & managedAttributes; mKey.header().clearAttribute(managedAttributes); mKey.header().setAttribute(forcedAttributes); // key is valid now mValidKey = true; } } // // Return a key's handle and header in external form // void Key::returnKey(Handle &h, CssmKey::Header &hdr) { // return handle h = handle(); // obtain the key header, from the valid key or the blob if no valid key if (mValidKey) { hdr = mKey.header(); } else { assert(mValidBlob); hdr = mBlob->header; n2hi(hdr); // correct for endian-ness } // adjust for external attributes hdr.clearAttribute(forcedAttributes); hdr.setAttribute(mAttributes); } // // Generate the canonical key digest. // This is defined by a CSP feature that we invoke here. // const CssmData &Key::canonicalDigest() { if (!mDigest) { CssmClient::PassThrough ctx(Server::csp()); ctx.key(keyValue()); CssmData *digest = NULL; ctx(CSSM_APPLECSP_KEYDIGEST, (const void *)NULL, &digest); assert(digest); mDigest.set(*digest); // takes ownership of digest data Server::csp().allocator().free(digest); // the CssmData itself } return mDigest.get(); } // // Encode a key into a blob. // We'll have to ask our Database to do this - we don't have its keys. // Note that this returns memory we own and keep. // KeyBlob *Key::blob() { if (mDatabase == NULL) // can't encode independent keys CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE); if (!mValidBlob) { assert(mValidKey); // must have valid key to encode //@@@ release mBlob memory here // export Key ACL to blob form CssmData pubAcl, privAcl; exportBlob(pubAcl, privAcl); // assemble external key form CssmKey externalKey = mKey; externalKey.clearAttribute(forcedAttributes); externalKey.setAttribute(mAttributes); // encode the key and replace blob KeyBlob *newBlob = database()->encodeKey(externalKey, pubAcl, privAcl); CssmAllocator::standard().free(mBlob); mBlob = newBlob; mValidBlob = true; // clean up and go database()->allocator.free(pubAcl); database()->allocator.free(privAcl); } return mBlob; } // // Return the UID of a key (the hash of its bits) // KeyUID &Key::uid() { if (!mValidUID) { //@@@ calculate UID here memset(&mUID, 0, sizeof(mUID)); mValidUID = true; } return mUID; } // // Intercept ACL change requests and reset blob validity // void Key::instantiateAcl() { decode(); } void Key::changedAcl() { mValidBlob = false; } const Database *Key::relatedDatabase() const { return database(); }