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