1/* 2 * Copyright (c) 2000-2001 Apple Computer, 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// SSCSPSession.cpp - Security Server CSP session. 21// 22#include "SSCSPSession.h" 23 24#include "CSPDLPlugin.h" 25#include "SSDatabase.h" 26#include "SSDLSession.h" 27#include "SSKey.h" 28#include <security_cdsa_utilities/cssmbridge.h> 29#include <memory> 30 31using namespace std; 32using namespace SecurityServer; 33 34// 35// SSCSPSession -- Security Server CSP session 36// 37SSCSPSession::SSCSPSession(CSSM_MODULE_HANDLE handle, 38 CSPDLPlugin &plug, 39 const CSSM_VERSION &version, 40 uint32 subserviceId, 41 CSSM_SERVICE_TYPE subserviceType, 42 CSSM_ATTACH_FLAGS attachFlags, 43 const CSSM_UPCALLS &upcalls, 44 SSCSPDLSession &ssCSPDLSession, 45 CssmClient::CSP &rawCsp) 46: CSPFullPluginSession(handle, plug, version, subserviceId, subserviceType, 47 attachFlags, upcalls), 48 mSSCSPDLSession(ssCSPDLSession), 49 mSSFactory(plug.mSSFactory), 50 mRawCsp(rawCsp), 51 mClientSession(Allocator::standard(), *this) 52{ 53 mClientSession.registerForAclEdits(SSCSPDLSession::didChangeKeyAclCallback, &mSSCSPDLSession); 54} 55 56// 57// Called at (CSSM) context create time. This is ignored; we do a full 58// context setup later, at setupContext time. 59// 60CSPFullPluginSession::CSPContext * 61SSCSPSession::contextCreate(CSSM_CC_HANDLE handle, const Context &context) 62{ 63 return NULL; 64} 65 66 67// 68// Called by CSPFullPluginSession when an op is actually commencing. 69// Context can safely assumed to be fully formed and stable for the 70// duration of the op; thus we wait until now to set up our 71// CSPContext as appropriate to the op. 72// 73void 74SSCSPSession::setupContext(CSPContext * &cspCtx, 75 const Context &context, 76 bool encoding) 77{ 78 // note we skip this if this CSPContext is being reused 79 if (cspCtx == NULL) 80 { 81 82 if (mSSFactory.setup(*this, cspCtx, context, encoding)) 83 return; 84 85#if 0 86 if (mBSafe4Factory.setup(*this, cspCtx, context)) 87 return; 88 89 if (mCryptKitFactory.setup(*this, cspCtx, context)) 90 return; 91#endif 92 93 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); 94 } 95} 96 97 98// 99// DL interaction 100// 101SSDatabase 102SSCSPSession::getDatabase(const Context &context) 103{ 104 return getDatabase(context.get<CSSM_DL_DB_HANDLE>(CSSM_ATTRIBUTE_DL_DB_HANDLE)); 105} 106 107SSDatabase 108SSCSPSession::getDatabase(CSSM_DL_DB_HANDLE *aDLDbHandle) 109{ 110 if (aDLDbHandle) 111 return findSession<SSDLSession>(aDLDbHandle->DLHandle).findDbHandle(aDLDbHandle->DBHandle); 112 else 113 return SSDatabase(); 114} 115 116 117// 118// Reference Key management 119// 120void 121SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle, CssmKey &ioKey, SSDatabase &inSSDatabase, 122 uint32 inKeyAttr, const CssmData *inKeyLabel) 123{ 124 return mSSCSPDLSession.makeReferenceKey(*this, inKeyHandle, ioKey, inSSDatabase, inKeyAttr, inKeyLabel); 125} 126 127SSKey & 128SSCSPSession::lookupKey(const CssmKey &inKey) 129{ 130 return mSSCSPDLSession.lookupKey(inKey); 131} 132 133 134// 135// Key creating and handeling members 136// 137void 138SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle, 139 const Context &context, 140 const AccessCredentials &AccessCred, 141 const CssmKey &Key, 142 const CssmData *DescriptiveData, 143 CssmKey &WrappedKey, 144 CSSM_PRIVILEGE Privilege) 145{ 146 // @@@ Deal with permanent keys 147 const CssmKey *keyInContext = 148 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY); 149 150 KeyHandle contextKeyHandle = (keyInContext 151 ? lookupKey(*keyInContext).keyHandle() 152 : noKey); 153 clientSession().wrapKey(context, contextKeyHandle, 154 lookupKey(Key).keyHandle(), &AccessCred, 155 DescriptiveData, WrappedKey, *this); 156} 157 158void 159SSCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle, 160 const Context &context, 161 const CssmKey *PublicKey, 162 const CssmWrappedKey &WrappedKey, 163 uint32 KeyUsage, 164 uint32 KeyAttr, 165 const CssmData *KeyLabel, 166 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry, 167 CssmKey &UnwrappedKey, 168 CssmData &DescriptiveData, 169 CSSM_PRIVILEGE Privilege) 170{ 171 SSDatabase database = getDatabase(context); 172 validateKeyAttr(KeyAttr); 173 const AccessCredentials *cred = NULL; 174 const AclEntryInput *owner = NULL; 175 if (CredAndAclEntry) 176 { 177 cred = AccessCredentials::overlay(CredAndAclEntry->AccessCred); 178 owner = &AclEntryInput::overlay(CredAndAclEntry->InitialAclEntry); 179 } 180 181 KeyHandle publicKey = noKey; 182 if (PublicKey) 183 { 184 if (PublicKey->blobType() == CSSM_KEYBLOB_RAW) 185 { 186 // @@@ We need to unwrap the publicKey into the SecurityServer 187 // before continuing 188 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 189 } 190 else 191 publicKey = lookupKey(*PublicKey).keyHandle(); 192 } 193 194 // @@@ Deal with permanent keys 195 const CssmKey *keyInContext = 196 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY); 197 198 KeyHandle contextKeyHandle = 199 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey; 200 201 KeyHandle unwrappedKeyHandle; 202 clientSession().unwrapKey(database.dbHandle(), context, contextKeyHandle, 203 publicKey, WrappedKey, KeyUsage, KeyAttr, 204 cred, owner, DescriptiveData, unwrappedKeyHandle, 205 UnwrappedKey.header(), *this); 206 makeReferenceKey(unwrappedKeyHandle, UnwrappedKey, database, KeyAttr, 207 KeyLabel); 208} 209 210void 211SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle, 212 const Context &context, 213 CssmData ¶m, 214 uint32 keyUsage, 215 uint32 keyAttr, 216 const CssmData *keyLabel, 217 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, 218 CssmKey &derivedKey) 219{ 220 SSDatabase database = getDatabase(context); 221 validateKeyAttr(keyAttr); 222 const AccessCredentials *cred = NULL; 223 const AclEntryInput *owner = NULL; 224 if (credAndAclEntry) 225 { 226 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred); 227 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry); 228 } 229 230 /* optional BaseKey */ 231 const CssmKey *keyInContext = 232 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY); 233 KeyHandle contextKeyHandle = 234 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey; 235 KeyHandle keyHandle; 236 switch(context.algorithm()) { 237 case CSSM_ALGID_KEYCHAIN_KEY: 238 { 239 // special interpretation: take DLDBHandle -> DbHandle from params 240 clientSession().extractMasterKey(database.dbHandle(), context, 241 getDatabase(param.interpretedAs<CSSM_DL_DB_HANDLE>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE)).dbHandle(), 242 keyUsage, keyAttr, cred, owner, keyHandle, derivedKey.header()); 243 } 244 break; 245 default: 246 clientSession().deriveKey(database.dbHandle(), context, contextKeyHandle, keyUsage, 247 keyAttr, param, cred, owner, keyHandle, derivedKey.header()); 248 break; 249 } 250 makeReferenceKey(keyHandle, derivedKey, database, keyAttr, keyLabel); 251} 252 253void 254SSCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle, 255 const Context &context, 256 uint32 keyUsage, 257 uint32 keyAttr, 258 const CssmData *keyLabel, 259 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, 260 CssmKey &key, 261 CSSM_PRIVILEGE privilege) 262{ 263 SSDatabase database = getDatabase(context); 264 validateKeyAttr(keyAttr); 265 const AccessCredentials *cred = NULL; 266 const AclEntryInput *owner = NULL; 267 if (credAndAclEntry) 268 { 269 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred); 270 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry); 271 } 272 273 KeyHandle keyHandle; 274 clientSession().generateKey(database.dbHandle(), context, keyUsage, 275 keyAttr, cred, owner, keyHandle, key.header()); 276 makeReferenceKey(keyHandle, key, database, keyAttr, keyLabel); 277} 278 279void 280SSCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle, 281 const Context &context, 282 uint32 publicKeyUsage, 283 uint32 publicKeyAttr, 284 const CssmData *publicKeyLabel, 285 CssmKey &publicKey, 286 uint32 privateKeyUsage, 287 uint32 privateKeyAttr, 288 const CssmData *privateKeyLabel, 289 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, 290 CssmKey &privateKey, 291 CSSM_PRIVILEGE privilege) 292{ 293 SSDatabase database = getDatabase(context); 294 validateKeyAttr(publicKeyAttr); 295 validateKeyAttr(privateKeyAttr); 296 const AccessCredentials *cred = NULL; 297 const AclEntryInput *owner = NULL; 298 if (credAndAclEntry) 299 { 300 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred); 301 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry); 302 } 303 304 /* 305 * Public keys must be extractable in the clear - that's the Apple 306 * policy. The raw CSP is unable to enforce the extractable 307 * bit since it always sees that as true (it's managed and forced 308 * true by the SecurityServer). So... 309 */ 310 if(!(publicKeyAttr & CSSM_KEYATTR_EXTRACTABLE)) { 311 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); 312 } 313 KeyHandle pubKeyHandle, privKeyHandle; 314 clientSession().generateKey(database.dbHandle(), context, 315 publicKeyUsage, publicKeyAttr, 316 privateKeyUsage, privateKeyAttr, 317 cred, owner, 318 pubKeyHandle, publicKey.header(), 319 privKeyHandle, privateKey.header()); 320 makeReferenceKey(privKeyHandle, privateKey, database, privateKeyAttr, 321 privateKeyLabel); 322 // @@@ What if this throws, we need to free privateKey. 323 makeReferenceKey(pubKeyHandle, publicKey, database, publicKeyAttr, 324 publicKeyLabel); 325} 326 327void 328SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey, 329 CssmKey &PrivateKey) 330{ 331 unimplemented(); 332} 333 334void 335SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle, 336 const Context *Context, 337 const CssmKey *Key, 338 CSSM_KEY_SIZE &KeySize) 339{ 340 unimplemented(); 341} 342 343void 344SSCSPSession::FreeKey(const AccessCredentials *accessCred, 345 CssmKey &ioKey, CSSM_BOOL deleteKey) 346{ 347 if (ioKey.blobType() == CSSM_KEYBLOB_REFERENCE) 348 { 349 // @@@ Note that this means that detaching a session should free 350 // all keys ascociated with it or else... 351 // -- or else what? 352 // exactly! 353 354 // @@@ There are thread safety issues when deleting a key that is 355 // in use by another thread, but the answer to that is: Don't do 356 // that! 357 358 // Find the key in the map. Tell tell the key to free itself 359 // (when the auto_ptr deletes the key it removes itself from the map). 360 secdebug("freeKey", "CSPDL FreeKey"); 361 auto_ptr<SSKey> ssKey(&mSSCSPDLSession.find<SSKey>(ioKey)); 362 ssKey->free(accessCred, ioKey, deleteKey); 363 } 364 else 365 { 366 CSPFullPluginSession::FreeKey(accessCred, ioKey, deleteKey); 367 } 368} 369 370 371// 372// Generation stuff. 373// 374void 375SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle, 376 const Context &context, 377 CssmData &randomNumber) 378{ 379 checkOperation(context.type(), CSSM_ALGCLASS_RANDOMGEN); 380 // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED); 381 uint32 needed = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE); 382 383 // @@@ What about the seed? 384 if (randomNumber.length()) 385 { 386 if (randomNumber.length() < needed) 387 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); 388 clientSession().generateRandom(context, randomNumber); 389 } 390 else 391 { 392 randomNumber.Data = alloc<uint8>(needed); 393 try 394 { 395 clientSession().generateRandom(context, randomNumber); 396 } 397 catch(...) 398 { 399 free(randomNumber.Data); 400 randomNumber.Data = NULL; 401 throw; 402 } 403 } 404} 405 406// 407// Login/Logout and token operational maintainance. These mean little 408// without support by the actual implementation, but we can help... 409// @@@ Should this be in CSP[non-Full]PluginSession? 410// 411void 412SSCSPSession::Login(const AccessCredentials &AccessCred, 413 const CssmData *LoginName, 414 const void *Reserved) 415{ 416 // @@@ Do a login to the securityServer making keys persistant until it 417 // goes away 418 unimplemented(); 419} 420 421void 422SSCSPSession::Logout() 423{ 424 unimplemented(); 425} 426 427void 428SSCSPSession::VerifyDevice(const CssmData &DeviceCert) 429{ 430 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED); 431} 432 433void 434SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics &statistics) 435{ 436 unimplemented(); 437} 438 439 440// 441// Utterly miscellaneous, rarely used, strange functions 442// 443void 444SSCSPSession::RetrieveCounter(CssmData &Counter) 445{ 446 unimplemented(); 447} 448 449void 450SSCSPSession::RetrieveUniqueId(CssmData &UniqueID) 451{ 452 unimplemented(); 453} 454 455void 456SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData) 457{ 458 unimplemented(); 459} 460 461 462// 463// ACL retrieval and change operations 464// 465void 466SSCSPSession::GetKeyOwner(const CssmKey &Key, 467 CSSM_ACL_OWNER_PROTOTYPE &Owner) 468{ 469 lookupKey(Key).getOwner(Owner, *this); 470} 471 472void 473SSCSPSession::ChangeKeyOwner(const AccessCredentials &AccessCred, 474 const CssmKey &Key, 475 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner) 476{ 477 lookupKey(Key).changeOwner(AccessCred, 478 AclOwnerPrototype::overlay(NewOwner)); 479} 480 481void 482SSCSPSession::GetKeyAcl(const CssmKey &Key, 483 const CSSM_STRING *SelectionTag, 484 uint32 &NumberOfAclInfos, 485 CSSM_ACL_ENTRY_INFO_PTR &AclInfos) 486{ 487 lookupKey(Key).getAcl(reinterpret_cast<const char *>(SelectionTag), 488 NumberOfAclInfos, 489 reinterpret_cast<AclEntryInfo *&>(AclInfos), *this); 490} 491 492void 493SSCSPSession::ChangeKeyAcl(const AccessCredentials &AccessCred, 494 const CSSM_ACL_EDIT &AclEdit, 495 const CssmKey &Key) 496{ 497 lookupKey(Key).changeAcl(AccessCred, AclEdit::overlay(AclEdit)); 498} 499 500void 501SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner) 502{ 503 unimplemented(); 504} 505 506void 507SSCSPSession::ChangeLoginOwner(const AccessCredentials &AccessCred, 508 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner) 509{ 510 unimplemented(); 511} 512 513void 514SSCSPSession::GetLoginAcl(const CSSM_STRING *SelectionTag, 515 uint32 &NumberOfAclInfos, 516 CSSM_ACL_ENTRY_INFO_PTR &AclInfos) 517{ 518 unimplemented(); 519} 520 521void 522SSCSPSession::ChangeLoginAcl(const AccessCredentials &AccessCred, 523 const CSSM_ACL_EDIT &AclEdit) 524{ 525 unimplemented(); 526} 527 528 529 530// 531// Passthroughs 532// 533void 534SSCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle, 535 const Context &context, 536 uint32 passThroughId, 537 const void *inData, 538 void **outData) 539{ 540 checkOperation(context.type(), CSSM_ALGCLASS_NONE); 541 switch (passThroughId) { 542 case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE: 543 { 544 // inData unused, must be NULL 545 if (inData) 546 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER); 547 548 // outData required, must be pointer-to-pointer-to-KeyHandle 549 KeyHandle &result = Required(reinterpret_cast<KeyHandle *>(outData)); 550 551 // we'll take the key from the context 552 const CssmKey &key = 553 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY); 554 555 // all ready 556 result = lookupKey(key).keyHandle(); 557 break; 558 } 559 case CSSM_APPLECSP_KEYDIGEST: 560 { 561 // inData unused, must be NULL 562 if (inData) 563 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER); 564 565 // outData required 566 Required(outData); 567 568 // take the key from the context, convert to KeyHandle 569 const CssmKey &key = 570 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY); 571 KeyHandle keyHandle = lookupKey(key).keyHandle(); 572 573 // allocate digest holder on app's behalf 574 CSSM_DATA *digest = alloc<CSSM_DATA>(sizeof(CSSM_DATA)); 575 digest->Data = NULL; 576 digest->Length = 0; 577 578 // go 579 try { 580 clientSession().getKeyDigest(keyHandle, CssmData::overlay(*digest)); 581 } 582 catch(...) { 583 free(digest); 584 throw; 585 } 586 *outData = digest; 587 break; 588 } 589 590 default: 591 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID); 592 } 593} 594 595/* Validate requested key attr flags for newly generated keys */ 596void SSCSPSession::validateKeyAttr(uint32 reqKeyAttr) 597{ 598 if(reqKeyAttr & (CSSM_KEYATTR_RETURN_DATA)) { 599 /* CSPDL only supports reference keys */ 600 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK); 601 } 602 if(reqKeyAttr & (CSSM_KEYATTR_ALWAYS_SENSITIVE | 603 CSSM_KEYATTR_NEVER_EXTRACTABLE)) { 604 /* invalid for any CSP */ 605 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); 606 } 607 /* There may be more, but we'll leave it to SS and CSP to decide */ 608} 609