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 inline 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 setContext(clonedCCHandle
, getStagedContext(ccHandle
, CSSM_ALGCLASS_DIGEST
)->clone(*this));
663 // Key generation, Derivation, and inquiry
665 void CSPFullPluginSession::GenerateKey(CSSM_CC_HANDLE ccHandle
,
666 const Context
&context
,
669 const CssmData
*keyLabel
,
670 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
672 CSSM_PRIVILEGE privilege
)
674 CSPContext
*alg
= init(ccHandle
, CSSM_ALGCLASS_KEYGEN
, context
);
675 setKey(key
, context
, CSSM_KEYCLASS_SESSION_KEY
, keyAttr
, keyUsage
);
676 CssmKey blank
; // dummy 2nd key (not used)
677 alg
->generate(context
, key
, blank
);
680 void CSPFullPluginSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
,
681 const Context
&context
,
682 uint32 publicKeyUsage
,
683 uint32 publicKeyAttr
,
684 const CssmData
*publicKeyLabel
,
686 uint32 privateKeyUsage
,
687 uint32 privateKeyAttr
,
688 const CssmData
*privateKeyLabel
,
689 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
691 CSSM_PRIVILEGE privilege
)
693 CSPContext
*alg
= init(ccHandle
, CSSM_ALGCLASS_KEYGEN
, context
);
695 setKey(publicKey
, context
, CSSM_KEYCLASS_PUBLIC_KEY
, publicKeyAttr
, publicKeyUsage
);
696 setKey(privateKey
, context
, CSSM_KEYCLASS_PRIVATE_KEY
, privateKeyAttr
, privateKeyUsage
);
697 alg
->generate(context
, publicKey
, privateKey
);
699 //@@@ handle reference keys
702 void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey
&PublicKey
,
708 void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle
,
709 const Context
*context
,
711 CSSM_KEY_SIZE
&keySize
)
714 getKeySize(context
->get
<CSSM_KEY
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
),
717 getKeySize(CssmKey::required(key
), keySize
);
723 // Free a key object.
725 void CSPFullPluginSession::FreeKey(const AccessCredentials
*AccessCred
,
734 // Random number and parameter generation
736 void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
,
737 const Context
&context
,
738 CssmData
&randomNumber
)
740 init(ccHandle
, CSSM_ALGCLASS_RANDOMGEN
, context
)->final(randomNumber
, *this);
743 void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle
,
744 const Context
&context
,
748 CSSM_CONTEXT_ATTRIBUTE_PTR
&attrs
)
750 Context::Attr
*attrList
;
751 init(ccHandle
, CSSM_ALGCLASS_NONE
, context
)->generate(context
, paramBits
,
752 param
, attrCount
, attrList
);
758 // Login/Logout and token operational maintainance.
759 // These mean little without support by the actual implementation, but we can help...
760 // @@@ Should this be in CSP[non-Full]PluginSession?
762 void CSPFullPluginSession::Login(const AccessCredentials
&AccessCred
,
763 const CssmData
*LoginName
,
764 const void *Reserved
)
766 if (Reserved
!= NULL
)
767 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
769 // default implementation refuses to log in
770 //@@@ should hand it to implementation virtual defaulting to this
771 CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME
);
774 void CSPFullPluginSession::Logout()
776 if (!loggedIn(false))
777 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN
);
780 void CSPFullPluginSession::VerifyDevice(const CssmData
&DeviceCert
)
782 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED
);
785 void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics
&statistics
)
787 memset(&statistics
, 0, sizeof(statistics
));
788 statistics
.UserAuthenticated
= loggedIn();
789 //@@@ collect device flags - capability matrix setup?
790 //@@@ collect token limitation parameters (static) - capability matrix setup?
791 //@@@ collect token statistics (dynamic) - dynamic accounting call-downs?
796 // Utterly miscellaneous, rarely used, strange functions
798 void CSPFullPluginSession::RetrieveCounter(CssmData
&Counter
)
803 void CSPFullPluginSession::RetrieveUniqueId(CssmData
&UniqueID
)
808 void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm
, CssmData
&TimeData
)
815 // ACL retrieval and change operations
817 void CSPFullPluginSession::GetKeyOwner(const CssmKey
&Key
,
818 CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
823 void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials
&AccessCred
,
825 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
830 void CSPFullPluginSession::GetKeyAcl(const CssmKey
&Key
,
831 const CSSM_STRING
*SelectionTag
,
832 uint32
&NumberOfAclInfos
,
833 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
838 void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials
&AccessCred
,
839 const CSSM_ACL_EDIT
&AclEdit
,
845 void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
850 void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials
&AccessCred
,
851 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
856 void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING
*SelectionTag
,
857 uint32
&NumberOfAclInfos
,
858 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
863 void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials
&AccessCred
,
864 const CSSM_ACL_EDIT
&AclEdit
)
872 // Passthroughs (by default, unimplemented)
874 void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle
,
875 const Context
&Context
,
876 uint32 PassThroughId
,
885 // KeyPool -- ReferencedKey management functionality
893 StLock
<Mutex
> _(mKeyMapLock
);
894 // Delete every ReferencedKey in the pool, but be careful to deactivate them first
895 // to keep them from calling erase (which would cause deadlock since we already hold mKeyMapLock).
896 KeyMap::iterator end
= mKeyMap
.end();
897 for (KeyMap::iterator it
= mKeyMap
.begin(); it
!= end
; ++it
)
901 it
->second
->deactivate();
910 KeyPool::add(ReferencedKey
&referencedKey
)
912 StLock
<Mutex
> _(mKeyMapLock
);
913 bool inserted
= mKeyMap
.insert(KeyMap::value_type(referencedKey
.keyReference(), &referencedKey
)).second
;
914 // Since add is only called from the constructor of ReferencedKey we should
915 // never add a key that is already in mKeyMap
920 KeyPool::findKey(const CSSM_KEY
&key
) const
922 return findKeyReference(ReferencedKey::keyReference(key
));
926 KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference
) const
928 StLock
<Mutex
> _(mKeyMapLock
);
929 KeyMap::const_iterator it
= mKeyMap
.find(keyReference
);
930 if (it
== mKeyMap
.end())
931 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
937 KeyPool::erase(ReferencedKey
&referencedKey
)
939 erase(referencedKey
.keyReference());
943 KeyPool::erase(ReferencedKey::KeyReference keyReference
)
945 StLock
<Mutex
> _(mKeyMapLock
);
946 KeyMap::iterator it
= mKeyMap
.find(keyReference
);
947 if (it
== mKeyMap
.end())
948 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
951 ReferencedKey
&referencedKey
= *it
->second
;
952 return referencedKey
;
955 // Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
957 KeyPool::freeKey(CssmAllocator
&allocator
, CSSM_KEY
&ioKey
)
959 delete &erase(ReferencedKey::freeReferenceKey(allocator
, ioKey
));
963 // ReferencedKey class
965 ReferencedKey::ReferencedKey(KeyPool
&keyPool
) : mKeyPool(&keyPool
)
967 mKeyPool
->add(*this);
970 ReferencedKey::~ReferencedKey()
973 mKeyPool
->erase(*this);
976 ReferencedKey::KeyReference
977 ReferencedKey::keyReference()
979 // @@@ Possibly check isActive() and return an invalid reference if it is not set.
980 return reinterpret_cast<ReferencedKey::KeyReference
>(this);
984 // Making, retrieving and freeing Key references of CssmKeys
987 ReferencedKey::makeReferenceKey(CssmAllocator
&allocator
, KeyReference keyReference
, CSSM_KEY
&key
)
989 key
.KeyHeader
.BlobType
= CSSM_KEYBLOB_REFERENCE
;
990 key
.KeyHeader
.Format
= CSSM_KEYBLOB_REF_FORMAT_INTEGER
;
991 key
.KeyData
.Length
= sizeof(KeyReference
);
992 key
.KeyData
.Data
= allocator
.alloc
<uint8
>(sizeof(KeyReference
));
993 uint8
*cp
= key
.KeyData
.Data
;
994 for (int i
= sizeof(KeyReference
); --i
>= 0;)
996 cp
[i
] = keyReference
& 0xff;
997 keyReference
= keyReference
>> 8;
1001 ReferencedKey::KeyReference
1002 ReferencedKey::keyReference(const CSSM_KEY
&key
)
1004 if (key
.KeyHeader
.BlobType
!= CSSM_KEYBLOB_REFERENCE
1005 || key
.KeyHeader
.Format
!= CSSM_KEYBLOB_REF_FORMAT_INTEGER
1006 || key
.KeyData
.Length
!= sizeof(KeyReference
)
1007 || key
.KeyData
.Data
== NULL
)
1008 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
1010 const uint8
*cp
= key
.KeyData
.Data
;
1011 KeyReference keyReference
= 0;
1012 for (uint32 i
= 0; i
< sizeof(KeyReference
); ++i
)
1013 keyReference
= (keyReference
<< 8) + cp
[i
];
1015 return keyReference
;
1018 ReferencedKey::KeyReference
1019 ReferencedKey::freeReferenceKey(CssmAllocator
&allocator
, CSSM_KEY
&key
)
1021 KeyReference aKeyReference
= keyReference(key
);
1022 allocator
.free(key
.KeyData
.Data
);
1023 key
.KeyData
.Data
= NULL
;
1024 key
.KeyData
.Length
= 0;
1025 return aKeyReference
;