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