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