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
);
114 // Session constructor
116 AppleCSPSession::AppleCSPSession(
117 CSSM_MODULE_HANDLE handle
,
118 AppleCSPPlugin
&plug
,
119 const CSSM_VERSION
&version
,
121 CSSM_SERVICE_TYPE subserviceType
,
122 CSSM_ATTACH_FLAGS attachFlags
,
123 const CSSM_UPCALLS
&upcalls
)
124 : CSPFullPluginSession(handle
,
131 #ifdef BSAFE_CSP_ENABLE
132 bSafe4Factory(*(dynamic_cast<BSafeFactory
*>(plug
.bSafe4Factory
))),
134 #ifdef CRYPTKIT_CSP_ENABLE
135 cryptKitFactory(*(dynamic_cast<CryptKitFactory
*>(plug
.cryptKitFactory
))),
137 miscAlgFactory(*(dynamic_cast<MiscAlgFactory
*>(plug
.miscAlgFactory
))),
138 #ifdef ASC_CSP_ENABLE
139 ascAlgFactory(*(dynamic_cast<AscAlgFactory
*>(plug
.ascAlgFactory
))),
141 rsaDsaAlgFactory(*(dynamic_cast<RSA_DSA_Factory
*>(plug
.rsaDsaAlgFactory
))),
142 dhAlgFactory(*(dynamic_cast<DH_Factory
*>(plug
.dhAlgFactory
))),
143 normAllocator(*this),
144 privAllocator(plug
.privAlloc())
149 AppleCSPSession::~AppleCSPSession()
155 // Called at (CSSM) context create time. This is ignored; we do a full
156 // context setup later, at setupContext time.
158 CSPFullPluginSession::CSPContext
*
159 AppleCSPSession::contextCreate(
160 CSSM_CC_HANDLE handle
,
161 const Context
&context
)
167 // Called by CSPFullPluginSession when an op is actually commencing.
168 // Context can safely assumed to be fully formed and stable for the
169 // duration of the op; thus we wait until now to set up our
170 // CSPContext as appropriate to the op.
172 void AppleCSPSession::setupContext(
173 CSPContext
* &cspCtx
,
174 const Context
&context
,
178 * Note we leave the decision as to whether it's OK to
179 * reuse a context to the individual factories.
181 #ifdef BSAFE_CSP_ENABLE
182 /* Give BSAFE the firsrt shot if it's present */
183 if (bSafe4Factory
.setup(*this, cspCtx
, context
)) {
184 CASSERT(cspCtx
!= NULL
);
188 if (rsaDsaAlgFactory
.setup(*this, cspCtx
, context
)) {
189 CASSERT(cspCtx
!= NULL
);
192 if (miscAlgFactory
.setup(*this, cspCtx
, context
)) {
193 CASSERT(cspCtx
!= NULL
);
196 if (dhAlgFactory
.setup(*this, cspCtx
, context
)) {
197 CASSERT(cspCtx
!= NULL
);
200 #ifdef CRYPTKIT_CSP_ENABLE
201 if (cryptKitFactory
.setup(*this, cspCtx
, context
)) {
202 CASSERT(cspCtx
!= NULL
);
206 #ifdef ASC_CSP_ENABLE
207 if (ascAlgFactory
.setup(*this, cspCtx
, context
)) {
208 CASSERT(cspCtx
!= NULL
);
212 if(setup(cspCtx
, context
)) {
213 CASSERT(cspCtx
!= NULL
);
216 dprintf0("AppleCSPSession::setupContext: invalid algorithm\n");
217 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
221 * Used for generating crypto contexts at this level.
222 * Analogous to AlgorithmFactory.setup().
224 bool AppleCSPSession::setup(
225 CSPFullPluginSession::CSPContext
* &cspCtx
,
226 const Context
&context
)
229 return false; // not ours or already set
232 switch(context
.type()) {
233 case CSSM_ALGCLASS_RANDOMGEN
:
234 switch (context
.algorithm()) {
235 case CSSM_ALGID_APPLE_YARROW
:
236 cspCtx
= new YarrowContext(*this);
238 /* other random algs here */
242 /* other contexts here */
249 // Context for CSSM_ALGID_APPLE_YARROW.
251 YarrowContext::YarrowContext(AppleCSPSession
&session
)
252 : AppleCSPContext(session
)
257 YarrowContext::~YarrowContext()
263 // Only job here is to snag the length and process the optional seed argument
265 void YarrowContext::init(
266 const Context
&context
,
269 /* stash requested length for use later in outputSize() */
270 outSize
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
,
271 CSSMERR_CSP_INVALID_ATTR_OUTPUT_SIZE
);
274 CssmCryptoData
*cseed
= context
.get
<CssmCryptoData
>(CSSM_ATTRIBUTE_SEED
);
279 CssmData seed
= (*cseed
)();
280 if((seed
.Length
== 0) ||
281 (seed
.Data
== NULL
)) {
282 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED
);
284 session().addEntropy((size_t)seed
.Length
, seed
.Data
);
287 void YarrowContext::final(
290 session().getRandomBytes((size_t)out
.Length
, out
.Data
);
294 *** Binary Key support.
297 // Given a CSSM_DATA, extract its KeyRef.
298 static KeyRef
CssmDataToKeyRef(
299 const CSSM_DATA
&data
)
301 if(data
.Length
!= sizeof(KeyRef
)) {
302 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
305 uint8
*cp
= data
.Data
+ sizeof(KeyRef
) - 1;
307 for(unsigned dex
=0; dex
<sizeof(KeyRef
); dex
++) {
314 // Place a KeyRef into a CSSM_DATA, mallocing if necessary.
315 static void keyRefToCssmData(
318 Allocator
&allocator
)
320 if(data
.Length
> sizeof(keyRef
)) {
321 /* don't leave old raw key material lying around */
322 memset(data
.Data
+ sizeof(keyRef
), 0, data
.Length
- sizeof(keyRef
));
324 else if(data
.Length
< sizeof(keyRef
)) {
325 /* not enough space for even a keyRef, force realloc */
326 allocator
.free(data
.Data
);
330 setUpData(data
, sizeof(keyRef
), allocator
);
332 uint8
*cp
= data
.Data
;
333 for(unsigned i
=0; i
<sizeof(keyRef
); i
++) {
334 *cp
++ = keyRef
& 0xff;
339 // Look up a BinaryKey by its KeyRef. Returns NULL if not
340 // found. refKeyMapLock held on entry and exit.
341 BinaryKey
*AppleCSPSession::lookupKeyRef(
344 const BinaryKey
*binKey
;
346 // use safe version, don't create new entry if this key
348 keyMap::iterator it
= refKeyMap
.find(keyRef
);
349 if(it
== refKeyMap
.end()) {
353 assert(binKey
== reinterpret_cast<const BinaryKey
*>(keyRef
));
354 assert(binKey
->mKeyRef
== keyRef
);
355 return const_cast<BinaryKey
*>(binKey
);
358 // add a BinaryKey to our refKeyMap. Sets up cssmKey
360 void AppleCSPSession::addRefKey(
364 // for now, KeyRef is just the address of the BinaryKey
365 KeyRef keyRef
= reinterpret_cast<KeyRef
>(&binKey
);
367 binKey
.mKeyRef
= keyRef
;
368 binKey
.mKeyHeader
= CssmKey::Header::overlay(cssmKey
.KeyHeader
);
370 StLock
<Mutex
> _(refKeyMapLock
);
371 assert(lookupKeyRef(keyRef
) == NULL
);
372 refKeyMap
[keyRef
] = &binKey
;
374 cssmKey
.KeyHeader
.BlobType
= CSSM_KEYBLOB_REFERENCE
;
375 cssmKey
.KeyHeader
.Format
= CSSM_KEYBLOB_REF_FORMAT_INTEGER
;
376 keyRefToCssmData(keyRef
, cssmKey
.KeyData
, normAllocator
);
377 secinfo("freeKey", "CSP addRefKey key %p keyData %p keyRef %p",
378 &cssmKey
, cssmKey
.KeyData
.Data
, &binKey
);
381 // Given a CssmKey in reference form, obtain the associated
382 // BinaryKey. Throws CSSMERR_CSP_INVALID_KEY_REFERENCE if
383 // key not found in session key map.
384 BinaryKey
& AppleCSPSession::lookupRefKey(
385 const CssmKey
&cssmKey
)
390 keyRef
= CssmDataToKeyRef(cssmKey
.KeyData
);
392 StLock
<Mutex
> _(refKeyMapLock
);
393 binKey
= lookupKeyRef(keyRef
);
396 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
398 assert(Guid::overlay(binKey
->mKeyHeader
.CspId
) == plugin
.myGuid());
401 * Verify sensitive fields have not changed between when the BinaryKey was
402 * created/stored and when the caller passed in the ref key.
403 * Some fields were changed by addRefKey, so make a local copy....
405 CSSM_KEYHEADER localHdr
= cssmKey
.KeyHeader
;
406 localHdr
.BlobType
= binKey
->mKeyHeader
.BlobType
;
407 localHdr
.Format
= binKey
->mKeyHeader
.Format
;
408 if(memcmp(&localHdr
, &binKey
->mKeyHeader
, sizeof(CSSM_KEYHEADER
))) {
409 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
414 // CSPFullPluginSession declares & implements this.
415 // Note that we ignore the delete argument; since we don't
416 // store anything, freeing is the same as deleting.
417 void AppleCSPSession::FreeKey(
418 const AccessCredentials
*AccessCred
,
423 if((KeyPtr
.blobType() == CSSM_KEYBLOB_REFERENCE
) &&
424 (KeyPtr
.cspGuid() == plugin
.myGuid())) {
425 // it's a ref key we generated - delete associated BinaryKey
426 KeyRef keyRef
= CssmDataToKeyRef(KeyPtr
.KeyData
);
428 StLock
<Mutex
> _(refKeyMapLock
);
429 BinaryKey
*binKey
= lookupKeyRef(keyRef
);
431 secinfo("freeKey", "CSP FreeKey key %p keyData %p binKey %p",
432 &KeyPtr
, KeyPtr
.KeyData
.Data
, binKey
);
434 refKeyMap
.erase(keyRef
);
438 errorLog0("Error deleting/erasing known "
443 secinfo("freeKey", "CSP freeKey unknown key");
447 CSPFullPluginSession::FreeKey(AccessCred
, KeyPtr
, Delete
);
450 /* Passthrough, used for key digest */
451 void AppleCSPSession::PassThrough(
452 CSSM_CC_HANDLE CCHandle
,
453 const Context
&Context
,
454 uint32 PassThroughId
,
460 /* validate context */
461 if(Context
.type() != CSSM_ALGCLASS_NONE
) {
462 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT
);
465 switch(PassThroughId
) {
466 case CSSM_APPLECSP_KEYDIGEST
:
468 CssmKey
&key
= Context
.get
<CssmKey
>(
470 CSSMERR_CSP_MISSING_ATTR_KEY
);
472 /* validate key as best we can */
473 switch(key
.keyClass()) {
474 case CSSM_KEYCLASS_PUBLIC_KEY
:
475 case CSSM_KEYCLASS_PRIVATE_KEY
:
476 case CSSM_KEYCLASS_SESSION_KEY
:
479 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
483 * Ref key: obtain binary, ask it for blob
484 * Raw key: get info provider, ask it for the blob. This
485 * allows for an optimized path which avoids
486 * converting to a BinaryKey.
489 switch(key
.blobType()) {
490 case CSSM_KEYBLOB_RAW
:
492 CSPKeyInfoProvider
*provider
= infoProvider(key
);
494 provider
->getHashableBlob(privAllocator
, blobToHash
);
496 /* took optimized case; proceed */
501 /* convert to BinaryKey and ask it to do the work */
503 CSSM_KEYATTR_FLAGS flags
= 0; // not used
504 provider
->CssmKeyToBinary(NULL
, // no paramKey
508 CssmKey::Header::overlay(key
.KeyHeader
);
509 CSSM_KEYBLOB_FORMAT rawFormat
;
510 rawFormat
= CSSM_KEYBLOB_RAW_FORMAT_DIGEST
;
511 CSSM_KEYATTR_FLAGS attrFlags
= 0;
512 binKey
->generateKeyBlob(privAllocator
,
522 case CSSM_KEYBLOB_REFERENCE
:
524 BinaryKey
&binKey
= lookupRefKey(key
);
525 CSSM_KEYBLOB_FORMAT rawFormat
;
526 rawFormat
= CSSM_KEYBLOB_RAW_FORMAT_DIGEST
;
527 CSSM_KEYATTR_FLAGS attrFlags
= 0;
528 binKey
.generateKeyBlob(privAllocator
,
537 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
540 /* obtain sha1 hash of blobToHash */
542 CSSM_DATA_PTR outHash
= NULL
;
545 (CSSM_DATA_PTR
)normAllocator
.malloc(sizeof(CSSM_DATA
));
547 (uint8
*)normAllocator
.malloc(SHA1_DIGEST_SIZE
);
548 outHash
->Length
= SHA1_DIGEST_SIZE
;
551 freeCssmData(blobToHash
, privAllocator
);
554 cspGenSha1Hash(blobToHash
.data(), blobToHash
.length(),
556 freeCssmData(blobToHash
, privAllocator
);
561 CssmError::throwMe(CSSMERR_CSP_INVALID_PASSTHROUGH_ID
);
567 * CSPSession version of QueryKeySizeInBits.
569 void AppleCSPSession::getKeySize(const CssmKey
&key
,
572 CSPKeyInfoProvider
*provider
= infoProvider(key
);
574 provider
->QueryKeySizeInBits(size
);
577 /* don't leak this on error */
584 void AppleCSPSession::getRandomBytes(size_t length
, uint8
*cp
)
587 cspGetRandomBytes(cp
, (unsigned)length
);
590 errorLog0("CSP: YarrowClient failure\n");
594 void AppleCSPSession::addEntropy(size_t length
, const uint8
*cp
)
597 cspAddEntropy(cp
, (unsigned)length
);
600 #if CSP_ALLOW_FEE_RNG
609 *** CSPKeyInfoProvider support.
613 * Find a CSPKeyInfoProvider subclass for the specified key.
615 CSPKeyInfoProvider
*AppleCSPSession::infoProvider(
618 CSPKeyInfoProvider
*provider
= NULL
;
620 #ifdef BSAFE_CSP_ENABLE
621 /* Give BSAFE first shot, if it's here */
622 provider
= BSafe::BSafeKeyInfoProvider::provider(key
, *this);
623 if(provider
!= NULL
) {
628 provider
= RSAKeyInfoProvider::provider(key
, *this);
629 if(provider
!= NULL
) {
633 provider
= SymmetricKeyInfoProvider::provider(key
, *this);
634 if(provider
!= NULL
) {
638 #ifdef CRYPTKIT_CSP_ENABLE
639 provider
= CryptKit::FEEKeyInfoProvider::provider(key
, *this);
640 if(provider
!= NULL
) {
645 provider
= DSAKeyInfoProvider::provider(key
, *this);
646 if(provider
!= NULL
) {
650 provider
= DHKeyInfoProvider::provider(key
, *this);
651 if(provider
!= NULL
) {
655 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);