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