]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / libsecurity_apple_cspdl / lib / SSCSPSession.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
b1ab9ed8
A
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19//
20// SSCSPSession.cpp - Security Server CSP session.
21//
22#include "SSCSPSession.h"
23
24#include "CSPDLPlugin.h"
25#include "SSDatabase.h"
26#include "SSDLSession.h"
27#include "SSKey.h"
28#include <security_cdsa_utilities/cssmbridge.h>
29#include <memory>
30
31using namespace std;
32using namespace SecurityServer;
33
34//
35// SSCSPSession -- Security Server CSP session
36//
37SSCSPSession::SSCSPSession(CSSM_MODULE_HANDLE handle,
38 CSPDLPlugin &plug,
39 const CSSM_VERSION &version,
40 uint32 subserviceId,
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),
50 mRawCsp(rawCsp),
51 mClientSession(Allocator::standard(), *this)
52{
53 mClientSession.registerForAclEdits(SSCSPDLSession::didChangeKeyAclCallback, &mSSCSPDLSession);
54}
55
56//
57// Called at (CSSM) context create time. This is ignored; we do a full
58// context setup later, at setupContext time.
59//
60CSPFullPluginSession::CSPContext *
61SSCSPSession::contextCreate(CSSM_CC_HANDLE handle, const Context &context)
62{
63 return NULL;
64}
65
66
67//
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.
72//
73void
74SSCSPSession::setupContext(CSPContext * &cspCtx,
75 const Context &context,
76 bool encoding)
77{
78 // note we skip this if this CSPContext is being reused
79 if (cspCtx == NULL)
80 {
81
82 if (mSSFactory.setup(*this, cspCtx, context, encoding))
83 return;
84
85#if 0
86 if (mBSafe4Factory.setup(*this, cspCtx, context))
87 return;
88
89 if (mCryptKitFactory.setup(*this, cspCtx, context))
90 return;
91#endif
92
93 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
94 }
95}
96
97
98//
99// DL interaction
100//
101SSDatabase
102SSCSPSession::getDatabase(const Context &context)
103{
104 return getDatabase(context.get<CSSM_DL_DB_HANDLE>(CSSM_ATTRIBUTE_DL_DB_HANDLE));
105}
106
107SSDatabase
108SSCSPSession::getDatabase(CSSM_DL_DB_HANDLE *aDLDbHandle)
109{
110 if (aDLDbHandle)
111 return findSession<SSDLSession>(aDLDbHandle->DLHandle).findDbHandle(aDLDbHandle->DBHandle);
112 else
113 return SSDatabase();
114}
115
116
117//
118// Reference Key management
119//
120void
121SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle, CssmKey &ioKey, SSDatabase &inSSDatabase,
122 uint32 inKeyAttr, const CssmData *inKeyLabel)
123{
124 return mSSCSPDLSession.makeReferenceKey(*this, inKeyHandle, ioKey, inSSDatabase, inKeyAttr, inKeyLabel);
125}
126
127SSKey &
128SSCSPSession::lookupKey(const CssmKey &inKey)
129{
130 return mSSCSPDLSession.lookupKey(inKey);
131}
132
133
134//
135// Key creating and handeling members
136//
137void
138SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle,
139 const Context &context,
140 const AccessCredentials &AccessCred,
141 const CssmKey &Key,
142 const CssmData *DescriptiveData,
143 CssmKey &WrappedKey,
144 CSSM_PRIVILEGE Privilege)
145{
146 // @@@ Deal with permanent keys
147 const CssmKey *keyInContext =
148 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
149
150 KeyHandle contextKeyHandle = (keyInContext
151 ? lookupKey(*keyInContext).keyHandle()
152 : noKey);
153 clientSession().wrapKey(context, contextKeyHandle,
154 lookupKey(Key).keyHandle(), &AccessCred,
155 DescriptiveData, WrappedKey, *this);
156}
157
158void
159SSCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle,
160 const Context &context,
161 const CssmKey *PublicKey,
162 const CssmWrappedKey &WrappedKey,
163 uint32 KeyUsage,
164 uint32 KeyAttr,
165 const CssmData *KeyLabel,
166 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
167 CssmKey &UnwrappedKey,
168 CssmData &DescriptiveData,
169 CSSM_PRIVILEGE Privilege)
170{
171 SSDatabase database = getDatabase(context);
172 validateKeyAttr(KeyAttr);
173 const AccessCredentials *cred = NULL;
174 const AclEntryInput *owner = NULL;
175 if (CredAndAclEntry)
176 {
177 cred = AccessCredentials::overlay(CredAndAclEntry->AccessCred);
178 owner = &AclEntryInput::overlay(CredAndAclEntry->InitialAclEntry);
179 }
180
181 KeyHandle publicKey = noKey;
182 if (PublicKey)
183 {
184 if (PublicKey->blobType() == CSSM_KEYBLOB_RAW)
185 {
186 // @@@ We need to unwrap the publicKey into the SecurityServer
187 // before continuing
188 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
189 }
190 else
191 publicKey = lookupKey(*PublicKey).keyHandle();
192 }
193
194 // @@@ Deal with permanent keys
195 const CssmKey *keyInContext =
196 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
197
198 KeyHandle contextKeyHandle =
199 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;
200
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,
207 KeyLabel);
208}
209
210void
211SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle,
212 const Context &context,
213 CssmData &param,
214 uint32 keyUsage,
215 uint32 keyAttr,
216 const CssmData *keyLabel,
217 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
218 CssmKey &derivedKey)
219{
220 SSDatabase database = getDatabase(context);
221 validateKeyAttr(keyAttr);
222 const AccessCredentials *cred = NULL;
223 const AclEntryInput *owner = NULL;
224 if (credAndAclEntry)
225 {
226 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
227 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
228 }
229
230 /* optional BaseKey */
231 const CssmKey *keyInContext =
232 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
233 KeyHandle contextKeyHandle =
234 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;
235 KeyHandle keyHandle;
236 switch(context.algorithm()) {
237 case CSSM_ALGID_KEYCHAIN_KEY:
238 {
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());
243 }
244 break;
245 default:
246 clientSession().deriveKey(database.dbHandle(), context, contextKeyHandle, keyUsage,
247 keyAttr, param, cred, owner, keyHandle, derivedKey.header());
248 break;
249 }
250 makeReferenceKey(keyHandle, derivedKey, database, keyAttr, keyLabel);
251}
252
253void
254SSCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle,
255 const Context &context,
256 uint32 keyUsage,
257 uint32 keyAttr,
258 const CssmData *keyLabel,
259 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
260 CssmKey &key,
261 CSSM_PRIVILEGE privilege)
262{
263 SSDatabase database = getDatabase(context);
264 validateKeyAttr(keyAttr);
265 const AccessCredentials *cred = NULL;
266 const AclEntryInput *owner = NULL;
267 if (credAndAclEntry)
268 {
269 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
270 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
271 }
272
273 KeyHandle keyHandle;
274 clientSession().generateKey(database.dbHandle(), context, keyUsage,
275 keyAttr, cred, owner, keyHandle, key.header());
276 makeReferenceKey(keyHandle, key, database, keyAttr, keyLabel);
277}
278
279void
280SSCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle,
281 const Context &context,
282 uint32 publicKeyUsage,
283 uint32 publicKeyAttr,
284 const CssmData *publicKeyLabel,
285 CssmKey &publicKey,
286 uint32 privateKeyUsage,
287 uint32 privateKeyAttr,
288 const CssmData *privateKeyLabel,
289 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
290 CssmKey &privateKey,
291 CSSM_PRIVILEGE privilege)
292{
293 SSDatabase database = getDatabase(context);
294 validateKeyAttr(publicKeyAttr);
295 validateKeyAttr(privateKeyAttr);
296 const AccessCredentials *cred = NULL;
297 const AclEntryInput *owner = NULL;
298 if (credAndAclEntry)
299 {
300 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
301 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
302 }
303
304 /*
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...
309 */
310 if(!(publicKeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
311 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
312 }
313 KeyHandle pubKeyHandle, privKeyHandle;
314 clientSession().generateKey(database.dbHandle(), context,
315 publicKeyUsage, publicKeyAttr,
316 privateKeyUsage, privateKeyAttr,
317 cred, owner,
318 pubKeyHandle, publicKey.header(),
319 privKeyHandle, privateKey.header());
320 makeReferenceKey(privKeyHandle, privateKey, database, privateKeyAttr,
321 privateKeyLabel);
322 // @@@ What if this throws, we need to free privateKey.
323 makeReferenceKey(pubKeyHandle, publicKey, database, publicKeyAttr,
324 publicKeyLabel);
325}
326
327void
328SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
329 CssmKey &PrivateKey)
330{
331 unimplemented();
332}
333
334void
335SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle,
427c49bc
A
336 const Context *Context,
337 const CssmKey *Key,
b1ab9ed8
A
338 CSSM_KEY_SIZE &KeySize)
339{
340 unimplemented();
341}
342
343void
344SSCSPSession::FreeKey(const AccessCredentials *accessCred,
345 CssmKey &ioKey, CSSM_BOOL deleteKey)
346{
347 if (ioKey.blobType() == CSSM_KEYBLOB_REFERENCE)
348 {
866f8763 349 StLock<Mutex> _(mSSCSPDLSession.mKeyDeletionMutex);
b1ab9ed8
A
350 // @@@ Note that this means that detaching a session should free
351 // all keys ascociated with it or else...
352 // -- or else what?
353 // exactly!
354
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
357 // that!
358
359 // Find the key in the map. Tell tell the key to free itself
360 // (when the auto_ptr deletes the key it removes itself from the map).
fa7225c8 361 secinfo("freeKey", "CSPDL FreeKey");
b1ab9ed8
A
362 auto_ptr<SSKey> ssKey(&mSSCSPDLSession.find<SSKey>(ioKey));
363 ssKey->free(accessCred, ioKey, deleteKey);
364 }
365 else
366 {
367 CSPFullPluginSession::FreeKey(accessCred, ioKey, deleteKey);
368 }
369}
370
371
372//
373// Generation stuff.
374//
375void
376SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
377 const Context &context,
378 CssmData &randomNumber)
379{
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);
383
384 // @@@ What about the seed?
385 if (randomNumber.length())
386 {
387 if (randomNumber.length() < needed)
388 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
389 clientSession().generateRandom(context, randomNumber);
390 }
391 else
392 {
393 randomNumber.Data = alloc<uint8>(needed);
394 try
395 {
396 clientSession().generateRandom(context, randomNumber);
397 }
398 catch(...)
399 {
400 free(randomNumber.Data);
401 randomNumber.Data = NULL;
402 throw;
403 }
404 }
405}
406
407//
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?
411//
412void
413SSCSPSession::Login(const AccessCredentials &AccessCred,
414 const CssmData *LoginName,
415 const void *Reserved)
416{
5c19dc3a 417 // @@@ Do a login to the securityServer making keys persistent until it
b1ab9ed8
A
418 // goes away
419 unimplemented();
420}
421
422void
423SSCSPSession::Logout()
424{
425 unimplemented();
426}
427
428void
429SSCSPSession::VerifyDevice(const CssmData &DeviceCert)
430{
431 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
432}
433
434void
435SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
436{
437 unimplemented();
438}
439
440
441//
442// Utterly miscellaneous, rarely used, strange functions
443//
444void
445SSCSPSession::RetrieveCounter(CssmData &Counter)
446{
447 unimplemented();
448}
449
450void
451SSCSPSession::RetrieveUniqueId(CssmData &UniqueID)
452{
453 unimplemented();
454}
455
456void
457SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
458{
459 unimplemented();
460}
461
462
463//
464// ACL retrieval and change operations
465//
466void
467SSCSPSession::GetKeyOwner(const CssmKey &Key,
468 CSSM_ACL_OWNER_PROTOTYPE &Owner)
469{
470 lookupKey(Key).getOwner(Owner, *this);
471}
472
473void
474SSCSPSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
475 const CssmKey &Key,
476 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
477{
478 lookupKey(Key).changeOwner(AccessCred,
479 AclOwnerPrototype::overlay(NewOwner));
480}
481
482void
483SSCSPSession::GetKeyAcl(const CssmKey &Key,
484 const CSSM_STRING *SelectionTag,
485 uint32 &NumberOfAclInfos,
486 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
487{
488 lookupKey(Key).getAcl(reinterpret_cast<const char *>(SelectionTag),
489 NumberOfAclInfos,
490 reinterpret_cast<AclEntryInfo *&>(AclInfos), *this);
491}
492
493void
494SSCSPSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
495 const CSSM_ACL_EDIT &AclEdit,
496 const CssmKey &Key)
497{
498 lookupKey(Key).changeAcl(AccessCred, AclEdit::overlay(AclEdit));
499}
500
501void
502SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
503{
504 unimplemented();
505}
506
507void
508SSCSPSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
509 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
510{
511 unimplemented();
512}
513
514void
515SSCSPSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
516 uint32 &NumberOfAclInfos,
517 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
518{
519 unimplemented();
520}
521
522void
523SSCSPSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
524 const CSSM_ACL_EDIT &AclEdit)
525{
526 unimplemented();
527}
528
529
530
531//
532// Passthroughs
533//
534void
535SSCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle,
536 const Context &context,
537 uint32 passThroughId,
538 const void *inData,
539 void **outData)
540{
541 checkOperation(context.type(), CSSM_ALGCLASS_NONE);
542 switch (passThroughId) {
543 case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE:
544 {
545 // inData unused, must be NULL
546 if (inData)
547 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
548
549 // outData required, must be pointer-to-pointer-to-KeyHandle
550 KeyHandle &result = Required(reinterpret_cast<KeyHandle *>(outData));
551
552 // we'll take the key from the context
553 const CssmKey &key =
554 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
555
556 // all ready
557 result = lookupKey(key).keyHandle();
558 break;
559 }
560 case CSSM_APPLECSP_KEYDIGEST:
561 {
562 // inData unused, must be NULL
563 if (inData)
564 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
565
566 // outData required
567 Required(outData);
568
569 // take the key from the context, convert to KeyHandle
570 const CssmKey &key =
571 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
572 KeyHandle keyHandle = lookupKey(key).keyHandle();
573
574 // allocate digest holder on app's behalf
575 CSSM_DATA *digest = alloc<CSSM_DATA>(sizeof(CSSM_DATA));
576 digest->Data = NULL;
577 digest->Length = 0;
578
579 // go
580 try {
581 clientSession().getKeyDigest(keyHandle, CssmData::overlay(*digest));
582 }
583 catch(...) {
584 free(digest);
585 throw;
586 }
587 *outData = digest;
588 break;
589 }
590
591 default:
592 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID);
593 }
594}
595
596/* Validate requested key attr flags for newly generated keys */
597void SSCSPSession::validateKeyAttr(uint32 reqKeyAttr)
598{
599 if(reqKeyAttr & (CSSM_KEYATTR_RETURN_DATA)) {
600 /* CSPDL only supports reference keys */
601 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
602 }
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);
607 }
608 /* There may be more, but we'll leave it to SS and CSP to decide */
609}