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 CRYPTKIT_CSP_ENABLE
30 #include "cryptkitcsp.h"
33 #include <miscAlgFactory.h>
35 #include "ascFactory.h"
37 #include <RSA_DSA_csp.h>
38 #include <RSA_DSA_keys.h>
42 #include "YarrowConnection.h"
45 // Make and break the plugin object
47 AppleCSPPlugin::AppleCSPPlugin() :
48 normAllocator(Allocator::standard(Allocator::normal
)),
49 privAllocator(Allocator::standard(Allocator::sensitive
)),
50 #ifdef CRYPTKIT_CSP_ENABLE
51 cryptKitFactory(new CryptKitFactory(&normAllocator
, &privAllocator
)),
53 miscAlgFactory(new MiscAlgFactory(&normAllocator
, &privAllocator
)),
55 ascAlgFactory(new AscAlgFactory(&normAllocator
, &privAllocator
)),
57 rsaDsaAlgFactory(new RSA_DSA_Factory(&normAllocator
, &privAllocator
)),
58 dhAlgFactory(new DH_Factory(&normAllocator
, &privAllocator
))
60 // misc. once-per-address-space cruft...
63 AppleCSPPlugin::~AppleCSPPlugin()
65 #ifdef CRYPTKIT_CSP_ENABLE
66 delete cryptKitFactory
;
68 delete miscAlgFactory
;
72 delete rsaDsaAlgFactory
;
78 // Create a new plugin session, our way
80 PluginSession
*AppleCSPPlugin::makeSession(
81 CSSM_MODULE_HANDLE handle
,
82 const CSSM_VERSION
&version
,
84 CSSM_SERVICE_TYPE subserviceType
,
85 CSSM_ATTACH_FLAGS attachFlags
,
86 const CSSM_UPCALLS
&upcalls
)
88 switch (subserviceType
) {
89 case CSSM_SERVICE_CSP
:
90 return new AppleCSPSession(handle
,
98 CssmError::throwMe(CSSMERR_CSSM_INVALID_SERVICE_MASK
);
104 // Session constructor
106 AppleCSPSession::AppleCSPSession(
107 CSSM_MODULE_HANDLE handle
,
108 AppleCSPPlugin
&plug
,
109 const CSSM_VERSION
&version
,
111 CSSM_SERVICE_TYPE subserviceType
,
112 CSSM_ATTACH_FLAGS attachFlags
,
113 const CSSM_UPCALLS
&upcalls
)
114 : CSPFullPluginSession(handle
,
121 #ifdef CRYPTKIT_CSP_ENABLE
122 cryptKitFactory(*(dynamic_cast<CryptKitFactory
*>(plug
.cryptKitFactory
))),
124 miscAlgFactory(*(dynamic_cast<MiscAlgFactory
*>(plug
.miscAlgFactory
))),
125 #ifdef ASC_CSP_ENABLE
126 ascAlgFactory(*(dynamic_cast<AscAlgFactory
*>(plug
.ascAlgFactory
))),
128 rsaDsaAlgFactory(*(dynamic_cast<RSA_DSA_Factory
*>(plug
.rsaDsaAlgFactory
))),
129 dhAlgFactory(*(dynamic_cast<DH_Factory
*>(plug
.dhAlgFactory
))),
130 normAllocator(*this),
131 privAllocator(plug
.privAlloc())
136 AppleCSPSession::~AppleCSPSession()
142 // Called at (CSSM) context create time. This is ignored; we do a full
143 // context setup later, at setupContext time.
145 CSPFullPluginSession::CSPContext
*
146 AppleCSPSession::contextCreate(
147 CSSM_CC_HANDLE handle
,
148 const Context
&context
)
154 // Called by CSPFullPluginSession when an op is actually commencing.
155 // Context can safely assumed to be fully formed and stable for the
156 // duration of the op; thus we wait until now to set up our
157 // CSPContext as appropriate to the op.
159 void AppleCSPSession::setupContext(
160 CSPContext
* &cspCtx
,
161 const Context
&context
,
165 * Note we leave the decision as to whether it's OK to
166 * reuse a context to the individual factories.
168 if (rsaDsaAlgFactory
.setup(*this, cspCtx
, context
)) {
169 CASSERT(cspCtx
!= NULL
);
172 if (miscAlgFactory
.setup(*this, cspCtx
, context
)) {
173 CASSERT(cspCtx
!= NULL
);
176 if (dhAlgFactory
.setup(*this, cspCtx
, context
)) {
177 CASSERT(cspCtx
!= NULL
);
180 #ifdef CRYPTKIT_CSP_ENABLE
181 if (cryptKitFactory
.setup(*this, cspCtx
, context
)) {
182 CASSERT(cspCtx
!= NULL
);
186 #ifdef ASC_CSP_ENABLE
187 if (ascAlgFactory
.setup(*this, cspCtx
, context
)) {
188 CASSERT(cspCtx
!= NULL
);
192 if(setup(cspCtx
, context
)) {
193 CASSERT(cspCtx
!= NULL
);
196 dprintf0("AppleCSPSession::setupContext: invalid algorithm\n");
197 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
201 * Used for generating crypto contexts at this level.
202 * Analogous to AlgorithmFactory.setup().
204 bool AppleCSPSession::setup(
205 CSPFullPluginSession::CSPContext
* &cspCtx
,
206 const Context
&context
)
209 return false; // not ours or already set
212 switch(context
.type()) {
213 case CSSM_ALGCLASS_RANDOMGEN
:
214 switch (context
.algorithm()) {
215 case CSSM_ALGID_APPLE_YARROW
:
216 cspCtx
= new YarrowContext(*this);
218 /* other random algs here */
222 /* other contexts here */
229 // Context for CSSM_ALGID_APPLE_YARROW.
231 YarrowContext::YarrowContext(AppleCSPSession
&session
)
232 : AppleCSPContext(session
)
237 YarrowContext::~YarrowContext()
243 // Only job here is to snag the length and process the optional seed argument
245 void YarrowContext::init(
246 const Context
&context
,
249 /* stash requested length for use later in outputSize() */
250 outSize
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
,
251 CSSMERR_CSP_INVALID_ATTR_OUTPUT_SIZE
);
254 CssmCryptoData
*cseed
= context
.get
<CssmCryptoData
>(CSSM_ATTRIBUTE_SEED
);
259 CssmData seed
= (*cseed
)();
260 if((seed
.Length
== 0) ||
261 (seed
.Data
== NULL
)) {
262 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED
);
264 session().addEntropy((size_t)seed
.Length
, seed
.Data
);
267 void YarrowContext::final(
270 session().getRandomBytes((size_t)out
.Length
, out
.Data
);
274 *** Binary Key support.
277 // Given a CSSM_DATA, extract its KeyRef.
278 static KeyRef
CssmDataToKeyRef(
279 const CSSM_DATA
&data
)
281 if(data
.Length
!= sizeof(KeyRef
)) {
282 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
285 uint8
*cp
= data
.Data
+ sizeof(KeyRef
) - 1;
287 for(unsigned dex
=0; dex
<sizeof(KeyRef
); dex
++) {
294 // Place a KeyRef into a CSSM_DATA, mallocing if necessary.
295 static void keyRefToCssmData(
298 Allocator
&allocator
)
300 if(data
.Length
> sizeof(keyRef
)) {
301 /* don't leave old raw key material lying around */
302 memset(data
.Data
+ sizeof(keyRef
), 0, data
.Length
- sizeof(keyRef
));
304 else if(data
.Length
< sizeof(keyRef
)) {
305 /* not enough space for even a keyRef, force realloc */
306 allocator
.free(data
.Data
);
310 setUpData(data
, sizeof(keyRef
), allocator
);
312 uint8
*cp
= data
.Data
;
313 for(unsigned i
=0; i
<sizeof(keyRef
); i
++) {
314 *cp
++ = keyRef
& 0xff;
319 // Look up a BinaryKey by its KeyRef. Returns NULL if not
320 // found. refKeyMapLock held on entry and exit.
321 BinaryKey
*AppleCSPSession::lookupKeyRef(
324 const BinaryKey
*binKey
;
326 // use safe version, don't create new entry if this key
328 keyMap::iterator it
= refKeyMap
.find(keyRef
);
329 if(it
== refKeyMap
.end()) {
333 assert(binKey
== reinterpret_cast<const BinaryKey
*>(keyRef
));
334 assert(binKey
->mKeyRef
== keyRef
);
335 return const_cast<BinaryKey
*>(binKey
);
338 // add a BinaryKey to our refKeyMap. Sets up cssmKey
340 void AppleCSPSession::addRefKey(
344 // for now, KeyRef is just the address of the BinaryKey
345 KeyRef keyRef
= reinterpret_cast<KeyRef
>(&binKey
);
347 binKey
.mKeyRef
= keyRef
;
348 binKey
.mKeyHeader
= CssmKey::Header::overlay(cssmKey
.KeyHeader
);
350 StLock
<Mutex
> _(refKeyMapLock
);
351 assert(lookupKeyRef(keyRef
) == NULL
);
352 refKeyMap
[keyRef
] = &binKey
;
354 cssmKey
.KeyHeader
.BlobType
= CSSM_KEYBLOB_REFERENCE
;
355 cssmKey
.KeyHeader
.Format
= CSSM_KEYBLOB_REF_FORMAT_INTEGER
;
356 keyRefToCssmData(keyRef
, cssmKey
.KeyData
, normAllocator
);
357 secinfo("freeKey", "CSP addRefKey key %p keyData %p keyRef %p",
358 &cssmKey
, cssmKey
.KeyData
.Data
, &binKey
);
361 // Given a CssmKey in reference form, obtain the associated
362 // BinaryKey. Throws CSSMERR_CSP_INVALID_KEY_REFERENCE if
363 // key not found in session key map.
364 BinaryKey
& AppleCSPSession::lookupRefKey(
365 const CssmKey
&cssmKey
)
370 keyRef
= CssmDataToKeyRef(cssmKey
.KeyData
);
372 StLock
<Mutex
> _(refKeyMapLock
);
373 binKey
= lookupKeyRef(keyRef
);
376 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
378 assert(Guid::overlay(binKey
->mKeyHeader
.CspId
) == plugin
.myGuid());
381 * Verify sensitive fields have not changed between when the BinaryKey was
382 * created/stored and when the caller passed in the ref key.
383 * Some fields were changed by addRefKey, so make a local copy....
385 CSSM_KEYHEADER localHdr
= cssmKey
.KeyHeader
;
386 localHdr
.BlobType
= binKey
->mKeyHeader
.BlobType
;
387 localHdr
.Format
= binKey
->mKeyHeader
.Format
;
388 if(memcmp(&localHdr
, &binKey
->mKeyHeader
, sizeof(CSSM_KEYHEADER
))) {
389 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
394 // CSPFullPluginSession declares & implements this.
395 // Note that we ignore the delete argument; since we don't
396 // store anything, freeing is the same as deleting.
397 void AppleCSPSession::FreeKey(
398 const AccessCredentials
*AccessCred
,
403 if((KeyPtr
.blobType() == CSSM_KEYBLOB_REFERENCE
) &&
404 (KeyPtr
.cspGuid() == plugin
.myGuid())) {
405 // it's a ref key we generated - delete associated BinaryKey
406 KeyRef keyRef
= CssmDataToKeyRef(KeyPtr
.KeyData
);
408 StLock
<Mutex
> _(refKeyMapLock
);
409 BinaryKey
*binKey
= lookupKeyRef(keyRef
);
411 secinfo("freeKey", "CSP FreeKey key %p keyData %p binKey %p",
412 &KeyPtr
, KeyPtr
.KeyData
.Data
, binKey
);
414 refKeyMap
.erase(keyRef
);
418 errorLog0("Error deleting/erasing known "
423 secinfo("freeKey", "CSP freeKey unknown key");
427 CSPFullPluginSession::FreeKey(AccessCred
, KeyPtr
, Delete
);
430 /* Passthrough, used for key digest */
431 void AppleCSPSession::PassThrough(
432 CSSM_CC_HANDLE CCHandle
,
433 const Context
&Context
,
434 uint32 PassThroughId
,
440 /* validate context */
441 if(Context
.type() != CSSM_ALGCLASS_NONE
) {
442 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT
);
445 switch(PassThroughId
) {
446 case CSSM_APPLECSP_KEYDIGEST
:
448 CssmKey
&key
= Context
.get
<CssmKey
>(
450 CSSMERR_CSP_MISSING_ATTR_KEY
);
452 /* validate key as best we can */
453 switch(key
.keyClass()) {
454 case CSSM_KEYCLASS_PUBLIC_KEY
:
455 case CSSM_KEYCLASS_PRIVATE_KEY
:
456 case CSSM_KEYCLASS_SESSION_KEY
:
459 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
463 * Ref key: obtain binary, ask it for blob
464 * Raw key: get info provider, ask it for the blob. This
465 * allows for an optimized path which avoids
466 * converting to a BinaryKey.
469 switch(key
.blobType()) {
470 case CSSM_KEYBLOB_RAW
:
472 CSPKeyInfoProvider
*provider
= infoProvider(key
);
474 provider
->getHashableBlob(privAllocator
, blobToHash
);
476 /* took optimized case; proceed */
481 /* convert to BinaryKey and ask it to do the work */
483 CSSM_KEYATTR_FLAGS flags
= 0; // not used
484 provider
->CssmKeyToBinary(NULL
, // no paramKey
488 CssmKey::Header::overlay(key
.KeyHeader
);
489 CSSM_KEYBLOB_FORMAT rawFormat
;
490 rawFormat
= CSSM_KEYBLOB_RAW_FORMAT_DIGEST
;
491 CSSM_KEYATTR_FLAGS attrFlags
= 0;
492 binKey
->generateKeyBlob(privAllocator
,
502 case CSSM_KEYBLOB_REFERENCE
:
504 BinaryKey
&binKey
= lookupRefKey(key
);
505 CSSM_KEYBLOB_FORMAT rawFormat
;
506 rawFormat
= CSSM_KEYBLOB_RAW_FORMAT_DIGEST
;
507 CSSM_KEYATTR_FLAGS attrFlags
= 0;
508 binKey
.generateKeyBlob(privAllocator
,
517 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
520 /* obtain sha1 hash of blobToHash */
522 CSSM_DATA_PTR outHash
= NULL
;
525 (CSSM_DATA_PTR
)normAllocator
.malloc(sizeof(CSSM_DATA
));
527 (uint8
*)normAllocator
.malloc(SHA1_DIGEST_SIZE
);
528 outHash
->Length
= SHA1_DIGEST_SIZE
;
531 freeCssmData(blobToHash
, privAllocator
);
534 cspGenSha1Hash(blobToHash
.data(), blobToHash
.length(),
536 freeCssmData(blobToHash
, privAllocator
);
541 CssmError::throwMe(CSSMERR_CSP_INVALID_PASSTHROUGH_ID
);
547 * CSPSession version of QueryKeySizeInBits.
549 void AppleCSPSession::getKeySize(const CssmKey
&key
,
552 CSPKeyInfoProvider
*provider
= infoProvider(key
);
554 provider
->QueryKeySizeInBits(size
);
557 /* don't leak this on error */
564 void AppleCSPSession::getRandomBytes(size_t length
, uint8
*cp
)
567 cspGetRandomBytes(cp
, (unsigned)length
);
570 errorLog0("CSP: YarrowClient failure\n");
574 void AppleCSPSession::addEntropy(size_t length
, const uint8
*cp
)
577 cspAddEntropy(cp
, (unsigned)length
);
580 #if CSP_ALLOW_FEE_RNG
589 *** CSPKeyInfoProvider support.
593 * Find a CSPKeyInfoProvider subclass for the specified key.
595 CSPKeyInfoProvider
*AppleCSPSession::infoProvider(
598 CSPKeyInfoProvider
*provider
= NULL
;
600 provider
= RSAKeyInfoProvider::provider(key
, *this);
601 if(provider
!= NULL
) {
605 provider
= SymmetricKeyInfoProvider::provider(key
, *this);
606 if(provider
!= NULL
) {
610 #ifdef CRYPTKIT_CSP_ENABLE
611 provider
= CryptKit::FEEKeyInfoProvider::provider(key
, *this);
612 if(provider
!= NULL
) {
617 provider
= DSAKeyInfoProvider::provider(key
, *this);
618 if(provider
!= NULL
) {
622 provider
= DHKeyInfoProvider::provider(key
, *this);
623 if(provider
!= NULL
) {
627 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);