]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_sd_cspdl/lib/SDContext.cpp
Security-59306.101.1.tar.gz
[apple/security.git] / OSX / libsecurity_sd_cspdl / lib / SDContext.cpp
1 /*
2 * Copyright (c) 2004,2011-2012,2014 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 // SDContext - cryptographic contexts for the security server
27 //
28 #include "SDContext.h"
29
30 #include "SDCSPSession.h"
31 #include "SDKey.h"
32 #include <security_utilities/debugging.h>
33
34 #define ssCryptDebug(args...) secinfo("ssCrypt", ## args)
35
36 using namespace SecurityServer;
37
38 //
39 // SDContext
40 //
41 SDContext::SDContext(SDCSPSession &session)
42 : mSession(session), mContext(NULL)
43 {
44 }
45
46 void SDContext::clearOutBuf()
47 {
48 if(mOutBuf.Data) {
49 mSession.free(mOutBuf.Data);
50 mOutBuf.clear();
51 }
52 }
53
54 void SDContext::copyOutBuf(CssmData &out)
55 {
56 if(out.length() < mOutBuf.length()) {
57 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
58 }
59 memmove(out.Data, mOutBuf.Data, mOutBuf.Length);
60 out.Length = mOutBuf.Length;
61 clearOutBuf();
62 }
63
64 void
65 SDContext::init(const Context &context,
66 bool /* encoding */) // @@@ should be removed from API since it's already in mDirection
67 {
68 mContext = &context;
69 clearOutBuf();
70 }
71
72 SecurityServer::ClientSession &
73 SDContext::clientSession()
74 {
75 return mSession.clientSession();
76 }
77
78
79 //
80 // SDRandomContext -- Context for GenerateRandom operations
81 //
82 SDRandomContext::SDRandomContext(SDCSPSession &session) : SDContext(session) {}
83
84 void
85 SDRandomContext::init(const Context &context, bool encoding)
86 {
87 SDContext::init(context, encoding);
88
89 // set/freeze output size
90 mOutSize = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE);
91
92 #if 0
93 // seed the PRNG (if specified)
94 if (const CssmCryptoData *seed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED)) {
95 const CssmData &seedValue = (*seed)();
96 clientSession().seedRandom(seedValue);
97 }
98 #endif
99 }
100
101 size_t
102 SDRandomContext::outputSize(bool final, size_t inSize)
103 {
104 return mOutSize;
105 }
106
107 void
108 SDRandomContext::final(CssmData &out)
109 {
110 clientSession().generateRandom(*mContext, out);
111 }
112
113
114 // signature contexts
115 SDSignatureContext::SDSignatureContext(SDCSPSession &session)
116 : SDContext(session),
117 mKeyHandle(noKey),
118 mNullDigest(NULL),
119 mDigest(NULL)
120 {
121 /* nothing else for now */
122 }
123
124 SDSignatureContext::~SDSignatureContext()
125 {
126 delete mNullDigest;
127 delete mDigest;
128 }
129
130 void SDSignatureContext::init(const Context &context, bool signing)
131 {
132 SDContext::init(context, signing);
133
134 /* reusable: skip everything except resetting digest state */
135 if((mNullDigest != NULL) || (mDigest != NULL)) {
136 if(mNullDigest != NULL) {
137 mNullDigest->digestInit();
138 }
139 return;
140 }
141
142 /* snag key from context */
143 const CssmKey &keyInContext =
144 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
145 CSSMERR_CSP_MISSING_ATTR_KEY);
146 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
147
148 /* get digest alg and sig alg from Context.algorithm */
149 switch(context.algorithm()) {
150 /*** DSA ***/
151 case CSSM_ALGID_SHA1WithDSA:
152 mDigestAlg = CSSM_ALGID_SHA1;
153 mSigAlg = CSSM_ALGID_DSA;
154 break;
155 case CSSM_ALGID_DSA: // Raw
156 mDigestAlg = CSSM_ALGID_NONE;
157 mSigAlg = CSSM_ALGID_DSA;
158 break;
159 /*** RSA ***/
160 case CSSM_ALGID_SHA1WithRSA:
161 mDigestAlg = CSSM_ALGID_SHA1;
162 mSigAlg = CSSM_ALGID_RSA;
163 break;
164 case CSSM_ALGID_MD5WithRSA:
165 mDigestAlg = CSSM_ALGID_MD5;
166 mSigAlg = CSSM_ALGID_RSA;
167 break;
168 case CSSM_ALGID_MD2WithRSA:
169 mDigestAlg = CSSM_ALGID_MD2;
170 mSigAlg = CSSM_ALGID_RSA;
171 break;
172 case CSSM_ALGID_SHA224WithRSA:
173 mDigestAlg = CSSM_ALGID_SHA224;
174 mSigAlg = CSSM_ALGID_RSA;
175 break;
176 case CSSM_ALGID_SHA256WithRSA:
177 mDigestAlg = CSSM_ALGID_SHA256;
178 mSigAlg = CSSM_ALGID_RSA;
179 break;
180 case CSSM_ALGID_SHA384WithRSA:
181 mDigestAlg = CSSM_ALGID_SHA384;
182 mSigAlg = CSSM_ALGID_RSA;
183 break;
184 case CSSM_ALGID_SHA512WithRSA:
185 mDigestAlg = CSSM_ALGID_SHA512;
186 mSigAlg = CSSM_ALGID_RSA;
187 break;
188 case CSSM_ALGID_RSA: // Raw
189 mDigestAlg = CSSM_ALGID_NONE;
190 mSigAlg = CSSM_ALGID_RSA;
191 break;
192 /*** FEE ***/
193 case CSSM_ALGID_FEE_SHA1:
194 mDigestAlg = CSSM_ALGID_SHA1;
195 mSigAlg = CSSM_ALGID_FEE;
196 break;
197 case CSSM_ALGID_FEE_MD5:
198 mDigestAlg = CSSM_ALGID_MD5;
199 mSigAlg = CSSM_ALGID_FEE;
200 break;
201 case CSSM_ALGID_FEE: // Raw
202 mDigestAlg = CSSM_ALGID_NONE;
203 mSigAlg = CSSM_ALGID_FEE;
204 break;
205 /*** ECDSA ***/
206 case CSSM_ALGID_SHA1WithECDSA:
207 mDigestAlg = CSSM_ALGID_SHA1;
208 mSigAlg = CSSM_ALGID_ECDSA;
209 break;
210 case CSSM_ALGID_SHA224WithECDSA:
211 mDigestAlg = CSSM_ALGID_SHA224;
212 mSigAlg = CSSM_ALGID_ECDSA;
213 break;
214 case CSSM_ALGID_SHA256WithECDSA:
215 mDigestAlg = CSSM_ALGID_SHA256;
216 mSigAlg = CSSM_ALGID_ECDSA;
217 break;
218 case CSSM_ALGID_SHA384WithECDSA:
219 mDigestAlg = CSSM_ALGID_SHA384;
220 mSigAlg = CSSM_ALGID_ECDSA;
221 break;
222 case CSSM_ALGID_SHA512WithECDSA:
223 mDigestAlg = CSSM_ALGID_SHA512;
224 mSigAlg = CSSM_ALGID_ECDSA;
225 break;
226 case CSSM_ALGID_ECDSA: // Raw
227 mDigestAlg = CSSM_ALGID_NONE;
228 mSigAlg = CSSM_ALGID_ECDSA;
229 break;
230 default:
231 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
232 }
233
234 /* set up mNullDigest or mDigest */
235 if(mDigestAlg == CSSM_ALGID_NONE) {
236 mNullDigest = new NullDigest();
237 }
238 else {
239 mDigest = new CssmClient::Digest(mSession.mRawCsp, mDigestAlg);
240 }
241 }
242
243 /*
244 * for raw sign/verify - optionally called after init.
245 * Note that in init (in this case), we set mDigestAlg to ALGID_NONE and set up
246 * a NullDigest. We now overwrite mDigestAlg, and we'll useÊthis
247 * new value when we do the actual sign/vfy.
248 */
249 void SDSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg)
250 {
251 mDigestAlg = digestAlg;
252 }
253
254 void SDSignatureContext::update(const CssmData &data)
255 {
256 /* Note that for this context, we really can not deal with an out-of-sequence
257 * update --> final(true, 0) --> update since we lose the pending digest state
258 * when we perform the implied final() during outputSize(true, 0). */
259 assert(mOutBuf.Data == NULL);
260
261 /* add incoming data to digest or accumulator */
262 if(mNullDigest) {
263 mNullDigest->digestUpdate(data.data(), data.length());
264 }
265 else {
266 mDigest->digest(data);
267 }
268 }
269
270 size_t SDSignatureContext::outputSize(bool final, size_t inSize)
271 {
272 if(!final) {
273 ssCryptDebug("===sig outputSize !final\n");
274 return 0;
275 }
276 if(!encoding()) {
277 ssCryptDebug("===sig outputSize final, !encoding\n");
278 /* don't see why this is even called... */
279 return 0;
280 }
281 if(inSize == 0) {
282 /*
283 * This is the implied signal to go for it. Note that in this case,
284 * we can not go back and re-do the op in case of an unexpected
285 * sequence of update/outputSize(final, 0)/final - we lose the digest
286 * state. Perhaps we should save the digest...? But still it would
287 * be impossible to do another update.
288 */
289 clearOutBuf();
290 sign(mOutBuf);
291 ssCryptDebug("===sig outputSize(pre-op) %u", (unsigned)mOutBuf.Length);
292 return (size_t)mOutBuf.Length;
293 }
294 else {
295 /* out-of-band case, ask CSP via SS */
296 uint32 outSize = clientSession().getOutputSize(*mContext,
297 mKeyHandle,
298 /* FIXME - what to use for inSize here - we don't want to
299 * interrogate mDigest, as that would result in another RPC...
300 * and signature size is not related to input size...right? */
301 (uint32)inSize,
302 true);
303 ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize);
304 return (size_t)outSize;
305 }
306 }
307
308 /* sign */
309
310 /* first the common routine shared by final and outputSize */
311 void SDSignatureContext::sign(CssmData &sig)
312 {
313 /* we have to pass down a modified Context, thus.... */
314 Context tempContext = *mContext;
315 tempContext.AlgorithmType = mSigAlg;
316
317 if(mNullDigest) {
318 CssmData dData(const_cast<void *>(mNullDigest->digestPtr()),
319 mNullDigest->digestSizeInBytes());
320 clientSession().generateSignature(tempContext,
321 mKeyHandle,
322 dData,
323 sig,
324 mDigestAlg);
325 }
326 else {
327 CssmAutoData d (mDigest->allocator ());
328 d.set((*mDigest) ());
329
330 clientSession().generateSignature(tempContext,
331 mKeyHandle,
332 d,
333 sig,
334 mDigestAlg);
335 }
336 }
337
338 /* this is the one called by CSPFullPluginSession */
339 void SDSignatureContext::final(CssmData &sig)
340 {
341 if(mOutBuf.Data) {
342 /* normal final case in which the actual RPC via SS was done in the
343 * previous outputSize() call. */
344 ssCryptDebug("===final via pre-op and copy");
345 copyOutBuf(sig);
346 return;
347 }
348
349 ssCryptDebug("===final via RPC");
350 sign(sig);
351 }
352
353 /* verify */
354 void
355 SDSignatureContext::final(const CssmData &sig)
356 {
357 /* we have to pass down a modified Context, thus.... */
358 Context tempContext = *mContext;
359 tempContext.AlgorithmType = mSigAlg;
360
361 if(mNullDigest) {
362 CssmData dData(const_cast<void *>(mNullDigest->digestPtr()),
363 mNullDigest->digestSizeInBytes());
364 clientSession().verifySignature(tempContext,
365 mKeyHandle,
366 dData,
367 sig,
368 mDigestAlg);
369 }
370 else {
371 clientSession().verifySignature(tempContext,
372 mKeyHandle,
373 (*mDigest)(),
374 sig,
375 mDigestAlg);
376 }
377 }
378
379
380 //
381 // SDCryptContext -- Context for Encrypt and Decrypt operations
382 //
383 SDCryptContext::SDCryptContext(SDCSPSession &session)
384 : SDContext(session), mKeyHandle(noKey)
385 {
386 /* nothing for now */
387 }
388
389
390 SDCryptContext::~SDCryptContext()
391 {
392 /* nothing for now */
393 }
394
395 void
396 SDCryptContext::init(const Context &context, bool encoding)
397 {
398 ssCryptDebug("===init");
399 SDContext::init(context, encoding);
400
401 /* reusable; reset accumulator */
402 mNullDigest.digestInit();
403
404 const CssmKey &keyInContext =
405 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
406 CSSMERR_CSP_MISSING_ATTR_KEY);
407 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
408 }
409
410 size_t
411 SDCryptContext::inputSize(size_t outSize)
412 {
413 ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize);
414 return UINT_MAX;
415 }
416
417 size_t
418 SDCryptContext::outputSize(bool final, size_t inSize)
419 {
420 ssCryptDebug("===outputSize final %d inSize=%u", final, (unsigned)inSize);
421 if(!final) {
422 /* we buffer until final; no intermediate output */
423 return 0;
424 }
425 size_t inBufSize = mNullDigest.digestSizeInBytes();
426 if(inSize == 0) {
427 /* This is the implied signal to go for it */
428 clearOutBuf();
429 if(inBufSize == 0) {
430 return 0;
431 }
432 const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inBufSize);
433 if (encoding()) {
434 clientSession().encrypt(*mContext, mKeyHandle, in, mOutBuf);
435 }
436 else {
437 clientSession().decrypt(*mContext, mKeyHandle, in, mOutBuf);
438 }
439 /* leave the accumulator as is in case of unexpected sequence */
440 ssCryptDebug(" ===outSize(pre-op) %u", (unsigned)mOutBuf.Length);
441 return mOutBuf.Length;
442 }
443 else {
444 /* out-of-band case, ask CSP via SS */
445 uint32 outSize = clientSession().getOutputSize(*mContext,
446 mKeyHandle,
447 (uint32)(inBufSize + inSize),
448 encoding());
449 ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize);
450 return (size_t)outSize;
451 }
452 }
453
454 void
455 SDCryptContext::minimumProgress(size_t &in, size_t &out)
456 {
457 in = 1;
458 out = 0;
459 }
460
461 void
462 SDCryptContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize)
463 {
464 ssCryptDebug("===update inSize=%u", (unsigned)inSize);
465 /* add incoming data to accumulator */
466 mNullDigest.digestUpdate(inp, inSize);
467 outSize = 0;
468 clearOutBuf();
469 }
470
471 void
472 SDCryptContext::final(CssmData &out)
473 {
474 if(mOutBuf.Data != NULL) {
475 /* normal final case in which the actual RPC via SS was done in the
476 * previous outputSize() call. A memcpy is needed here because
477 * CSPFullPluginSession has just allocated the buf size we need. */
478 ssCryptDebug("===final via pre-op and copy");
479 copyOutBuf(out);
480 return;
481 }
482
483 /* when is this path taken...? */
484 ssCryptDebug("===final via RPC");
485 size_t inSize = mNullDigest.digestSizeInBytes();
486 if(!inSize) return;
487
488 const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inSize);
489 IFDEBUG(size_t origOutSize = out.length());
490 if (encoding()) {
491 clientSession().encrypt(*mContext, mKeyHandle, in, out);
492 }
493 else {
494 clientSession().decrypt(*mContext, mKeyHandle, in, out);
495 }
496 assert(out.length() <= origOutSize);
497 mNullDigest.digestInit();
498 }
499
500 // Digest, using raw CSP
501 SDDigestContext::SDDigestContext(SDCSPSession &session)
502 : SDContext(session), mDigest(NULL)
503 {
504
505 }
506
507 SDDigestContext::~SDDigestContext()
508 {
509 delete mDigest;
510 }
511
512 void SDDigestContext::init(const Context &context, bool encoding)
513 {
514 CSSM_ALGORITHMS alg;
515
516 SDContext::init(context, encoding);
517 alg = context.algorithm();
518 mDigest = new CssmClient::Digest(mSession.mRawCsp, alg);
519 }
520
521 void SDDigestContext::update(const CssmData &data)
522 {
523 mDigest->digest(data);
524 }
525
526 void SDDigestContext::final(CssmData &out)
527 {
528 (*mDigest)(out);
529 }
530
531 size_t SDDigestContext::outputSize(bool final, size_t inSize)
532 {
533 if(!final) {
534 return 0;
535 }
536 else {
537 return (size_t)mDigest->getOutputSize((uint32)inSize);
538 }
539 }
540
541 // MACContext - common class for MAC generate, verify
542 SDMACContext::SDMACContext(SDCSPSession &session)
543 : SDContext(session), mKeyHandle(noKey)
544 {
545
546 }
547
548 void SDMACContext::init(const Context &context, bool encoding)
549 {
550 SDContext::init(context, encoding);
551
552 /* reusable; reset accumulator */
553 mNullDigest.digestInit();
554
555 /* snag key from context */
556 const CssmKey &keyInContext =
557 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
558 CSSMERR_CSP_MISSING_ATTR_KEY);
559 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
560 }
561
562 void SDMACContext::update(const CssmData &data)
563 {
564 /* add incoming data to accumulator */
565 mNullDigest.digestUpdate(data.data(), data.length());
566 }
567
568 size_t SDMACContext::outputSize(bool final, size_t inSize)
569 {
570 if(!final) {
571 ssCryptDebug("===mac outputSize !final\n");
572 return 0;
573 }
574 if(!encoding()) {
575 ssCryptDebug("===mac outputSize final, !encoding\n");
576 /* don't see why this is even called... */
577 return 0;
578 }
579 if(inSize == 0) {
580 /*
581 * This is the implied signal to go for it.
582 */
583 clearOutBuf();
584 genMac(mOutBuf);
585 ssCryptDebug("===mac outputSize(pre-op) %u", (unsigned)mOutBuf.Length);
586 return (size_t)mOutBuf.Length;
587 }
588 else {
589 /* out-of-band case, ask CSP via SS */
590 uint32 outSize = clientSession().getOutputSize(*mContext,
591 mKeyHandle,
592 (uint32)(inSize + mNullDigest.digestSizeInBytes()),
593 true);
594 ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize);
595 return (size_t)outSize;
596 }
597 }
598
599 /* generate */
600
601 /* first the common routine used by final() and outputSize() */
602 void SDMACContext::genMac(CssmData &mac)
603 {
604 CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
605 mNullDigest.digestSizeInBytes());
606 clientSession().generateMac(*mContext, mKeyHandle, allData, mac);
607 }
608
609 void SDMACContext::final(CssmData &mac)
610 {
611 genMac(mac);
612 }
613
614 /* verify */
615 void SDMACContext::final(const CssmData &mac)
616 {
617 CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
618 mNullDigest.digestSizeInBytes());
619 clientSession().verifyMac(*mContext, mKeyHandle, allData, mac);
620 }