]> git.saurik.com Git - apple/security.git/blob - AppleCSPDL/SSCSPSession.cpp
Security-179.tar.gz
[apple/security.git] / AppleCSPDL / SSCSPSession.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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
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(CssmAllocator::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 secdebug("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 randomNumber.Length = needed;
389 clientSession().generateRandom(randomNumber);
390 }
391 else
392 {
393 randomNumber.Data = alloc<uint8>(needed);
394 try
395 {
396 randomNumber.Length = needed;
397 clientSession().generateRandom(randomNumber);
398 }
399 catch(...)
400 {
401 free(randomNumber.Data);
402 randomNumber.Data = NULL;
403 throw;
404 }
405 }
406 }
407
408 //
409 // Login/Logout and token operational maintainance. These mean little
410 // without support by the actual implementation, but we can help...
411 // @@@ Should this be in CSP[non-Full]PluginSession?
412 //
413 void
414 SSCSPSession::Login(const AccessCredentials &AccessCred,
415 const CssmData *LoginName,
416 const void *Reserved)
417 {
418 // @@@ Do a login to the securityServer making keys persistant until it
419 // goes away
420 unimplemented();
421 }
422
423 void
424 SSCSPSession::Logout()
425 {
426 unimplemented();
427 }
428
429 void
430 SSCSPSession::VerifyDevice(const CssmData &DeviceCert)
431 {
432 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
433 }
434
435 void
436 SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
437 {
438 unimplemented();
439 }
440
441
442 //
443 // Utterly miscellaneous, rarely used, strange functions
444 //
445 void
446 SSCSPSession::RetrieveCounter(CssmData &Counter)
447 {
448 unimplemented();
449 }
450
451 void
452 SSCSPSession::RetrieveUniqueId(CssmData &UniqueID)
453 {
454 unimplemented();
455 }
456
457 void
458 SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
459 {
460 unimplemented();
461 }
462
463
464 //
465 // ACL retrieval and change operations
466 //
467 void
468 SSCSPSession::GetKeyOwner(const CssmKey &Key,
469 CSSM_ACL_OWNER_PROTOTYPE &Owner)
470 {
471 lookupKey(Key).getOwner(Owner, *this);
472 }
473
474 void
475 SSCSPSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
476 const CssmKey &Key,
477 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
478 {
479 lookupKey(Key).changeOwner(AccessCred,
480 AclOwnerPrototype::overlay(NewOwner));
481 }
482
483 void
484 SSCSPSession::GetKeyAcl(const CssmKey &Key,
485 const CSSM_STRING *SelectionTag,
486 uint32 &NumberOfAclInfos,
487 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
488 {
489 lookupKey(Key).getAcl(reinterpret_cast<const char *>(SelectionTag),
490 NumberOfAclInfos,
491 reinterpret_cast<AclEntryInfo *&>(AclInfos), *this);
492 }
493
494 void
495 SSCSPSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
496 const CSSM_ACL_EDIT &AclEdit,
497 const CssmKey &Key)
498 {
499 lookupKey(Key).changeAcl(AccessCred, AclEdit::overlay(AclEdit));
500 }
501
502 void
503 SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
504 {
505 unimplemented();
506 }
507
508 void
509 SSCSPSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
510 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
511 {
512 unimplemented();
513 }
514
515 void
516 SSCSPSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
517 uint32 &NumberOfAclInfos,
518 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
519 {
520 unimplemented();
521 }
522
523 void
524 SSCSPSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
525 const CSSM_ACL_EDIT &AclEdit)
526 {
527 unimplemented();
528 }
529
530
531
532 //
533 // Passthroughs
534 //
535 void
536 SSCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle,
537 const Context &context,
538 uint32 passThroughId,
539 const void *inData,
540 void **outData)
541 {
542 checkOperation(context.type(), CSSM_ALGCLASS_NONE);
543 switch (passThroughId) {
544 case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE:
545 {
546 // inData unused, must be NULL
547 if (inData)
548 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
549
550 // outData required, must be pointer-to-pointer-to-KeyHandle
551 KeyHandle &result = Required(reinterpret_cast<KeyHandle *>(outData));
552
553 // we'll take the key from the context
554 const CssmKey &key =
555 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
556
557 // all ready
558 result = lookupKey(key).keyHandle();
559 break;
560 }
561 case CSSM_APPLECSP_KEYDIGEST:
562 {
563 // inData unused, must be NULL
564 if (inData)
565 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
566
567 // outData required
568 Required(outData);
569
570 // take the key from the context, convert to KeyHandle
571 const CssmKey &key =
572 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
573 KeyHandle keyHandle = lookupKey(key).keyHandle();
574
575 // allocate digest holder on app's behalf
576 CSSM_DATA *digest = alloc<CSSM_DATA>(sizeof(CSSM_DATA));
577 digest->Data = NULL;
578 digest->Length = 0;
579
580 // go
581 try {
582 clientSession().getKeyDigest(keyHandle, CssmData::overlay(*digest));
583 }
584 catch(...) {
585 free(digest);
586 throw;
587 }
588 *outData = digest;
589 break;
590 }
591
592 default:
593 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID);
594 }
595 }
596
597 /* Validate requested key attr flags for newly generated keys */
598 void SSCSPSession::validateKeyAttr(uint32 reqKeyAttr)
599 {
600 if(reqKeyAttr & (CSSM_KEYATTR_RETURN_DATA)) {
601 /* CSPDL only supports reference keys */
602 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
603 }
604 if(reqKeyAttr & (CSSM_KEYATTR_ALWAYS_SENSITIVE |
605 CSSM_KEYATTR_NEVER_EXTRACTABLE)) {
606 /* invalid for any CSP */
607 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
608 }
609 /* There may be more, but we'll leave it to SS and CSP to decide */
610 }