]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_plugin/lib/CSPsession.cpp
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_plugin / lib / CSPsession.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2012,2014 Apple 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
27 typedef CSPFullPluginSession::CSPContext CSPContext;
28
29
30 //
31 // PluginContext construction
32 //
33 CSPPluginSession::PluginContext::~PluginContext()
34 { /* virtual */ }
35
36 CSPFullPluginSession::AlgorithmFactory::~AlgorithmFactory()
37 { /* virtual */ }
38
39
40 //
41 // Internal utilities
42 //
43 CssmData CSPFullPluginSession::makeBuffer(size_t size, Allocator &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(Allocator &)
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, 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
225 void 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 //
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 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
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 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
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 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
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 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
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 (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 //
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 class ContextMinder
684 {
685 private:
686 CSSM_CC_HANDLE mHandle;
687
688 public:
689 ContextMinder(CSSM_CC_HANDLE ccHandle) : mHandle(ccHandle) {}
690 ~ContextMinder() {CSSM_DeleteContext(mHandle);}
691 };
692
693
694
695 void 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
831 void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
832 CssmKey &PrivateKey)
833 {
834 unimplemented();
835 }
836
837 void 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 //
854 void 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 //
865 void 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
872 void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle,
873 const Context &context,
874 uint32 paramBits,
875 CssmData &param,
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 //
891 void 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
903 void CSPFullPluginSession::Logout()
904 {
905 if (!loggedIn(false))
906 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN);
907 }
908
909 void CSPFullPluginSession::VerifyDevice(const CssmData &DeviceCert)
910 {
911 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
912 }
913
914 void 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 //
927 void CSPFullPluginSession::RetrieveCounter(CssmData &Counter)
928 {
929 unimplemented();
930 }
931
932 void CSPFullPluginSession::RetrieveUniqueId(CssmData &UniqueID)
933 {
934 unimplemented();
935 }
936
937 void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
938 {
939 unimplemented();
940 }
941
942
943 //
944 // ACL retrieval and change operations
945 //
946 void CSPFullPluginSession::GetKeyOwner(const CssmKey &Key,
947 CSSM_ACL_OWNER_PROTOTYPE &Owner)
948 {
949 unimplemented();
950 }
951
952 void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
953 const CssmKey &Key,
954 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
955 {
956 unimplemented();
957 }
958
959 void 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
967 void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
968 const CSSM_ACL_EDIT &AclEdit,
969 const CssmKey &Key)
970 {
971 unimplemented();
972 }
973
974 void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
975 {
976 unimplemented();
977 }
978
979 void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
980 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
981 {
982 unimplemented();
983 }
984
985 void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
986 uint32 &NumberOfAclInfos,
987 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
988 {
989 unimplemented();
990 }
991
992 void 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 //
1003 void 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 //
1016 KeyPool::KeyPool()
1017 {
1018 }
1019
1020 KeyPool::~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
1038 void
1039 KeyPool::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 secinfo("SecAccessReference", "added a referenced key %p for key reference %ld", &referencedKey, referencedKey.keyReference());
1049 }
1050
1051 ReferencedKey &
1052 KeyPool::findKey(const CSSM_KEY &key) const
1053 {
1054 return findKeyReference(ReferencedKey::keyReference(key));
1055 }
1056
1057 ReferencedKey &
1058 KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference) const
1059 {
1060 StLock<Mutex> _(mKeyMapLock);
1061 KeyMap::const_iterator it = mKeyMap.find(keyReference);
1062 if (it == mKeyMap.end())
1063 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1064
1065 secinfo("SecAccessReference", "found a referenced key %p for key reference %ld [%ld]", it->second, keyReference, it->second->keyReference());
1066
1067 return *it->second;
1068 }
1069
1070 void
1071 KeyPool::erase(ReferencedKey &referencedKey)
1072 {
1073 erase(referencedKey.keyReference());
1074 }
1075
1076 ReferencedKey &
1077 KeyPool::erase(ReferencedKey::KeyReference keyReference)
1078 {
1079 StLock<Mutex> _(mKeyMapLock);
1080 KeyMap::iterator it = mKeyMap.find(keyReference);
1081 if (it == mKeyMap.end())
1082 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1083
1084 ReferencedKey &referencedKey = *it->second;
1085 mKeyMap.erase(it);
1086 return referencedKey;
1087 }
1088
1089 // Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
1090 void
1091 KeyPool::freeKey(Allocator &allocator, CSSM_KEY &ioKey)
1092 {
1093 delete &erase(ReferencedKey::freeReferenceKey(allocator, ioKey));
1094 }
1095
1096 //
1097 // ReferencedKey class
1098 //
1099 ReferencedKey::ReferencedKey(KeyPool &keyPool) : mKeyPool(&keyPool)
1100 {
1101 mKeyPool->add(*this);
1102 }
1103
1104 ReferencedKey::~ReferencedKey()
1105 {
1106 if (isActive())
1107 mKeyPool->erase(*this);
1108 }
1109
1110 ReferencedKey::KeyReference
1111 ReferencedKey::keyReference()
1112 {
1113 // @@@ Possibly check isActive() and return an invalid reference if it is not set.
1114 return reinterpret_cast<ReferencedKey::KeyReference>(this);
1115 }
1116
1117 //
1118 // Making, retrieving and freeing Key references of CssmKeys
1119 //
1120 void
1121 ReferencedKey::makeReferenceKey(Allocator &allocator, KeyReference keyReference, CSSM_KEY &key)
1122 {
1123 key.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE;
1124 key.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER;
1125 key.KeyData.Length = sizeof(KeyReference);
1126 key.KeyData.Data = allocator.alloc<uint8>(sizeof(KeyReference));
1127 uint8 *cp = key.KeyData.Data;
1128 for (int i = sizeof(KeyReference); --i >= 0;)
1129 {
1130 cp[i] = keyReference & 0xff;
1131 keyReference = keyReference >> 8;
1132 }
1133 }
1134
1135 ReferencedKey::KeyReference
1136 ReferencedKey::keyReference(const CSSM_KEY &key)
1137 {
1138 if (key.KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE
1139 || key.KeyHeader.Format != CSSM_KEYBLOB_REF_FORMAT_INTEGER
1140 || key.KeyData.Length != sizeof(KeyReference)
1141 || key.KeyData.Data == NULL)
1142 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1143
1144 const uint8 *cp = key.KeyData.Data;
1145 KeyReference keyReference = 0;
1146 for (uint32 i = 0; i < sizeof(KeyReference); ++i)
1147 keyReference = (keyReference << 8) + cp[i];
1148
1149 return keyReference;
1150 }
1151
1152 ReferencedKey::KeyReference
1153 ReferencedKey::freeReferenceKey(Allocator &allocator, CSSM_KEY &key)
1154 {
1155 KeyReference aKeyReference = keyReference(key);
1156 allocator.free(key.KeyData.Data);
1157 key.KeyData.Data = NULL;
1158 key.KeyData.Length = 0;
1159 return aKeyReference;
1160 }