2 * Copyright (c) 2000-2001 Apple Computer, 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"
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(CssmAllocator::standard(), *this)
56 // Called at (CSSM) context create time. This is ignored; we do a full
57 // context setup later, at setupContext time.
59 CSPFullPluginSession::CSPContext
*
60 SSCSPSession::contextCreate(CSSM_CC_HANDLE handle
, const Context
&context
)
67 // Called by CSPFullPluginSession when an op is actually commencing.
68 // Context can safely assumed to be fully formed and stable for the
69 // duration of the op; thus we wait until now to set up our
70 // CSPContext as appropriate to the op.
73 SSCSPSession::setupContext(CSPContext
* &cspCtx
,
74 const Context
&context
,
77 // note we skip this if this CSPContext is being reused
81 if (mSSFactory
.setup(*this, cspCtx
, context
, encoding
))
85 if (mBSafe4Factory
.setup(*this, cspCtx
, context
))
88 if (mCryptKitFactory
.setup(*this, cspCtx
, context
))
92 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
101 SSCSPSession::getDatabase(const Context
&context
)
103 return getDatabase(context
.get
<CSSM_DL_DB_HANDLE
>(CSSM_ATTRIBUTE_DL_DB_HANDLE
));
107 SSCSPSession::getDatabase(CSSM_DL_DB_HANDLE
*aDLDbHandle
)
110 return findSession
<SSDLSession
>(aDLDbHandle
->DLHandle
).findDbHandle(aDLDbHandle
->DBHandle
);
117 // Reference Key management
120 SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle
, CssmKey
&ioKey
, SSDatabase
&inSSDatabase
,
121 uint32 inKeyAttr
, const CssmData
*inKeyLabel
)
123 return mSSCSPDLSession
.makeReferenceKey(*this, inKeyHandle
, ioKey
, inSSDatabase
, inKeyAttr
, inKeyLabel
);
127 SSCSPSession::lookupKey(const CssmKey
&inKey
)
129 return mSSCSPDLSession
.lookupKey(inKey
);
134 // Key creating and handeling members
137 SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle
,
138 const Context
&context
,
139 const AccessCredentials
&AccessCred
,
141 const CssmData
*DescriptiveData
,
143 CSSM_PRIVILEGE Privilege
)
145 // @@@ Deal with permanent keys
146 const CssmKey
*keyInContext
=
147 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
149 KeyHandle contextKeyHandle
= (keyInContext
150 ? lookupKey(*keyInContext
).keyHandle()
152 clientSession().wrapKey(context
, contextKeyHandle
,
153 lookupKey(Key
).keyHandle(), &AccessCred
,
154 DescriptiveData
, WrappedKey
, *this);
158 SSCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle
,
159 const Context
&context
,
160 const CssmKey
*PublicKey
,
161 const CssmWrappedKey
&WrappedKey
,
164 const CssmData
*KeyLabel
,
165 const CSSM_RESOURCE_CONTROL_CONTEXT
*CredAndAclEntry
,
166 CssmKey
&UnwrappedKey
,
167 CssmData
&DescriptiveData
,
168 CSSM_PRIVILEGE Privilege
)
170 SSDatabase database
= getDatabase(context
);
171 validateKeyAttr(KeyAttr
);
172 const AccessCredentials
*cred
= NULL
;
173 const AclEntryInput
*owner
= NULL
;
176 cred
= AccessCredentials::overlay(CredAndAclEntry
->AccessCred
);
177 owner
= &AclEntryInput::overlay(CredAndAclEntry
->InitialAclEntry
);
180 KeyHandle publicKey
= noKey
;
183 if (PublicKey
->blobType() == CSSM_KEYBLOB_RAW
)
185 // @@@ We need to unwrap the publicKey into the SecurityServer
187 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
190 publicKey
= lookupKey(*PublicKey
).keyHandle();
193 // @@@ Deal with permanent keys
194 const CssmKey
*keyInContext
=
195 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
197 KeyHandle contextKeyHandle
=
198 keyInContext
? lookupKey(*keyInContext
).keyHandle() : noKey
;
200 KeyHandle unwrappedKeyHandle
;
201 clientSession().unwrapKey(database
.dbHandle(), context
, contextKeyHandle
,
202 publicKey
, WrappedKey
, KeyUsage
, KeyAttr
,
203 cred
, owner
, DescriptiveData
, unwrappedKeyHandle
,
204 UnwrappedKey
.header(), *this);
205 makeReferenceKey(unwrappedKeyHandle
, UnwrappedKey
, database
, KeyAttr
,
210 SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle
,
211 const Context
&context
,
215 const CssmData
*keyLabel
,
216 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
219 SSDatabase database
= getDatabase(context
);
220 validateKeyAttr(keyAttr
);
221 const AccessCredentials
*cred
= NULL
;
222 const AclEntryInput
*owner
= NULL
;
225 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
226 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
229 /* optional BaseKey */
230 const CssmKey
*keyInContext
=
231 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
);
232 KeyHandle contextKeyHandle
=
233 keyInContext
? lookupKey(*keyInContext
).keyHandle() : noKey
;
235 switch(context
.algorithm()) {
236 case CSSM_ALGID_KEYCHAIN_KEY
:
238 // special interpretation: take DLDBHandle -> DbHandle from params
239 clientSession().extractMasterKey(database
.dbHandle(), context
,
240 getDatabase(param
.interpretedAs
<CSSM_DL_DB_HANDLE
>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE
)).dbHandle(),
241 keyUsage
, keyAttr
, cred
, owner
, keyHandle
, derivedKey
.header());
245 clientSession().deriveKey(database
.dbHandle(), context
, contextKeyHandle
, keyUsage
,
246 keyAttr
, param
, cred
, owner
, keyHandle
, derivedKey
.header());
249 makeReferenceKey(keyHandle
, derivedKey
, database
, keyAttr
, keyLabel
);
253 SSCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle
,
254 const Context
&context
,
257 const CssmData
*keyLabel
,
258 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
260 CSSM_PRIVILEGE privilege
)
262 SSDatabase database
= getDatabase(context
);
263 validateKeyAttr(keyAttr
);
264 const AccessCredentials
*cred
= NULL
;
265 const AclEntryInput
*owner
= NULL
;
268 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
269 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
273 clientSession().generateKey(database
.dbHandle(), context
, keyUsage
,
274 keyAttr
, cred
, owner
, keyHandle
, key
.header());
275 makeReferenceKey(keyHandle
, key
, database
, keyAttr
, keyLabel
);
279 SSCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
,
280 const Context
&context
,
281 uint32 publicKeyUsage
,
282 uint32 publicKeyAttr
,
283 const CssmData
*publicKeyLabel
,
285 uint32 privateKeyUsage
,
286 uint32 privateKeyAttr
,
287 const CssmData
*privateKeyLabel
,
288 const CSSM_RESOURCE_CONTROL_CONTEXT
*credAndAclEntry
,
290 CSSM_PRIVILEGE privilege
)
292 SSDatabase database
= getDatabase(context
);
293 validateKeyAttr(publicKeyAttr
);
294 validateKeyAttr(privateKeyAttr
);
295 const AccessCredentials
*cred
= NULL
;
296 const AclEntryInput
*owner
= NULL
;
299 cred
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
);
300 owner
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
);
304 * Public keys must be extractable in the clear - that's the Apple
305 * policy. The raw CSP is unable to enforce the extractable
306 * bit since it always sees that as true (it's managed and forced
307 * true by the SecurityServer). So...
309 if(!(publicKeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
310 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
312 KeyHandle pubKeyHandle
, privKeyHandle
;
313 clientSession().generateKey(database
.dbHandle(), context
,
314 publicKeyUsage
, publicKeyAttr
,
315 privateKeyUsage
, privateKeyAttr
,
317 pubKeyHandle
, publicKey
.header(),
318 privKeyHandle
, privateKey
.header());
319 makeReferenceKey(privKeyHandle
, privateKey
, database
, privateKeyAttr
,
321 // @@@ What if this throws, we need to free privateKey.
322 makeReferenceKey(pubKeyHandle
, publicKey
, database
, publicKeyAttr
,
327 SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey
&PublicKey
,
334 SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle
,
335 const Context
&Context
,
337 CSSM_KEY_SIZE
&KeySize
)
343 SSCSPSession::FreeKey(const AccessCredentials
*accessCred
,
344 CssmKey
&ioKey
, CSSM_BOOL deleteKey
)
346 if (ioKey
.blobType() == CSSM_KEYBLOB_REFERENCE
)
348 // @@@ Note that this means that detaching a session should free
349 // all keys ascociated with it or else...
353 // @@@ There are thread safety issues when deleting a key that is
354 // in use by another thread, but the answer to that is: Don't do
357 // Find the key in the map. Tell tell the key to free itself
358 // (when the auto_ptr deletes the key it removes itself from the map).
359 secdebug("freeKey", "CSPDL FreeKey");
360 auto_ptr
<SSKey
> ssKey(&mSSCSPDLSession
.find
<SSKey
>(ioKey
));
361 ssKey
->free(accessCred
, ioKey
, deleteKey
);
365 CSPFullPluginSession::FreeKey(accessCred
, ioKey
, deleteKey
);
374 SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
,
375 const Context
&context
,
376 CssmData
&randomNumber
)
378 checkOperation(context
.type(), CSSM_ALGCLASS_RANDOMGEN
);
379 // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED);
380 uint32 needed
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
);
382 // @@@ What about the seed?
383 if (randomNumber
.length())
385 if (randomNumber
.length() < needed
)
386 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
387 randomNumber
.Length
= needed
;
388 clientSession().generateRandom(randomNumber
);
392 randomNumber
.Data
= alloc
<uint8
>(needed
);
395 randomNumber
.Length
= needed
;
396 clientSession().generateRandom(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 persistant 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 */