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// CSPsession - Plugin framework for CSP plugin modules 21// 22#include <security_cdsa_plugin/CSPsession.h> 23#include <security_cdsa_plugin/cssmplugin.h> 24#include <security_cdsa_utilities/cssmbridge.h> 25 26 27typedef CSPFullPluginSession::CSPContext CSPContext; 28 29 30// 31// PluginContext construction 32// 33CSPPluginSession::PluginContext::~PluginContext() 34{ /* virtual */ } 35 36CSPFullPluginSession::AlgorithmFactory::~AlgorithmFactory() 37{ /* virtual */ } 38 39 40// 41// Internal utilities 42// 43CssmData CSPFullPluginSession::makeBuffer(size_t size, Allocator &alloc) 44{ 45 return CssmData(alloc.malloc(size), size); 46} 47 48inline size_t CSPFullPluginSession::totalBufferSize(const CssmData *data, uint32 count) 49{ 50 size_t size = 0; 51 for (uint32 n = 0; n < count; n++) 52 size += data[n].length(); 53 return size; 54} 55 56 57// 58// Notify a context that its underlying CSSM context has (well, may have) changed. 59// The default reaction is to ask the frame to delete the context and start over. 60// 61bool CSPPluginSession::PluginContext::changed(const Context &context) 62{ 63 return false; // delete me, please 64} 65 66 67// 68// The Session's init() function calls your setupContext() method to prepare 69// it for action, then calls the context's init() method. 70// 71CSPContext *CSPFullPluginSession::init(CSSM_CC_HANDLE ccHandle, 72 CSSM_CONTEXT_TYPE type, 73 const Context &context, bool encoding) 74{ 75 CSPContext *ctx = getContext<CSPContext>(ccHandle); 76 checkOperation(context.type(), type); 77 78 // ask the implementation to set up an internal context 79 setupContext(ctx, context, encoding); 80 assert(ctx != NULL); // must have context now (@@@ throw INTERNAL_ERROR instead?) 81 ctx->mType = context.type(); 82 ctx->mDirection = encoding; 83 setContext(ccHandle, ctx); 84 85 // initialize the context and return it 86 ctx->init(context, encoding); 87 return ctx; 88} 89 90 91// 92// Retrieve a context for a staged operation in progress. 93// 94CSPContext *CSPFullPluginSession::getStagedContext(CSSM_CC_HANDLE ccHandle, 95 CSSM_CONTEXT_TYPE type, bool encoding) 96{ 97 CSPContext *ctx = getContext<CSPContext>(ccHandle); 98 if (ctx == NULL) 99 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT); //@@@ better diagnostic? 100 checkOperation(ctx->type(), type); 101 if (ctx->encoding() != encoding) 102 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT); 103 return ctx; 104} 105 106 107// 108// The Session's checkState() function is called for subsequent staged operations 109// (update/final) to verify that the user didn't screw up the sequencing. 110// 111void CSPFullPluginSession::checkOperation(CSSM_CONTEXT_TYPE ctxType, CSSM_CONTEXT_TYPE opType) 112{ 113 switch (opType) { 114 case CSSM_ALGCLASS_NONE: // no check 115 return; 116 case CSSM_ALGCLASS_CRYPT: // symmetric or asymmetric encryption 117 if (ctxType == CSSM_ALGCLASS_SYMMETRIC || 118 ctxType == CSSM_ALGCLASS_ASYMMETRIC) 119 return; 120 default: // plain match 121 if (ctxType == opType) 122 return; 123 } 124 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT); 125} 126 127 128// 129// The default implementations of the primary context operations throw internal 130// errors. You must implement any of these that are actually called by the 131// operations involved. The others, of course, can be left alone. 132// 133void CSPContext::init(const Context &context, bool encoding) 134{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 135 136void CSPContext::update(const CssmData &data) 137{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 138 139void CSPContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize) 140{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 141 142void CSPContext::final(CssmData &out) 143{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 144 145void CSPContext::final(const CssmData &in) 146{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 147 148void CSPContext::generate(const Context &, CssmKey &pubKey, CssmKey &privKey) 149{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 150 151void CSPContext::generate(const Context &, uint32, CssmData ¶ms, 152 uint32 &attrCount, Context::Attr * &attrs) 153{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 154 155size_t CSPContext::inputSize(size_t outSize) 156{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 157 158size_t CSPContext::outputSize(bool final, size_t inSize) 159{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 160 161void CSPContext::minimumProgress(size_t &in, size_t &out) 162{ CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); } 163 164CSPFullPluginSession::CSPContext *CSPContext::clone(Allocator &) 165{ CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); } 166 167void CSPContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg) 168{ CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } 169 170void CSPContext::update(const CssmData *in, 171 uint32 inCount, Writer &writer) 172{ 173 const CssmData *lastIn = in + inCount; 174 CssmData current; 175 for (;;) { 176 if (current.length() == 0) { 177 if (in == lastIn) 178 return; // all done 179 current = *in++; 180 continue; // Just in case next block is zero length too. 181 } 182 // match up current input and output buffers 183 void *outP; size_t outSize; 184 writer.nextBlock(outP, outSize); 185 size_t inSize = inputSize(outSize); 186 if (inSize > current.length()) 187 inSize = current.length(); // cap to remaining input buffer 188 if (inSize > 0) { 189 // we can stuff into the current output buffer - do it 190 update(current.data(), inSize, outP, outSize); 191 current.use(inSize); 192 writer.use(outSize); 193 } else { 194 // We have remaining output buffer space, but not enough 195 // for the algorithm to make progress with it. We must proceed with 196 // a bounce buffer and split it manually into this and the next buffer(s). 197 size_t minOutput; 198 minimumProgress(inSize, minOutput); 199 assert(minOutput > outSize); // PluginContext consistency (not fatal) 200 char splitBuffer[128]; 201 assert(minOutput <= sizeof(splitBuffer)); // @@@ static buffer for now 202 outSize = sizeof(splitBuffer); 203 if (current.length() < inSize) 204 inSize = current.length(); // cap to data remaining in input buffer 205 update(current.data(), inSize, splitBuffer, outSize); 206 assert(inSize > 0); // progress made 207 writer.put(splitBuffer, outSize); // stuff into buffer, the hard way 208 current.use(inSize); 209 } 210 } 211} 212 213void CSPContext::final(CssmData &out, Allocator &alloc) 214{ 215 size_t needed = outputSize(true, 0); 216 if (out) { 217 if (out.length() < needed) 218 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); 219 } else { 220 out = makeBuffer(needed, alloc); 221 } 222 final(out); 223} 224 225void CSPContext::final(Writer &writer, Allocator &alloc) 226{ 227 if (size_t needed = outputSize(true, 0)) { 228 // need to generate additional output 229 writer.allocate(needed, alloc); // belt + suspender 230 231 void *addr; size_t size; 232 writer.nextBlock(addr, size); // next single block available 233 if (needed <= size) { // rest fits into one block 234 CssmData chunk(addr, size); 235 final(chunk); 236 writer.use(chunk.length()); 237 } else { // need to split it up 238 char splitBuffer[128]; 239 assert(needed <= sizeof(splitBuffer)); 240 CssmData chunk(splitBuffer, sizeof(splitBuffer)); 241 final(chunk); 242 writer.put(chunk.data(), chunk.length()); 243 } 244 } 245} 246 247 248// 249// Default context response functions 250// 251CSPPluginSession::PluginContext * 252CSPPluginSession::contextCreate(CSSM_CC_HANDLE, const Context &) 253{ 254 return NULL; // request no local context 255} 256 257void CSPPluginSession::contextUpdate(CSSM_CC_HANDLE ccHandle, 258 const Context &context, PluginContext * &ctx) 259{ 260 // call update notifier in context object 261 if (ctx && !ctx->changed(context)) { 262 // context requested that it be removed 263 delete ctx; 264 ctx = NULL; 265 } 266} 267 268void CSPPluginSession::contextDelete(CSSM_CC_HANDLE, const Context &, PluginContext *) 269{ 270 // do nothing (you can't prohibit deletion here) 271} 272 273 274// 275// Default event notification handler. 276// This default handler calls the virtual context* methods to dispose of context actions. 277// 278void CSPPluginSession::EventNotify(CSSM_CONTEXT_EVENT event, 279 CSSM_CC_HANDLE ccHandle, const Context &context) 280{ 281 switch (event) { 282 case CSSM_CONTEXT_EVENT_CREATE: 283 if (PluginContext *ctx = contextCreate(ccHandle, context)) { 284 StLock<Mutex> _(contextMapLock); 285 assert(contextMap[ccHandle] == NULL); // check context re-creation 286 contextMap[ccHandle] = ctx; 287 } 288 break; 289 case CSSM_CONTEXT_EVENT_UPDATE: 290 // note that the handler can change the map entry (even to NULL, if desired) 291 { 292 StLock<Mutex> _(contextMapLock); 293 contextUpdate(ccHandle, context, contextMap[ccHandle]); 294 } 295 break; 296 case CSSM_CONTEXT_EVENT_DELETE: 297 { 298 StLock<Mutex> _(contextMapLock); 299 if (PluginContext *ctx = contextMap[ccHandle]) { 300 contextDelete(ccHandle, context, ctx); 301 delete ctx; 302 } 303 contextMap.erase(ccHandle); 304 } 305 break; 306 default: 307 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); // unexpected event code 308 } 309} 310 311 312// 313// Defaults for methods you *should* implement. 314// If you don't, they'll throw UNIMPLEMENTED. 315// 316void CSPFullPluginSession::getKeySize(const CssmKey &key, CSSM_KEY_SIZE &size) 317{ unimplemented(); } 318 319 320// 321// Encryption and decryption 322// 323void CSPFullPluginSession::EncryptData(CSSM_CC_HANDLE ccHandle, 324 const Context &context, 325 const CssmData clearBufs[], 326 uint32 clearBufCount, 327 CssmData cipherBufs[], 328 uint32 cipherBufCount, 329 CSSM_SIZE &bytesEncrypted, 330 CssmData &remData, 331 CSSM_PRIVILEGE privilege) 332{ 333 Writer writer(cipherBufs, cipherBufCount, &remData); 334 CSPContext *ctx = init(ccHandle, CSSM_ALGCLASS_CRYPT, context, true); 335 size_t outNeeded = ctx->outputSize(true, totalBufferSize(clearBufs, clearBufCount)); 336 writer.allocate(outNeeded, *this); 337 ctx->update(clearBufs, clearBufCount, writer); 338 ctx->final(writer, *this); 339 bytesEncrypted = writer.close(); 340} 341 342void CSPFullPluginSession::EncryptDataInit(CSSM_CC_HANDLE ccHandle, 343 const Context &context, 344 CSSM_PRIVILEGE Privilege) 345{ 346 init(ccHandle, CSSM_ALGCLASS_CRYPT, context, true); 347} 348 349void CSPFullPluginSession::EncryptDataUpdate(CSSM_CC_HANDLE ccHandle, 350 const CssmData clearBufs[], 351 uint32 clearBufCount, 352 CssmData cipherBufs[], 353 uint32 cipherBufCount, 354 CSSM_SIZE &bytesEncrypted) 355{ 356 CSPContext *alg = getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, true); 357 Writer writer(cipherBufs, cipherBufCount); 358 size_t outNeeded = alg->outputSize(false, totalBufferSize(clearBufs, clearBufCount)); 359 writer.allocate(outNeeded, *this); 360 alg->update(clearBufs, clearBufCount, writer); 361 bytesEncrypted = writer.close(); 362} 363 364void CSPFullPluginSession::EncryptDataFinal(CSSM_CC_HANDLE ccHandle, 365 CssmData &remData) 366{ 367 getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, true)->final(remData, *this); 368} 369 370 371void CSPFullPluginSession::DecryptData(CSSM_CC_HANDLE ccHandle, 372 const Context &context, 373 const CssmData cipherBufs[], 374 uint32 cipherBufCount, 375 CssmData clearBufs[], 376 uint32 clearBufCount, 377 CSSM_SIZE &bytesDecrypted, 378 CssmData &remData, 379 CSSM_PRIVILEGE privilege) 380{ 381 Writer writer(clearBufs, clearBufCount, &remData); 382 CSPContext *ctx = init(ccHandle, CSSM_ALGCLASS_CRYPT, context, false); 383 size_t outNeeded = ctx->outputSize(true, totalBufferSize(cipherBufs, cipherBufCount)); 384 writer.allocate(outNeeded, *this); 385 ctx->update(cipherBufs, cipherBufCount, writer); 386 ctx->final(writer, *this); 387 bytesDecrypted = writer.close(); 388} 389 390void CSPFullPluginSession::DecryptDataInit(CSSM_CC_HANDLE ccHandle, 391 const Context &context, 392 CSSM_PRIVILEGE Privilege) 393{ 394 init(ccHandle, CSSM_ALGCLASS_CRYPT, context, false); 395} 396 397void CSPFullPluginSession::DecryptDataUpdate(CSSM_CC_HANDLE ccHandle, 398 const CssmData cipherBufs[], 399 uint32 cipherBufCount, 400 CssmData clearBufs[], 401 uint32 clearBufCount, 402 CSSM_SIZE &bytesDecrypted) 403{ 404 CSPContext *ctx = getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, false); 405 Writer writer(clearBufs, clearBufCount); 406 size_t outNeeded = ctx->outputSize(false, totalBufferSize(cipherBufs, cipherBufCount)); 407 writer.allocate(outNeeded, *this); 408 ctx->update(cipherBufs, cipherBufCount, writer); 409 bytesDecrypted = writer.close(); 410} 411 412void CSPFullPluginSession::DecryptDataFinal(CSSM_CC_HANDLE ccHandle, 413 CssmData &remData) 414{ 415 getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, false)->final(remData, *this); 416} 417 418void CSPFullPluginSession::QuerySize(CSSM_CC_HANDLE ccHandle, 419 const Context &context, 420 CSSM_BOOL encrypt, 421 uint32 querySizeCount, 422 QuerySizeData *dataBlock) 423{ 424 if (querySizeCount == 0) 425 return; // nothing ventured, nothing gained 426 CSPContext *ctx = getContext<CSPContext>(ccHandle); // existing context? 427 if (ctx == NULL) // force internal context creation (as best we can) 428 ctx = init(ccHandle, context.type(), context, encrypt); 429 // If QuerySizeCount > 1, we assume this inquires about a staged 430 // operation, and the LAST item gets the 'final' treatment. 431 //@@@ Intel revised algspec says "use the staged flag" -- TBD 432 for (uint32 n = 0; n < querySizeCount; n++) { 433 // the outputSize() call might throw CSSMERR_CSP_QUERY_SIZE_UNKNOWN 434 dataBlock[n].SizeOutputBlock = 435 (uint32)ctx->outputSize(n == querySizeCount-1, dataBlock[n].inputSize()); 436 } 437 //@@@ if we forced a context creation, should we discard it now? 438} 439 440 441// 442// Key wrapping and unwrapping. 443// 444void CSPFullPluginSession::WrapKey(CSSM_CC_HANDLE CCHandle, 445 const Context &Context, 446 const AccessCredentials &AccessCred, 447 const CssmKey &Key, 448 const CssmData *DescriptiveData, 449 CssmKey &WrappedKey, 450 CSSM_PRIVILEGE Privilege) 451{ 452 unimplemented(); 453} 454 455void CSPFullPluginSession::UnwrapKey(CSSM_CC_HANDLE CCHandle, 456 const Context &Context, 457 const CssmKey *PublicKey, 458 const CssmKey &WrappedKey, 459 uint32 KeyUsage, 460 uint32 KeyAttr, 461 const CssmData *KeyLabel, 462 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry, 463 CssmKey &UnwrappedKey, 464 CssmData &DescriptiveData, 465 CSSM_PRIVILEGE Privilege) 466{ 467 unimplemented(); 468} 469 470void CSPFullPluginSession::DeriveKey(CSSM_CC_HANDLE CCHandle, 471 const Context &Context, 472 CssmData &Param, 473 uint32 KeyUsage, 474 uint32 KeyAttr, 475 const CssmData *KeyLabel, 476 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry, 477 CssmKey &DerivedKey) 478{ 479 unimplemented(); 480} 481 482 483// 484// Message Authentication Codes. 485// Almost like signatures (signatures with symmetric keys), though the 486// underlying implementation may be somewhat different. 487// 488void CSPFullPluginSession::GenerateMac(CSSM_CC_HANDLE ccHandle, 489 const Context &context, 490 const CssmData dataBufs[], 491 uint32 dataBufCount, 492 CssmData &mac) 493{ 494 GenerateMacInit(ccHandle, context); 495 GenerateMacUpdate(ccHandle, dataBufs, dataBufCount); 496 GenerateMacFinal(ccHandle, mac); 497} 498 499void CSPFullPluginSession::GenerateMacInit(CSSM_CC_HANDLE ccHandle, 500 const Context &context) 501{ 502 init(ccHandle, CSSM_ALGCLASS_MAC, context, true); 503} 504 505void CSPFullPluginSession::GenerateMacUpdate(CSSM_CC_HANDLE ccHandle, 506 const CssmData dataBufs[], 507 uint32 dataBufCount) 508{ 509 getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, true)->update(dataBufs, dataBufCount); 510} 511 512void CSPFullPluginSession::GenerateMacFinal(CSSM_CC_HANDLE ccHandle, 513 CssmData &mac) 514{ 515 getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, true)->final(mac, *this); 516} 517 518void CSPFullPluginSession::VerifyMac(CSSM_CC_HANDLE ccHandle, 519 const Context &context, 520 const CssmData dataBufs[], 521 uint32 dataBufCount, 522 const CssmData &mac) 523{ 524 VerifyMacInit(ccHandle, context); 525 VerifyMacUpdate(ccHandle, dataBufs, dataBufCount); 526 VerifyMacFinal(ccHandle, mac); 527} 528 529void CSPFullPluginSession::VerifyMacInit(CSSM_CC_HANDLE ccHandle, 530 const Context &context) 531{ 532 init(ccHandle, CSSM_ALGCLASS_MAC, context, false); 533} 534 535void CSPFullPluginSession::VerifyMacUpdate(CSSM_CC_HANDLE ccHandle, 536 const CssmData dataBufs[], 537 uint32 dataBufCount) 538{ 539 getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, false)->update(dataBufs, dataBufCount); 540} 541 542void CSPFullPluginSession::VerifyMacFinal(CSSM_CC_HANDLE ccHandle, 543 const CssmData &mac) 544{ 545 getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, false)->final(mac); 546} 547 548 549// 550// Signatures 551// 552void CSPFullPluginSession::SignData(CSSM_CC_HANDLE ccHandle, 553 const Context &context, 554 const CssmData dataBufs[], 555 uint32 dataBufCount, 556 CSSM_ALGORITHMS digestAlgorithm, 557 CssmData &Signature) 558{ 559 SignDataInit(ccHandle, context); 560 if(digestAlgorithm != CSSM_ALGID_NONE) { 561 getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, 562 true)->setDigestAlgorithm(digestAlgorithm); 563 } 564 SignDataUpdate(ccHandle, dataBufs, dataBufCount); 565 SignDataFinal(ccHandle, Signature); 566} 567 568void CSPFullPluginSession::SignDataInit(CSSM_CC_HANDLE ccHandle, 569 const Context &context) 570{ 571 init(ccHandle, CSSM_ALGCLASS_SIGNATURE, context, true); 572} 573 574void CSPFullPluginSession::SignDataUpdate(CSSM_CC_HANDLE ccHandle, 575 const CssmData dataBufs[], 576 uint32 dataBufCount) 577{ 578 getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, true)->update(dataBufs, dataBufCount); 579} 580 581void CSPFullPluginSession::SignDataFinal(CSSM_CC_HANDLE ccHandle, 582 CssmData &signature) 583{ 584 getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, true)->final(signature, *this); 585} 586 587 588void CSPFullPluginSession::VerifyData(CSSM_CC_HANDLE ccHandle, 589 const Context &context, 590 const CssmData dataBufs[], 591 uint32 dataBufCount, 592 CSSM_ALGORITHMS digestAlgorithm, 593 const CssmData &Signature) 594{ 595 VerifyDataInit(ccHandle, context); 596 if(digestAlgorithm != CSSM_ALGID_NONE) { 597 getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, 598 false)->setDigestAlgorithm(digestAlgorithm); 599 } 600 VerifyDataUpdate(ccHandle, dataBufs, dataBufCount); 601 VerifyDataFinal(ccHandle, Signature); 602} 603 604void CSPFullPluginSession::VerifyDataInit(CSSM_CC_HANDLE ccHandle, const Context &context) 605{ 606 init(ccHandle, CSSM_ALGCLASS_SIGNATURE, context, false); 607} 608 609void CSPFullPluginSession::VerifyDataUpdate(CSSM_CC_HANDLE ccHandle, 610 const CssmData dataBufs[], 611 uint32 dataBufCount) 612{ 613 getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, false)->update(dataBufs, dataBufCount); 614} 615 616void CSPFullPluginSession::VerifyDataFinal(CSSM_CC_HANDLE ccHandle, 617 const CssmData &signature) 618{ 619 getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, false)->final(signature); 620} 621 622 623// 624// Digesting 625// 626void CSPFullPluginSession::DigestData(CSSM_CC_HANDLE ccHandle, 627 const Context &context, 628 const CssmData dataBufs[], 629 uint32 DataBufCount, 630 CssmData &Digest) 631{ 632 DigestDataInit(ccHandle, context); 633 DigestDataUpdate(ccHandle, dataBufs, DataBufCount); 634 DigestDataFinal(ccHandle, Digest); 635} 636 637void CSPFullPluginSession::DigestDataInit(CSSM_CC_HANDLE ccHandle, const Context &context) 638{ 639 init(ccHandle, CSSM_ALGCLASS_DIGEST, context); 640} 641 642void CSPFullPluginSession::DigestDataUpdate(CSSM_CC_HANDLE ccHandle, 643 const CssmData dataBufs[], 644 uint32 dataBufCount) 645{ 646 getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->update(dataBufs, dataBufCount); 647} 648 649void CSPFullPluginSession::DigestDataFinal(CSSM_CC_HANDLE ccHandle, 650 CssmData &digest) 651{ 652 getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->final(digest, *this); 653} 654 655void CSPFullPluginSession::DigestDataClone(CSSM_CC_HANDLE ccHandle, 656 CSSM_CC_HANDLE clonedCCHandle) 657{ 658 CSPContext *cloned = getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->clone(*this); 659 cloned->mDirection = true; 660 cloned->mType = CSSM_ALGCLASS_DIGEST; 661 setContext(clonedCCHandle, cloned); 662} 663 664 665// 666// Key generation, Derivation, and inquiry 667// 668void CSPFullPluginSession::GenerateKey(CSSM_CC_HANDLE ccHandle, 669 const Context &context, 670 uint32 keyUsage, 671 uint32 keyAttr, 672 const CssmData *keyLabel, 673 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, 674 CssmKey &key, 675 CSSM_PRIVILEGE privilege) 676{ 677 CSPContext *alg = init(ccHandle, CSSM_ALGCLASS_KEYGEN, context); 678 setKey(key, context, CSSM_KEYCLASS_SESSION_KEY, keyAttr, keyUsage); 679 CssmKey blank; // dummy 2nd key (not used) 680 alg->generate(context, key, blank); 681} 682 683class ContextMinder 684{ 685private: 686 CSSM_CC_HANDLE mHandle; 687 688public: 689 ContextMinder(CSSM_CC_HANDLE ccHandle) : mHandle(ccHandle) {} 690 ~ContextMinder() {CSSM_DeleteContext(mHandle);} 691}; 692 693 694 695void CSPFullPluginSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle, 696 const Context &context, 697 uint32 publicKeyUsage, 698 uint32 publicKeyAttr, 699 const CssmData *publicKeyLabel, 700 CssmKey &publicKey, 701 uint32 privateKeyUsage, 702 uint32 privateKeyAttr, 703 const CssmData *privateKeyLabel, 704 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, 705 CssmKey &privateKey, 706 CSSM_PRIVILEGE privilege) 707{ 708 CSPContext *alg = init(ccHandle, CSSM_ALGCLASS_KEYGEN, context); 709 710 setKey(publicKey, context, CSSM_KEYCLASS_PUBLIC_KEY, publicKeyAttr, publicKeyUsage); 711 setKey(privateKey, context, CSSM_KEYCLASS_PRIVATE_KEY, privateKeyAttr, privateKeyUsage); 712 alg->generate(context, publicKey, privateKey); 713 714 //@@@ handle labels 715 //@@@ handle reference keys 716 717 bool encryptPublic = publicKeyUsage & CSSM_KEYUSE_ENCRYPT; 718 bool encryptPrivate = privateKeyUsage & CSSM_KEYUSE_ENCRYPT; 719 720 if (!(encryptPublic || encryptPrivate)) 721 { 722 return ; 723 } 724 725 // time to do the FIPS required test! 726 CSSM_CSP_HANDLE moduleHandle = handle(); 727 CSSM_CC_HANDLE encryptHandle; 728 CSSM_ACCESS_CREDENTIALS nullCreds; 729 memset(&nullCreds, 0, sizeof(nullCreds)); 730 731 CSSM_KEY_PTR encryptingKey, decryptingKey; 732 if (encryptPublic) 733 { 734 encryptingKey = &publicKey; 735 decryptingKey = &privateKey; 736 } 737 else 738 { 739 encryptingKey = &privateKey; 740 decryptingKey = &publicKey; 741 } 742 743 // make data to be encrypted 744 unsigned bytesInKey = encryptingKey->KeyHeader.LogicalKeySizeInBits / 8; 745 u_int8_t buffer[bytesInKey]; 746 unsigned i; 747 748 for (i = 0; i < bytesInKey; ++i) 749 { 750 buffer[i] = i; 751 } 752 753 CSSM_DATA clearBuf = {bytesInKey, buffer}; 754 CSSM_DATA cipherBuf; // have the CSP allocate the resulting memory 755 CSSM_SIZE bytesEncrypted; 756 CSSM_DATA remData = {0, NULL}; 757 CSSM_DATA decryptedBuf = {bytesInKey, buffer}; 758 759 CSSM_RETURN result = CSSM_CSP_CreateAsymmetricContext(moduleHandle, encryptingKey->KeyHeader.AlgorithmId, &nullCreds, encryptingKey, CSSM_PADDING_NONE, &encryptHandle); 760 if (result != CSSM_OK) 761 { 762 CssmError::throwMe(result); 763 } 764 765 ContextMinder encryptMinder(encryptHandle); // auto throw away if we error out 766 767 CSSM_QUERY_SIZE_DATA qsData; 768 qsData.SizeInputBlock = bytesInKey; 769 result = CSSM_QuerySize(encryptHandle, CSSM_TRUE, 1, &qsData); 770 if (result == CSSMERR_CSP_INVALID_ALGORITHM) 771 { 772 return; 773 } 774 775 uint8 cipherBuffer[qsData.SizeOutputBlock]; 776 cipherBuf.Length = qsData.SizeOutputBlock; 777 cipherBuf.Data = cipherBuffer; 778 779 // do the encryption 780 result = CSSM_EncryptData(encryptHandle, &clearBuf, 1, &cipherBuf, 1, &bytesEncrypted, &remData); 781 if (result != CSSM_OK) 782 { 783 CssmError::throwMe(result); 784 } 785 786 // check the result 787 if (memcmp(cipherBuf.Data, clearBuf.Data, clearBuf.Length) == 0) 788 { 789 // we have a match, that's not good news... 790 abort(); 791 } 792 793 // clean up 794 if (remData.Data != NULL) 795 { 796 free(remData.Data); 797 } 798 799 // make a context to perform the decryption 800 CSSM_CC_HANDLE decryptHandle; 801 result = CSSM_CSP_CreateAsymmetricContext(moduleHandle, encryptingKey->KeyHeader.AlgorithmId, &nullCreds, decryptingKey, CSSM_PADDING_NONE, &decryptHandle); 802 ContextMinder decryptMinder(decryptHandle); 803 804 if (result != CSSM_OK) 805 { 806 CssmError::throwMe(result); 807 } 808 809 result = CSSM_DecryptData(decryptHandle, &cipherBuf, 1, &decryptedBuf, 1, &bytesEncrypted, &remData); 810 if (result != CSSM_OK) 811 { 812 CssmError::throwMe(result); 813 } 814 815 // check the results 816 for (i = 0; i < bytesInKey; ++i) 817 { 818 if (decryptedBuf.Data[i] != (i & 0xFF)) 819 { 820 // bad news 821 abort(); 822 } 823 } 824 825 if (remData.Data != NULL) 826 { 827 free(remData.Data); 828 } 829} 830 831void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey, 832 CssmKey &PrivateKey) 833{ 834 unimplemented(); 835} 836 837void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle, 838 const Context *context, 839 const CssmKey *key, 840 CSSM_KEY_SIZE &keySize) 841{ 842 if (context) { 843 getKeySize(context->get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY), 844 keySize); 845 } else { 846 getKeySize(CssmKey::required(key), keySize); 847 } 848} 849 850 851// 852// Free a key object. 853// 854void CSPFullPluginSession::FreeKey(const AccessCredentials *AccessCred, 855 CssmKey &key, 856 CSSM_BOOL Delete) 857{ 858 free(key.data()); 859} 860 861 862// 863// Random number and parameter generation 864// 865void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle, 866 const Context &context, 867 CssmData &randomNumber) 868{ 869 init(ccHandle, CSSM_ALGCLASS_RANDOMGEN, context)->final(randomNumber, *this); 870} 871 872void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle, 873 const Context &context, 874 uint32 paramBits, 875 CssmData ¶m, 876 uint32 &attrCount, 877 CSSM_CONTEXT_ATTRIBUTE_PTR &attrs) 878{ 879 Context::Attr *attrList; 880 init(ccHandle, CSSM_ALGCLASS_NONE, context)->generate(context, paramBits, 881 param, attrCount, attrList); 882 attrs = attrList; 883} 884 885 886// 887// Login/Logout and token operational maintainance. 888// These mean little without support by the actual implementation, but we can help... 889// @@@ Should this be in CSP[non-Full]PluginSession? 890// 891void CSPFullPluginSession::Login(const AccessCredentials &AccessCred, 892 const CssmData *LoginName, 893 const void *Reserved) 894{ 895 if (Reserved != NULL) 896 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER); 897 898 // default implementation refuses to log in 899 //@@@ should hand it to implementation virtual defaulting to this 900 CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME); 901} 902 903void CSPFullPluginSession::Logout() 904{ 905 if (!loggedIn(false)) 906 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN); 907} 908 909void CSPFullPluginSession::VerifyDevice(const CssmData &DeviceCert) 910{ 911 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED); 912} 913 914void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics &statistics) 915{ 916 memset(&statistics, 0, sizeof(statistics)); 917 statistics.UserAuthenticated = loggedIn(); 918 //@@@ collect device flags - capability matrix setup? 919 //@@@ collect token limitation parameters (static) - capability matrix setup? 920 //@@@ collect token statistics (dynamic) - dynamic accounting call-downs? 921} 922 923 924// 925// Utterly miscellaneous, rarely used, strange functions 926// 927void CSPFullPluginSession::RetrieveCounter(CssmData &Counter) 928{ 929 unimplemented(); 930} 931 932void CSPFullPluginSession::RetrieveUniqueId(CssmData &UniqueID) 933{ 934 unimplemented(); 935} 936 937void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData) 938{ 939 unimplemented(); 940} 941 942 943// 944// ACL retrieval and change operations 945// 946void CSPFullPluginSession::GetKeyOwner(const CssmKey &Key, 947 CSSM_ACL_OWNER_PROTOTYPE &Owner) 948{ 949 unimplemented(); 950} 951 952void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials &AccessCred, 953 const CssmKey &Key, 954 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner) 955{ 956 unimplemented(); 957} 958 959void CSPFullPluginSession::GetKeyAcl(const CssmKey &Key, 960 const CSSM_STRING *SelectionTag, 961 uint32 &NumberOfAclInfos, 962 CSSM_ACL_ENTRY_INFO_PTR &AclInfos) 963{ 964 unimplemented(); 965} 966 967void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials &AccessCred, 968 const CSSM_ACL_EDIT &AclEdit, 969 const CssmKey &Key) 970{ 971 unimplemented(); 972} 973 974void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner) 975{ 976 unimplemented(); 977} 978 979void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials &AccessCred, 980 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner) 981{ 982 unimplemented(); 983} 984 985void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING *SelectionTag, 986 uint32 &NumberOfAclInfos, 987 CSSM_ACL_ENTRY_INFO_PTR &AclInfos) 988{ 989 unimplemented(); 990} 991 992void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials &AccessCred, 993 const CSSM_ACL_EDIT &AclEdit) 994{ 995 unimplemented(); 996} 997 998 999 1000// 1001// Passthroughs (by default, unimplemented) 1002// 1003void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle, 1004 const Context &Context, 1005 uint32 PassThroughId, 1006 const void *InData, 1007 void **OutData) 1008{ 1009 unimplemented(); 1010} 1011 1012 1013// 1014// KeyPool -- ReferencedKey management functionality 1015// 1016KeyPool::KeyPool() 1017{ 1018} 1019 1020KeyPool::~KeyPool() 1021{ 1022 StLock<Mutex> _(mKeyMapLock); 1023 // Delete every ReferencedKey in the pool, but be careful to deactivate them first 1024 // to keep them from calling erase (which would cause deadlock since we already hold mKeyMapLock). 1025 KeyMap::iterator end = mKeyMap.end(); 1026 for (KeyMap::iterator it = mKeyMap.begin(); it != end; ++it) 1027 { 1028 try 1029 { 1030 it->second->deactivate(); 1031 } 1032 catch(...) {} 1033 delete it->second; 1034 } 1035 mKeyMap.clear(); 1036} 1037 1038void 1039KeyPool::add(ReferencedKey &referencedKey) 1040{ 1041 StLock<Mutex> _(mKeyMapLock); 1042 bool inserted; 1043 inserted = mKeyMap.insert(KeyMap::value_type(referencedKey.keyReference(), &referencedKey)).second; 1044 // Since add is only called from the constructor of ReferencedKey we should 1045 // never add a key that is already in mKeyMap 1046 assert(inserted); 1047} 1048 1049ReferencedKey & 1050KeyPool::findKey(const CSSM_KEY &key) const 1051{ 1052 return findKeyReference(ReferencedKey::keyReference(key)); 1053} 1054 1055ReferencedKey & 1056KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference) const 1057{ 1058 StLock<Mutex> _(mKeyMapLock); 1059 KeyMap::const_iterator it = mKeyMap.find(keyReference); 1060 if (it == mKeyMap.end()) 1061 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE); 1062 1063 return *it->second; 1064} 1065 1066void 1067KeyPool::erase(ReferencedKey &referencedKey) 1068{ 1069 erase(referencedKey.keyReference()); 1070} 1071 1072ReferencedKey & 1073KeyPool::erase(ReferencedKey::KeyReference keyReference) 1074{ 1075 StLock<Mutex> _(mKeyMapLock); 1076 KeyMap::iterator it = mKeyMap.find(keyReference); 1077 if (it == mKeyMap.end()) 1078 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE); 1079 1080 ReferencedKey &referencedKey = *it->second; 1081 mKeyMap.erase(it); 1082 return referencedKey; 1083} 1084 1085// Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey 1086void 1087KeyPool::freeKey(Allocator &allocator, CSSM_KEY &ioKey) 1088{ 1089 delete &erase(ReferencedKey::freeReferenceKey(allocator, ioKey)); 1090} 1091 1092// 1093// ReferencedKey class 1094// 1095ReferencedKey::ReferencedKey(KeyPool &keyPool) : mKeyPool(&keyPool) 1096{ 1097 mKeyPool->add(*this); 1098} 1099 1100ReferencedKey::~ReferencedKey() 1101{ 1102 if (isActive()) 1103 mKeyPool->erase(*this); 1104} 1105 1106ReferencedKey::KeyReference 1107ReferencedKey::keyReference() 1108{ 1109 // @@@ Possibly check isActive() and return an invalid reference if it is not set. 1110 return reinterpret_cast<ReferencedKey::KeyReference>(this); 1111} 1112 1113// 1114// Making, retrieving and freeing Key references of CssmKeys 1115// 1116void 1117ReferencedKey::makeReferenceKey(Allocator &allocator, KeyReference keyReference, CSSM_KEY &key) 1118{ 1119 key.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE; 1120 key.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER; 1121 key.KeyData.Length = sizeof(KeyReference); 1122 key.KeyData.Data = allocator.alloc<uint8>(sizeof(KeyReference)); 1123 uint8 *cp = key.KeyData.Data; 1124 for (int i = sizeof(KeyReference); --i >= 0;) 1125 { 1126 cp[i] = keyReference & 0xff; 1127 keyReference = keyReference >> 8; 1128 } 1129} 1130 1131ReferencedKey::KeyReference 1132ReferencedKey::keyReference(const CSSM_KEY &key) 1133{ 1134 if (key.KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE 1135 || key.KeyHeader.Format != CSSM_KEYBLOB_REF_FORMAT_INTEGER 1136 || key.KeyData.Length != sizeof(KeyReference) 1137 || key.KeyData.Data == NULL) 1138 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE); 1139 1140 const uint8 *cp = key.KeyData.Data; 1141 KeyReference keyReference = 0; 1142 for (uint32 i = 0; i < sizeof(KeyReference); ++i) 1143 keyReference = (keyReference << 8) + cp[i]; 1144 1145 return keyReference; 1146} 1147 1148ReferencedKey::KeyReference 1149ReferencedKey::freeReferenceKey(Allocator &allocator, CSSM_KEY &key) 1150{ 1151 KeyReference aKeyReference = keyReference(key); 1152 allocator.free(key.KeyData.Data); 1153 key.KeyData.Data = NULL; 1154 key.KeyData.Length = 0; 1155 return aKeyReference; 1156} 1157