]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp
Security-57740.1.18.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 // @@@ Note that this means that detaching a session should free
350 // all keys ascociated with it or else...
351 // -- or else what?
352 // exactly!
353
354 // @@@ There are thread safety issues when deleting a key that is
355 // in use by another thread, but the answer to that is: Don't do
356 // that!
357
358 // Find the key in the map. Tell tell the key to free itself
359 // (when the auto_ptr deletes the key it removes itself from the map).
360 secinfo("freeKey", "CSPDL FreeKey");
361 auto_ptr<SSKey> ssKey(&mSSCSPDLSession.find<SSKey>(ioKey));
362 ssKey->free(accessCred, ioKey, deleteKey);
363 }
364 else
365 {
366 CSPFullPluginSession::FreeKey(accessCred, ioKey, deleteKey);
367 }
368 }
369
370
371 //
372 // Generation stuff.
373 //
374 void
375 SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
376 const Context &context,
377 CssmData &randomNumber)
378 {
379 checkOperation(context.type(), CSSM_ALGCLASS_RANDOMGEN);
380 // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED);
381 uint32 needed = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE);
382
383 // @@@ What about the seed?
384 if (randomNumber.length())
385 {
386 if (randomNumber.length() < needed)
387 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
388 clientSession().generateRandom(context, randomNumber);
389 }
390 else
391 {
392 randomNumber.Data = alloc<uint8>(needed);
393 try
394 {
395 clientSession().generateRandom(context, randomNumber);
396 }
397 catch(...)
398 {
399 free(randomNumber.Data);
400 randomNumber.Data = NULL;
401 throw;
402 }
403 }
404 }
405
406 //
407 // Login/Logout and token operational maintainance. These mean little
408 // without support by the actual implementation, but we can help...
409 // @@@ Should this be in CSP[non-Full]PluginSession?
410 //
411 void
412 SSCSPSession::Login(const AccessCredentials &AccessCred,
413 const CssmData *LoginName,
414 const void *Reserved)
415 {
416 // @@@ Do a login to the securityServer making keys persistent until it
417 // goes away
418 unimplemented();
419 }
420
421 void
422 SSCSPSession::Logout()
423 {
424 unimplemented();
425 }
426
427 void
428 SSCSPSession::VerifyDevice(const CssmData &DeviceCert)
429 {
430 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
431 }
432
433 void
434 SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
435 {
436 unimplemented();
437 }
438
439
440 //
441 // Utterly miscellaneous, rarely used, strange functions
442 //
443 void
444 SSCSPSession::RetrieveCounter(CssmData &Counter)
445 {
446 unimplemented();
447 }
448
449 void
450 SSCSPSession::RetrieveUniqueId(CssmData &UniqueID)
451 {
452 unimplemented();
453 }
454
455 void
456 SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
457 {
458 unimplemented();
459 }
460
461
462 //
463 // ACL retrieval and change operations
464 //
465 void
466 SSCSPSession::GetKeyOwner(const CssmKey &Key,
467 CSSM_ACL_OWNER_PROTOTYPE &Owner)
468 {
469 lookupKey(Key).getOwner(Owner, *this);
470 }
471
472 void
473 SSCSPSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
474 const CssmKey &Key,
475 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
476 {
477 lookupKey(Key).changeOwner(AccessCred,
478 AclOwnerPrototype::overlay(NewOwner));
479 }
480
481 void
482 SSCSPSession::GetKeyAcl(const CssmKey &Key,
483 const CSSM_STRING *SelectionTag,
484 uint32 &NumberOfAclInfos,
485 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
486 {
487 lookupKey(Key).getAcl(reinterpret_cast<const char *>(SelectionTag),
488 NumberOfAclInfos,
489 reinterpret_cast<AclEntryInfo *&>(AclInfos), *this);
490 }
491
492 void
493 SSCSPSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
494 const CSSM_ACL_EDIT &AclEdit,
495 const CssmKey &Key)
496 {
497 lookupKey(Key).changeAcl(AccessCred, AclEdit::overlay(AclEdit));
498 }
499
500 void
501 SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
502 {
503 unimplemented();
504 }
505
506 void
507 SSCSPSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
508 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
509 {
510 unimplemented();
511 }
512
513 void
514 SSCSPSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
515 uint32 &NumberOfAclInfos,
516 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
517 {
518 unimplemented();
519 }
520
521 void
522 SSCSPSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
523 const CSSM_ACL_EDIT &AclEdit)
524 {
525 unimplemented();
526 }
527
528
529
530 //
531 // Passthroughs
532 //
533 void
534 SSCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle,
535 const Context &context,
536 uint32 passThroughId,
537 const void *inData,
538 void **outData)
539 {
540 checkOperation(context.type(), CSSM_ALGCLASS_NONE);
541 switch (passThroughId) {
542 case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE:
543 {
544 // inData unused, must be NULL
545 if (inData)
546 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
547
548 // outData required, must be pointer-to-pointer-to-KeyHandle
549 KeyHandle &result = Required(reinterpret_cast<KeyHandle *>(outData));
550
551 // we'll take the key from the context
552 const CssmKey &key =
553 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
554
555 // all ready
556 result = lookupKey(key).keyHandle();
557 break;
558 }
559 case CSSM_APPLECSP_KEYDIGEST:
560 {
561 // inData unused, must be NULL
562 if (inData)
563 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
564
565 // outData required
566 Required(outData);
567
568 // take the key from the context, convert to KeyHandle
569 const CssmKey &key =
570 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
571 KeyHandle keyHandle = lookupKey(key).keyHandle();
572
573 // allocate digest holder on app's behalf
574 CSSM_DATA *digest = alloc<CSSM_DATA>(sizeof(CSSM_DATA));
575 digest->Data = NULL;
576 digest->Length = 0;
577
578 // go
579 try {
580 clientSession().getKeyDigest(keyHandle, CssmData::overlay(*digest));
581 }
582 catch(...) {
583 free(digest);
584 throw;
585 }
586 *outData = digest;
587 break;
588 }
589
590 default:
591 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID);
592 }
593 }
594
595 /* Validate requested key attr flags for newly generated keys */
596 void SSCSPSession::validateKeyAttr(uint32 reqKeyAttr)
597 {
598 if(reqKeyAttr & (CSSM_KEYATTR_RETURN_DATA)) {
599 /* CSPDL only supports reference keys */
600 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
601 }
602 if(reqKeyAttr & (CSSM_KEYATTR_ALWAYS_SENSITIVE |
603 CSSM_KEYATTR_NEVER_EXTRACTABLE)) {
604 /* invalid for any CSP */
605 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
606 }
607 /* There may be more, but we'll leave it to SS and CSP to decide */
608 }