1/* 2 * Copyright (c) 2000-2001,2008,2011-2012 Apple Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19// 20// SSKey - reference keys for the security server 21// 22#include "SSKey.h" 23 24#include "SSCSPSession.h" 25#include "SSCSPDLSession.h" 26#include "SSDatabase.h" 27#include "SSDLSession.h" 28#include <security_cdsa_utilities/KeySchema.h> 29#include <security_cdsa_plugin/cssmplugin.h> 30 31using namespace CssmClient; 32using namespace SecurityServer; 33 34// Constructor for a Security Server generated key. 35SSKey::SSKey(SSCSPSession &session, KeyHandle keyHandle, CssmKey &ioKey, 36 SSDatabase &inSSDatabase, uint32 inKeyAttr, 37 const CssmData *inKeyLabel) 38: ReferencedKey(session.mSSCSPDLSession), 39mAllocator(session), mKeyHandle(keyHandle), 40mClientSession(session.clientSession()) 41{ 42 CssmKey::Header &header = ioKey.header(); 43 if (inKeyAttr & CSSM_KEYATTR_PERMANENT) 44 { 45 if (!inSSDatabase) 46 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE); 47 48 // EncodeKey and store it in the db. 49 CssmDataContainer blob(mAllocator); 50 clientSession().encodeKey(keyHandle, blob); 51 52 assert(header.HeaderVersion == CSSM_KEYHEADER_VERSION); 53 switch (header.KeyClass) 54 { 55 case CSSM_KEYCLASS_PUBLIC_KEY: 56 mRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY; 57 break; 58 case CSSM_KEYCLASS_PRIVATE_KEY: 59 mRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; 60 break; 61 case CSSM_KEYCLASS_SESSION_KEY: 62 mRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY; 63 break; 64 default: 65 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 66 } 67 68 CssmData label; 69 if (inKeyLabel) 70 label = *inKeyLabel; 71 72 CssmData none; 73 // We store the keys real CSP guid on disk 74 CssmGuidData creatorGuid(header.CspId); 75 CssmDateData startDate(header.StartDate); 76 CssmDateData endDate(header.EndDate); 77 78 DbAttributes attributes(inSSDatabase); 79 attributes.recordType(mRecordType); 80 attributes.add(KeySchema::KeyClass, mRecordType); 81 attributes.add(KeySchema::PrintName, label); 82 attributes.add(KeySchema::Alias, none); 83 attributes.add(KeySchema::Permanent, 84 header.attribute(CSSM_KEYATTR_PERMANENT)); 85 attributes.add(KeySchema::Private, 86 header.attribute(CSSM_KEYATTR_PRIVATE)); 87 attributes.add(KeySchema::Modifiable, 88 header.attribute(CSSM_KEYATTR_MODIFIABLE)); 89 attributes.add(KeySchema::Label, label); 90 attributes.add(KeySchema::ApplicationTag, none); 91 attributes.add(KeySchema::KeyCreator, creatorGuid); 92 attributes.add(KeySchema::KeyType, header.AlgorithmId); 93 attributes.add(KeySchema::KeySizeInBits, header.LogicalKeySizeInBits); 94 // @@@ Get the real effective key size. 95 attributes.add(KeySchema::EffectiveKeySize, header.LogicalKeySizeInBits); 96 attributes.add(KeySchema::StartDate, startDate); 97 attributes.add(KeySchema::EndDate, endDate); 98 attributes.add(KeySchema::Sensitive, 99 header.attribute(CSSM_KEYATTR_SENSITIVE)); 100 attributes.add(KeySchema::AlwaysSensitive, 101 header.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE)); 102 attributes.add(KeySchema::Extractable, 103 header.attribute(CSSM_KEYATTR_EXTRACTABLE)); 104 attributes.add(KeySchema::NeverExtractable, 105 header.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE)); 106 attributes.add(KeySchema::Encrypt, 107 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_ENCRYPT)); 108 attributes.add(KeySchema::Decrypt, 109 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DECRYPT)); 110 attributes.add(KeySchema::Derive, 111 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DERIVE)); 112 attributes.add(KeySchema::Sign, 113 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_SIGN)); 114 attributes.add(KeySchema::Verify, 115 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_VERIFY)); 116 attributes.add(KeySchema::SignRecover, 117 header.useFor(CSSM_KEYUSE_ANY 118 | CSSM_KEYUSE_SIGN_RECOVER)); 119 attributes.add(KeySchema::VerifyRecover, 120 header.useFor(CSSM_KEYUSE_ANY 121 | CSSM_KEYUSE_VERIFY_RECOVER)); 122 attributes.add(KeySchema::Wrap, 123 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_WRAP)); 124 attributes.add(KeySchema::Unwrap, 125 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_UNWRAP)); 126 127 // @@@ Fixme 128 mUniqueId = inSSDatabase->insert(mRecordType, &attributes, &blob, 129 true); 130 } 131 132 header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me. 133 makeReferenceKey(mAllocator, keyReference(), ioKey); 134} 135 136// Constructor for a key retrived from a Db. 137SSKey::SSKey(SSDLSession &session, CssmKey &ioKey, SSDatabase &inSSDatabase, 138 const SSUniqueRecord &uniqueId, CSSM_DB_RECORDTYPE recordType, 139 CssmData &keyBlob) 140: ReferencedKey(session.mSSCSPDLSession), 141mAllocator(session.allocator()), mKeyHandle(noKey), mUniqueId(uniqueId), 142mRecordType(recordType), 143mClientSession(session.clientSession()) 144{ 145 CssmKey::Header &header = ioKey.header(); 146 memset(&header, 0, sizeof(header)); // Clear key header 147 148 if (!mUniqueId || !mUniqueId->database()) 149 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 150 151 header.HeaderVersion = CSSM_KEYHEADER_VERSION; 152 switch (mRecordType) 153 { 154 case CSSM_DL_DB_RECORD_PUBLIC_KEY: 155 header.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; 156 break; 157 case CSSM_DL_DB_RECORD_PRIVATE_KEY: 158 header.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; 159 break; 160 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY: 161 header.KeyClass = CSSM_KEYCLASS_SESSION_KEY; 162 break; 163 default: 164 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 165 } 166 167 DbAttributes attributes(mUniqueId->database()); 168 attributes.recordType(mRecordType); 169 attributes.add(KeySchema::KeyClass); // 0 170 attributes.add(KeySchema::Permanent); // 1 171 attributes.add(KeySchema::Private); // 2 172 attributes.add(KeySchema::Modifiable); // 3 173 attributes.add(KeySchema::KeyCreator); // 4 174 attributes.add(KeySchema::KeyType); // 5 175 attributes.add(KeySchema::KeySizeInBits); // 6 176 attributes.add(KeySchema::StartDate); // 7 177 attributes.add(KeySchema::EndDate); // 8 178 attributes.add(KeySchema::Sensitive); // 9 179 attributes.add(KeySchema::AlwaysSensitive); // 10 180 attributes.add(KeySchema::Extractable); // 11 181 attributes.add(KeySchema::NeverExtractable); // 12 182 attributes.add(KeySchema::Encrypt); // 13 183 attributes.add(KeySchema::Decrypt); // 14 184 attributes.add(KeySchema::Derive); // 15 185 attributes.add(KeySchema::Sign); // 16 186 attributes.add(KeySchema::Verify); // 17 187 attributes.add(KeySchema::SignRecover); // 18 188 attributes.add(KeySchema::VerifyRecover); // 19 189 attributes.add(KeySchema::Wrap); // 20 190 attributes.add(KeySchema::Unwrap); // 21 191 192 mUniqueId->get(&attributes, NULL); 193 194 // Assert that the mRecordType matches the KeyClass attribute. 195 if (mRecordType != uint32(attributes[0])) 196 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 197 198 header.AlgorithmId = attributes[5]; // KeyType 199 header.LogicalKeySizeInBits = attributes[6]; // KeySizeInBits 200 201 if (attributes[1]) header.setAttribute(CSSM_KEYATTR_PERMANENT); 202 if (attributes[2]) header.setAttribute(CSSM_KEYATTR_PRIVATE); 203 if (attributes[3]) header.setAttribute(CSSM_KEYATTR_MODIFIABLE); 204 if (attributes[9]) header.setAttribute(CSSM_KEYATTR_SENSITIVE); 205 if (attributes[11]) header.setAttribute(CSSM_KEYATTR_EXTRACTABLE); 206 if (attributes[10]) header.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE); 207 if (attributes[12]) header.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE); 208 209 if (attributes[13]) header.usage(CSSM_KEYUSE_ENCRYPT); 210 if (attributes[14]) header.usage(CSSM_KEYUSE_DECRYPT); 211 if (attributes[15]) header.usage(CSSM_KEYUSE_DERIVE); 212 if (attributes[16]) header.usage(CSSM_KEYUSE_SIGN); 213 if (attributes[17]) header.usage(CSSM_KEYUSE_VERIFY); 214 if (attributes[18]) header.usage(CSSM_KEYUSE_SIGN_RECOVER); 215 if (attributes[19]) header.usage(CSSM_KEYUSE_VERIFY_RECOVER); 216 if (attributes[20]) header.usage(CSSM_KEYUSE_WRAP); 217 if (attributes[21]) header.usage(CSSM_KEYUSE_UNWRAP); 218 219 // If all usages are allowed set usage to CSSM_KEYUSE_ANY 220 if (header.usage() == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT 221 | CSSM_KEYUSE_DERIVE | CSSM_KEYUSE_SIGN 222 | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER 223 | CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP 224 | CSSM_KEYUSE_UNWRAP)) 225 header.usage(CSSM_KEYUSE_ANY); 226 227 if (!attributes[7].size() || !attributes[8].size()) 228 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 229 230 header.StartDate = attributes[7].at<CSSM_DATE>(0); 231 header.EndDate = attributes[8].at<CSSM_DATE>(0); 232 233 makeReferenceKey(mAllocator, keyReference(), ioKey); 234 header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me. 235} 236 237SSKey::~SSKey() 238{ 239 if (mKeyHandle != noKey) 240 clientSession().releaseKey(mKeyHandle); 241} 242 243void 244SSKey::free(const AccessCredentials *accessCred, CssmKey &ioKey, 245 CSSM_BOOL deleteKey) 246{ 247 freeReferenceKey(mAllocator, ioKey); 248 if (deleteKey) 249 { 250 if (!mUniqueId || !mUniqueId->database()) 251 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 252 253 // @@@ Evaluate accessCred against Db acl. 254 // What should we do with accessCred? Reauthenticate 255 // mUniqueId->database()? 256 mUniqueId->deleteRecord(); 257 } 258 259 if (mKeyHandle != noKey) 260 { 261 clientSession().releaseKey(mKeyHandle); 262 mKeyHandle = noKey; 263 } 264} 265 266SecurityServer::ClientSession & 267SSKey::clientSession() 268{ 269 return mClientSession; 270} 271 272KeyHandle SSKey::optionalKeyHandle() const 273{ 274 return mKeyHandle; 275} 276 277KeyHandle 278SSKey::keyHandle() 279{ 280 if (mKeyHandle == noKey) 281 { 282 // Deal with uninstantiated keys. 283 if (!mUniqueId || !mUniqueId->database()) 284 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 285 286 CssmDataContainer blob(mAllocator); 287 mUniqueId->get(NULL, &blob); 288 CssmKey::Header dummyHeader; // @@@ Unused 289 mKeyHandle = 290 clientSession().decodeKey(mUniqueId->database().dbHandle(), blob, 291 dummyHeader); 292 293 // @@@ Check decoded header against returned header 294 } 295 296 return mKeyHandle; 297} 298 299// 300// ACL retrieval and change operations 301// 302void 303SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE &owner, Allocator &allocator) 304{ 305 clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner), 306 allocator); 307} 308 309void 310SSKey::changeOwner(const AccessCredentials &accessCred, 311 const AclOwnerPrototype &newOwner) 312{ 313 clientSession().changeKeyOwner(keyHandle(), accessCred, newOwner); 314 didChangeAcl(); 315} 316 317void 318SSKey::getAcl(const char *selectionTag, uint32 &numberOfAclInfos, 319 AclEntryInfo *&aclInfos, Allocator &allocator) 320{ 321 clientSession().getKeyAcl(keyHandle(), selectionTag, numberOfAclInfos, 322 aclInfos, allocator); 323} 324 325void 326SSKey::changeAcl(const AccessCredentials &accessCred, const AclEdit &aclEdit) 327{ 328 clientSession().changeKeyAcl(keyHandle(), accessCred, aclEdit); 329 didChangeAcl(); 330} 331 332void 333SSKey::didChangeAcl() 334{ 335 if (mUniqueId == true) 336 { 337 secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", (unsigned long)mKeyHandle); 338 // The key is persistent, make the change on disk. 339 CssmDataContainer keyBlob(mAllocator); 340 clientSession().encodeKey(keyHandle(), keyBlob); 341 mUniqueId->modify(mRecordType, NULL, &keyBlob, CSSM_DB_MODIFY_ATTRIBUTE_NONE); 342 } 343 else 344 { 345 secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", (unsigned long)mKeyHandle); 346 } 347} 348