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