]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_apple_cspdl / lib / SSCSPSession.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
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
31 using namespace std;
32 using namespace SecurityServer;
33
34 //
35 // SSCSPSession -- Security Server CSP session
36 //
37 SSCSPSession::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 //
60 CSPFullPluginSession::CSPContext *
61 SSCSPSession::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 //
73 void
74 SSCSPSession::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 //
101 SSDatabase
102 SSCSPSession::getDatabase(const Context &context)
103 {
104 return getDatabase(context.get<CSSM_DL_DB_HANDLE>(CSSM_ATTRIBUTE_DL_DB_HANDLE));
105 }
106
107 SSDatabase
108 SSCSPSession::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 //
120 void
121 SSCSPSession::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
127 SSKey &
128 SSCSPSession::lookupKey(const CssmKey &inKey)
129 {
130 return mSSCSPDLSession.lookupKey(inKey);
131 }
132
133
134 //
135 // Key creating and handeling members
136 //
137 void
138 SSCSPSession::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
158 void
159 SSCSPSession::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
210 void
211 SSCSPSession::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
253 void
254 SSCSPSession::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
279 void
280 SSCSPSession::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
327 void
328 SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
329 CssmKey &PrivateKey)
330 {
331 unimplemented();
332 }
333
334 void
335 SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle,
336 const Context *Context,
337 const CssmKey *Key,
338 CSSM_KEY_SIZE &KeySize)
339 {
340 unimplemented();
341 }
342
343 void
344 SSCSPSession::FreeKey(const AccessCredentials *accessCred,
345 CssmKey &ioKey, CSSM_BOOL deleteKey)
346 {
347 if (ioKey.blobType() == CSSM_KEYBLOB_REFERENCE)
348 {
349 StLock<Mutex> _(mSSCSPDLSession.mKeyDeletionMutex);
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 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);
364 }
365 else
366 {
367 CSPFullPluginSession::FreeKey(accessCred, ioKey, deleteKey);
368 }
369 }
370
371
372 //
373 // Generation stuff.
374 //
375 void
376 SSCSPSession::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 //
412 void
413 SSCSPSession::Login(const AccessCredentials &AccessCred,
414 const CssmData *LoginName,
415 const void *Reserved)
416 {
417 // @@@ Do a login to the securityServer making keys persistent until it
418 // goes away
419 unimplemented();
420 }
421
422 void
423 SSCSPSession::Logout()
424 {
425 unimplemented();
426 }
427
428 void
429 SSCSPSession::VerifyDevice(const CssmData &DeviceCert)
430 {
431 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
432 }
433
434 void
435 SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
436 {
437 unimplemented();
438 }
439
440
441 //
442 // Utterly miscellaneous, rarely used, strange functions
443 //
444 void
445 SSCSPSession::RetrieveCounter(CssmData &Counter)
446 {
447 unimplemented();
448 }
449
450 void
451 SSCSPSession::RetrieveUniqueId(CssmData &UniqueID)
452 {
453 unimplemented();
454 }
455
456 void
457 SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
458 {
459 unimplemented();
460 }
461
462
463 //
464 // ACL retrieval and change operations
465 //
466 void
467 SSCSPSession::GetKeyOwner(const CssmKey &Key,
468 CSSM_ACL_OWNER_PROTOTYPE &Owner)
469 {
470 lookupKey(Key).getOwner(Owner, *this);
471 }
472
473 void
474 SSCSPSession::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
482 void
483 SSCSPSession::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
493 void
494 SSCSPSession::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
501 void
502 SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
503 {
504 unimplemented();
505 }
506
507 void
508 SSCSPSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
509 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
510 {
511 unimplemented();
512 }
513
514 void
515 SSCSPSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
516 uint32 &NumberOfAclInfos,
517 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
518 {
519 unimplemented();
520 }
521
522 void
523 SSCSPSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
524 const CSSM_ACL_EDIT &AclEdit)
525 {
526 unimplemented();
527 }
528
529
530
531 //
532 // Passthroughs
533 //
534 void
535 SSCSPSession::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 */
597 void 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 }