]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_pluginlib/CSPsession.cpp
d18fd08e010255b17dbafdf6dbf4a8f600c55981
[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 inline 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 setContext(clonedCCHandle, getStagedContext(ccHandle, CSSM_ALGCLASS_DIGEST)->clone(*this));
659 }
660
661
662 //
663 // Key generation, Derivation, and inquiry
664 //
665 void CSPFullPluginSession::GenerateKey(CSSM_CC_HANDLE ccHandle,
666 const Context &context,
667 uint32 keyUsage,
668 uint32 keyAttr,
669 const CssmData *keyLabel,
670 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
671 CssmKey &key,
672 CSSM_PRIVILEGE privilege)
673 {
674 CSPContext *alg = init(ccHandle, CSSM_ALGCLASS_KEYGEN, context);
675 setKey(key, context, CSSM_KEYCLASS_SESSION_KEY, keyAttr, keyUsage);
676 CssmKey blank; // dummy 2nd key (not used)
677 alg->generate(context, key, blank);
678 }
679
680 void CSPFullPluginSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle,
681 const Context &context,
682 uint32 publicKeyUsage,
683 uint32 publicKeyAttr,
684 const CssmData *publicKeyLabel,
685 CssmKey &publicKey,
686 uint32 privateKeyUsage,
687 uint32 privateKeyAttr,
688 const CssmData *privateKeyLabel,
689 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
690 CssmKey &privateKey,
691 CSSM_PRIVILEGE privilege)
692 {
693 CSPContext *alg = init(ccHandle, CSSM_ALGCLASS_KEYGEN, context);
694
695 setKey(publicKey, context, CSSM_KEYCLASS_PUBLIC_KEY, publicKeyAttr, publicKeyUsage);
696 setKey(privateKey, context, CSSM_KEYCLASS_PRIVATE_KEY, privateKeyAttr, privateKeyUsage);
697 alg->generate(context, publicKey, privateKey);
698 //@@@ handle labels
699 //@@@ handle reference keys
700 }
701
702 void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
703 CssmKey &PrivateKey)
704 {
705 unimplemented();
706 }
707
708 void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle,
709 const Context *context,
710 const CssmKey *key,
711 CSSM_KEY_SIZE &keySize)
712 {
713 if (context) {
714 getKeySize(context->get<CSSM_KEY>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY),
715 keySize);
716 } else {
717 getKeySize(CssmKey::required(key), keySize);
718 }
719 }
720
721
722 //
723 // Free a key object.
724 //
725 void CSPFullPluginSession::FreeKey(const AccessCredentials *AccessCred,
726 CssmKey &key,
727 CSSM_BOOL Delete)
728 {
729 free(key.data());
730 }
731
732
733 //
734 // Random number and parameter generation
735 //
736 void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
737 const Context &context,
738 CssmData &randomNumber)
739 {
740 init(ccHandle, CSSM_ALGCLASS_RANDOMGEN, context)->final(randomNumber, *this);
741 }
742
743 void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle,
744 const Context &context,
745 uint32 paramBits,
746 CssmData &param,
747 uint32 &attrCount,
748 CSSM_CONTEXT_ATTRIBUTE_PTR &attrs)
749 {
750 Context::Attr *attrList;
751 init(ccHandle, CSSM_ALGCLASS_NONE, context)->generate(context, paramBits,
752 param, attrCount, attrList);
753 attrs = attrList;
754 }
755
756
757 //
758 // Login/Logout and token operational maintainance.
759 // These mean little without support by the actual implementation, but we can help...
760 // @@@ Should this be in CSP[non-Full]PluginSession?
761 //
762 void CSPFullPluginSession::Login(const AccessCredentials &AccessCred,
763 const CssmData *LoginName,
764 const void *Reserved)
765 {
766 if (Reserved != NULL)
767 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
768
769 // default implementation refuses to log in
770 //@@@ should hand it to implementation virtual defaulting to this
771 CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME);
772 }
773
774 void CSPFullPluginSession::Logout()
775 {
776 if (!loggedIn(false))
777 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN);
778 }
779
780 void CSPFullPluginSession::VerifyDevice(const CssmData &DeviceCert)
781 {
782 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
783 }
784
785 void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
786 {
787 memset(&statistics, 0, sizeof(statistics));
788 statistics.UserAuthenticated = loggedIn();
789 //@@@ collect device flags - capability matrix setup?
790 //@@@ collect token limitation parameters (static) - capability matrix setup?
791 //@@@ collect token statistics (dynamic) - dynamic accounting call-downs?
792 }
793
794
795 //
796 // Utterly miscellaneous, rarely used, strange functions
797 //
798 void CSPFullPluginSession::RetrieveCounter(CssmData &Counter)
799 {
800 unimplemented();
801 }
802
803 void CSPFullPluginSession::RetrieveUniqueId(CssmData &UniqueID)
804 {
805 unimplemented();
806 }
807
808 void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
809 {
810 unimplemented();
811 }
812
813
814 //
815 // ACL retrieval and change operations
816 //
817 void CSPFullPluginSession::GetKeyOwner(const CssmKey &Key,
818 CSSM_ACL_OWNER_PROTOTYPE &Owner)
819 {
820 unimplemented();
821 }
822
823 void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
824 const CssmKey &Key,
825 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
826 {
827 unimplemented();
828 }
829
830 void CSPFullPluginSession::GetKeyAcl(const CssmKey &Key,
831 const CSSM_STRING *SelectionTag,
832 uint32 &NumberOfAclInfos,
833 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
834 {
835 unimplemented();
836 }
837
838 void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
839 const CSSM_ACL_EDIT &AclEdit,
840 const CssmKey &Key)
841 {
842 unimplemented();
843 }
844
845 void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
846 {
847 unimplemented();
848 }
849
850 void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
851 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
852 {
853 unimplemented();
854 }
855
856 void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
857 uint32 &NumberOfAclInfos,
858 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
859 {
860 unimplemented();
861 }
862
863 void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
864 const CSSM_ACL_EDIT &AclEdit)
865 {
866 unimplemented();
867 }
868
869
870
871 //
872 // Passthroughs (by default, unimplemented)
873 //
874 void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle,
875 const Context &Context,
876 uint32 PassThroughId,
877 const void *InData,
878 void **OutData)
879 {
880 unimplemented();
881 }
882
883
884 //
885 // KeyPool -- ReferencedKey management functionality
886 //
887 KeyPool::KeyPool()
888 {
889 }
890
891 KeyPool::~KeyPool()
892 {
893 StLock<Mutex> _(mKeyMapLock);
894 // Delete every ReferencedKey in the pool, but be careful to deactivate them first
895 // to keep them from calling erase (which would cause deadlock since we already hold mKeyMapLock).
896 KeyMap::iterator end = mKeyMap.end();
897 for (KeyMap::iterator it = mKeyMap.begin(); it != end; ++it)
898 {
899 try
900 {
901 it->second->deactivate();
902 }
903 catch(...) {}
904 delete it->second;
905 }
906 mKeyMap.clear();
907 }
908
909 void
910 KeyPool::add(ReferencedKey &referencedKey)
911 {
912 StLock<Mutex> _(mKeyMapLock);
913 bool inserted = mKeyMap.insert(KeyMap::value_type(referencedKey.keyReference(), &referencedKey)).second;
914 // Since add is only called from the constructor of ReferencedKey we should
915 // never add a key that is already in mKeyMap
916 assert(inserted);
917 }
918
919 ReferencedKey &
920 KeyPool::findKey(const CSSM_KEY &key) const
921 {
922 return findKeyReference(ReferencedKey::keyReference(key));
923 }
924
925 ReferencedKey &
926 KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference) const
927 {
928 StLock<Mutex> _(mKeyMapLock);
929 KeyMap::const_iterator it = mKeyMap.find(keyReference);
930 if (it == mKeyMap.end())
931 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
932
933 return *it->second;
934 }
935
936 void
937 KeyPool::erase(ReferencedKey &referencedKey)
938 {
939 erase(referencedKey.keyReference());
940 }
941
942 ReferencedKey &
943 KeyPool::erase(ReferencedKey::KeyReference keyReference)
944 {
945 StLock<Mutex> _(mKeyMapLock);
946 KeyMap::iterator it = mKeyMap.find(keyReference);
947 if (it == mKeyMap.end())
948 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
949
950 mKeyMap.erase(it);
951 ReferencedKey &referencedKey = *it->second;
952 return referencedKey;
953 }
954
955 // Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
956 void
957 KeyPool::freeKey(CssmAllocator &allocator, CSSM_KEY &ioKey)
958 {
959 delete &erase(ReferencedKey::freeReferenceKey(allocator, ioKey));
960 }
961
962 //
963 // ReferencedKey class
964 //
965 ReferencedKey::ReferencedKey(KeyPool &keyPool) : mKeyPool(&keyPool)
966 {
967 mKeyPool->add(*this);
968 }
969
970 ReferencedKey::~ReferencedKey()
971 {
972 if (isActive())
973 mKeyPool->erase(*this);
974 }
975
976 ReferencedKey::KeyReference
977 ReferencedKey::keyReference()
978 {
979 // @@@ Possibly check isActive() and return an invalid reference if it is not set.
980 return reinterpret_cast<ReferencedKey::KeyReference>(this);
981 }
982
983 //
984 // Making, retrieving and freeing Key references of CssmKeys
985 //
986 void
987 ReferencedKey::makeReferenceKey(CssmAllocator &allocator, KeyReference keyReference, CSSM_KEY &key)
988 {
989 key.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE;
990 key.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER;
991 key.KeyData.Length = sizeof(KeyReference);
992 key.KeyData.Data = allocator.alloc<uint8>(sizeof(KeyReference));
993 uint8 *cp = key.KeyData.Data;
994 for (int i = sizeof(KeyReference); --i >= 0;)
995 {
996 cp[i] = keyReference & 0xff;
997 keyReference = keyReference >> 8;
998 }
999 }
1000
1001 ReferencedKey::KeyReference
1002 ReferencedKey::keyReference(const CSSM_KEY &key)
1003 {
1004 if (key.KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE
1005 || key.KeyHeader.Format != CSSM_KEYBLOB_REF_FORMAT_INTEGER
1006 || key.KeyData.Length != sizeof(KeyReference)
1007 || key.KeyData.Data == NULL)
1008 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1009
1010 const uint8 *cp = key.KeyData.Data;
1011 KeyReference keyReference = 0;
1012 for (uint32 i = 0; i < sizeof(KeyReference); ++i)
1013 keyReference = (keyReference << 8) + cp[i];
1014
1015 return keyReference;
1016 }
1017
1018 ReferencedKey::KeyReference
1019 ReferencedKey::freeReferenceKey(CssmAllocator &allocator, CSSM_KEY &key)
1020 {
1021 KeyReference aKeyReference = keyReference(key);
1022 allocator.free(key.KeyData.Data);
1023 key.KeyData.Data = NULL;
1024 key.KeyData.Length = 0;
1025 return aKeyReference;
1026 }