2 * Copyright (c) 2004,2008,2011-2012 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // SDCSPSession.cpp - Security Server CSP session.
28 #include "SDCSPSession.h"
30 #include "SDCSPDLPlugin.h"
31 #include "SDDLSession.h"
33 #include <security_cdsa_utilities/cssmbridge.h>
37 using namespace SecurityServer
;
40 // SDCSPSession -- Security Server CSP session
42 SDCSPSession::SDCSPSession(CSSM_MODULE_HANDLE handle
,
44 const CSSM_VERSION
&version
,
46 CSSM_SERVICE_TYPE subserviceType
,
47 CSSM_ATTACH_FLAGS attachFlags
,
48 const CSSM_UPCALLS
&upcalls
,
49 SDCSPDLSession
&ssCSPDLSession
,
50 CssmClient::CSP
&rawCsp
)
51 : CSPFullPluginSession(handle
, plug
, version
, subserviceId
, subserviceType
,
52 attachFlags
, upcalls
),
53 mSDCSPDLSession(ssCSPDLSession
),
54 mSDFactory(plug
.mSDFactory
),
56 mClientSession(Allocator::standard(), *this)
61 // Called at (CSSM) context create time. This is ignored; we do a full
62 // context setup later, at setupContext time.
64 CSPFullPluginSession::CSPContext
*
65 SDCSPSession::contextCreate(CSSM_CC_HANDLE handle
, const Context
&context
)
72 // Called by CSPFullPluginSession when an op is actually commencing.
73 // Context can safely assumed to be fully formed and stable for the
74 // duration of the op; thus we wait until now to set up our
75 // CSPContext as appropriate to the op.
78 SDCSPSession::setupContext(CSPContext
* &cspCtx
,
79 const Context
&context
,
82 // note we skip this if this CSPContext is being reused
86 if (mSDFactory
.setup(*this, cspCtx
, context
, encoding
))
90 if (mBSafe4Factory
.setup(*this, cspCtx
, context
))
93 if (mCryptKitFactory
.setup(*this, cspCtx
, context
))
97 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
106 SDCSPSession::getDatabase(const Context
&context
)
108 return getDatabase(context
.get
<CSSM_DL_DB_HANDLE
>(CSSM_ATTRIBUTE_DL_DB_HANDLE
));
112 SDCSPSession::getDatabase(CSSM_DL_DB_HANDLE
*aDLDbHandle
)
115 return aDLDbHandle
->DBHandle
;
117 return CSSM_INVALID_HANDLE
;
122 // Reference Key management
125 SDCSPSession::makeReferenceKey(KeyHandle inKeyHandle
, CssmKey
&ioKey
, CSSM_DB_HANDLE inDBHandle
,
126 uint32 inKeyAttr
, const CssmData
*inKeyLabel
)
128 return mSDCSPDLSession
.makeReferenceKey(*this, inKeyHandle
, ioKey
, inDBHandle
, inKeyAttr
, inKeyLabel
);
132 SDCSPSession::lookupKey(const CssmKey
&inKey
)
134 return mSDCSPDLSession
.lookupKey(inKey
);
139 // Key creating and handeling members
142 SDCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle
,
143 const Context
&context
,
144 const AccessCredentials
&AccessCred
,
146 const CssmData
*DescriptiveData
,
148 CSSM_PRIVILEGE Privilege
)
150 // @@@ Deal with permanent keys
151 const CssmKey
*keyInContext
=
152 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
154 KeyHandle contextKeyHandle
= (keyInContext
155 ? lookupKey(*keyInContext
).keyHandle()
157 clientSession().wrapKey(context
, contextKeyHandle
,
158 lookupKey(Key
).keyHandle(), &AccessCred
,
159 DescriptiveData
, WrappedKey
, *this);
163 SDCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle
,
164 const Context
&context
,
165 const CssmKey
*PublicKey
,
166 const CssmWrappedKey
&WrappedKey
,
169 const CssmData
*KeyLabel
,
170 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
171 CssmKey
&UnwrappedKey
,
172 CssmData
&DescriptiveData
,
173 CSSM_PRIVILEGE Privilege
)
175 CSSM_DB_HANDLE database
= getDatabase(context
);
176 validateKeyAttr(KeyAttr
);
177 const AccessCredentials
*cred
= NULL
;
178 const AclEntryInput
*owner
= NULL
;
181 cred
= AccessCredentials::overlay(CredAndAclEntry
->AccessCred
);
182 owner
= &AclEntryInput::overlay(CredAndAclEntry
->InitialAclEntry
);
185 KeyHandle publicKey
= noKey
;
188 if (PublicKey
->blobType() == CSSM_KEYBLOB_RAW
)
190 // @@@ We need to unwrap the publicKey into the SecurityServer
192 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
195 publicKey
= lookupKey(*PublicKey
).keyHandle();
198 // @@@ Deal with permanent keys
199 const CssmKey
*keyInContext
=
200 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
202 KeyHandle contextKeyHandle
=
203 keyInContext
? lookupKey(*keyInContext
).keyHandle() : noKey
;
205 KeyHandle unwrappedKeyHandle
;
206 clientSession().unwrapKey(ClientSession::toIPCHandle(database
), context
, contextKeyHandle
,
207 publicKey
, WrappedKey
, KeyUsage
, KeyAttr
,
208 cred
, owner
, DescriptiveData
, unwrappedKeyHandle
,
209 UnwrappedKey
.header(), *this);
210 makeReferenceKey(unwrappedKeyHandle
, UnwrappedKey
, database
, KeyAttr
,
215 SDCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle
,
216 const Context
&context
,
220 const CssmData
*keyLabel
,
221 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
224 CSSM_DB_HANDLE database
= getDatabase(context
);
225 validateKeyAttr(keyAttr
);
226 const AccessCredentials
*cred
= NULL
;
227 const AclEntryInput
*owner
= NULL
;
230 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
231 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
234 /* optional BaseKey */
235 const CssmKey
*keyInContext
=
236 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
237 KeyHandle contextKeyHandle
=
238 keyInContext
? lookupKey(*keyInContext
).keyHandle() : noKey
;
240 switch(context
.algorithm()) {
241 case CSSM_ALGID_KEYCHAIN_KEY
:
243 // special interpretation: take DLDBHandle -> DbHandle from params
244 clientSession().extractMasterKey(ClientSession::toIPCHandle(database
), context
,
245 (DbHandle
)getDatabase(param
.interpretedAs
<CSSM_DL_DB_HANDLE
>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE
)),
246 keyUsage
, keyAttr
, cred
, owner
, keyHandle
, derivedKey
.header());
250 clientSession().deriveKey(ClientSession::toIPCHandle(database
), context
, contextKeyHandle
, keyUsage
,
251 keyAttr
, param
, cred
, owner
, keyHandle
, derivedKey
.header());
254 makeReferenceKey(keyHandle
, derivedKey
, database
, keyAttr
, keyLabel
);
258 SDCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle
,
259 const Context
&context
,
262 const CssmData
*keyLabel
,
263 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
265 CSSM_PRIVILEGE privilege
)
267 CSSM_DB_HANDLE database
= getDatabase(context
);
268 validateKeyAttr(keyAttr
);
269 const AccessCredentials
*cred
= NULL
;
270 const AclEntryInput
*owner
= NULL
;
273 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
274 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
278 clientSession().generateKey(ClientSession::toIPCHandle(database
), context
, keyUsage
,
279 keyAttr
, cred
, owner
, keyHandle
, key
.header());
280 makeReferenceKey(keyHandle
, key
, database
, keyAttr
, keyLabel
);
284 SDCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
,
285 const Context
&context
,
286 uint32 publicKeyUsage
,
287 uint32 publicKeyAttr
,
288 const CssmData
*publicKeyLabel
,
290 uint32 privateKeyUsage
,
291 uint32 privateKeyAttr
,
292 const CssmData
*privateKeyLabel
,
293 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
295 CSSM_PRIVILEGE privilege
)
297 CSSM_DB_HANDLE database
= getDatabase(context
);
298 validateKeyAttr(publicKeyAttr
);
299 validateKeyAttr(privateKeyAttr
);
300 const AccessCredentials
*cred
= NULL
;
301 const AclEntryInput
*owner
= NULL
;
304 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
305 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
309 * Public keys must be extractable in the clear - that's the Apple
310 * policy. The raw CSP is unable to enforce the extractable
311 * bit since it always sees that as true (it's managed and forced
312 * true by the SecurityServer). So...
314 if(!(publicKeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
315 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
317 KeyHandle pubKeyHandle
, privKeyHandle
;
318 clientSession().generateKey(ClientSession::toIPCHandle(database
), context
,
319 publicKeyUsage
, publicKeyAttr
,
320 privateKeyUsage
, privateKeyAttr
,
322 pubKeyHandle
, publicKey
.header(),
323 privKeyHandle
, privateKey
.header());
324 makeReferenceKey(privKeyHandle
, privateKey
, database
, privateKeyAttr
,
326 // @@@ What if this throws, we need to free privateKey.
327 makeReferenceKey(pubKeyHandle
, publicKey
, database
, publicKeyAttr
,
332 SDCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey
&PublicKey
,
339 SDCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle
,
340 const Context
*Context
,
342 CSSM_KEY_SIZE
&KeySize
)
348 SDCSPSession::FreeKey(const AccessCredentials
*accessCred
,
349 CssmKey
&ioKey
, CSSM_BOOL deleteKey
)
351 if (ioKey
.blobType() == CSSM_KEYBLOB_REFERENCE
)
353 // @@@ Note that this means that detaching a session should free
354 // all keys ascociated with it or else...
358 // @@@ There are thread safety issues when deleting a key that is
359 // in use by another thread, but the answer to that is: Don't do
362 // Find the key in the map. Tell tell the key to free itself
363 // (when the unique_ptr deletes the key it removes itself from the map).
364 secinfo("freeKey", "CSPDL FreeKey");
365 unique_ptr
<SDKey
> ssKey(&mSDCSPDLSession
.find
<SDKey
>(ioKey
));
366 ssKey
->free(accessCred
, ioKey
, deleteKey
);
370 CSPFullPluginSession::FreeKey(accessCred
, ioKey
, deleteKey
);
379 SDCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
,
380 const Context
&context
,
381 CssmData
&randomNumber
)
383 checkOperation(context
.type(), CSSM_ALGCLASS_RANDOMGEN
);
384 // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED);
385 uint32 needed
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
);
387 // @@@ What about the seed?
388 if (randomNumber
.length())
390 if (randomNumber
.length() < needed
)
391 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
392 clientSession().generateRandom(context
, randomNumber
);
396 randomNumber
.Data
= alloc
<uint8
>(needed
);
399 clientSession().generateRandom(context
, randomNumber
);
403 free(randomNumber
.Data
);
404 randomNumber
.Data
= NULL
;
411 // Login/Logout and token operational maintainance. These mean little
412 // without support by the actual implementation, but we can help...
413 // @@@ Should this be in CSP[non-Full]PluginSession?
416 SDCSPSession::Login(const AccessCredentials
&AccessCred
,
417 const CssmData
*LoginName
,
418 const void *Reserved
)
420 // @@@ Do a login to the securityServer making keys persistent until it
426 SDCSPSession::Logout()
432 SDCSPSession::VerifyDevice(const CssmData
&DeviceCert
)
434 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED
);
438 SDCSPSession::GetOperationalStatistics(CSPOperationalStatistics
&statistics
)
445 // Utterly miscellaneous, rarely used, strange functions
448 SDCSPSession::RetrieveCounter(CssmData
&Counter
)
454 SDCSPSession::RetrieveUniqueId(CssmData
&UniqueID
)
460 SDCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm
, CssmData
&TimeData
)
467 // ACL retrieval and change operations
470 SDCSPSession::GetKeyOwner(const CssmKey
&Key
,
471 CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
473 lookupKey(Key
).getOwner(Owner
, *this);
477 SDCSPSession::ChangeKeyOwner(const AccessCredentials
&AccessCred
,
479 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
481 lookupKey(Key
).changeOwner(AccessCred
,
482 AclOwnerPrototype::overlay(NewOwner
));
486 SDCSPSession::GetKeyAcl(const CssmKey
&Key
,
487 const CSSM_STRING
*SelectionTag
,
488 uint32
&NumberOfAclInfos
,
489 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
491 lookupKey(Key
).getAcl(reinterpret_cast<const char *>(SelectionTag
),
493 reinterpret_cast<AclEntryInfo
*&>(AclInfos
), *this);
497 SDCSPSession::ChangeKeyAcl(const AccessCredentials
&AccessCred
,
498 const CSSM_ACL_EDIT
&AclEdit
,
501 lookupKey(Key
).changeAcl(AccessCred
, AclEdit::overlay(AclEdit
));
505 SDCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE
&Owner
)
511 SDCSPSession::ChangeLoginOwner(const AccessCredentials
&AccessCred
,
512 const CSSM_ACL_OWNER_PROTOTYPE
&NewOwner
)
518 SDCSPSession::GetLoginAcl(const CSSM_STRING
*SelectionTag
,
519 uint32
&NumberOfAclInfos
,
520 CSSM_ACL_ENTRY_INFO_PTR
&AclInfos
)
526 SDCSPSession::ChangeLoginAcl(const AccessCredentials
&AccessCred
,
527 const CSSM_ACL_EDIT
&AclEdit
)
538 SDCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle
,
539 const Context
&context
,
540 uint32 passThroughId
,
544 checkOperation(context
.type(), CSSM_ALGCLASS_NONE
);
545 switch (passThroughId
) {
546 case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE
:
548 // inData unused, must be NULL
550 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
);
552 // outData required, must be pointer-to-pointer-to-KeyHandle
553 KeyHandle
&result
= Required(reinterpret_cast<KeyHandle
*>(outData
));
555 // we'll take the key from the context
557 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
);
560 result
= lookupKey(key
).keyHandle();
563 case CSSM_APPLECSP_KEYDIGEST
:
565 // inData unused, must be NULL
567 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
);
572 // take the key from the context, convert to KeyHandle
574 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
, CSSMERR_CSP_MISSING_ATTR_KEY
);
575 KeyHandle keyHandle
= lookupKey(key
).keyHandle();
577 // allocate digest holder on app's behalf
578 CSSM_DATA
*digest
= alloc
<CSSM_DATA
>(sizeof(CSSM_DATA
));
584 clientSession().getKeyDigest(keyHandle
, CssmData::overlay(*digest
));
595 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID
);
599 /* Validate requested key attr flags for newly generated keys */
600 void SDCSPSession::validateKeyAttr(uint32 reqKeyAttr
)
602 if(reqKeyAttr
& (CSSM_KEYATTR_RETURN_DATA
)) {
603 /* CSPDL only supports reference keys */
604 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
);
606 if(reqKeyAttr
& (CSSM_KEYATTR_ALWAYS_SENSITIVE
|
607 CSSM_KEYATTR_NEVER_EXTRACTABLE
)) {
608 /* invalid for any CSP */
609 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
611 /* There may be more, but we'll leave it to SS and CSP to decide */