]> git.saurik.com Git - apple/security.git/blob - AppleCSPDL/SSCSPSession.cpp
Security-163.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 }
54
55 //
56 // Called at (CSSM) context create time. This is ignored; we do a full
57 // context setup later, at setupContext time.
58 //
59 CSPFullPluginSession::CSPContext *
60 SSCSPSession::contextCreate(CSSM_CC_HANDLE handle, const Context &context)
61 {
62 return NULL;
63 }
64
65
66 //
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.
71 //
72 void
73 SSCSPSession::setupContext(CSPContext * &cspCtx,
74 const Context &context,
75 bool encoding)
76 {
77 // note we skip this if this CSPContext is being reused
78 if (cspCtx == NULL)
79 {
80
81 if (mSSFactory.setup(*this, cspCtx, context, encoding))
82 return;
83
84 #if 0
85 if (mBSafe4Factory.setup(*this, cspCtx, context))
86 return;
87
88 if (mCryptKitFactory.setup(*this, cspCtx, context))
89 return;
90 #endif
91
92 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
93 }
94 }
95
96
97 //
98 // DL interaction
99 //
100 SSDatabase
101 SSCSPSession::getDatabase(const Context &context)
102 {
103 return getDatabase(context.get<CSSM_DL_DB_HANDLE>(CSSM_ATTRIBUTE_DL_DB_HANDLE));
104 }
105
106 SSDatabase
107 SSCSPSession::getDatabase(CSSM_DL_DB_HANDLE *aDLDbHandle)
108 {
109 if (aDLDbHandle)
110 return findSession<SSDLSession>(aDLDbHandle->DLHandle).findDbHandle(aDLDbHandle->DBHandle);
111 else
112 return SSDatabase();
113 }
114
115
116 //
117 // Reference Key management
118 //
119 void
120 SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle, CssmKey &ioKey, SSDatabase &inSSDatabase,
121 uint32 inKeyAttr, const CssmData *inKeyLabel)
122 {
123 return mSSCSPDLSession.makeReferenceKey(*this, inKeyHandle, ioKey, inSSDatabase, inKeyAttr, inKeyLabel);
124 }
125
126 SSKey &
127 SSCSPSession::lookupKey(const CssmKey &inKey)
128 {
129 return mSSCSPDLSession.lookupKey(inKey);
130 }
131
132
133 //
134 // Key creating and handeling members
135 //
136 void
137 SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle,
138 const Context &context,
139 const AccessCredentials &AccessCred,
140 const CssmKey &Key,
141 const CssmData *DescriptiveData,
142 CssmKey &WrappedKey,
143 CSSM_PRIVILEGE Privilege)
144 {
145 // @@@ Deal with permanent keys
146 const CssmKey *keyInContext =
147 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
148
149 KeyHandle contextKeyHandle = (keyInContext
150 ? lookupKey(*keyInContext).keyHandle()
151 : noKey);
152 clientSession().wrapKey(context, contextKeyHandle,
153 lookupKey(Key).keyHandle(), &AccessCred,
154 DescriptiveData, WrappedKey, *this);
155 }
156
157 void
158 SSCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle,
159 const Context &context,
160 const CssmKey *PublicKey,
161 const CssmWrappedKey &WrappedKey,
162 uint32 KeyUsage,
163 uint32 KeyAttr,
164 const CssmData *KeyLabel,
165 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
166 CssmKey &UnwrappedKey,
167 CssmData &DescriptiveData,
168 CSSM_PRIVILEGE Privilege)
169 {
170 SSDatabase database = getDatabase(context);
171 validateKeyAttr(KeyAttr);
172 const AccessCredentials *cred = NULL;
173 const AclEntryInput *owner = NULL;
174 if (CredAndAclEntry)
175 {
176 cred = AccessCredentials::overlay(CredAndAclEntry->AccessCred);
177 owner = &AclEntryInput::overlay(CredAndAclEntry->InitialAclEntry);
178 }
179
180 KeyHandle publicKey = noKey;
181 if (PublicKey)
182 {
183 if (PublicKey->blobType() == CSSM_KEYBLOB_RAW)
184 {
185 // @@@ We need to unwrap the publicKey into the SecurityServer
186 // before continuing
187 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
188 }
189 else
190 publicKey = lookupKey(*PublicKey).keyHandle();
191 }
192
193 // @@@ Deal with permanent keys
194 const CssmKey *keyInContext =
195 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
196
197 KeyHandle contextKeyHandle =
198 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;
199
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,
206 KeyLabel);
207 }
208
209 void
210 SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle,
211 const Context &context,
212 CssmData &param,
213 uint32 keyUsage,
214 uint32 keyAttr,
215 const CssmData *keyLabel,
216 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
217 CssmKey &derivedKey)
218 {
219 SSDatabase database = getDatabase(context);
220 validateKeyAttr(keyAttr);
221 const AccessCredentials *cred = NULL;
222 const AclEntryInput *owner = NULL;
223 if (credAndAclEntry)
224 {
225 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
226 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
227 }
228
229 /* optional BaseKey */
230 const CssmKey *keyInContext =
231 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
232 KeyHandle contextKeyHandle =
233 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;
234 KeyHandle keyHandle;
235 switch(context.algorithm()) {
236 case CSSM_ALGID_KEYCHAIN_KEY:
237 {
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());
242 }
243 break;
244 default:
245 clientSession().deriveKey(database.dbHandle(), context, contextKeyHandle, keyUsage,
246 keyAttr, param, cred, owner, keyHandle, derivedKey.header());
247 break;
248 }
249 makeReferenceKey(keyHandle, derivedKey, database, keyAttr, keyLabel);
250 }
251
252 void
253 SSCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle,
254 const Context &context,
255 uint32 keyUsage,
256 uint32 keyAttr,
257 const CssmData *keyLabel,
258 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
259 CssmKey &key,
260 CSSM_PRIVILEGE privilege)
261 {
262 SSDatabase database = getDatabase(context);
263 validateKeyAttr(keyAttr);
264 const AccessCredentials *cred = NULL;
265 const AclEntryInput *owner = NULL;
266 if (credAndAclEntry)
267 {
268 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
269 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
270 }
271
272 KeyHandle keyHandle;
273 clientSession().generateKey(database.dbHandle(), context, keyUsage,
274 keyAttr, cred, owner, keyHandle, key.header());
275 makeReferenceKey(keyHandle, key, database, keyAttr, keyLabel);
276 }
277
278 void
279 SSCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle,
280 const Context &context,
281 uint32 publicKeyUsage,
282 uint32 publicKeyAttr,
283 const CssmData *publicKeyLabel,
284 CssmKey &publicKey,
285 uint32 privateKeyUsage,
286 uint32 privateKeyAttr,
287 const CssmData *privateKeyLabel,
288 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
289 CssmKey &privateKey,
290 CSSM_PRIVILEGE privilege)
291 {
292 SSDatabase database = getDatabase(context);
293 validateKeyAttr(publicKeyAttr);
294 validateKeyAttr(privateKeyAttr);
295 const AccessCredentials *cred = NULL;
296 const AclEntryInput *owner = NULL;
297 if (credAndAclEntry)
298 {
299 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
300 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
301 }
302
303 /*
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...
308 */
309 if(!(publicKeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
310 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
311 }
312 KeyHandle pubKeyHandle, privKeyHandle;
313 clientSession().generateKey(database.dbHandle(), context,
314 publicKeyUsage, publicKeyAttr,
315 privateKeyUsage, privateKeyAttr,
316 cred, owner,
317 pubKeyHandle, publicKey.header(),
318 privKeyHandle, privateKey.header());
319 makeReferenceKey(privKeyHandle, privateKey, database, privateKeyAttr,
320 privateKeyLabel);
321 // @@@ What if this throws, we need to free privateKey.
322 makeReferenceKey(pubKeyHandle, publicKey, database, publicKeyAttr,
323 publicKeyLabel);
324 }
325
326 void
327 SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
328 CssmKey &PrivateKey)
329 {
330 unimplemented();
331 }
332
333 void
334 SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle,
335 const Context &Context,
336 const CssmKey &Key,
337 CSSM_KEY_SIZE &KeySize)
338 {
339 unimplemented();
340 }
341
342 void
343 SSCSPSession::FreeKey(const AccessCredentials *accessCred,
344 CssmKey &ioKey, CSSM_BOOL deleteKey)
345 {
346 if (ioKey.blobType() == CSSM_KEYBLOB_REFERENCE)
347 {
348 // @@@ Note that this means that detaching a session should free
349 // all keys ascociated with it or else...
350 // -- or else what?
351 // exactly!
352
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
355 // that!
356
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);
362 }
363 else
364 {
365 CSPFullPluginSession::FreeKey(accessCred, ioKey, deleteKey);
366 }
367 }
368
369
370 //
371 // Generation stuff.
372 //
373 void
374 SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
375 const Context &context,
376 CssmData &randomNumber)
377 {
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);
381
382 // @@@ What about the seed?
383 if (randomNumber.length())
384 {
385 if (randomNumber.length() < needed)
386 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
387 randomNumber.Length = needed;
388 clientSession().generateRandom(randomNumber);
389 }
390 else
391 {
392 randomNumber.Data = alloc<uint8>(needed);
393 try
394 {
395 randomNumber.Length = needed;
396 clientSession().generateRandom(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 persistant 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 }
610