2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // CSPsession - Plugin framework for CSP plugin modules
23 #define _CPP_CSPSESSION
26 #include <Security/CSPsession.h>
27 #include <Security/cssmplugin.h>
30 typedef CSPFullPluginSession::CSPContext CSPContext
;
34 // PluginContext construction
36 CSPPluginSession::PluginContext::~PluginContext()
43 CssmData
CSPFullPluginSession::makeBuffer(size_t size
, CssmAllocator
&alloc
)
45 return CssmData(alloc
.malloc(size
), size
);
48 inline size_t CSPFullPluginSession::totalBufferSize(const CssmData
*data
, uint32 count
)
51 for (uint32 n
= 0; n
< count
; n
++)
52 size
+= data
[n
].length();
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.
61 bool CSPPluginSession::PluginContext::changed(const Context
&context
)
63 return false; // delete me, please
68 // The Session's init() function calls your setupContext() method to prepare
69 // it for action, then calls the context's init() method.
71 CSPContext
*CSPFullPluginSession::init(CSSM_CC_HANDLE ccHandle
,
72 CSSM_CONTEXT_TYPE type
,
73 const Context
&context
, bool encoding
)
75 CSPContext
*ctx
= getContext
<CSPContext
>(ccHandle
);
76 checkOperation(context
.type(), type
);
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
);
85 // initialize the context and return it
86 ctx
->init(context
, encoding
);
92 // Retrieve a context for a staged operation in progress.
94 CSPContext
*CSPFullPluginSession::getStagedContext(CSSM_CC_HANDLE ccHandle
,
95 CSSM_CONTEXT_TYPE type
, bool encoding
)
97 CSPContext
*ctx
= getContext
<CSPContext
>(ccHandle
);
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
);
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.
111 void CSPFullPluginSession::checkOperation(CSSM_CONTEXT_TYPE ctxType
, CSSM_CONTEXT_TYPE opType
)
114 case CSSM_ALGCLASS_NONE
: // no check
116 case CSSM_ALGCLASS_CRYPT
: // symmetric or asymmetric encryption
117 if (ctxType
== CSSM_ALGCLASS_SYMMETRIC
||
118 ctxType
== CSSM_ALGCLASS_ASYMMETRIC
)
120 default: // plain match
121 if (ctxType
== opType
)
124 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT
);
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.
133 void CSPContext::init(const Context
&context
, bool encoding
)
134 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
136 void CSPContext::update(const CssmData
&data
)
137 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
139 void CSPContext::update(void *inp
, size_t &inSize
, void *outp
, size_t &outSize
)
140 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
142 void CSPContext::final(CssmData
&out
)
143 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
145 void CSPContext::final(const CssmData
&in
)
146 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
148 void CSPContext::generate(const Context
&, CssmKey
&pubKey
, CssmKey
&privKey
)
149 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
151 void CSPContext::generate(const Context
&, uint32
, CssmData
¶ms
,
152 uint32
&attrCount
, Context::Attr
* &attrs
)
153 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
155 size_t CSPContext::inputSize(size_t outSize
)
156 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
158 size_t CSPContext::outputSize(bool final
, size_t inSize
)
159 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
161 void CSPContext::minimumProgress(size_t &in
, size_t &out
)
162 { CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); }
164 CSPFullPluginSession::CSPContext
*CSPContext::clone(CssmAllocator
&)
165 { CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
); }
167 void CSPContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg
)
168 { CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); }
170 void CSPContext::update(const CssmData
*in
,
171 uint32 inCount
, Writer
&writer
)
173 const CssmData
*lastIn
= in
+ inCount
;
176 if (current
.length() == 0) {
180 continue; // Just in case next block is zero length too.
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
189 // we can stuff into the current output buffer - do it
190 update(current
.data(), inSize
, outP
, outSize
);
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).
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
213 void CSPContext::final(CssmData
&out
, CssmAllocator
&alloc
)
215 size_t needed
= outputSize(true, 0);
217 if (out
.length() < needed
)
218 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
220 out
= makeBuffer(needed
, alloc
);
225 void CSPContext::final(Writer
&writer
, CssmAllocator
&alloc
)
227 if (size_t needed
= outputSize(true, 0)) {
228 // need to generate additional output
229 writer
.allocate(needed
, alloc
); // belt + suspender
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
);
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
));
242 writer
.put(chunk
.data(), chunk
.length());
249 // Default context response functions
251 CSPPluginSession::PluginContext
*
252 CSPPluginSession::contextCreate(CSSM_CC_HANDLE
, const Context
&)
254 return NULL
; // request no local context
257 void CSPPluginSession::contextUpdate(CSSM_CC_HANDLE ccHandle
,
258 const Context
&context
, PluginContext
* &ctx
)
260 // call update notifier in context object
261 if (ctx
&& !ctx
->changed(context
)) {
262 // context requested that it be removed
268 void CSPPluginSession::contextDelete(CSSM_CC_HANDLE
, const Context
&, PluginContext
*)
270 // do nothing (you can't prohibit deletion here)
275 // Default event notification handler.
276 // This default handler calls the virtual context* methods to dispose of context actions.
278 void CSPPluginSession::EventNotify(CSSM_CONTEXT_EVENT event
,
279 CSSM_CC_HANDLE ccHandle
, const Context
&context
)
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
;
289 case CSSM_CONTEXT_EVENT_UPDATE
:
290 // note that the handler can change the map entry (even to NULL, if desired)
292 StLock
<Mutex
> _(contextMapLock
);
293 contextUpdate(ccHandle
, context
, contextMap
[ccHandle
]);
296 case CSSM_CONTEXT_EVENT_DELETE
:
298 StLock
<Mutex
> _(contextMapLock
);
299 if (PluginContext
*ctx
= contextMap
[ccHandle
]) {
300 contextDelete(ccHandle
, context
, ctx
);
303 contextMap
.erase(ccHandle
);
307 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); // unexpected event code
313 // Defaults for methods you *should* implement.
314 // If you don't, they'll throw UNIMPLEMENTED.
316 void CSPFullPluginSession::getKeySize(const CssmKey
&key
, CSSM_KEY_SIZE
&size
)
321 // Encryption and decryption
323 void CSPFullPluginSession::EncryptData(CSSM_CC_HANDLE ccHandle
,
324 const Context
&context
,
325 const CssmData clearBufs
[],
326 uint32 clearBufCount
,
327 CssmData cipherBufs
[],
328 uint32 cipherBufCount
,
329 uint32
&bytesEncrypted
,
331 CSSM_PRIVILEGE privilege
)
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();
342 void CSPFullPluginSession::EncryptDataInit(CSSM_CC_HANDLE ccHandle
,
343 const Context
&context
,
344 CSSM_PRIVILEGE Privilege
)
346 init(ccHandle
, CSSM_ALGCLASS_CRYPT
, context
, true);
349 void CSPFullPluginSession::EncryptDataUpdate(CSSM_CC_HANDLE ccHandle
,
350 const CssmData clearBufs
[],
351 uint32 clearBufCount
,
352 CssmData cipherBufs
[],
353 uint32 cipherBufCount
,
354 uint32
&bytesEncrypted
)
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();
364 void CSPFullPluginSession::EncryptDataFinal(CSSM_CC_HANDLE ccHandle
,
367 getStagedContext(ccHandle
, CSSM_ALGCLASS_CRYPT
, true)->final(remData
, *this);
371 void CSPFullPluginSession::DecryptData(CSSM_CC_HANDLE ccHandle
,
372 const Context
&context
,
373 const CssmData cipherBufs
[],
374 uint32 cipherBufCount
,
375 CssmData clearBufs
[],
376 uint32 clearBufCount
,
377 uint32
&bytesDecrypted
,
379 CSSM_PRIVILEGE privilege
)
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();
390 void CSPFullPluginSession::DecryptDataInit(CSSM_CC_HANDLE ccHandle
,
391 const Context
&context
,
392 CSSM_PRIVILEGE Privilege
)
394 init(ccHandle
, CSSM_ALGCLASS_CRYPT
, context
, false);
397 void CSPFullPluginSession::DecryptDataUpdate(CSSM_CC_HANDLE ccHandle
,
398 const CssmData cipherBufs
[],
399 uint32 cipherBufCount
,
400 CssmData clearBufs
[],
401 uint32 clearBufCount
,
402 uint32
&bytesDecrypted
)
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();
412 void CSPFullPluginSession::DecryptDataFinal(CSSM_CC_HANDLE ccHandle
,
415 getStagedContext(ccHandle
, CSSM_ALGCLASS_CRYPT
, false)->final(remData
, *this);
418 void CSPFullPluginSession::QuerySize(CSSM_CC_HANDLE ccHandle
,
419 const Context
&context
,
421 uint32 querySizeCount
,
422 QuerySizeData
*dataBlock
)
424 if (querySizeCount
== 0)
425 return; // nothing ventured, nothing gained
426 CSPContext
*ctx
= getContext
<CSPContext
>(ccHandle
); // existing context?
427 if (ctx
== NULL
) // force internal context creation (as best we can)
428 ctx
= init(ccHandle
, context
.type(), context
, encrypt
);
429 // If QuerySizeCount > 1, we assume this inquires about a staged
430 // operation, and the LAST item gets the 'final' treatment.
431 //@@@ Intel revised algspec says "use the staged flag" -- TBD
432 for (uint32 n
= 0; n
< querySizeCount
; n
++) {
433 // the outputSize() call might throw CSSMERR_CSP_QUERY_SIZE_UNKNOWN
434 dataBlock
[n
].SizeOutputBlock
=
435 ctx
->outputSize(n
== querySizeCount
-1, dataBlock
[n
].inputSize());
437 //@@@ if we forced a context creation, should we discard it now?
442 // Key wrapping and unwrapping.
444 void CSPFullPluginSession::WrapKey(CSSM_CC_HANDLE CCHandle
,
445 const Context
&Context
,
446 const AccessCredentials
&AccessCred
,
448 const CssmData
*DescriptiveData
,
450 CSSM_PRIVILEGE Privilege
)
455 void CSPFullPluginSession::UnwrapKey(CSSM_CC_HANDLE CCHandle
,
456 const Context
&Context
,
457 const CssmKey
*PublicKey
,
458 const CssmKey
&WrappedKey
,
461 const CssmData
*KeyLabel
,
462 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
463 CssmKey
&UnwrappedKey
,
464 CssmData
&DescriptiveData
,
465 CSSM_PRIVILEGE Privilege
)
470 void CSPFullPluginSession::DeriveKey(CSSM_CC_HANDLE CCHandle
,
471 const Context
&Context
,
475 const CssmData
*KeyLabel
,
476 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
484 // Message Authentication Codes.
485 // Almost like signatures (signatures with symmetric keys), though the
486 // underlying implementation may be somewhat different.
488 void CSPFullPluginSession::GenerateMac(CSSM_CC_HANDLE ccHandle
,
489 const Context
&context
,
490 const CssmData dataBufs
[],
494 GenerateMacInit(ccHandle
, context
);
495 GenerateMacUpdate(ccHandle
, dataBufs
, dataBufCount
);
496 GenerateMacFinal(ccHandle
, mac
);
499 void CSPFullPluginSession::GenerateMacInit(CSSM_CC_HANDLE ccHandle
,
500 const Context
&context
)
502 init(ccHandle
, CSSM_ALGCLASS_MAC
, context
, true);
505 void CSPFullPluginSession::GenerateMacUpdate(CSSM_CC_HANDLE ccHandle
,
506 const CssmData dataBufs
[],
509 getStagedContext(ccHandle
, CSSM_ALGCLASS_MAC
, true)->update(dataBufs
, dataBufCount
);
512 void CSPFullPluginSession::GenerateMacFinal(CSSM_CC_HANDLE ccHandle
,
515 getStagedContext(ccHandle
, CSSM_ALGCLASS_MAC
, true)->final(mac
, *this);
518 void CSPFullPluginSession::VerifyMac(CSSM_CC_HANDLE ccHandle
,
519 const Context
&context
,
520 const CssmData dataBufs
[],
524 VerifyMacInit(ccHandle
, context
);
525 VerifyMacUpdate(ccHandle
, dataBufs
, dataBufCount
);
526 VerifyMacFinal(ccHandle
, mac
);
529 void CSPFullPluginSession::VerifyMacInit(CSSM_CC_HANDLE ccHandle
,
530 const Context
&context
)
532 init(ccHandle
, CSSM_ALGCLASS_MAC
, context
, false);
535 void CSPFullPluginSession::VerifyMacUpdate(CSSM_CC_HANDLE ccHandle
,
536 const CssmData dataBufs
[],
539 getStagedContext(ccHandle
, CSSM_ALGCLASS_MAC
, false)->update(dataBufs
, dataBufCount
);
542 void CSPFullPluginSession::VerifyMacFinal(CSSM_CC_HANDLE ccHandle
,
545 getStagedContext(ccHandle
, CSSM_ALGCLASS_MAC
, false)->final(mac
);
552 void CSPFullPluginSession::SignData(CSSM_CC_HANDLE ccHandle
,
553 const Context
&context
,
554 const CssmData dataBufs
[],
556 CSSM_ALGORITHMS digestAlgorithm
,
559 SignDataInit(ccHandle
, context
);
560 if(digestAlgorithm
!= CSSM_ALGID_NONE
) {
561 getStagedContext(ccHandle
, CSSM_ALGCLASS_SIGNATURE
,
562 true)->setDigestAlgorithm(digestAlgorithm
);
564 SignDataUpdate(ccHandle
, dataBufs
, dataBufCount
);
565 SignDataFinal(ccHandle
, Signature
);
568 void CSPFullPluginSession::SignDataInit(CSSM_CC_HANDLE ccHandle
,
569 const Context
&context
)
571 init(ccHandle
, CSSM_ALGCLASS_SIGNATURE
, context
, true);
574 void CSPFullPluginSession::SignDataUpdate(CSSM_CC_HANDLE ccHandle
,
575 const CssmData dataBufs
[],
578 getStagedContext(ccHandle
, CSSM_ALGCLASS_SIGNATURE
, true)->update(dataBufs
, dataBufCount
);
581 void CSPFullPluginSession::SignDataFinal(CSSM_CC_HANDLE ccHandle
,
584 getStagedContext(ccHandle
, CSSM_ALGCLASS_SIGNATURE
, true)->final(signature
, *this);
588 void CSPFullPluginSession::VerifyData(CSSM_CC_HANDLE ccHandle
,
589 const Context
&context
,
590 const CssmData dataBufs
[],
592 CSSM_ALGORITHMS digestAlgorithm
,
593 const CssmData
&Signature
)
595 VerifyDataInit(ccHandle
, context
);
596 if(digestAlgorithm
!= CSSM_ALGID_NONE
) {
597 getStagedContext(ccHandle
, CSSM_ALGCLASS_SIGNATURE
,
598 false)->setDigestAlgorithm(digestAlgorithm
);
600 VerifyDataUpdate(ccHandle
, dataBufs
, dataBufCount
);
601 VerifyDataFinal(ccHandle
, Signature
);
604 void CSPFullPluginSession::VerifyDataInit(CSSM_CC_HANDLE ccHandle
, const Context
&context
)
606 init(ccHandle
, CSSM_ALGCLASS_SIGNATURE
, context
, false);
609 void CSPFullPluginSession::VerifyDataUpdate(CSSM_CC_HANDLE ccHandle
,
610 const CssmData dataBufs
[],
613 getStagedContext(ccHandle
, CSSM_ALGCLASS_SIGNATURE
, false)->update(dataBufs
, dataBufCount
);
616 void CSPFullPluginSession::VerifyDataFinal(CSSM_CC_HANDLE ccHandle
,
617 const CssmData
&signature
)
619 getStagedContext(ccHandle
, CSSM_ALGCLASS_SIGNATURE
, false)->final(signature
);
626 void CSPFullPluginSession::DigestData(CSSM_CC_HANDLE ccHandle
,
627 const Context
&context
,
628 const CssmData dataBufs
[],
632 DigestDataInit(ccHandle
, context
);
633 DigestDataUpdate(ccHandle
, dataBufs
, DataBufCount
);
634 DigestDataFinal(ccHandle
, Digest
);
637 void CSPFullPluginSession::DigestDataInit(CSSM_CC_HANDLE ccHandle
, const Context
&context
)
639 init(ccHandle
, CSSM_ALGCLASS_DIGEST
, context
);
642 void CSPFullPluginSession::DigestDataUpdate(CSSM_CC_HANDLE ccHandle
,
643 const CssmData dataBufs
[],
646 getStagedContext(ccHandle
, CSSM_ALGCLASS_DIGEST
)->update(dataBufs
, dataBufCount
);
649 void CSPFullPluginSession::DigestDataFinal(CSSM_CC_HANDLE ccHandle
,
652 getStagedContext(ccHandle
, CSSM_ALGCLASS_DIGEST
)->final(digest
, *this);
655 void CSPFullPluginSession::DigestDataClone(CSSM_CC_HANDLE ccHandle
,
656 CSSM_CC_HANDLE clonedCCHandle
)
658 CSPContext
*cloned
= getStagedContext(ccHandle
, CSSM_ALGCLASS_DIGEST
)->clone(*this);
659 cloned
->mDirection
= true;
660 cloned
->mType
= CSSM_ALGCLASS_DIGEST
;
661 setContext(clonedCCHandle
, cloned
);
666 // Key generation, Derivation, and inquiry
668 void CSPFullPluginSession::GenerateKey(CSSM_CC_HANDLE ccHandle
,
669 const Context
&context
,
672 const CssmData
*keyLabel
,
673 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
675 CSSM_PRIVILEGE privilege
)
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
);
683 void CSPFullPluginSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
,
684 const Context
&context
,
685 uint32 publicKeyUsage
,
686 uint32 publicKeyAttr
,
687 const CssmData
*publicKeyLabel
,
689 uint32 privateKeyUsage
,
690 uint32 privateKeyAttr
,
691 const CssmData
*privateKeyLabel
,
692 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
694 CSSM_PRIVILEGE privilege
)
696 CSPContext
*alg
= init(ccHandle
, CSSM_ALGCLASS_KEYGEN
, context
);
698 setKey(publicKey
, context
, CSSM_KEYCLASS_PUBLIC_KEY
, publicKeyAttr
, publicKeyUsage
);
699 setKey(privateKey
, context
, CSSM_KEYCLASS_PRIVATE_KEY
, privateKeyAttr
, privateKeyUsage
);
700 alg
->generate(context
, publicKey
, privateKey
);
702 //@@@ handle reference keys
705 void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey
&PublicKey
,
711 void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle
,
712 const Context
*context
,
714 CSSM_KEY_SIZE
&keySize
)
717 getKeySize(context
->get
<CssmKey
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
),
720 getKeySize(CssmKey::required(key
), keySize
);
726 // Free a key object.
728 void CSPFullPluginSession::FreeKey(const AccessCredentials
*AccessCred
,
737 // Random number and parameter generation
739 void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
,
740 const Context
&context
,
741 CssmData
&randomNumber
)
743 init(ccHandle
, CSSM_ALGCLASS_RANDOMGEN
, context
)->final(randomNumber
, *this);
746 void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle
,
747 const Context
&context
,
751 CSSM_CONTEXT_ATTRIBUTE_PTR
&attrs
)
753 Context::Attr
*attrList
;
754 init(ccHandle
, CSSM_ALGCLASS_NONE
, context
)->generate(context
, paramBits
,
755 param
, attrCount
, attrList
);
761 // Login/Logout and token operational maintainance.
762 // These mean little without support by the actual implementation, but we can help...
763 // @@@ Should this be in CSP[non-Full]PluginSession?
765 void CSPFullPluginSession::Login(const AccessCredentials
&AccessCred
,
766 const CssmData
*LoginName
,
767 const void *Reserved
)
769 if (Reserved
!= NULL
)
770 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
772 // default implementation refuses to log in
773 //@@@ should hand it to implementation virtual defaulting to this
774 CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME
);
777 void CSPFullPluginSession::Logout()
779 if (!loggedIn(false))
780 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN
);
783 void CSPFullPluginSession::VerifyDevice(const CssmData
&DeviceCert
)
785 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED
);
788 void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics
&statistics
)
790 memset(&statistics
, 0, sizeof(statistics
));
791 statistics
.UserAuthenticated
= loggedIn();
792 //@@@ collect device flags - capability matrix setup?
793 //@@@ collect token limitation parameters (static) - capability matrix setup?
794 //@@@ collect token statistics (dynamic) - dynamic accounting call-downs?
799 // Utterly miscellaneous, rarely used, strange functions
801 void CSPFullPluginSession::RetrieveCounter(CssmData
&Counter
)
806 void CSPFullPluginSession::RetrieveUniqueId(CssmData
&UniqueID
)
811 void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm
, CssmData
&TimeData
)
818 // ACL retrieval and change operations
820 void CSPFullPluginSession::GetKeyOwner(const CssmKey
&Key
,
821 CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
826 void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials
&AccessCred
,
828 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
833 void CSPFullPluginSession::GetKeyAcl(const CssmKey
&Key
,
834 const CSSM_STRING
*SelectionTag
,
835 uint32
&NumberOfAclInfos
,
836 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
841 void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials
&AccessCred
,
842 const CSSM_ACL_EDIT
&AclEdit
,
848 void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
853 void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials
&AccessCred
,
854 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
859 void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING
*SelectionTag
,
860 uint32
&NumberOfAclInfos
,
861 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
866 void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials
&AccessCred
,
867 const CSSM_ACL_EDIT
&AclEdit
)
875 // Passthroughs (by default, unimplemented)
877 void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle
,
878 const Context
&Context
,
879 uint32 PassThroughId
,
888 // KeyPool -- ReferencedKey management functionality
896 StLock
<Mutex
> _(mKeyMapLock
);
897 // Delete every ReferencedKey in the pool, but be careful to deactivate them first
898 // to keep them from calling erase (which would cause deadlock since we already hold mKeyMapLock).
899 KeyMap::iterator end
= mKeyMap
.end();
900 for (KeyMap::iterator it
= mKeyMap
.begin(); it
!= end
; ++it
)
904 it
->second
->deactivate();
913 KeyPool::add(ReferencedKey
&referencedKey
)
915 StLock
<Mutex
> _(mKeyMapLock
);
916 IFDEBUG(bool inserted
=)
917 mKeyMap
.insert(KeyMap::value_type(referencedKey
.keyReference(), &referencedKey
)).second
;
918 // Since add is only called from the constructor of ReferencedKey we should
919 // never add a key that is already in mKeyMap
924 KeyPool::findKey(const CSSM_KEY
&key
) const
926 return findKeyReference(ReferencedKey::keyReference(key
));
930 KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference
) const
932 StLock
<Mutex
> _(mKeyMapLock
);
933 KeyMap::const_iterator it
= mKeyMap
.find(keyReference
);
934 if (it
== mKeyMap
.end())
935 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
941 KeyPool::erase(ReferencedKey
&referencedKey
)
943 erase(referencedKey
.keyReference());
947 KeyPool::erase(ReferencedKey::KeyReference keyReference
)
949 StLock
<Mutex
> _(mKeyMapLock
);
950 KeyMap::iterator it
= mKeyMap
.find(keyReference
);
951 if (it
== mKeyMap
.end())
952 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
955 ReferencedKey
&referencedKey
= *it
->second
;
956 return referencedKey
;
959 // Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
961 KeyPool::freeKey(CssmAllocator
&allocator
, CSSM_KEY
&ioKey
)
963 delete &erase(ReferencedKey::freeReferenceKey(allocator
, ioKey
));
967 // ReferencedKey class
969 ReferencedKey::ReferencedKey(KeyPool
&keyPool
) : mKeyPool(&keyPool
)
971 mKeyPool
->add(*this);
974 ReferencedKey::~ReferencedKey()
977 mKeyPool
->erase(*this);
980 ReferencedKey::KeyReference
981 ReferencedKey::keyReference()
983 // @@@ Possibly check isActive() and return an invalid reference if it is not set.
984 return reinterpret_cast<ReferencedKey::KeyReference
>(this);
988 // Making, retrieving and freeing Key references of CssmKeys
991 ReferencedKey::makeReferenceKey(CssmAllocator
&allocator
, KeyReference keyReference
, CSSM_KEY
&key
)
993 key
.KeyHeader
.BlobType
= CSSM_KEYBLOB_REFERENCE
;
994 key
.KeyHeader
.Format
= CSSM_KEYBLOB_REF_FORMAT_INTEGER
;
995 key
.KeyData
.Length
= sizeof(KeyReference
);
996 key
.KeyData
.Data
= allocator
.alloc
<uint8
>(sizeof(KeyReference
));
997 uint8
*cp
= key
.KeyData
.Data
;
998 for (int i
= sizeof(KeyReference
); --i
>= 0;)
1000 cp
[i
] = keyReference
& 0xff;
1001 keyReference
= keyReference
>> 8;
1005 ReferencedKey::KeyReference
1006 ReferencedKey::keyReference(const CSSM_KEY
&key
)
1008 if (key
.KeyHeader
.BlobType
!= CSSM_KEYBLOB_REFERENCE
1009 || key
.KeyHeader
.Format
!= CSSM_KEYBLOB_REF_FORMAT_INTEGER
1010 || key
.KeyData
.Length
!= sizeof(KeyReference
)
1011 || key
.KeyData
.Data
== NULL
)
1012 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
1014 const uint8
*cp
= key
.KeyData
.Data
;
1015 KeyReference keyReference
= 0;
1016 for (uint32 i
= 0; i
< sizeof(KeyReference
); ++i
)
1017 keyReference
= (keyReference
<< 8) + cp
[i
];
1019 return keyReference
;
1022 ReferencedKey::KeyReference
1023 ReferencedKey::freeReferenceKey(CssmAllocator
&allocator
, CSSM_KEY
&key
)
1025 KeyReference aKeyReference
= keyReference(key
);
1026 allocator
.free(key
.KeyData
.Data
);
1027 key
.KeyData
.Data
= NULL
;
1028 key
.KeyData
.Length
= 0;
1029 return aKeyReference
;