2 * Copyright (c) 2000-2001,2011-2012,2014 Apple 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
22 #include <security_cdsa_plugin/CSPsession.h>
23 #include <security_cdsa_plugin/cssmplugin.h>
24 #include <security_cdsa_utilities/cssmbridge.h>
27 typedef CSPFullPluginSession::CSPContext CSPContext
;
31 // PluginContext construction
33 CSPPluginSession::PluginContext::~PluginContext()
36 CSPFullPluginSession::AlgorithmFactory::~AlgorithmFactory()
43 CssmData
CSPFullPluginSession::makeBuffer(size_t size
, Allocator
&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(Allocator
&)
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
, Allocator
&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
, Allocator
&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 CSSM_SIZE
&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 CSSM_SIZE
&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 CSSM_SIZE
&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 CSSM_SIZE
&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 (uint32
)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
);
686 CSSM_CC_HANDLE mHandle
;
689 ContextMinder(CSSM_CC_HANDLE ccHandle
) : mHandle(ccHandle
) {}
690 ~ContextMinder() {CSSM_DeleteContext(mHandle
);}
695 void CSPFullPluginSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
,
696 const Context
&context
,
697 uint32 publicKeyUsage
,
698 uint32 publicKeyAttr
,
699 const CssmData
*publicKeyLabel
,
701 uint32 privateKeyUsage
,
702 uint32 privateKeyAttr
,
703 const CssmData
*privateKeyLabel
,
704 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
706 CSSM_PRIVILEGE privilege
)
708 CSPContext
*alg
= init(ccHandle
, CSSM_ALGCLASS_KEYGEN
, context
);
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
);
715 //@@@ handle reference keys
717 bool encryptPublic
= publicKeyUsage
& CSSM_KEYUSE_ENCRYPT
;
718 bool encryptPrivate
= privateKeyUsage
& CSSM_KEYUSE_ENCRYPT
;
720 if (!(encryptPublic
|| encryptPrivate
))
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
));
731 CSSM_KEY_PTR encryptingKey
, decryptingKey
;
734 encryptingKey
= &publicKey
;
735 decryptingKey
= &privateKey
;
739 encryptingKey
= &privateKey
;
740 decryptingKey
= &publicKey
;
743 // make data to be encrypted
744 unsigned bytesInKey
= encryptingKey
->KeyHeader
.LogicalKeySizeInBits
/ 8;
745 u_int8_t
*buffer
= (u_int8_t
*)malloc(bytesInKey
);
746 if (buffer
== NULL
) {
747 CssmError::throwMe(CSSMERR_CSSM_MEMORY_ERROR
);
752 for (i
= 0; i
< bytesInKey
; ++i
)
757 CSSM_DATA clearBuf
= {bytesInKey
, buffer
};
758 CSSM_DATA cipherBuf
; // have the CSP allocate the resulting memory
759 CSSM_SIZE bytesEncrypted
;
760 CSSM_DATA remData
= {0, NULL
};
761 CSSM_DATA decryptedBuf
= {bytesInKey
, buffer
};
763 CSSM_RETURN result
= CSSM_CSP_CreateAsymmetricContext(moduleHandle
, encryptingKey
->KeyHeader
.AlgorithmId
, &nullCreds
, encryptingKey
, CSSM_PADDING_NONE
, &encryptHandle
);
764 if (result
!= CSSM_OK
)
767 CssmError::throwMe(result
);
770 ContextMinder
encryptMinder(encryptHandle
); // auto throw away if we error out
772 CSSM_QUERY_SIZE_DATA qsData
;
773 qsData
.SizeInputBlock
= bytesInKey
;
774 result
= CSSM_QuerySize(encryptHandle
, CSSM_TRUE
, 1, &qsData
);
775 if (result
== CSSMERR_CSP_INVALID_ALGORITHM
)
781 uint8 cipherBuffer
[qsData
.SizeOutputBlock
];
782 cipherBuf
.Length
= qsData
.SizeOutputBlock
;
783 cipherBuf
.Data
= cipherBuffer
;
786 result
= CSSM_EncryptData(encryptHandle
, &clearBuf
, 1, &cipherBuf
, 1, &bytesEncrypted
, &remData
);
787 if (result
!= CSSM_OK
)
790 CssmError::throwMe(result
);
794 if (memcmp(cipherBuf
.Data
, clearBuf
.Data
, clearBuf
.Length
) == 0)
796 // we have a match, that's not good news...
801 if (remData
.Data
!= NULL
)
806 // make a context to perform the decryption
807 CSSM_CC_HANDLE decryptHandle
;
808 result
= CSSM_CSP_CreateAsymmetricContext(moduleHandle
, encryptingKey
->KeyHeader
.AlgorithmId
, &nullCreds
, decryptingKey
, CSSM_PADDING_NONE
, &decryptHandle
);
809 ContextMinder
decryptMinder(decryptHandle
);
811 if (result
!= CSSM_OK
)
814 CssmError::throwMe(result
);
817 result
= CSSM_DecryptData(decryptHandle
, &cipherBuf
, 1, &decryptedBuf
, 1, &bytesEncrypted
, &remData
);
818 if (result
!= CSSM_OK
)
821 CssmError::throwMe(result
);
825 for (i
= 0; i
< bytesInKey
; ++i
)
827 if (decryptedBuf
.Data
[i
] != (i
& 0xFF))
834 if (remData
.Data
!= NULL
)
842 void CSPFullPluginSession::ObtainPrivateKeyFromPublicKey(const CssmKey
&PublicKey
,
848 void CSPFullPluginSession::QueryKeySizeInBits(CSSM_CC_HANDLE ccHandle
,
849 const Context
*context
,
851 CSSM_KEY_SIZE
&keySize
)
854 getKeySize(context
->get
<CssmKey
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
),
857 getKeySize(CssmKey::required(key
), keySize
);
863 // Free a key object.
865 void CSPFullPluginSession::FreeKey(const AccessCredentials
*AccessCred
,
874 // Random number and parameter generation
876 void CSPFullPluginSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
,
877 const Context
&context
,
878 CssmData
&randomNumber
)
880 init(ccHandle
, CSSM_ALGCLASS_RANDOMGEN
, context
)->final(randomNumber
, *this);
883 void CSPFullPluginSession::GenerateAlgorithmParams(CSSM_CC_HANDLE ccHandle
,
884 const Context
&context
,
888 CSSM_CONTEXT_ATTRIBUTE_PTR
&attrs
)
890 Context::Attr
*attrList
;
891 init(ccHandle
, CSSM_ALGCLASS_NONE
, context
)->generate(context
, paramBits
,
892 param
, attrCount
, attrList
);
898 // Login/Logout and token operational maintainance.
899 // These mean little without support by the actual implementation, but we can help...
900 // @@@ Should this be in CSP[non-Full]PluginSession?
902 void CSPFullPluginSession::Login(const AccessCredentials
&AccessCred
,
903 const CssmData
*LoginName
,
904 const void *Reserved
)
906 if (Reserved
!= NULL
)
907 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
);
909 // default implementation refuses to log in
910 //@@@ should hand it to implementation virtual defaulting to this
911 CssmError::throwMe(CSSMERR_CSP_INVALID_LOGIN_NAME
);
914 void CSPFullPluginSession::Logout()
916 if (!loggedIn(false))
917 CssmError::throwMe(CSSMERR_CSP_NOT_LOGGED_IN
);
920 void CSPFullPluginSession::VerifyDevice(const CssmData
&DeviceCert
)
922 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED
);
925 void CSPFullPluginSession::GetOperationalStatistics(CSPOperationalStatistics
&statistics
)
927 memset(&statistics
, 0, sizeof(statistics
));
928 statistics
.UserAuthenticated
= loggedIn();
929 //@@@ collect device flags - capability matrix setup?
930 //@@@ collect token limitation parameters (static) - capability matrix setup?
931 //@@@ collect token statistics (dynamic) - dynamic accounting call-downs?
936 // Utterly miscellaneous, rarely used, strange functions
938 void CSPFullPluginSession::RetrieveCounter(CssmData
&Counter
)
943 void CSPFullPluginSession::RetrieveUniqueId(CssmData
&UniqueID
)
948 void CSPFullPluginSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm
, CssmData
&TimeData
)
955 // ACL retrieval and change operations
957 void CSPFullPluginSession::GetKeyOwner(const CssmKey
&Key
,
958 CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
963 void CSPFullPluginSession::ChangeKeyOwner(const AccessCredentials
&AccessCred
,
965 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
970 void CSPFullPluginSession::GetKeyAcl(const CssmKey
&Key
,
971 const CSSM_STRING
*SelectionTag
,
972 uint32
&NumberOfAclInfos
,
973 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
978 void CSPFullPluginSession::ChangeKeyAcl(const AccessCredentials
&AccessCred
,
979 const CSSM_ACL_EDIT
&AclEdit
,
985 void CSPFullPluginSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
990 void CSPFullPluginSession::ChangeLoginOwner(const AccessCredentials
&AccessCred
,
991 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
996 void CSPFullPluginSession::GetLoginAcl(const CSSM_STRING
*SelectionTag
,
997 uint32
&NumberOfAclInfos
,
998 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
1003 void CSPFullPluginSession::ChangeLoginAcl(const AccessCredentials
&AccessCred
,
1004 const CSSM_ACL_EDIT
&AclEdit
)
1012 // Passthroughs (by default, unimplemented)
1014 void CSPFullPluginSession::PassThrough(CSSM_CC_HANDLE CCHandle
,
1015 const Context
&Context
,
1016 uint32 PassThroughId
,
1025 // KeyPool -- ReferencedKey management functionality
1033 StLock
<Mutex
> _(mKeyMapLock
);
1034 // Delete every ReferencedKey in the pool, but be careful to deactivate them first
1035 // to keep them from calling erase (which would cause deadlock since we already hold mKeyMapLock).
1036 KeyMap::iterator end
= mKeyMap
.end();
1037 for (KeyMap::iterator it
= mKeyMap
.begin(); it
!= end
; ++it
)
1041 it
->second
->deactivate();
1050 KeyPool::add(ReferencedKey
&referencedKey
)
1052 StLock
<Mutex
> _(mKeyMapLock
);
1054 inserted
= mKeyMap
.insert(KeyMap::value_type(referencedKey
.keyReference(), &referencedKey
)).second
;
1055 // Since add is only called from the constructor of ReferencedKey we should
1056 // never add a key that is already in mKeyMap
1059 secinfo("SecAccessReference", "added a referenced key %p for key reference %ld", &referencedKey
, referencedKey
.keyReference());
1063 KeyPool::findKey(const CSSM_KEY
&key
) const
1065 return findKeyReference(ReferencedKey::keyReference(key
));
1069 KeyPool::findKeyReference(ReferencedKey::KeyReference keyReference
) const
1071 StLock
<Mutex
> _(mKeyMapLock
);
1072 KeyMap::const_iterator it
= mKeyMap
.find(keyReference
);
1073 if (it
== mKeyMap
.end())
1074 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
1076 secinfo("SecAccessReference", "found a referenced key %p for key reference %ld [%ld]", it
->second
, keyReference
, it
->second
->keyReference());
1082 KeyPool::erase(ReferencedKey
&referencedKey
)
1084 erase(referencedKey
.keyReference());
1088 KeyPool::erase(ReferencedKey::KeyReference keyReference
)
1090 StLock
<Mutex
> _(mKeyMapLock
);
1091 KeyMap::iterator it
= mKeyMap
.find(keyReference
);
1092 if (it
== mKeyMap
.end())
1093 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
1095 ReferencedKey
&referencedKey
= *it
->second
;
1097 return referencedKey
;
1100 // Erase keyReference from mKeyMap, free the ioKey, and delete the ReferencedKey
1102 KeyPool::freeKey(Allocator
&allocator
, CSSM_KEY
&ioKey
)
1104 delete &erase(ReferencedKey::freeReferenceKey(allocator
, ioKey
));
1108 // ReferencedKey class
1110 ReferencedKey::ReferencedKey(KeyPool
&keyPool
) : mKeyPool(&keyPool
)
1112 mKeyPool
->add(*this);
1115 ReferencedKey::~ReferencedKey()
1118 mKeyPool
->erase(*this);
1121 ReferencedKey::KeyReference
1122 ReferencedKey::keyReference()
1124 // @@@ Possibly check isActive() and return an invalid reference if it is not set.
1125 return reinterpret_cast<ReferencedKey::KeyReference
>(this);
1129 // Making, retrieving and freeing Key references of CssmKeys
1132 ReferencedKey::makeReferenceKey(Allocator
&allocator
, KeyReference keyReference
, CSSM_KEY
&key
)
1134 key
.KeyHeader
.BlobType
= CSSM_KEYBLOB_REFERENCE
;
1135 key
.KeyHeader
.Format
= CSSM_KEYBLOB_REF_FORMAT_INTEGER
;
1136 key
.KeyData
.Length
= sizeof(KeyReference
);
1137 key
.KeyData
.Data
= allocator
.alloc
<uint8
>(sizeof(KeyReference
));
1138 uint8
*cp
= key
.KeyData
.Data
;
1139 for (int i
= sizeof(KeyReference
); --i
>= 0;)
1141 cp
[i
] = keyReference
& 0xff;
1142 keyReference
= keyReference
>> 8;
1146 ReferencedKey::KeyReference
1147 ReferencedKey::keyReference(const CSSM_KEY
&key
)
1149 if (key
.KeyHeader
.BlobType
!= CSSM_KEYBLOB_REFERENCE
1150 || key
.KeyHeader
.Format
!= CSSM_KEYBLOB_REF_FORMAT_INTEGER
1151 || key
.KeyData
.Length
!= sizeof(KeyReference
)
1152 || key
.KeyData
.Data
== NULL
)
1153 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
1155 const uint8
*cp
= key
.KeyData
.Data
;
1156 KeyReference keyReference
= 0;
1157 for (uint32 i
= 0; i
< sizeof(KeyReference
); ++i
)
1158 keyReference
= (keyReference
<< 8) + cp
[i
];
1160 return keyReference
;
1163 ReferencedKey::KeyReference
1164 ReferencedKey::freeReferenceKey(Allocator
&allocator
, CSSM_KEY
&key
)
1166 KeyReference aKeyReference
= keyReference(key
);
1167 allocator
.free(key
.KeyData
.Data
);
1168 key
.KeyData
.Data
= NULL
;
1169 key
.KeyData
.Length
= 0;
1170 return aKeyReference
;