]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_plugin/lib/CSPsession.cpp
Security-58286.270.3.0.1.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 = (u_int8_t*)malloc(bytesInKey);
746 if (buffer == NULL) {
747 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR);
748 }
749
750 unsigned i;
751
752 for (i = 0; i < bytesInKey; ++i)
753 {
754 buffer[i] = i;
755 }
756
757 CSSM_DATA clearBuf = {bytesInKey, buffer};
758 CSSM_DATA cipherBuf; // have the CSP allocate the resulting memory
759 CSSM_SIZE bytesEncrypted;
760 CSSM_DATA remData = {0, NULL};
761 CSSM_DATA decryptedBuf = {bytesInKey, buffer};
762
763 CSSM_RETURN result = CSSM_CSP_CreateAsymmetricContext(moduleHandle, encryptingKey->KeyHeader.AlgorithmId, &nullCreds, encryptingKey, CSSM_PADDING_NONE, &encryptHandle);
764 if (result != CSSM_OK)
765 {
766 free(buffer);
767 CssmError::throwMe(result);
768 }
769
770 ContextMinder encryptMinder(encryptHandle); // auto throw away if we error out
771
772 CSSM_QUERY_SIZE_DATA qsData;
773 qsData.SizeInputBlock = bytesInKey;
774 result = CSSM_QuerySize(encryptHandle, CSSM_TRUE, 1, &qsData);
775 if (result == CSSMERR_CSP_INVALID_ALGORITHM)
776 {
777 free(buffer);
778 return;
779 }
780
781 uint8 cipherBuffer[qsData.SizeOutputBlock];
782 cipherBuf.Length = qsData.SizeOutputBlock;
783 cipherBuf.Data = cipherBuffer;
784
785 // do the encryption
786 result = CSSM_EncryptData(encryptHandle, &clearBuf, 1, &cipherBuf, 1, &bytesEncrypted, &remData);
787 if (result != CSSM_OK)
788 {
789 free(buffer);
790 CssmError::throwMe(result);
791 }
792
793 // check the result
794 if (memcmp(cipherBuf.Data, clearBuf.Data, clearBuf.Length) == 0)
795 {
796 // we have a match, that's not good news...
797 abort();
798 }
799
800 // clean up
801 if (remData.Data != NULL)
802 {
803 free(remData.Data);
804 }
805
806 // make a context to perform the decryption
807 CSSM_CC_HANDLE decryptHandle;
808 result = CSSM_CSP_CreateAsymmetricContext(moduleHandle, encryptingKey->KeyHeader.AlgorithmId, &nullCreds, decryptingKey, CSSM_PADDING_NONE, &decryptHandle);
809 ContextMinder decryptMinder(decryptHandle);
810
811 if (result != CSSM_OK)
812 {
813 free(buffer);
814 CssmError::throwMe(result);
815 }
816
817 result = CSSM_DecryptData(decryptHandle, &cipherBuf, 1, &decryptedBuf, 1, &bytesEncrypted, &remData);
818 if (result != CSSM_OK)
819 {
820 free(buffer);
821 CssmError::throwMe(result);
822 }
823
824 // check the results
825 for (i = 0; i < bytesInKey; ++i)
826 {
827 if (decryptedBuf.Data[i] != (i & 0xFF))
828 {
829 // bad news
830 abort();
831 }
832 }
833
834 if (remData.Data != NULL)
835 {
836 free(remData.Data);
837 }
838
839 free(buffer);
840 }
841
842 void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
843 CssmKey &PrivateKey)
844 {
845 unimplemented();
846 }
847
848 void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle,
849 const Context *context,
850 const CssmKey *key,
851 CSSM_KEY_SIZE &keySize)
852 {
853 if (context) {
854 getKeySize(context->get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY),
855 keySize);
856 } else {
857 getKeySize(CssmKey::required(key), keySize);
858 }
859 }
860
861
862 //
863 // Free a key object.
864 //
865 void CSPFullPluginSession::FreeKey(const AccessCredentials *AccessCred,
866 CssmKey &key,
867 CSSM_BOOL Delete)
868 {
869 free(key.data());
870 }
871
872
873 //
874 // Random number and parameter generation
875 //
876 void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
877 const Context &context,
878 CssmData &randomNumber)
879 {
880 init(ccHandle, CSSM_ALGCLASS_RANDOMGEN, context)->final(randomNumber, *this);
881 }
882
883 void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle,
884 const Context &context,
885 uint32 paramBits,
886 CssmData &param,
887 uint32 &attrCount,
888 CSSM_CONTEXT_ATTRIBUTE_PTR &attrs)
889 {
890 Context::Attr *attrList;
891 init(ccHandle, CSSM_ALGCLASS_NONE, context)->generate(context, paramBits,
892 param, attrCount, attrList);
893 attrs = attrList;
894 }
895
896
897 //
898 // Login/Logout and token operational maintainance.
899 // These mean little without support by the actual implementation, but we can help...
900 // @@@ Should this be in CSP[non-Full]PluginSession?
901 //
902 void CSPFullPluginSession::Login(const AccessCredentials &AccessCred,
903 const CssmData *LoginName,
904 const void *Reserved)
905 {
906 if (Reserved != NULL)
907 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
908
909 // default implementation refuses to log in
910 //@@@ should hand it to implementation virtual defaulting to this
911 CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME);
912 }
913
914 void CSPFullPluginSession::Logout()
915 {
916 if (!loggedIn(false))
917 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN);
918 }
919
920 void CSPFullPluginSession::VerifyDevice(const CssmData &DeviceCert)
921 {
922 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
923 }
924
925 void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
926 {
927 memset(&statistics, 0, sizeof(statistics));
928 statistics.UserAuthenticated = loggedIn();
929 //@@@ collect device flags - capability matrix setup?
930 //@@@ collect token limitation parameters (static) - capability matrix setup?
931 //@@@ collect token statistics (dynamic) - dynamic accounting call-downs?
932 }
933
934
935 //
936 // Utterly miscellaneous, rarely used, strange functions
937 //
938 void CSPFullPluginSession::RetrieveCounter(CssmData &Counter)
939 {
940 unimplemented();
941 }
942
943 void CSPFullPluginSession::RetrieveUniqueId(CssmData &UniqueID)
944 {
945 unimplemented();
946 }
947
948 void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
949 {
950 unimplemented();
951 }
952
953
954 //
955 // ACL retrieval and change operations
956 //
957 void CSPFullPluginSession::GetKeyOwner(const CssmKey &Key,
958 CSSM_ACL_OWNER_PROTOTYPE &Owner)
959 {
960 unimplemented();
961 }
962
963 void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
964 const CssmKey &Key,
965 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
966 {
967 unimplemented();
968 }
969
970 void CSPFullPluginSession::GetKeyAcl(const CssmKey &Key,
971 const CSSM_STRING *SelectionTag,
972 uint32 &NumberOfAclInfos,
973 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
974 {
975 unimplemented();
976 }
977
978 void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
979 const CSSM_ACL_EDIT &AclEdit,
980 const CssmKey &Key)
981 {
982 unimplemented();
983 }
984
985 void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
986 {
987 unimplemented();
988 }
989
990 void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
991 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
992 {
993 unimplemented();
994 }
995
996 void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
997 uint32 &NumberOfAclInfos,
998 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
999 {
1000 unimplemented();
1001 }
1002
1003 void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
1004 const CSSM_ACL_EDIT &AclEdit)
1005 {
1006 unimplemented();
1007 }
1008
1009
1010
1011 //
1012 // Passthroughs (by default, unimplemented)
1013 //
1014 void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle,
1015 const Context &Context,
1016 uint32 PassThroughId,
1017 const void *InData,
1018 void **OutData)
1019 {
1020 unimplemented();
1021 }
1022
1023
1024 //
1025 // KeyPool -- ReferencedKey management functionality
1026 //
1027 KeyPool::KeyPool()
1028 {
1029 }
1030
1031 KeyPool::~KeyPool()
1032 {
1033 StLock<Mutex> _(mKeyMapLock);
1034 // Delete every ReferencedKey in the pool, but be careful to deactivate them first
1035 // to keep them from calling erase (which would cause deadlock since we already hold mKeyMapLock).
1036 KeyMap::iterator end = mKeyMap.end();
1037 for (KeyMap::iterator it = mKeyMap.begin(); it != end; ++it)
1038 {
1039 try
1040 {
1041 it->second->deactivate();
1042 }
1043 catch(...) {}
1044 delete it->second;
1045 }
1046 mKeyMap.clear();
1047 }
1048
1049 void
1050 KeyPool::add(ReferencedKey &referencedKey)
1051 {
1052 StLock<Mutex> _(mKeyMapLock);
1053 bool inserted;
1054 inserted = mKeyMap.insert(KeyMap::value_type(referencedKey.keyReference(), &referencedKey)).second;
1055 // Since add is only called from the constructor of ReferencedKey we should
1056 // never add a key that is already in mKeyMap
1057 assert(inserted);
1058
1059 secinfo("SecAccessReference", "added a referenced key %p for key reference %ld", &referencedKey, referencedKey.keyReference());
1060 }
1061
1062 ReferencedKey &
1063 KeyPool::findKey(const CSSM_KEY &key) const
1064 {
1065 return findKeyReference(ReferencedKey::keyReference(key));
1066 }
1067
1068 ReferencedKey &
1069 KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference) const
1070 {
1071 StLock<Mutex> _(mKeyMapLock);
1072 KeyMap::const_iterator it = mKeyMap.find(keyReference);
1073 if (it == mKeyMap.end())
1074 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1075
1076 secinfo("SecAccessReference", "found a referenced key %p for key reference %ld [%ld]", it->second, keyReference, it->second->keyReference());
1077
1078 return *it->second;
1079 }
1080
1081 void
1082 KeyPool::erase(ReferencedKey &referencedKey)
1083 {
1084 erase(referencedKey.keyReference());
1085 }
1086
1087 ReferencedKey &
1088 KeyPool::erase(ReferencedKey::KeyReference keyReference)
1089 {
1090 StLock<Mutex> _(mKeyMapLock);
1091 KeyMap::iterator it = mKeyMap.find(keyReference);
1092 if (it == mKeyMap.end())
1093 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1094
1095 ReferencedKey &referencedKey = *it->second;
1096 mKeyMap.erase(it);
1097 return referencedKey;
1098 }
1099
1100 // Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
1101 void
1102 KeyPool::freeKey(Allocator &allocator, CSSM_KEY &ioKey)
1103 {
1104 delete &erase(ReferencedKey::freeReferenceKey(allocator, ioKey));
1105 }
1106
1107 //
1108 // ReferencedKey class
1109 //
1110 ReferencedKey::ReferencedKey(KeyPool &keyPool) : mKeyPool(&keyPool)
1111 {
1112 mKeyPool->add(*this);
1113 }
1114
1115 ReferencedKey::~ReferencedKey()
1116 {
1117 if (isActive())
1118 mKeyPool->erase(*this);
1119 }
1120
1121 ReferencedKey::KeyReference
1122 ReferencedKey::keyReference()
1123 {
1124 // @@@ Possibly check isActive() and return an invalid reference if it is not set.
1125 return reinterpret_cast<ReferencedKey::KeyReference>(this);
1126 }
1127
1128 //
1129 // Making, retrieving and freeing Key references of CssmKeys
1130 //
1131 void
1132 ReferencedKey::makeReferenceKey(Allocator &allocator, KeyReference keyReference, CSSM_KEY &key)
1133 {
1134 key.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE;
1135 key.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER;
1136 key.KeyData.Length = sizeof(KeyReference);
1137 key.KeyData.Data = allocator.alloc<uint8>(sizeof(KeyReference));
1138 uint8 *cp = key.KeyData.Data;
1139 for (int i = sizeof(KeyReference); --i >= 0;)
1140 {
1141 cp[i] = keyReference & 0xff;
1142 keyReference = keyReference >> 8;
1143 }
1144 }
1145
1146 ReferencedKey::KeyReference
1147 ReferencedKey::keyReference(const CSSM_KEY &key)
1148 {
1149 if (key.KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE
1150 || key.KeyHeader.Format != CSSM_KEYBLOB_REF_FORMAT_INTEGER
1151 || key.KeyData.Length != sizeof(KeyReference)
1152 || key.KeyData.Data == NULL)
1153 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1154
1155 const uint8 *cp = key.KeyData.Data;
1156 KeyReference keyReference = 0;
1157 for (uint32 i = 0; i < sizeof(KeyReference); ++i)
1158 keyReference = (keyReference << 8) + cp[i];
1159
1160 return keyReference;
1161 }
1162
1163 ReferencedKey::KeyReference
1164 ReferencedKey::freeReferenceKey(Allocator &allocator, CSSM_KEY &key)
1165 {
1166 KeyReference aKeyReference = keyReference(key);
1167 allocator.free(key.KeyData.Data);
1168 key.KeyData.Data = NULL;
1169 key.KeyData.Length = 0;
1170 return aKeyReference;
1171 }