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 // SSCSPSession.cpp - Security Server CSP session.
22 #include "SSCSPSession.h"
24 #include "CSPDLPlugin.h"
25 #include "SSDatabase.h"
26 #include "SSDLSession.h"
28 #include <security_cdsa_utilities/cssmbridge.h>
32 using namespace SecurityServer
;
35 // SSCSPSession -- Security Server CSP session
37 SSCSPSession::SSCSPSession(CSSM_MODULE_HANDLE handle
,
39 const CSSM_VERSION
&version
,
41 CSSM_SERVICE_TYPE subserviceType
,
42 CSSM_ATTACH_FLAGS attachFlags
,
43 const CSSM_UPCALLS
&upcalls
,
44 SSCSPDLSession
&ssCSPDLSession
,
45 CssmClient::CSP
&rawCsp
)
46 : CSPFullPluginSession(handle
, plug
, version
, subserviceId
, subserviceType
,
47 attachFlags
, upcalls
),
48 mSSCSPDLSession(ssCSPDLSession
),
49 mSSFactory(plug
.mSSFactory
),
51 mClientSession(Allocator::standard(), *this)
53 mClientSession
.registerForAclEdits(SSCSPDLSession::didChangeKeyAclCallback
, &mSSCSPDLSession
);
57 // Called at (CSSM) context create time. This is ignored; we do a full
58 // context setup later, at setupContext time.
60 CSPFullPluginSession::CSPContext
*
61 SSCSPSession::contextCreate(CSSM_CC_HANDLE handle
, const Context
&context
)
68 // Called by CSPFullPluginSession when an op is actually commencing.
69 // Context can safely assumed to be fully formed and stable for the
70 // duration of the op; thus we wait until now to set up our
71 // CSPContext as appropriate to the op.
74 SSCSPSession::setupContext(CSPContext
* &cspCtx
,
75 const Context
&context
,
78 // note we skip this if this CSPContext is being reused
82 if (mSSFactory
.setup(*this, cspCtx
, context
, encoding
))
86 if (mBSafe4Factory
.setup(*this, cspCtx
, context
))
89 if (mCryptKitFactory
.setup(*this, cspCtx
, context
))
93 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
102 SSCSPSession::getDatabase(const Context
&context
)
104 return getDatabase(context
.get
<CSSM_DL_DB_HANDLE
>(CSSM_ATTRIBUTE_DL_DB_HANDLE
));
108 SSCSPSession::getDatabase(CSSM_DL_DB_HANDLE
*aDLDbHandle
)
111 return findSession
<SSDLSession
>(aDLDbHandle
->DLHandle
).findDbHandle(aDLDbHandle
->DBHandle
);
118 // Reference Key management
121 SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle
, CssmKey
&ioKey
, SSDatabase
&inSSDatabase
,
122 uint32 inKeyAttr
, const CssmData
*inKeyLabel
)
124 return mSSCSPDLSession
.makeReferenceKey(*this, inKeyHandle
, ioKey
, inSSDatabase
, inKeyAttr
, inKeyLabel
);
128 SSCSPSession::lookupKey(const CssmKey
&inKey
)
130 return mSSCSPDLSession
.lookupKey(inKey
);
135 // Key creating and handeling members
138 SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle
,
139 const Context
&context
,
140 const AccessCredentials
&AccessCred
,
142 const CssmData
*DescriptiveData
,
144 CSSM_PRIVILEGE Privilege
)
146 // @@@ Deal with permanent keys
147 const CssmKey
*keyInContext
=
148 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
150 KeyHandle contextKeyHandle
= (keyInContext
151 ? lookupKey(*keyInContext
).keyHandle()
153 clientSession().wrapKey(context
, contextKeyHandle
,
154 lookupKey(Key
).keyHandle(), &AccessCred
,
155 DescriptiveData
, WrappedKey
, *this);
159 SSCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle
,
160 const Context
&context
,
161 const CssmKey
*PublicKey
,
162 const CssmWrappedKey
&WrappedKey
,
165 const CssmData
*KeyLabel
,
166 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
167 CssmKey
&UnwrappedKey
,
168 CssmData
&DescriptiveData
,
169 CSSM_PRIVILEGE Privilege
)
171 SSDatabase database
= getDatabase(context
);
172 validateKeyAttr(KeyAttr
);
173 const AccessCredentials
*cred
= NULL
;
174 const AclEntryInput
*owner
= NULL
;
177 cred
= AccessCredentials::overlay(CredAndAclEntry
->AccessCred
);
178 owner
= &AclEntryInput::overlay(CredAndAclEntry
->InitialAclEntry
);
181 KeyHandle publicKey
= noKey
;
184 if (PublicKey
->blobType() == CSSM_KEYBLOB_RAW
)
186 // @@@ We need to unwrap the publicKey into the SecurityServer
188 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
191 publicKey
= lookupKey(*PublicKey
).keyHandle();
194 // @@@ Deal with permanent keys
195 const CssmKey
*keyInContext
=
196 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
198 KeyHandle contextKeyHandle
=
199 keyInContext
? lookupKey(*keyInContext
).keyHandle() : noKey
;
201 KeyHandle unwrappedKeyHandle
;
202 clientSession().unwrapKey(database
.dbHandle(), context
, contextKeyHandle
,
203 publicKey
, WrappedKey
, KeyUsage
, KeyAttr
,
204 cred
, owner
, DescriptiveData
, unwrappedKeyHandle
,
205 UnwrappedKey
.header(), *this);
206 makeReferenceKey(unwrappedKeyHandle
, UnwrappedKey
, database
, KeyAttr
,
211 SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle
,
212 const Context
&context
,
216 const CssmData
*keyLabel
,
217 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
220 SSDatabase database
= getDatabase(context
);
221 validateKeyAttr(keyAttr
);
222 const AccessCredentials
*cred
= NULL
;
223 const AclEntryInput
*owner
= NULL
;
226 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
227 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
230 /* optional BaseKey */
231 const CssmKey
*keyInContext
=
232 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
233 KeyHandle contextKeyHandle
=
234 keyInContext
? lookupKey(*keyInContext
).keyHandle() : noKey
;
236 switch(context
.algorithm()) {
237 case CSSM_ALGID_KEYCHAIN_KEY
:
239 // special interpretation: take DLDBHandle -> DbHandle from params
240 clientSession().extractMasterKey(database
.dbHandle(), context
,
241 getDatabase(param
.interpretedAs
<CSSM_DL_DB_HANDLE
>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE
)).dbHandle(),
242 keyUsage
, keyAttr
, cred
, owner
, keyHandle
, derivedKey
.header());
246 clientSession().deriveKey(database
.dbHandle(), context
, contextKeyHandle
, keyUsage
,
247 keyAttr
, param
, cred
, owner
, keyHandle
, derivedKey
.header());
250 makeReferenceKey(keyHandle
, derivedKey
, database
, keyAttr
, keyLabel
);
254 SSCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle
,
255 const Context
&context
,
258 const CssmData
*keyLabel
,
259 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
261 CSSM_PRIVILEGE privilege
)
263 SSDatabase database
= getDatabase(context
);
264 validateKeyAttr(keyAttr
);
265 const AccessCredentials
*cred
= NULL
;
266 const AclEntryInput
*owner
= NULL
;
269 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
270 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
274 clientSession().generateKey(database
.dbHandle(), context
, keyUsage
,
275 keyAttr
, cred
, owner
, keyHandle
, key
.header());
276 makeReferenceKey(keyHandle
, key
, database
, keyAttr
, keyLabel
);
280 SSCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
,
281 const Context
&context
,
282 uint32 publicKeyUsage
,
283 uint32 publicKeyAttr
,
284 const CssmData
*publicKeyLabel
,
286 uint32 privateKeyUsage
,
287 uint32 privateKeyAttr
,
288 const CssmData
*privateKeyLabel
,
289 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
291 CSSM_PRIVILEGE privilege
)
293 SSDatabase database
= getDatabase(context
);
294 validateKeyAttr(publicKeyAttr
);
295 validateKeyAttr(privateKeyAttr
);
296 const AccessCredentials
*cred
= NULL
;
297 const AclEntryInput
*owner
= NULL
;
300 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
301 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
305 * Public keys must be extractable in the clear - that's the Apple
306 * policy. The raw CSP is unable to enforce the extractable
307 * bit since it always sees that as true (it's managed and forced
308 * true by the SecurityServer). So...
310 if(!(publicKeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
311 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
313 KeyHandle pubKeyHandle
, privKeyHandle
;
314 clientSession().generateKey(database
.dbHandle(), context
,
315 publicKeyUsage
, publicKeyAttr
,
316 privateKeyUsage
, privateKeyAttr
,
318 pubKeyHandle
, publicKey
.header(),
319 privKeyHandle
, privateKey
.header());
320 makeReferenceKey(privKeyHandle
, privateKey
, database
, privateKeyAttr
,
322 // @@@ What if this throws, we need to free privateKey.
323 makeReferenceKey(pubKeyHandle
, publicKey
, database
, publicKeyAttr
,
328 SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey
&PublicKey
,
335 SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle
,
336 const Context
*Context
,
338 CSSM_KEY_SIZE
&KeySize
)
344 SSCSPSession::FreeKey(const AccessCredentials
*accessCred
,
345 CssmKey
&ioKey
, CSSM_BOOL deleteKey
)
347 if (ioKey
.blobType() == CSSM_KEYBLOB_REFERENCE
)
349 StLock
<Mutex
> _(mSSCSPDLSession
.mKeyDeletionMutex
);
350 // @@@ Note that this means that detaching a session should free
351 // all keys ascociated with it or else...
355 // @@@ There are thread safety issues when deleting a key that is
356 // in use by another thread, but the answer to that is: Don't do
359 // Find the key in the map. Tell tell the key to free itself
360 // (when the unique_ptr deletes the key it removes itself from the map).
361 secinfo("freeKey", "CSPDL FreeKey");
362 unique_ptr
<SSKey
> ssKey(&mSSCSPDLSession
.find
<SSKey
>(ioKey
));
363 ssKey
->free(accessCred
, ioKey
, deleteKey
);
367 CSPFullPluginSession::FreeKey(accessCred
, ioKey
, deleteKey
);
376 SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
,
377 const Context
&context
,
378 CssmData
&randomNumber
)
380 checkOperation(context
.type(), CSSM_ALGCLASS_RANDOMGEN
);
381 // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED);
382 uint32 needed
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
);
384 // @@@ What about the seed?
385 if (randomNumber
.length())
387 if (randomNumber
.length() < needed
)
388 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
389 clientSession().generateRandom(context
, randomNumber
);
393 randomNumber
.Data
= alloc
<uint8
>(needed
);
396 clientSession().generateRandom(context
, randomNumber
);
400 free(randomNumber
.Data
);
401 randomNumber
.Data
= NULL
;
408 // Login/Logout and token operational maintainance. These mean little
409 // without support by the actual implementation, but we can help...
410 // @@@ Should this be in CSP[non-Full]PluginSession?
413 SSCSPSession::Login(const AccessCredentials
&AccessCred
,
414 const CssmData
*LoginName
,
415 const void *Reserved
)
417 // @@@ Do a login to the securityServer making keys persistent until it
423 SSCSPSession::Logout()
429 SSCSPSession::VerifyDevice(const CssmData
&DeviceCert
)
431 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED
);
435 SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics
&statistics
)
442 // Utterly miscellaneous, rarely used, strange functions
445 SSCSPSession::RetrieveCounter(CssmData
&Counter
)
451 SSCSPSession::RetrieveUniqueId(CssmData
&UniqueID
)
457 SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm
, CssmData
&TimeData
)
464 // ACL retrieval and change operations
467 SSCSPSession::GetKeyOwner(const CssmKey
&Key
,
468 CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
470 lookupKey(Key
).getOwner(Owner
, *this);
474 SSCSPSession::ChangeKeyOwner(const AccessCredentials
&AccessCred
,
476 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
478 lookupKey(Key
).changeOwner(AccessCred
,
479 AclOwnerPrototype::overlay(NewOwner
));
483 SSCSPSession::GetKeyAcl(const CssmKey
&Key
,
484 const CSSM_STRING
*SelectionTag
,
485 uint32
&NumberOfAclInfos
,
486 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
488 lookupKey(Key
).getAcl(reinterpret_cast<const char *>(SelectionTag
),
490 reinterpret_cast<AclEntryInfo
*&>(AclInfos
), *this);
494 SSCSPSession::ChangeKeyAcl(const AccessCredentials
&AccessCred
,
495 const CSSM_ACL_EDIT
&AclEdit
,
498 lookupKey(Key
).changeAcl(AccessCred
, AclEdit::overlay(AclEdit
));
502 SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
508 SSCSPSession::ChangeLoginOwner(const AccessCredentials
&AccessCred
,
509 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
515 SSCSPSession::GetLoginAcl(const CSSM_STRING
*SelectionTag
,
516 uint32
&NumberOfAclInfos
,
517 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
523 SSCSPSession::ChangeLoginAcl(const AccessCredentials
&AccessCred
,
524 const CSSM_ACL_EDIT
&AclEdit
)
535 SSCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle
,
536 const Context
&context
,
537 uint32 passThroughId
,
541 checkOperation(context
.type(), CSSM_ALGCLASS_NONE
);
542 switch (passThroughId
) {
543 case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE
:
545 // inData unused, must be NULL
547 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
);
549 // outData required, must be pointer-to-pointer-to-KeyHandle
550 KeyHandle
&result
= Required(reinterpret_cast<KeyHandle
*>(outData
));
552 // we'll take the key from the context
554 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
);
557 result
= lookupKey(key
).keyHandle();
560 case CSSM_APPLECSP_KEYDIGEST
:
562 // inData unused, must be NULL
564 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
);
569 // take the key from the context, convert to KeyHandle
571 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
);
572 KeyHandle keyHandle
= lookupKey(key
).keyHandle();
574 // allocate digest holder on app's behalf
575 CSSM_DATA
*digest
= alloc
<CSSM_DATA
>(sizeof(CSSM_DATA
));
581 clientSession().getKeyDigest(keyHandle
, CssmData::overlay(*digest
));
592 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID
);
596 /* Validate requested key attr flags for newly generated keys */
597 void SSCSPSession::validateKeyAttr(uint32 reqKeyAttr
)
599 if(reqKeyAttr
& (CSSM_KEYATTR_RETURN_DATA
)) {
600 /* CSPDL only supports reference keys */
601 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
);
603 if(reqKeyAttr
& (CSSM_KEYATTR_ALWAYS_SENSITIVE
|
604 CSSM_KEYATTR_NEVER_EXTRACTABLE
)) {
605 /* invalid for any CSP */
606 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
608 /* There may be more, but we'll leave it to SS and CSP to decide */