1/* 2 * Copyright (c) 2000-2001,2004-2006,2008-2009 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// key - representation of securityd key objects 27// 28#include "kckey.h" 29#include "server.h" 30#include "database.h" 31#include <security_cdsa_utilities/acl_any.h> 32#include <security_cdsa_utilities/cssmendian.h> 33 34 35// 36// Create a Key object from a database-encoded blob. 37// Note that this doesn't decode the blob (yet). 38// 39KeychainKey::KeychainKey(Database &db, const KeyBlob *blob) 40 : LocalKey(db, n2h(blob->header.attributes())) 41{ 42 // perform basic validation on the incoming blob 43 assert(blob); 44 blob->validate(CSSMERR_APPLEDL_INVALID_KEY_BLOB); 45 switch (blob->version()) { 46#if defined(COMPAT_OSX_10_0) 47 case KeyBlob::version_MacOS_10_0: 48 break; 49#endif 50 case KeyBlob::version_MacOS_10_1: 51 break; 52 default: 53 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_KEY_BLOB); 54 } 55 56 // set it up 57 mBlob = blob->copy(Allocator::standard()); 58 mValidBlob = true; 59 db.addReference(*this); 60 secdebug("SSkey", "%p (handle %#x) created from blob version %x", 61 this, handle(), blob->version()); 62} 63 64 65// 66// Create a Key from an explicit CssmKey. 67// 68KeychainKey::KeychainKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, 69 const AclEntryPrototype *owner) 70 : LocalKey(db, newKey, moreAttributes) 71{ 72 assert(moreAttributes & CSSM_KEYATTR_PERMANENT); 73 setOwner(owner); 74 mBlob = NULL; 75 mValidBlob = false; 76 db.addReference(*this); 77} 78 79 80KeychainKey::~KeychainKey() 81{ 82 Allocator::standard().free(mBlob); 83 secdebug("SSkey", "%p destroyed", this); 84} 85 86 87KeychainDatabase &KeychainKey::database() const 88{ 89 return referent<KeychainDatabase>(); 90} 91 92 93// 94// Retrieve the actual CssmKey value for the key object. 95// This will decode its blob if needed (and appropriate). 96// 97void KeychainKey::getKey() 98{ 99 decode(); 100} 101 102void KeychainKey::getHeader(CssmKey::Header &hdr) 103{ 104 assert(mValidBlob); 105 hdr = mBlob->header; 106 n2hi(hdr); // correct for endian-ness 107} 108 109 110// 111// Ensure that a key is fully decoded. 112// This makes the mKey key value available for use, as well as its ACL. 113// Caller must hold the key object lock. 114// 115void KeychainKey::decode() 116{ 117 if (!mValidKey) { 118 assert(mValidBlob); // must have a blob to decode 119 120 // decode the key 121 void *publicAcl, *privateAcl; 122 CssmKey key; 123 database().decodeKey(mBlob, key, publicAcl, privateAcl); 124 mKey = CssmClient::Key(Server::csp(), key); 125 acl().importBlob(publicAcl, privateAcl); 126 // publicAcl points into the blob; privateAcl was allocated for us 127 Allocator::standard().free(privateAcl); 128 129 // extract managed attribute bits 130 mAttributes = mKey.header().attributes() & managedAttributes; 131 mKey.header().clearAttribute(managedAttributes); 132 mKey.header().setAttribute(forcedAttributes); 133 134 // key is valid now 135 mValidKey = true; 136 } 137} 138 139 140// 141// Encode a key into a blob. 142// We'll have to ask our Database to do this - we don't have its keys. 143// Note that this returns memory we own and keep. 144// 145KeyBlob *KeychainKey::blob() 146{ 147 if (!mValidBlob) { 148 assert(mValidKey); // must have valid key to encode 149 150 // export Key ACL to blob form 151 CssmData pubAcl, privAcl; 152 acl().exportBlob(pubAcl, privAcl); 153 154 // assemble external key form 155 CssmKey externalKey = mKey; 156 externalKey.clearAttribute(forcedAttributes); 157 externalKey.setAttribute(mAttributes); 158 159 // encode the key and replace blob 160 KeyBlob *newBlob = database().encodeKey(externalKey, pubAcl, privAcl); 161 Allocator::standard().free(mBlob); 162 mBlob = newBlob; 163 mValidBlob = true; 164 165 // clean up and go 166 acl().allocator.free(pubAcl); 167 acl().allocator.free(privAcl); 168 } 169 return mBlob; 170} 171 172void KeychainKey::invalidateBlob() 173{ 174 mValidBlob = false; 175} 176 177 178// 179// Override ACL-related methods and events. 180// Decode the key before ACL activity; invalidate the stored blob on ACL edits; 181// and return the key's database as "related". 182// 183void KeychainKey::instantiateAcl() 184{ 185 StLock<Mutex> _(*this); 186 decode(); 187} 188 189void KeychainKey::changedAcl() 190{ 191 invalidateBlob(); 192} 193 194 195// 196// Intercept Key validation and double-check that the keychain is (still) unlocked 197// 198void KeychainKey::validate(AclAuthorization auth, const AccessCredentials *cred, 199 Database *relatedDatabase) 200{ 201 if(!mBlob->isClearText()) { 202 /* unlock not needed for cleartext keys */ 203 if (KeychainDatabase *db = dynamic_cast<KeychainDatabase *>(relatedDatabase)) 204 db->unlockDb(); 205 } 206 SecurityServerAcl::validate(auth, cred, relatedDatabase); 207 database().activity(); // upon successful validation 208} 209 210 211// 212// We're a key (duh) 213// 214AclKind KeychainKey::aclKind() const 215{ 216 return keyAcl; 217} 218 219 220Database *KeychainKey::relatedDatabase() 221{ 222 return &database(); 223} 224 225SecurityServerAcl &KeychainKey::acl() 226{ 227 return *this; 228} 229