]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_sd_cspdl/lib/SDCSPSession.cpp
Security-59306.101.1.tar.gz
[apple/security.git] / OSX / libsecurity_sd_cspdl / lib / SDCSPSession.cpp
1 /*
2 * Copyright (c) 2004,2008,2011-2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // SDCSPSession.cpp - Security Server CSP session.
27 //
28 #include "SDCSPSession.h"
29
30 #include "SDCSPDLPlugin.h"
31 #include "SDDLSession.h"
32 #include "SDKey.h"
33 #include <security_cdsa_utilities/cssmbridge.h>
34 #include <memory>
35
36 using namespace std;
37 using namespace SecurityServer;
38
39 //
40 // SDCSPSession -- Security Server CSP session
41 //
42 SDCSPSession::SDCSPSession(CSSM_MODULE_HANDLE handle,
43 SDCSPDLPlugin &plug,
44 const CSSM_VERSION &version,
45 uint32 subserviceId,
46 CSSM_SERVICE_TYPE subserviceType,
47 CSSM_ATTACH_FLAGS attachFlags,
48 const CSSM_UPCALLS &upcalls,
49 SDCSPDLSession &ssCSPDLSession,
50 CssmClient::CSP &rawCsp)
51 : CSPFullPluginSession(handle, plug, version, subserviceId, subserviceType,
52 attachFlags, upcalls),
53 mSDCSPDLSession(ssCSPDLSession),
54 mSDFactory(plug.mSDFactory),
55 mRawCsp(rawCsp),
56 mClientSession(Allocator::standard(), *this)
57 {
58 }
59
60 //
61 // Called at (CSSM) context create time. This is ignored; we do a full
62 // context setup later, at setupContext time.
63 //
64 CSPFullPluginSession::CSPContext *
65 SDCSPSession::contextCreate(CSSM_CC_HANDLE handle, const Context &context)
66 {
67 return NULL;
68 }
69
70
71 //
72 // Called by CSPFullPluginSession when an op is actually commencing.
73 // Context can safely assumed to be fully formed and stable for the
74 // duration of the op; thus we wait until now to set up our
75 // CSPContext as appropriate to the op.
76 //
77 void
78 SDCSPSession::setupContext(CSPContext * &cspCtx,
79 const Context &context,
80 bool encoding)
81 {
82 // note we skip this if this CSPContext is being reused
83 if (cspCtx == NULL)
84 {
85
86 if (mSDFactory.setup(*this, cspCtx, context, encoding))
87 return;
88
89 #if 0
90 if (mBSafe4Factory.setup(*this, cspCtx, context))
91 return;
92
93 if (mCryptKitFactory.setup(*this, cspCtx, context))
94 return;
95 #endif
96
97 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
98 }
99 }
100
101
102 //
103 // DL interaction
104 //
105 CSSM_DB_HANDLE
106 SDCSPSession::getDatabase(const Context &context)
107 {
108 return getDatabase(context.get<CSSM_DL_DB_HANDLE>(CSSM_ATTRIBUTE_DL_DB_HANDLE));
109 }
110
111 CSSM_DB_HANDLE
112 SDCSPSession::getDatabase(CSSM_DL_DB_HANDLE *aDLDbHandle)
113 {
114 if (aDLDbHandle)
115 return aDLDbHandle->DBHandle;
116 else
117 return CSSM_INVALID_HANDLE;
118 }
119
120
121 //
122 // Reference Key management
123 //
124 void
125 SDCSPSession::makeReferenceKey(KeyHandle inKeyHandle, CssmKey &ioKey, CSSM_DB_HANDLE inDBHandle,
126 uint32 inKeyAttr, const CssmData *inKeyLabel)
127 {
128 return mSDCSPDLSession.makeReferenceKey(*this, inKeyHandle, ioKey, inDBHandle, inKeyAttr, inKeyLabel);
129 }
130
131 SDKey &
132 SDCSPSession::lookupKey(const CssmKey &inKey)
133 {
134 return mSDCSPDLSession.lookupKey(inKey);
135 }
136
137
138 //
139 // Key creating and handeling members
140 //
141 void
142 SDCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle,
143 const Context &context,
144 const AccessCredentials &AccessCred,
145 const CssmKey &Key,
146 const CssmData *DescriptiveData,
147 CssmKey &WrappedKey,
148 CSSM_PRIVILEGE Privilege)
149 {
150 // @@@ Deal with permanent keys
151 const CssmKey *keyInContext =
152 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
153
154 KeyHandle contextKeyHandle = (keyInContext
155 ? lookupKey(*keyInContext).keyHandle()
156 : noKey);
157 clientSession().wrapKey(context, contextKeyHandle,
158 lookupKey(Key).keyHandle(), &AccessCred,
159 DescriptiveData, WrappedKey, *this);
160 }
161
162 void
163 SDCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle,
164 const Context &context,
165 const CssmKey *PublicKey,
166 const CssmWrappedKey &WrappedKey,
167 uint32 KeyUsage,
168 uint32 KeyAttr,
169 const CssmData *KeyLabel,
170 const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
171 CssmKey &UnwrappedKey,
172 CssmData &DescriptiveData,
173 CSSM_PRIVILEGE Privilege)
174 {
175 CSSM_DB_HANDLE database = getDatabase(context);
176 validateKeyAttr(KeyAttr);
177 const AccessCredentials *cred = NULL;
178 const AclEntryInput *owner = NULL;
179 if (CredAndAclEntry)
180 {
181 cred = AccessCredentials::overlay(CredAndAclEntry->AccessCred);
182 owner = &AclEntryInput::overlay(CredAndAclEntry->InitialAclEntry);
183 }
184
185 KeyHandle publicKey = noKey;
186 if (PublicKey)
187 {
188 if (PublicKey->blobType() == CSSM_KEYBLOB_RAW)
189 {
190 // @@@ We need to unwrap the publicKey into the SecurityServer
191 // before continuing
192 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
193 }
194 else
195 publicKey = lookupKey(*PublicKey).keyHandle();
196 }
197
198 // @@@ Deal with permanent keys
199 const CssmKey *keyInContext =
200 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
201
202 KeyHandle contextKeyHandle =
203 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;
204
205 KeyHandle unwrappedKeyHandle;
206 clientSession().unwrapKey(ClientSession::toIPCHandle(database), context, contextKeyHandle,
207 publicKey, WrappedKey, KeyUsage, KeyAttr,
208 cred, owner, DescriptiveData, unwrappedKeyHandle,
209 UnwrappedKey.header(), *this);
210 makeReferenceKey(unwrappedKeyHandle, UnwrappedKey, database, KeyAttr,
211 KeyLabel);
212 }
213
214 void
215 SDCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle,
216 const Context &context,
217 CssmData &param,
218 uint32 keyUsage,
219 uint32 keyAttr,
220 const CssmData *keyLabel,
221 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
222 CssmKey &derivedKey)
223 {
224 CSSM_DB_HANDLE database = getDatabase(context);
225 validateKeyAttr(keyAttr);
226 const AccessCredentials *cred = NULL;
227 const AclEntryInput *owner = NULL;
228 if (credAndAclEntry)
229 {
230 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
231 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
232 }
233
234 /* optional BaseKey */
235 const CssmKey *keyInContext =
236 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
237 KeyHandle contextKeyHandle =
238 keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;
239 KeyHandle keyHandle;
240 switch(context.algorithm()) {
241 case CSSM_ALGID_KEYCHAIN_KEY:
242 {
243 // special interpretation: take DLDBHandle -> DbHandle from params
244 clientSession().extractMasterKey(ClientSession::toIPCHandle(database), context,
245 (DbHandle)getDatabase(param.interpretedAs<CSSM_DL_DB_HANDLE>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE)),
246 keyUsage, keyAttr, cred, owner, keyHandle, derivedKey.header());
247 }
248 break;
249 default:
250 clientSession().deriveKey(ClientSession::toIPCHandle(database), context, contextKeyHandle, keyUsage,
251 keyAttr, param, cred, owner, keyHandle, derivedKey.header());
252 break;
253 }
254 makeReferenceKey(keyHandle, derivedKey, database, keyAttr, keyLabel);
255 }
256
257 void
258 SDCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle,
259 const Context &context,
260 uint32 keyUsage,
261 uint32 keyAttr,
262 const CssmData *keyLabel,
263 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
264 CssmKey &key,
265 CSSM_PRIVILEGE privilege)
266 {
267 CSSM_DB_HANDLE database = getDatabase(context);
268 validateKeyAttr(keyAttr);
269 const AccessCredentials *cred = NULL;
270 const AclEntryInput *owner = NULL;
271 if (credAndAclEntry)
272 {
273 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
274 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
275 }
276
277 KeyHandle keyHandle;
278 clientSession().generateKey(ClientSession::toIPCHandle(database), context, keyUsage,
279 keyAttr, cred, owner, keyHandle, key.header());
280 makeReferenceKey(keyHandle, key, database, keyAttr, keyLabel);
281 }
282
283 void
284 SDCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle,
285 const Context &context,
286 uint32 publicKeyUsage,
287 uint32 publicKeyAttr,
288 const CssmData *publicKeyLabel,
289 CssmKey &publicKey,
290 uint32 privateKeyUsage,
291 uint32 privateKeyAttr,
292 const CssmData *privateKeyLabel,
293 const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
294 CssmKey &privateKey,
295 CSSM_PRIVILEGE privilege)
296 {
297 CSSM_DB_HANDLE database = getDatabase(context);
298 validateKeyAttr(publicKeyAttr);
299 validateKeyAttr(privateKeyAttr);
300 const AccessCredentials *cred = NULL;
301 const AclEntryInput *owner = NULL;
302 if (credAndAclEntry)
303 {
304 cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
305 owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
306 }
307
308 /*
309 * Public keys must be extractable in the clear - that's the Apple
310 * policy. The raw CSP is unable to enforce the extractable
311 * bit since it always sees that as true (it's managed and forced
312 * true by the SecurityServer). So...
313 */
314 if(!(publicKeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
315 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
316 }
317 KeyHandle pubKeyHandle, privKeyHandle;
318 clientSession().generateKey(ClientSession::toIPCHandle(database), context,
319 publicKeyUsage, publicKeyAttr,
320 privateKeyUsage, privateKeyAttr,
321 cred, owner,
322 pubKeyHandle, publicKey.header(),
323 privKeyHandle, privateKey.header());
324 makeReferenceKey(privKeyHandle, privateKey, database, privateKeyAttr,
325 privateKeyLabel);
326 // @@@ What if this throws, we need to free privateKey.
327 makeReferenceKey(pubKeyHandle, publicKey, database, publicKeyAttr,
328 publicKeyLabel);
329 }
330
331 void
332 SDCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey,
333 CssmKey &PrivateKey)
334 {
335 unimplemented();
336 }
337
338 void
339 SDCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle,
340 const Context *Context,
341 const CssmKey *Key,
342 CSSM_KEY_SIZE &KeySize)
343 {
344 unimplemented();
345 }
346
347 void
348 SDCSPSession::FreeKey(const AccessCredentials *accessCred,
349 CssmKey &ioKey, CSSM_BOOL deleteKey)
350 {
351 if (ioKey.blobType() == CSSM_KEYBLOB_REFERENCE)
352 {
353 // @@@ Note that this means that detaching a session should free
354 // all keys ascociated with it or else...
355 // -- or else what?
356 // exactly!
357
358 // @@@ There are thread safety issues when deleting a key that is
359 // in use by another thread, but the answer to that is: Don't do
360 // that!
361
362 // Find the key in the map. Tell tell the key to free itself
363 // (when the auto_ptr deletes the key it removes itself from the map).
364 secinfo("freeKey", "CSPDL FreeKey");
365 auto_ptr<SDKey> ssKey(&mSDCSPDLSession.find<SDKey>(ioKey));
366 ssKey->free(accessCred, ioKey, deleteKey);
367 }
368 else
369 {
370 CSPFullPluginSession::FreeKey(accessCred, ioKey, deleteKey);
371 }
372 }
373
374
375 //
376 // Generation stuff.
377 //
378 void
379 SDCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle,
380 const Context &context,
381 CssmData &randomNumber)
382 {
383 checkOperation(context.type(), CSSM_ALGCLASS_RANDOMGEN);
384 // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED);
385 uint32 needed = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE);
386
387 // @@@ What about the seed?
388 if (randomNumber.length())
389 {
390 if (randomNumber.length() < needed)
391 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
392 clientSession().generateRandom(context, randomNumber);
393 }
394 else
395 {
396 randomNumber.Data = alloc<uint8>(needed);
397 try
398 {
399 clientSession().generateRandom(context, randomNumber);
400 }
401 catch(...)
402 {
403 free(randomNumber.Data);
404 randomNumber.Data = NULL;
405 throw;
406 }
407 }
408 }
409
410 //
411 // Login/Logout and token operational maintainance. These mean little
412 // without support by the actual implementation, but we can help...
413 // @@@ Should this be in CSP[non-Full]PluginSession?
414 //
415 void
416 SDCSPSession::Login(const AccessCredentials &AccessCred,
417 const CssmData *LoginName,
418 const void *Reserved)
419 {
420 // @@@ Do a login to the securityServer making keys persistent until it
421 // goes away
422 unimplemented();
423 }
424
425 void
426 SDCSPSession::Logout()
427 {
428 unimplemented();
429 }
430
431 void
432 SDCSPSession::VerifyDevice(const CssmData &DeviceCert)
433 {
434 CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED);
435 }
436
437 void
438 SDCSPSession::GetOperationalStatistics(CSPOperationalStatistics &statistics)
439 {
440 unimplemented();
441 }
442
443
444 //
445 // Utterly miscellaneous, rarely used, strange functions
446 //
447 void
448 SDCSPSession::RetrieveCounter(CssmData &Counter)
449 {
450 unimplemented();
451 }
452
453 void
454 SDCSPSession::RetrieveUniqueId(CssmData &UniqueID)
455 {
456 unimplemented();
457 }
458
459 void
460 SDCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData)
461 {
462 unimplemented();
463 }
464
465
466 //
467 // ACL retrieval and change operations
468 //
469 void
470 SDCSPSession::GetKeyOwner(const CssmKey &Key,
471 CSSM_ACL_OWNER_PROTOTYPE &Owner)
472 {
473 lookupKey(Key).getOwner(Owner, *this);
474 }
475
476 void
477 SDCSPSession::ChangeKeyOwner(const AccessCredentials &AccessCred,
478 const CssmKey &Key,
479 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
480 {
481 lookupKey(Key).changeOwner(AccessCred,
482 AclOwnerPrototype::overlay(NewOwner));
483 }
484
485 void
486 SDCSPSession::GetKeyAcl(const CssmKey &Key,
487 const CSSM_STRING *SelectionTag,
488 uint32 &NumberOfAclInfos,
489 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
490 {
491 lookupKey(Key).getAcl(reinterpret_cast<const char *>(SelectionTag),
492 NumberOfAclInfos,
493 reinterpret_cast<AclEntryInfo *&>(AclInfos), *this);
494 }
495
496 void
497 SDCSPSession::ChangeKeyAcl(const AccessCredentials &AccessCred,
498 const CSSM_ACL_EDIT &AclEdit,
499 const CssmKey &Key)
500 {
501 lookupKey(Key).changeAcl(AccessCred, AclEdit::overlay(AclEdit));
502 }
503
504 void
505 SDCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner)
506 {
507 unimplemented();
508 }
509
510 void
511 SDCSPSession::ChangeLoginOwner(const AccessCredentials &AccessCred,
512 const CSSM_ACL_OWNER_PROTOTYPE &NewOwner)
513 {
514 unimplemented();
515 }
516
517 void
518 SDCSPSession::GetLoginAcl(const CSSM_STRING *SelectionTag,
519 uint32 &NumberOfAclInfos,
520 CSSM_ACL_ENTRY_INFO_PTR &AclInfos)
521 {
522 unimplemented();
523 }
524
525 void
526 SDCSPSession::ChangeLoginAcl(const AccessCredentials &AccessCred,
527 const CSSM_ACL_EDIT &AclEdit)
528 {
529 unimplemented();
530 }
531
532
533
534 //
535 // Passthroughs
536 //
537 void
538 SDCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle,
539 const Context &context,
540 uint32 passThroughId,
541 const void *inData,
542 void **outData)
543 {
544 checkOperation(context.type(), CSSM_ALGCLASS_NONE);
545 switch (passThroughId) {
546 case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE:
547 {
548 // inData unused, must be NULL
549 if (inData)
550 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
551
552 // outData required, must be pointer-to-pointer-to-KeyHandle
553 KeyHandle &result = Required(reinterpret_cast<KeyHandle *>(outData));
554
555 // we'll take the key from the context
556 const CssmKey &key =
557 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
558
559 // all ready
560 result = lookupKey(key).keyHandle();
561 break;
562 }
563 case CSSM_APPLECSP_KEYDIGEST:
564 {
565 // inData unused, must be NULL
566 if (inData)
567 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
568
569 // outData required
570 Required(outData);
571
572 // take the key from the context, convert to KeyHandle
573 const CssmKey &key =
574 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
575 KeyHandle keyHandle = lookupKey(key).keyHandle();
576
577 // allocate digest holder on app's behalf
578 CSSM_DATA *digest = alloc<CSSM_DATA>(sizeof(CSSM_DATA));
579 digest->Data = NULL;
580 digest->Length = 0;
581
582 // go
583 try {
584 clientSession().getKeyDigest(keyHandle, CssmData::overlay(*digest));
585 }
586 catch(...) {
587 free(digest);
588 throw;
589 }
590 *outData = digest;
591 break;
592 }
593
594 default:
595 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID);
596 }
597 }
598
599 /* Validate requested key attr flags for newly generated keys */
600 void SDCSPSession::validateKeyAttr(uint32 reqKeyAttr)
601 {
602 if(reqKeyAttr & (CSSM_KEYATTR_RETURN_DATA)) {
603 /* CSPDL only supports reference keys */
604 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
605 }
606 if(reqKeyAttr & (CSSM_KEYATTR_ALWAYS_SENSITIVE |
607 CSSM_KEYATTR_NEVER_EXTRACTABLE)) {
608 /* invalid for any CSP */
609 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
610 }
611 /* There may be more, but we'll leave it to SS and CSP to decide */
612 }