]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/AppleCSP.cpp
Security-59306.11.20.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / AppleCSP.cpp
1 /*
2 * Copyright (c) 2000-2001,2011,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 // AppleCSP.cpp - top-level plugin and session implementation
21 //
22 #include "AppleCSP.h"
23 #include "AppleCSPSession.h"
24 #include "AppleCSPUtils.h"
25 #include <stdio.h>
26 #include "cspdebugging.h"
27 #include <security_cdsa_plugin/CSPsession.h>
28 #include <security_utilities/alloc.h>
29 #ifdef CRYPTKIT_CSP_ENABLE
30 #include "cryptkitcsp.h"
31 #include "FEEKeys.h"
32 #endif
33 #include <miscAlgFactory.h>
34 #ifdef ASC_CSP_ENABLE
35 #include "ascFactory.h"
36 #endif
37 #include <RSA_DSA_csp.h>
38 #include <RSA_DSA_keys.h>
39 #include <DH_csp.h>
40 #include <DH_keys.h>
41
42 #include "YarrowConnection.h"
43
44 //
45 // Make and break the plugin object
46 //
47 AppleCSPPlugin::AppleCSPPlugin() :
48 normAllocator(Allocator::standard(Allocator::normal)),
49 privAllocator(Allocator::standard(Allocator::sensitive)),
50 #ifdef CRYPTKIT_CSP_ENABLE
51 cryptKitFactory(new CryptKitFactory(&normAllocator, &privAllocator)),
52 #endif
53 miscAlgFactory(new MiscAlgFactory(&normAllocator, &privAllocator)),
54 #ifdef ASC_CSP_ENABLE
55 ascAlgFactory(new AscAlgFactory(&normAllocator, &privAllocator)),
56 #endif
57 rsaDsaAlgFactory(new RSA_DSA_Factory(&normAllocator, &privAllocator)),
58 dhAlgFactory(new DH_Factory(&normAllocator, &privAllocator))
59 {
60 // misc. once-per-address-space cruft...
61 }
62
63 AppleCSPPlugin::~AppleCSPPlugin()
64 {
65 #ifdef CRYPTKIT_CSP_ENABLE
66 delete cryptKitFactory;
67 #endif
68 delete miscAlgFactory;
69 #ifdef ASC_CSP_ENABLE
70 delete ascAlgFactory;
71 #endif
72 delete rsaDsaAlgFactory;
73 delete dhAlgFactory;
74 }
75
76
77 //
78 // Create a new plugin session, our way
79 //
80 PluginSession *AppleCSPPlugin::makeSession(
81 CSSM_MODULE_HANDLE handle,
82 const CSSM_VERSION &version,
83 uint32 subserviceId,
84 CSSM_SERVICE_TYPE subserviceType,
85 CSSM_ATTACH_FLAGS attachFlags,
86 const CSSM_UPCALLS &upcalls)
87 {
88 switch (subserviceType) {
89 case CSSM_SERVICE_CSP:
90 return new AppleCSPSession(handle,
91 *this,
92 version,
93 subserviceId,
94 subserviceType,
95 attachFlags,
96 upcalls);
97 default:
98 CssmError::throwMe(CSSMERR_CSSM_INVALID_SERVICE_MASK);
99 }
100 }
101
102
103 //
104 // Session constructor
105 //
106 AppleCSPSession::AppleCSPSession(
107 CSSM_MODULE_HANDLE handle,
108 AppleCSPPlugin &plug,
109 const CSSM_VERSION &version,
110 uint32 subserviceId,
111 CSSM_SERVICE_TYPE subserviceType,
112 CSSM_ATTACH_FLAGS attachFlags,
113 const CSSM_UPCALLS &upcalls)
114 : CSPFullPluginSession(handle,
115 plug,
116 version,
117 subserviceId,
118 subserviceType,
119 attachFlags,
120 upcalls),
121 #ifdef CRYPTKIT_CSP_ENABLE
122 cryptKitFactory(*(dynamic_cast<CryptKitFactory *>(plug.cryptKitFactory))),
123 #endif
124 miscAlgFactory(*(dynamic_cast<MiscAlgFactory *>(plug.miscAlgFactory))),
125 #ifdef ASC_CSP_ENABLE
126 ascAlgFactory(*(dynamic_cast<AscAlgFactory *>(plug.ascAlgFactory))),
127 #endif
128 rsaDsaAlgFactory(*(dynamic_cast<RSA_DSA_Factory *>(plug.rsaDsaAlgFactory))),
129 dhAlgFactory(*(dynamic_cast<DH_Factory *>(plug.dhAlgFactory))),
130 normAllocator(*this),
131 privAllocator(plug.privAlloc())
132 {
133 // anything?
134 }
135
136 AppleCSPSession::~AppleCSPSession()
137 {
138 // anything?
139 }
140
141 //
142 // Called at (CSSM) context create time. This is ignored; we do a full
143 // context setup later, at setupContext time.
144 //
145 CSPFullPluginSession::CSPContext *
146 AppleCSPSession::contextCreate(
147 CSSM_CC_HANDLE handle,
148 const Context &context)
149 {
150 return NULL;
151 }
152
153 //
154 // Called by CSPFullPluginSession when an op is actually commencing.
155 // Context can safely assumed to be fully formed and stable for the
156 // duration of the op; thus we wait until now to set up our
157 // CSPContext as appropriate to the op.
158 //
159 void AppleCSPSession::setupContext(
160 CSPContext * &cspCtx,
161 const Context &context,
162 bool encoding)
163 {
164 /*
165 * Note we leave the decision as to whether it's OK to
166 * reuse a context to the individual factories.
167 */
168 if (rsaDsaAlgFactory.setup(*this, cspCtx, context)) {
169 CASSERT(cspCtx != NULL);
170 return;
171 }
172 if (miscAlgFactory.setup(*this, cspCtx, context)) {
173 CASSERT(cspCtx != NULL);
174 return;
175 }
176 if (dhAlgFactory.setup(*this, cspCtx, context)) {
177 CASSERT(cspCtx != NULL);
178 return;
179 }
180 #ifdef CRYPTKIT_CSP_ENABLE
181 if (cryptKitFactory.setup(*this, cspCtx, context)) {
182 CASSERT(cspCtx != NULL);
183 return;
184 }
185 #endif
186 #ifdef ASC_CSP_ENABLE
187 if (ascAlgFactory.setup(*this, cspCtx, context)) {
188 CASSERT(cspCtx != NULL);
189 return;
190 }
191 #endif
192 if(setup(cspCtx, context)) {
193 CASSERT(cspCtx != NULL);
194 return;
195 }
196 dprintf0("AppleCSPSession::setupContext: invalid algorithm\n");
197 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
198 }
199
200 /*
201 * Used for generating crypto contexts at this level.
202 * Analogous to AlgorithmFactory.setup().
203 */
204 bool AppleCSPSession::setup(
205 CSPFullPluginSession::CSPContext * &cspCtx,
206 const Context &context)
207 {
208 if (cspCtx) {
209 return false; // not ours or already set
210 }
211
212 switch(context.type()) {
213 case CSSM_ALGCLASS_RANDOMGEN:
214 switch (context.algorithm()) {
215 case CSSM_ALGID_APPLE_YARROW:
216 cspCtx = new YarrowContext(*this);
217 return true;
218 /* other random algs here */
219 default:
220 return false;
221 }
222 /* other contexts here */
223 default:
224 return false;
225 }
226 }
227
228 //
229 // Context for CSSM_ALGID_APPLE_YARROW.
230 //
231 YarrowContext::YarrowContext(AppleCSPSession &session)
232 : AppleCSPContext(session)
233 {
234 // nothing for now
235 }
236
237 YarrowContext::~YarrowContext()
238 {
239 // nothing for now
240 }
241
242 //
243 // Only job here is to snag the length and process the optional seed argument
244 //
245 void YarrowContext::init(
246 const Context &context,
247 bool encoding)
248 {
249 /* stash requested length for use later in outputSize() */
250 outSize = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE,
251 CSSMERR_CSP_INVALID_ATTR_OUTPUT_SIZE);
252
253 /* optional seed */
254 CssmCryptoData *cseed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED);
255 if(cseed == NULL) {
256 /* we're done */
257 return;
258 }
259 CssmData seed = (*cseed)();
260 if((seed.Length == 0) ||
261 (seed.Data == NULL)) {
262 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED);
263 }
264 session().addEntropy((size_t)seed.Length, seed.Data);
265 }
266
267 void YarrowContext::final(
268 CssmData &out)
269 {
270 session().getRandomBytes((size_t)out.Length, out.Data);
271 }
272
273 /***
274 *** Binary Key support.
275 ***/
276
277 // Given a CSSM_DATA, extract its KeyRef.
278 static KeyRef CssmDataToKeyRef(
279 const CSSM_DATA &data)
280 {
281 if(data.Length != sizeof(KeyRef)) {
282 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
283 }
284
285 uint8 *cp = data.Data + sizeof(KeyRef) - 1;
286 KeyRef keyRef = 0;
287 for(unsigned dex=0; dex<sizeof(KeyRef); dex++) {
288 keyRef <<= 8;
289 keyRef |= *cp--;
290 }
291 return keyRef;
292 }
293
294 // Place a KeyRef into a CSSM_DATA, mallocing if necessary.
295 static void keyRefToCssmData(
296 KeyRef keyRef,
297 CSSM_DATA &data,
298 Allocator &allocator)
299 {
300 if(data.Length > sizeof(keyRef)) {
301 /* don't leave old raw key material lying around */
302 memset(data.Data + sizeof(keyRef), 0, data.Length - sizeof(keyRef));
303 }
304 else if(data.Length < sizeof(keyRef)) {
305 /* not enough space for even a keyRef, force realloc */
306 allocator.free(data.Data);
307 data.Data = NULL;
308 data.Length = 0;
309 }
310 setUpData(data, sizeof(keyRef), allocator);
311
312 uint8 *cp = data.Data;
313 for(unsigned i=0; i<sizeof(keyRef); i++) {
314 *cp++ = keyRef & 0xff;
315 keyRef >>= 8;
316 }
317 }
318
319 // Look up a BinaryKey by its KeyRef. Returns NULL if not
320 // found. refKeyMapLock held on entry and exit.
321 BinaryKey *AppleCSPSession::lookupKeyRef(
322 KeyRef keyRef)
323 {
324 const BinaryKey *binKey;
325
326 // use safe version, don't create new entry if this key
327 // isn't there
328 keyMap::iterator it = refKeyMap.find(keyRef);
329 if(it == refKeyMap.end()) {
330 return NULL;
331 }
332 binKey = it->second;
333 assert(binKey == reinterpret_cast<const BinaryKey *>(keyRef));
334 assert(binKey->mKeyRef == keyRef);
335 return const_cast<BinaryKey *>(binKey);
336 }
337
338 // add a BinaryKey to our refKeyMap. Sets up cssmKey
339 // as appropriate.
340 void AppleCSPSession::addRefKey(
341 BinaryKey &binKey,
342 CssmKey &cssmKey)
343 {
344 // for now, KeyRef is just the address of the BinaryKey
345 KeyRef keyRef = reinterpret_cast<KeyRef>(&binKey);
346
347 binKey.mKeyRef = keyRef;
348 binKey.mKeyHeader = CssmKey::Header::overlay(cssmKey.KeyHeader);
349 {
350 StLock<Mutex> _(refKeyMapLock);
351 assert(lookupKeyRef(keyRef) == NULL);
352 refKeyMap[keyRef] = &binKey;
353 }
354 cssmKey.KeyHeader.BlobType = CSSM_KEYBLOB_REFERENCE;
355 cssmKey.KeyHeader.Format = CSSM_KEYBLOB_REF_FORMAT_INTEGER;
356 keyRefToCssmData(keyRef, cssmKey.KeyData, normAllocator);
357 secinfo("freeKey", "CSP addRefKey key %p keyData %p keyRef %p",
358 &cssmKey, cssmKey.KeyData.Data, &binKey);
359 }
360
361 // Given a CssmKey in reference form, obtain the associated
362 // BinaryKey. Throws CSSMERR_CSP_INVALID_KEY_REFERENCE if
363 // key not found in session key map.
364 BinaryKey & AppleCSPSession::lookupRefKey(
365 const CssmKey &cssmKey)
366 {
367 KeyRef keyRef;
368 BinaryKey *binKey;
369
370 keyRef = CssmDataToKeyRef(cssmKey.KeyData);
371 {
372 StLock<Mutex> _(refKeyMapLock);
373 binKey = lookupKeyRef(keyRef);
374 }
375 if(binKey == NULL) {
376 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
377 }
378 assert(Guid::overlay(binKey->mKeyHeader.CspId) == plugin.myGuid());
379
380 /*
381 * Verify sensitive fields have not changed between when the BinaryKey was
382 * created/stored and when the caller passed in the ref key.
383 * Some fields were changed by addRefKey, so make a local copy....
384 */
385 CSSM_KEYHEADER localHdr = cssmKey.KeyHeader;
386 localHdr.BlobType = binKey->mKeyHeader.BlobType;
387 localHdr.Format = binKey->mKeyHeader.Format;
388 if(memcmp(&localHdr, &binKey->mKeyHeader, sizeof(CSSM_KEYHEADER))) {
389 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
390 }
391 return (*binKey);
392 }
393
394 // CSPFullPluginSession declares & implements this.
395 // Note that we ignore the delete argument; since we don't
396 // store anything, freeing is the same as deleting.
397 void AppleCSPSession::FreeKey(
398 const AccessCredentials *AccessCred,
399 CssmKey &KeyPtr,
400 CSSM_BOOL Delete)
401 {
402
403 if((KeyPtr.blobType() == CSSM_KEYBLOB_REFERENCE) &&
404 (KeyPtr.cspGuid() == plugin.myGuid())) {
405 // it's a ref key we generated - delete associated BinaryKey
406 KeyRef keyRef = CssmDataToKeyRef(KeyPtr.KeyData);
407 {
408 StLock<Mutex> _(refKeyMapLock);
409 BinaryKey *binKey = lookupKeyRef(keyRef);
410 if(binKey != NULL) {
411 secinfo("freeKey", "CSP FreeKey key %p keyData %p binKey %p",
412 &KeyPtr, KeyPtr.KeyData.Data, binKey);
413 try {
414 refKeyMap.erase(keyRef);
415 delete binKey;
416 }
417 catch (...) {
418 errorLog0("Error deleting/erasing known "
419 "ref key\n");
420 }
421 }
422 else {
423 secinfo("freeKey", "CSP freeKey unknown key");
424 }
425 }
426 }
427 CSPFullPluginSession::FreeKey(AccessCred, KeyPtr, Delete);
428 }
429
430 /* Passthrough, used for key digest */
431 void AppleCSPSession::PassThrough(
432 CSSM_CC_HANDLE CCHandle,
433 const Context &Context,
434 uint32 PassThroughId,
435 const void *InData,
436 void **OutData)
437 {
438 *OutData = NULL;
439
440 /* validate context */
441 if(Context.type() != CSSM_ALGCLASS_NONE) {
442 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
443 }
444
445 switch(PassThroughId) {
446 case CSSM_APPLECSP_KEYDIGEST:
447 {
448 CssmKey &key = Context.get<CssmKey>(
449 CSSM_ATTRIBUTE_KEY,
450 CSSMERR_CSP_MISSING_ATTR_KEY);
451
452 /* validate key as best we can */
453 switch(key.keyClass()) {
454 case CSSM_KEYCLASS_PUBLIC_KEY:
455 case CSSM_KEYCLASS_PRIVATE_KEY:
456 case CSSM_KEYCLASS_SESSION_KEY:
457 break;
458 default:
459 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
460 }
461
462 /*
463 * Ref key: obtain binary, ask it for blob
464 * Raw key: get info provider, ask it for the blob. This
465 * allows for an optimized path which avoids
466 * converting to a BinaryKey.
467 */
468 CssmData blobToHash;
469 switch(key.blobType()) {
470 case CSSM_KEYBLOB_RAW:
471 {
472 CSPKeyInfoProvider *provider = infoProvider(key);
473 bool converted =
474 provider->getHashableBlob(privAllocator, blobToHash);
475 if(converted) {
476 /* took optimized case; proceed */
477 delete provider;
478 break;
479 }
480
481 /* convert to BinaryKey and ask it to do the work */
482 BinaryKey *binKey;
483 CSSM_KEYATTR_FLAGS flags = 0; // not used
484 provider->CssmKeyToBinary(NULL, // no paramKey
485 flags,
486 &binKey);
487 binKey->mKeyHeader =
488 CssmKey::Header::overlay(key.KeyHeader);
489 CSSM_KEYBLOB_FORMAT rawFormat;
490 rawFormat = CSSM_KEYBLOB_RAW_FORMAT_DIGEST;
491 CSSM_KEYATTR_FLAGS attrFlags = 0;
492 binKey->generateKeyBlob(privAllocator,
493 blobToHash,
494 rawFormat,
495 *this,
496 NULL,
497 attrFlags);
498 delete binKey;
499 delete provider;
500 break;
501 }
502 case CSSM_KEYBLOB_REFERENCE:
503 {
504 BinaryKey &binKey = lookupRefKey(key);
505 CSSM_KEYBLOB_FORMAT rawFormat;
506 rawFormat = CSSM_KEYBLOB_RAW_FORMAT_DIGEST;
507 CSSM_KEYATTR_FLAGS attrFlags = 0;
508 binKey.generateKeyBlob(privAllocator,
509 blobToHash,
510 rawFormat,
511 *this,
512 NULL,
513 attrFlags);
514 }
515 break;
516 default:
517 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
518 }
519
520 /* obtain sha1 hash of blobToHash */
521
522 CSSM_DATA_PTR outHash = NULL;
523 try {
524 outHash =
525 (CSSM_DATA_PTR)normAllocator.malloc(sizeof(CSSM_DATA));
526 outHash->Data =
527 (uint8 *)normAllocator.malloc(SHA1_DIGEST_SIZE);
528 outHash->Length = SHA1_DIGEST_SIZE;
529 }
530 catch(...) {
531 freeCssmData(blobToHash, privAllocator);
532 throw;
533 }
534 cspGenSha1Hash(blobToHash.data(), blobToHash.length(),
535 outHash->Data);
536 freeCssmData(blobToHash, privAllocator);
537 *OutData = outHash;
538 return;
539 }
540 default:
541 CssmError::throwMe(CSSMERR_CSP_INVALID_PASSTHROUGH_ID);
542 }
543 /* NOT REACHED */
544 }
545
546 /*
547 * CSPSession version of QueryKeySizeInBits.
548 */
549 void AppleCSPSession::getKeySize(const CssmKey &key,
550 CSSM_KEY_SIZE &size)
551 {
552 CSPKeyInfoProvider *provider = infoProvider(key);
553 try {
554 provider->QueryKeySizeInBits(size);
555 }
556 catch(...) {
557 /* don't leak this on error */
558 delete provider;
559 throw;
560 }
561 delete provider;
562 }
563
564 void AppleCSPSession::getRandomBytes(size_t length, uint8 *cp)
565 {
566 try {
567 cspGetRandomBytes(cp, (unsigned)length);
568 }
569 catch(...) {
570 errorLog0("CSP: YarrowClient failure\n");
571 }
572 }
573
574 void AppleCSPSession::addEntropy(size_t length, const uint8 *cp)
575 {
576 try {
577 cspAddEntropy(cp, (unsigned)length);
578 }
579 catch(...) {
580 #if CSP_ALLOW_FEE_RNG
581 return;
582 #else
583 throw;
584 #endif
585 }
586 }
587
588 /***
589 *** CSPKeyInfoProvider support.
590 ***/
591
592 /*
593 * Find a CSPKeyInfoProvider subclass for the specified key.
594 */
595 CSPKeyInfoProvider *AppleCSPSession::infoProvider(
596 const CssmKey &key)
597 {
598 CSPKeyInfoProvider *provider = NULL;
599
600 provider = RSAKeyInfoProvider::provider(key, *this);
601 if(provider != NULL) {
602 return provider;
603 }
604
605 provider = SymmetricKeyInfoProvider::provider(key, *this);
606 if(provider != NULL) {
607 return provider;
608 }
609
610 #ifdef CRYPTKIT_CSP_ENABLE
611 provider = CryptKit::FEEKeyInfoProvider::provider(key, *this);
612 if(provider != NULL) {
613 return provider;
614 }
615 #endif
616
617 provider = DSAKeyInfoProvider::provider(key, *this);
618 if(provider != NULL) {
619 return provider;
620 }
621
622 provider = DHKeyInfoProvider::provider(key, *this);
623 if(provider != NULL) {
624 return provider;
625 }
626
627 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
628 }
629