]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_pluginlib/CSPsession.cpp
Security-163.tar.gz
[apple/security.git] / cdsa / cdsa_pluginlib / CSPsession.cpp
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 #ifdef __MWERKS__
23 #define _CPP_CSPSESSION
24 #endif
25
26 #include <Security/CSPsession.h>
27 #include <Security/cssmplugin.h>
28
29
30 typedef CSPFullPluginSession::CSPContext CSPContext;
31
32
33 //
34 // PluginContext construction
35 //
36 CSPPluginSession::PluginContext::~PluginContext()
37 { }
38
39
40 //
41 // Internal utilities
42 //
43 CssmData CSPFullPluginSession::makeBuffer(size_t size, CssmAllocator &alloc)
44 {
45 return CssmData(alloc.malloc(size), size);
46 }
47
48 inline 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 //
61 bool 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 //
71 CSPContext *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 //
94 CSPContext *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 //
111 void 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 //
133 void CSPContext::init(const Context &context, bool encoding)
134 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
135
136 void CSPContext::update(const CssmData &data)
137 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
138
139 void CSPContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize)
140 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
141
142 void CSPContext::final(CssmData &out)
143 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
144
145 void CSPContext::final(const CssmData &in)
146 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
147
148 void CSPContext::generate(const Context &, CssmKey &pubKey, CssmKey &privKey)
149 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
150
151 void CSPContext::generate(const Context &, uint32, CssmData &params,
152 uint32 &attrCount, Context::Attr * &attrs)
153 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
154
155 size_t CSPContext::inputSize(size_t outSize)
156 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
157
158 size_t CSPContext::outputSize(bool final, size_t inSize)
159 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
160
161 void CSPContext::minimumProgress(size_t &in, size_t &out)
162 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); }
163
164 CSPFullPluginSession::CSPContext *CSPContext::clone(CssmAllocator &)
165 { CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); }
166
167 void CSPContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg)
168 { CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); }
169
170 void 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
213 void CSPContext::final(CssmData &out, CssmAllocator &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
225 void CSPContext::final(Writer &writer, CssmAllocator &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 //
251 CSPPluginSession::PluginContext *
252 CSPPluginSession::contextCreate(CSSM_CC_HANDLE, const Context &)
253 {
254 return NULL; // request no local context
255 }
256
257 void 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
268 void 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 //
278 void 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 //
316 void CSPFullPluginSession::getKeySize(const CssmKey &key, CSSM_KEY_SIZE &size)
317 { unimplemented(); }
318
319
320 //
321 // Encryption and decryption
322 //
323 void CSPFullPluginSession::EncryptData(CSSM_CC_HANDLE ccHandle,
324 const Context &context,
325 const CssmData clearBufs[],
326 uint32 clearBufCount,
327 CssmData cipherBufs[],
328 uint32 cipherBufCount,
329 uint32 &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
342 void 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
349 void CSPFullPluginSession::EncryptDataUpdate(CSSM_CC_HANDLE ccHandle,
350 const CssmData clearBufs[],
351 uint32 clearBufCount,
352 CssmData cipherBufs[],
353 uint32 cipherBufCount,
354 uint32 &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
364 void CSPFullPluginSession::EncryptDataFinal(CSSM_CC_HANDLE ccHandle,
365 CssmData &remData)
366 {
367 getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, true)->final(remData, *this);
368 }
369
370
371 void CSPFullPluginSession::DecryptData(CSSM_CC_HANDLE ccHandle,
372 const Context &context,
373 const CssmData cipherBufs[],
374 uint32 cipherBufCount,
375 CssmData clearBufs[],
376 uint32 clearBufCount,
377 uint32 &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
390 void 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
397 void CSPFullPluginSession::DecryptDataUpdate(CSSM_CC_HANDLE ccHandle,
398 const CssmData cipherBufs[],
399 uint32 cipherBufCount,
400 CssmData clearBufs[],
401 uint32 clearBufCount,
402 uint32 &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
412 void CSPFullPluginSession::DecryptDataFinal(CSSM_CC_HANDLE ccHandle,
413 CssmData &remData)
414 {
415 getStagedContext(ccHandle, CSSM_ALGCLASS_CRYPT, false)->final(remData, *this);
416 }
417
418 void 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 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 //
444 void 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
455 void 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
470 void 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 //
488 void 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
499 void CSPFullPluginSession::GenerateMacInit(CSSM_CC_HANDLE ccHandle,
500 const Context &context)
501 {
502 init(ccHandle, CSSM_ALGCLASS_MAC, context, true);
503 }
504
505 void 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
512 void CSPFullPluginSession::GenerateMacFinal(CSSM_CC_HANDLE ccHandle,
513 CssmData &mac)
514 {
515 getStagedContext(ccHandle, CSSM_ALGCLASS_MAC, true)->final(mac, *this);
516 }
517
518 void 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
529 void CSPFullPluginSession::VerifyMacInit(CSSM_CC_HANDLE ccHandle,
530 const Context &context)
531 {
532 init(ccHandle, CSSM_ALGCLASS_MAC, context, false);
533 }
534
535 void 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
542 void 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 //
552 void 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
568 void CSPFullPluginSession::SignDataInit(CSSM_CC_HANDLE ccHandle,
569 const Context &context)
570 {
571 init(ccHandle, CSSM_ALGCLASS_SIGNATURE, context, true);
572 }
573
574 void 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
581 void CSPFullPluginSession::SignDataFinal(CSSM_CC_HANDLE ccHandle,
582 CssmData &signature)
583 {
584 getStagedContext(ccHandle, CSSM_ALGCLASS_SIGNATURE, true)->final(signature, *this);
585 }
586
587
588 void 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
604 void CSPFullPluginSession::VerifyDataInit(CSSM_CC_HANDLE ccHandle, const Context &context)
605 {
606 init(ccHandle, CSSM_ALGCLASS_SIGNATURE, context, false);
607 }
608
609 void 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
616 void 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 //
626 void 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
637 void CSPFullPluginSession::DigestDataInit(CSSM_CC_HANDLE ccHandle, const Context &context)
638 {
639 init(ccHandle, CSSM_ALGCLASS_DIGEST, context);
640 }
641
642 void 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
649 void CSPFullPluginSession::DigestDataFinal(CSSM_CC_HANDLE ccHandle,
650 CssmData &digest)
651 {
652 getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->final(digest, *this);
653 }
654
655 void 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 //
668 void 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
683 void CSPFullPluginSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle,
684 const Context &context,
685 uint32 publicKeyUsage,
686 uint32 publicKeyAttr,
687 const CssmData *publicKeyLabel,
688 CssmKey &publicKey,
689 uint32 privateKeyUsage,
690 uint32 privateKeyAttr,
691 const CssmData *privateKeyLabel,
692 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
693 CssmKey &privateKey,
694 CSSM_PRIVILEGE privilege)
695 {
696 CSPContext *alg = init(ccHandle, CSSM_ALGCLASS_KEYGEN, context);
697
698 setKey(publicKey, context, CSSM_KEYCLASS_PUBLIC_KEY, publicKeyAttr, publicKeyUsage);
699 setKey(privateKey, context, CSSM_KEYCLASS_PRIVATE_KEY, privateKeyAttr, privateKeyUsage);
700 alg->generate(context, publicKey, privateKey);
701 //@@@ handle labels
702 //@@@ handle reference keys
703 }
704
705 void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
706 CssmKey &PrivateKey)
707 {
708 unimplemented();
709 }
710
711 void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle,
712 const Context *context,
713 const CssmKey *key,
714 CSSM_KEY_SIZE &keySize)
715 {
716 if (context) {
717 getKeySize(context->get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY),
718 keySize);
719 } else {
720 getKeySize(CssmKey::required(key), keySize);
721 }
722 }
723
724
725 //
726 // Free a key object.
727 //
728 void CSPFullPluginSession::FreeKey(const AccessCredentials *AccessCred,
729 CssmKey &key,
730 CSSM_BOOL Delete)
731 {
732 free(key.data());
733 }
734
735
736 //
737 // Random number and parameter generation
738 //
739 void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
740 const Context &context,
741 CssmData &randomNumber)
742 {
743 init(ccHandle, CSSM_ALGCLASS_RANDOMGEN, context)->final(randomNumber, *this);
744 }
745
746 void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle,
747 const Context &context,
748 uint32 paramBits,
749 CssmData &param,
750 uint32 &attrCount,
751 CSSM_CONTEXT_ATTRIBUTE_PTR &attrs)
752 {
753 Context::Attr *attrList;
754 init(ccHandle, CSSM_ALGCLASS_NONE, context)->generate(context, paramBits,
755 param, attrCount, attrList);
756 attrs = attrList;
757 }
758
759
760 //
761 // Login/Logout and token operational maintainance.
762 // These mean little without support by the actual implementation, but we can help...
763 // @@@ Should this be in CSP[non-Full]PluginSession?
764 //
765 void CSPFullPluginSession::Login(const AccessCredentials &AccessCred,
766 const CssmData *LoginName,
767 const void *Reserved)
768 {
769 if (Reserved != NULL)
770 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
771
772 // default implementation refuses to log in
773 //@@@ should hand it to implementation virtual defaulting to this
774 CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME);
775 }
776
777 void CSPFullPluginSession::Logout()
778 {
779 if (!loggedIn(false))
780 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN);
781 }
782
783 void CSPFullPluginSession::VerifyDevice(const CssmData &DeviceCert)
784 {
785 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
786 }
787
788 void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
789 {
790 memset(&statistics, 0, sizeof(statistics));
791 statistics.UserAuthenticated = loggedIn();
792 //@@@ collect device flags - capability matrix setup?
793 //@@@ collect token limitation parameters (static) - capability matrix setup?
794 //@@@ collect token statistics (dynamic) - dynamic accounting call-downs?
795 }
796
797
798 //
799 // Utterly miscellaneous, rarely used, strange functions
800 //
801 void CSPFullPluginSession::RetrieveCounter(CssmData &Counter)
802 {
803 unimplemented();
804 }
805
806 void CSPFullPluginSession::RetrieveUniqueId(CssmData &UniqueID)
807 {
808 unimplemented();
809 }
810
811 void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
812 {
813 unimplemented();
814 }
815
816
817 //
818 // ACL retrieval and change operations
819 //
820 void CSPFullPluginSession::GetKeyOwner(const CssmKey &Key,
821 CSSM_ACL_OWNER_PROTOTYPE &Owner)
822 {
823 unimplemented();
824 }
825
826 void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
827 const CssmKey &Key,
828 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
829 {
830 unimplemented();
831 }
832
833 void CSPFullPluginSession::GetKeyAcl(const CssmKey &Key,
834 const CSSM_STRING *SelectionTag,
835 uint32 &NumberOfAclInfos,
836 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
837 {
838 unimplemented();
839 }
840
841 void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
842 const CSSM_ACL_EDIT &AclEdit,
843 const CssmKey &Key)
844 {
845 unimplemented();
846 }
847
848 void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
849 {
850 unimplemented();
851 }
852
853 void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
854 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
855 {
856 unimplemented();
857 }
858
859 void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
860 uint32 &NumberOfAclInfos,
861 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
862 {
863 unimplemented();
864 }
865
866 void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
867 const CSSM_ACL_EDIT &AclEdit)
868 {
869 unimplemented();
870 }
871
872
873
874 //
875 // Passthroughs (by default, unimplemented)
876 //
877 void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle,
878 const Context &Context,
879 uint32 PassThroughId,
880 const void *InData,
881 void **OutData)
882 {
883 unimplemented();
884 }
885
886
887 //
888 // KeyPool -- ReferencedKey management functionality
889 //
890 KeyPool::KeyPool()
891 {
892 }
893
894 KeyPool::~KeyPool()
895 {
896 StLock<Mutex> _(mKeyMapLock);
897 // Delete every ReferencedKey in the pool, but be careful to deactivate them first
898 // to keep them from calling erase (which would cause deadlock since we already hold mKeyMapLock).
899 KeyMap::iterator end = mKeyMap.end();
900 for (KeyMap::iterator it = mKeyMap.begin(); it != end; ++it)
901 {
902 try
903 {
904 it->second->deactivate();
905 }
906 catch(...) {}
907 delete it->second;
908 }
909 mKeyMap.clear();
910 }
911
912 void
913 KeyPool::add(ReferencedKey &referencedKey)
914 {
915 StLock<Mutex> _(mKeyMapLock);
916 IFDEBUG(bool inserted =)
917 mKeyMap.insert(KeyMap::value_type(referencedKey.keyReference(), &referencedKey)).second;
918 // Since add is only called from the constructor of ReferencedKey we should
919 // never add a key that is already in mKeyMap
920 assert(inserted);
921 }
922
923 ReferencedKey &
924 KeyPool::findKey(const CSSM_KEY &key) const
925 {
926 return findKeyReference(ReferencedKey::keyReference(key));
927 }
928
929 ReferencedKey &
930 KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference) const
931 {
932 StLock<Mutex> _(mKeyMapLock);
933 KeyMap::const_iterator it = mKeyMap.find(keyReference);
934 if (it == mKeyMap.end())
935 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
936
937 return *it->second;
938 }
939
940 void
941 KeyPool::erase(ReferencedKey &referencedKey)
942 {
943 erase(referencedKey.keyReference());
944 }
945
946 ReferencedKey &
947 KeyPool::erase(ReferencedKey::KeyReference keyReference)
948 {
949 StLock<Mutex> _(mKeyMapLock);
950 KeyMap::iterator it = mKeyMap.find(keyReference);
951 if (it == mKeyMap.end())
952 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
953
954 mKeyMap.erase(it);
955 ReferencedKey &referencedKey = *it->second;
956 return referencedKey;
957 }
958
959 // Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
960 void
961 KeyPool::freeKey(CssmAllocator &allocator, CSSM_KEY &ioKey)
962 {
963 delete &erase(ReferencedKey::freeReferenceKey(allocator, ioKey));
964 }
965
966 //
967 // ReferencedKey class
968 //
969 ReferencedKey::ReferencedKey(KeyPool &keyPool) : mKeyPool(&keyPool)
970 {
971 mKeyPool->add(*this);
972 }
973
974 ReferencedKey::~ReferencedKey()
975 {
976 if (isActive())
977 mKeyPool->erase(*this);
978 }
979
980 ReferencedKey::KeyReference
981 ReferencedKey::keyReference()
982 {
983 // @@@ Possibly check isActive() and return an invalid reference if it is not set.
984 return reinterpret_cast<ReferencedKey::KeyReference>(this);
985 }
986
987 //
988 // Making, retrieving and freeing Key references of CssmKeys
989 //
990 void
991 ReferencedKey::makeReferenceKey(CssmAllocator &allocator, KeyReference keyReference, CSSM_KEY &key)
992 {
993 key.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE;
994 key.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER;
995 key.KeyData.Length = sizeof(KeyReference);
996 key.KeyData.Data = allocator.alloc<uint8>(sizeof(KeyReference));
997 uint8 *cp = key.KeyData.Data;
998 for (int i = sizeof(KeyReference); --i >= 0;)
999 {
1000 cp[i] = keyReference & 0xff;
1001 keyReference = keyReference >> 8;
1002 }
1003 }
1004
1005 ReferencedKey::KeyReference
1006 ReferencedKey::keyReference(const CSSM_KEY &key)
1007 {
1008 if (key.KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE
1009 || key.KeyHeader.Format != CSSM_KEYBLOB_REF_FORMAT_INTEGER
1010 || key.KeyData.Length != sizeof(KeyReference)
1011 || key.KeyData.Data == NULL)
1012 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1013
1014 const uint8 *cp = key.KeyData.Data;
1015 KeyReference keyReference = 0;
1016 for (uint32 i = 0; i < sizeof(KeyReference); ++i)
1017 keyReference = (keyReference << 8) + cp[i];
1018
1019 return keyReference;
1020 }
1021
1022 ReferencedKey::KeyReference
1023 ReferencedKey::freeReferenceKey(CssmAllocator &allocator, CSSM_KEY &key)
1024 {
1025 KeyReference aKeyReference = keyReference(key);
1026 allocator.free(key.KeyData.Data);
1027 key.KeyData.Data = NULL;
1028 key.KeyData.Length = 0;
1029 return aKeyReference;
1030 }