2 * Copyright (c) 2000-2001,2011,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 // AppleCSP.cpp - top-level plugin and session implementation
23 #include "AppleCSPSession.h"
24 #include "AppleCSPUtils.h"
26 #include "cspdebugging.h"
27 #include <security_cdsa_plugin/CSPsession.h>
28 #include <security_utilities/alloc.h>
29 #ifdef BSAFE_CSP_ENABLE
31 #include "bsafecspi.h"
33 #ifdef CRYPTKIT_CSP_ENABLE
34 #include "cryptkitcsp.h"
37 #include <miscAlgFactory.h>
39 #include "ascFactory.h"
41 #include <RSA_DSA_csp.h>
42 #include <RSA_DSA_keys.h>
46 #include "YarrowConnection.h"
49 // Make and break the plugin object
51 AppleCSPPlugin::AppleCSPPlugin() :
52 normAllocator(Allocator::standard(Allocator::normal
)),
53 privAllocator(Allocator::standard(Allocator::sensitive
)),
54 #ifdef BSAFE_CSP_ENABLE
55 bSafe4Factory(new BSafeFactory(&normAllocator
, &privAllocator
)),
57 #ifdef CRYPTKIT_CSP_ENABLE
58 cryptKitFactory(new CryptKitFactory(&normAllocator
, &privAllocator
)),
60 miscAlgFactory(new MiscAlgFactory(&normAllocator
, &privAllocator
)),
62 ascAlgFactory(new AscAlgFactory(&normAllocator
, &privAllocator
)),
64 rsaDsaAlgFactory(new RSA_DSA_Factory(&normAllocator
, &privAllocator
)),
65 dhAlgFactory(new DH_Factory(&normAllocator
, &privAllocator
))
67 // misc. once-per-address-space cruft...
70 AppleCSPPlugin::~AppleCSPPlugin()
72 #ifdef BSAFE_CSP_ENABLE
75 #ifdef CRYPTKIT_CSP_ENABLE
76 delete cryptKitFactory
;
78 delete miscAlgFactory
;
82 delete rsaDsaAlgFactory
;
88 // Create a new plugin session, our way
90 PluginSession
*AppleCSPPlugin::makeSession(
91 CSSM_MODULE_HANDLE handle
,
92 const CSSM_VERSION
&version
,
94 CSSM_SERVICE_TYPE subserviceType
,
95 CSSM_ATTACH_FLAGS attachFlags
,
96 const CSSM_UPCALLS
&upcalls
)
98 switch (subserviceType
) {
99 case CSSM_SERVICE_CSP
:
100 return new AppleCSPSession(handle
,
108 CssmError::throwMe(CSSMERR_CSSM_INVALID_SERVICE_MASK
);
115 // Session constructor
117 AppleCSPSession::AppleCSPSession(
118 CSSM_MODULE_HANDLE handle
,
119 AppleCSPPlugin
&plug
,
120 const CSSM_VERSION
&version
,
122 CSSM_SERVICE_TYPE subserviceType
,
123 CSSM_ATTACH_FLAGS attachFlags
,
124 const CSSM_UPCALLS
&upcalls
)
125 : CSPFullPluginSession(handle
,
132 #ifdef BSAFE_CSP_ENABLE
133 bSafe4Factory(*(dynamic_cast<BSafeFactory
*>(plug
.bSafe4Factory
))),
135 #ifdef CRYPTKIT_CSP_ENABLE
136 cryptKitFactory(*(dynamic_cast<CryptKitFactory
*>(plug
.cryptKitFactory
))),
138 miscAlgFactory(*(dynamic_cast<MiscAlgFactory
*>(plug
.miscAlgFactory
))),
139 #ifdef ASC_CSP_ENABLE
140 ascAlgFactory(*(dynamic_cast<AscAlgFactory
*>(plug
.ascAlgFactory
))),
142 rsaDsaAlgFactory(*(dynamic_cast<RSA_DSA_Factory
*>(plug
.rsaDsaAlgFactory
))),
143 dhAlgFactory(*(dynamic_cast<DH_Factory
*>(plug
.dhAlgFactory
))),
144 normAllocator(*this),
145 privAllocator(plug
.privAlloc())
150 AppleCSPSession::~AppleCSPSession()
156 // Called at (CSSM) context create time. This is ignored; we do a full
157 // context setup later, at setupContext time.
159 CSPFullPluginSession::CSPContext
*
160 AppleCSPSession::contextCreate(
161 CSSM_CC_HANDLE handle
,
162 const Context
&context
)
168 // Called by CSPFullPluginSession when an op is actually commencing.
169 // Context can safely assumed to be fully formed and stable for the
170 // duration of the op; thus we wait until now to set up our
171 // CSPContext as appropriate to the op.
173 void AppleCSPSession::setupContext(
174 CSPContext
* &cspCtx
,
175 const Context
&context
,
179 * Note we leave the decision as to whether it's OK to
180 * reuse a context to the individual factories.
182 #ifdef BSAFE_CSP_ENABLE
183 /* Give BSAFE the firsrt shot if it's present */
184 if (bSafe4Factory
.setup(*this, cspCtx
, context
)) {
185 CASSERT(cspCtx
!= NULL
);
189 if (rsaDsaAlgFactory
.setup(*this, cspCtx
, context
)) {
190 CASSERT(cspCtx
!= NULL
);
193 if (miscAlgFactory
.setup(*this, cspCtx
, context
)) {
194 CASSERT(cspCtx
!= NULL
);
197 if (dhAlgFactory
.setup(*this, cspCtx
, context
)) {
198 CASSERT(cspCtx
!= NULL
);
201 #ifdef CRYPTKIT_CSP_ENABLE
202 if (cryptKitFactory
.setup(*this, cspCtx
, context
)) {
203 CASSERT(cspCtx
!= NULL
);
207 #ifdef ASC_CSP_ENABLE
208 if (ascAlgFactory
.setup(*this, cspCtx
, context
)) {
209 CASSERT(cspCtx
!= NULL
);
213 if(setup(cspCtx
, context
)) {
214 CASSERT(cspCtx
!= NULL
);
217 dprintf0("AppleCSPSession::setupContext: invalid algorithm\n");
218 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
222 * Used for generating crypto contexts at this level.
223 * Analogous to AlgorithmFactory.setup().
225 bool AppleCSPSession::setup(
226 CSPFullPluginSession::CSPContext
* &cspCtx
,
227 const Context
&context
)
230 return false; // not ours or already set
233 switch(context
.type()) {
234 case CSSM_ALGCLASS_RANDOMGEN
:
235 switch (context
.algorithm()) {
236 case CSSM_ALGID_APPLE_YARROW
:
237 cspCtx
= new YarrowContext(*this);
239 /* other random algs here */
243 /* other contexts here */
253 // Context for CSSM_ALGID_APPLE_YARROW.
255 YarrowContext::YarrowContext(AppleCSPSession
&session
)
256 : AppleCSPContext(session
)
261 YarrowContext::~YarrowContext()
267 // Only job here is to snag the length and process the optional seed argument
269 void YarrowContext::init(
270 const Context
&context
,
273 /* stash requested length for use later in outputSize() */
274 outSize
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
,
275 CSSMERR_CSP_INVALID_ATTR_OUTPUT_SIZE
);
278 CssmCryptoData
*cseed
= context
.get
<CssmCryptoData
>(CSSM_ATTRIBUTE_SEED
);
283 CssmData seed
= (*cseed
)();
284 if((seed
.Length
== 0) ||
285 (seed
.Data
== NULL
)) {
286 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED
);
288 session().addEntropy((size_t)seed
.Length
, seed
.Data
);
291 void YarrowContext::final(
294 session().getRandomBytes((size_t)out
.Length
, out
.Data
);
298 *** Binary Key support.
301 // Given a CSSM_DATA, extract its KeyRef.
302 static KeyRef
CssmDataToKeyRef(
303 const CSSM_DATA
&data
)
305 if(data
.Length
!= sizeof(KeyRef
)) {
306 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
309 uint8
*cp
= data
.Data
+ sizeof(KeyRef
) - 1;
311 for(unsigned dex
=0; dex
<sizeof(KeyRef
); dex
++) {
318 // Place a KeyRef into a CSSM_DATA, mallocing if necessary.
319 static void keyRefToCssmData(
322 Allocator
&allocator
)
324 if(data
.Length
> sizeof(keyRef
)) {
325 /* don't leave old raw key material lying around */
326 memset(data
.Data
+ sizeof(keyRef
), 0, data
.Length
- sizeof(keyRef
));
328 else if(data
.Length
< sizeof(keyRef
)) {
329 /* not enough space for even a keyRef, force realloc */
330 allocator
.free(data
.Data
);
334 setUpData(data
, sizeof(keyRef
), allocator
);
336 uint8
*cp
= data
.Data
;
337 for(unsigned i
=0; i
<sizeof(keyRef
); i
++) {
338 *cp
++ = keyRef
& 0xff;
343 // Look up a BinaryKey by its KeyRef. Returns NULL if not
344 // found. refKeyMapLock held on entry and exit.
345 BinaryKey
*AppleCSPSession::lookupKeyRef(
348 const BinaryKey
*binKey
;
350 // use safe version, don't create new entry if this key
352 keyMap::iterator it
= refKeyMap
.find(keyRef
);
353 if(it
== refKeyMap
.end()) {
357 assert(binKey
== reinterpret_cast<const BinaryKey
*>(keyRef
));
358 assert(binKey
->mKeyRef
== keyRef
);
359 return const_cast<BinaryKey
*>(binKey
);
362 // add a BinaryKey to our refKeyMap. Sets up cssmKey
364 void AppleCSPSession::addRefKey(
368 // for now, KeyRef is just the address of the BinaryKey
369 KeyRef keyRef
= reinterpret_cast<KeyRef
>(&binKey
);
371 binKey
.mKeyRef
= keyRef
;
372 binKey
.mKeyHeader
= CssmKey::Header::overlay(cssmKey
.KeyHeader
);
374 StLock
<Mutex
> _(refKeyMapLock
);
375 assert(lookupKeyRef(keyRef
) == NULL
);
376 refKeyMap
[keyRef
] = &binKey
;
378 cssmKey
.KeyHeader
.BlobType
= CSSM_KEYBLOB_REFERENCE
;
379 cssmKey
.KeyHeader
.Format
= CSSM_KEYBLOB_REF_FORMAT_INTEGER
;
380 keyRefToCssmData(keyRef
, cssmKey
.KeyData
, normAllocator
);
381 secinfo("freeKey", "CSP addRefKey key %p keyData %p keyRef %p",
382 &cssmKey
, cssmKey
.KeyData
.Data
, &binKey
);
385 // Given a CssmKey in reference form, obtain the associated
386 // BinaryKey. Throws CSSMERR_CSP_INVALID_KEY_REFERENCE if
387 // key not found in session key map.
388 BinaryKey
& AppleCSPSession::lookupRefKey(
389 const CssmKey
&cssmKey
)
394 keyRef
= CssmDataToKeyRef(cssmKey
.KeyData
);
396 StLock
<Mutex
> _(refKeyMapLock
);
397 binKey
= lookupKeyRef(keyRef
);
400 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
402 assert(Guid::overlay(binKey
->mKeyHeader
.CspId
) == plugin
.myGuid());
405 * Verify sensitive fields have not changed between when the BinaryKey was
406 * created/stored and when the caller passed in the ref key.
407 * Some fields were changed by addRefKey, so make a local copy....
409 CSSM_KEYHEADER localHdr
= cssmKey
.KeyHeader
;
410 localHdr
.BlobType
= binKey
->mKeyHeader
.BlobType
;
411 localHdr
.Format
= binKey
->mKeyHeader
.Format
;
412 if(memcmp(&localHdr
, &binKey
->mKeyHeader
, sizeof(CSSM_KEYHEADER
))) {
413 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
418 // CSPFullPluginSession declares & implements this.
419 // Note that we ignore the delete argument; since we don't
420 // store anything, freeing is the same as deleting.
421 void AppleCSPSession::FreeKey(
422 const AccessCredentials
*AccessCred
,
427 if((KeyPtr
.blobType() == CSSM_KEYBLOB_REFERENCE
) &&
428 (KeyPtr
.cspGuid() == plugin
.myGuid())) {
429 // it's a ref key we generated - delete associated BinaryKey
430 KeyRef keyRef
= CssmDataToKeyRef(KeyPtr
.KeyData
);
432 StLock
<Mutex
> _(refKeyMapLock
);
433 BinaryKey
*binKey
= lookupKeyRef(keyRef
);
435 secinfo("freeKey", "CSP FreeKey key %p keyData %p binKey %p",
436 &KeyPtr
, KeyPtr
.KeyData
.Data
, binKey
);
438 refKeyMap
.erase(keyRef
);
442 errorLog0("Error deleting/erasing known "
447 secinfo("freeKey", "CSP freeKey unknown key");
451 CSPFullPluginSession::FreeKey(AccessCred
, KeyPtr
, Delete
);
454 /* Passthrough, used for key digest */
455 void AppleCSPSession::PassThrough(
456 CSSM_CC_HANDLE CCHandle
,
457 const Context
&Context
,
458 uint32 PassThroughId
,
464 /* validate context */
465 if(Context
.type() != CSSM_ALGCLASS_NONE
) {
466 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT
);
469 switch(PassThroughId
) {
470 case CSSM_APPLECSP_KEYDIGEST
:
472 CssmKey
&key
= Context
.get
<CssmKey
>(
474 CSSMERR_CSP_MISSING_ATTR_KEY
);
476 /* validate key as best we can */
477 switch(key
.keyClass()) {
478 case CSSM_KEYCLASS_PUBLIC_KEY
:
479 case CSSM_KEYCLASS_PRIVATE_KEY
:
480 case CSSM_KEYCLASS_SESSION_KEY
:
483 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
487 * Ref key: obtain binary, ask it for blob
488 * Raw key: get info provider, ask it for the blob. This
489 * allows for an optimized path which avoids
490 * converting to a BinaryKey.
493 switch(key
.blobType()) {
494 case CSSM_KEYBLOB_RAW
:
496 CSPKeyInfoProvider
*provider
= infoProvider(key
);
498 provider
->getHashableBlob(privAllocator
, blobToHash
);
500 /* took optimized case; proceed */
505 /* convert to BinaryKey and ask it to do the work */
507 CSSM_KEYATTR_FLAGS flags
= 0; // not used
508 provider
->CssmKeyToBinary(NULL
, // no paramKey
512 CssmKey::Header::overlay(key
.KeyHeader
);
513 CSSM_KEYBLOB_FORMAT rawFormat
;
514 rawFormat
= CSSM_KEYBLOB_RAW_FORMAT_DIGEST
;
515 CSSM_KEYATTR_FLAGS attrFlags
= 0;
516 binKey
->generateKeyBlob(privAllocator
,
526 case CSSM_KEYBLOB_REFERENCE
:
528 BinaryKey
&binKey
= lookupRefKey(key
);
529 CSSM_KEYBLOB_FORMAT rawFormat
;
530 rawFormat
= CSSM_KEYBLOB_RAW_FORMAT_DIGEST
;
531 CSSM_KEYATTR_FLAGS attrFlags
= 0;
532 binKey
.generateKeyBlob(privAllocator
,
541 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
544 /* obtain sha1 hash of blobToHash */
546 CSSM_DATA_PTR outHash
= NULL
;
549 (CSSM_DATA_PTR
)normAllocator
.malloc(sizeof(CSSM_DATA
));
551 (uint8
*)normAllocator
.malloc(SHA1_DIGEST_SIZE
);
552 outHash
->Length
= SHA1_DIGEST_SIZE
;
555 freeCssmData(blobToHash
, privAllocator
);
558 cspGenSha1Hash(blobToHash
.data(), blobToHash
.length(),
560 freeCssmData(blobToHash
, privAllocator
);
565 CssmError::throwMe(CSSMERR_CSP_INVALID_PASSTHROUGH_ID
);
571 * CSPSession version of QueryKeySizeInBits.
573 void AppleCSPSession::getKeySize(const CssmKey
&key
,
576 CSPKeyInfoProvider
*provider
= infoProvider(key
);
578 provider
->QueryKeySizeInBits(size
);
581 /* don't leak this on error */
588 void AppleCSPSession::getRandomBytes(size_t length
, uint8
*cp
)
591 cspGetRandomBytes(cp
, (unsigned)length
);
594 errorLog0("CSP: YarrowClient failure\n");
598 void AppleCSPSession::addEntropy(size_t length
, const uint8
*cp
)
601 cspAddEntropy(cp
, (unsigned)length
);
604 #if CSP_ALLOW_FEE_RNG
613 *** CSPKeyInfoProvider support.
617 * Find a CSPKeyInfoProvider subclass for the specified key.
619 CSPKeyInfoProvider
*AppleCSPSession::infoProvider(
622 CSPKeyInfoProvider
*provider
= NULL
;
624 #ifdef BSAFE_CSP_ENABLE
625 /* Give BSAFE first shot, if it's here */
626 provider
= BSafe::BSafeKeyInfoProvider::provider(key
, *this);
627 if(provider
!= NULL
) {
632 provider
= RSAKeyInfoProvider::provider(key
, *this);
633 if(provider
!= NULL
) {
637 provider
= SymmetricKeyInfoProvider::provider(key
, *this);
638 if(provider
!= NULL
) {
642 #ifdef CRYPTKIT_CSP_ENABLE
643 provider
= CryptKit::FEEKeyInfoProvider::provider(key
, *this);
644 if(provider
!= NULL
) {
649 provider
= DSAKeyInfoProvider::provider(key
, *this);
650 if(provider
!= NULL
) {
654 provider
= DHKeyInfoProvider::provider(key
, *this);
655 if(provider
!= NULL
) {
659 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);