]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_sd_cspdl/lib/SDContext.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / 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...) secdebug("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_RSA: // Raw
173 mDigestAlg = CSSM_ALGID_NONE;
174 mSigAlg = CSSM_ALGID_RSA;
175 break;
176 /*** FEE ***/
177 case CSSM_ALGID_FEE_SHA1:
178 mDigestAlg = CSSM_ALGID_SHA1;
179 mSigAlg = CSSM_ALGID_FEE;
180 break;
181 case CSSM_ALGID_FEE_MD5:
182 mDigestAlg = CSSM_ALGID_MD5;
183 mSigAlg = CSSM_ALGID_FEE;
184 break;
185 case CSSM_ALGID_FEE: // Raw
186 mDigestAlg = CSSM_ALGID_NONE;
187 mSigAlg = CSSM_ALGID_FEE;
188 break;
189 /*** ECDSA ***/
190 case CSSM_ALGID_SHA1WithECDSA:
191 mDigestAlg = CSSM_ALGID_SHA1;
192 mSigAlg = CSSM_ALGID_ECDSA;
193 break;
194 case CSSM_ALGID_SHA224WithECDSA:
195 mDigestAlg = CSSM_ALGID_SHA224;
196 mSigAlg = CSSM_ALGID_ECDSA;
197 break;
198 case CSSM_ALGID_SHA256WithECDSA:
199 mDigestAlg = CSSM_ALGID_SHA256;
200 mSigAlg = CSSM_ALGID_ECDSA;
201 break;
202 case CSSM_ALGID_SHA384WithECDSA:
203 mDigestAlg = CSSM_ALGID_SHA384;
204 mSigAlg = CSSM_ALGID_ECDSA;
205 break;
206 case CSSM_ALGID_SHA512WithECDSA:
207 mDigestAlg = CSSM_ALGID_SHA512;
208 mSigAlg = CSSM_ALGID_ECDSA;
209 break;
210 case CSSM_ALGID_ECDSA: // Raw
211 mDigestAlg = CSSM_ALGID_NONE;
212 mSigAlg = CSSM_ALGID_ECDSA;
213 break;
214 default:
215 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
216 }
217
218 /* set up mNullDigest or mDigest */
219 if(mDigestAlg == CSSM_ALGID_NONE) {
220 mNullDigest = new NullDigest();
221 }
222 else {
223 mDigest = new CssmClient::Digest(mSession.mRawCsp, mDigestAlg);
224 }
225 }
226
227 /*
228 * for raw sign/verify - optionally called after init.
229 * Note that in init (in this case), we set mDigestAlg to ALGID_NONE and set up
230 * a NullDigest. We now overwrite mDigestAlg, and we'll useÊthis
231 * new value when we do the actual sign/vfy.
232 */
233 void SDSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg)
234 {
235 mDigestAlg = digestAlg;
236 }
237
238 void SDSignatureContext::update(const CssmData &data)
239 {
240 /* Note that for this context, we really can not deal with an out-of-sequence
241 * update --> final(true, 0) --> update since we lose the pending digest state
242 * when we perform the implied final() during outputSize(true, 0). */
243 assert(mOutBuf.Data == NULL);
244
245 /* add incoming data to digest or accumulator */
246 if(mNullDigest) {
247 mNullDigest->digestUpdate(data.data(), data.length());
248 }
249 else {
250 mDigest->digest(data);
251 }
252 }
253
254 size_t SDSignatureContext::outputSize(bool final, size_t inSize)
255 {
256 if(!final) {
257 ssCryptDebug("===sig outputSize !final\n");
258 return 0;
259 }
260 if(!encoding()) {
261 ssCryptDebug("===sig outputSize final, !encoding\n");
262 /* don't see why this is even called... */
263 return 0;
264 }
265 if(inSize == 0) {
266 /*
267 * This is the implied signal to go for it. Note that in this case,
268 * we can not go back and re-do the op in case of an unexpected
269 * sequence of update/outputSize(final, 0)/final - we lose the digest
270 * state. Perhaps we should save the digest...? But still it would
271 * be impossible to do another update.
272 */
273 clearOutBuf();
274 sign(mOutBuf);
275 ssCryptDebug("===sig outputSize(pre-op) %u", (unsigned)mOutBuf.Length);
276 return (size_t)mOutBuf.Length;
277 }
278 else {
279 /* out-of-band case, ask CSP via SS */
280 uint32 outSize = clientSession().getOutputSize(*mContext,
281 mKeyHandle,
282 /* FIXME - what to use for inSize here - we don't want to
283 * interrogate mDigest, as that would result in another RPC...
284 * and signature size is not related to input size...right? */
285 (uint32)inSize,
286 true);
287 ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize);
288 return (size_t)outSize;
289 }
290 }
291
292 /* sign */
293
294 /* first the common routine shared by final and outputSize */
295 void SDSignatureContext::sign(CssmData &sig)
296 {
297 /* we have to pass down a modified Context, thus.... */
298 Context tempContext = *mContext;
299 tempContext.AlgorithmType = mSigAlg;
300
301 if(mNullDigest) {
302 CssmData dData(const_cast<void *>(mNullDigest->digestPtr()),
303 mNullDigest->digestSizeInBytes());
304 clientSession().generateSignature(tempContext,
305 mKeyHandle,
306 dData,
307 sig,
308 mDigestAlg);
309 }
310 else {
311 CssmAutoData d (mDigest->allocator ());
312 d.set((*mDigest) ());
313
314 clientSession().generateSignature(tempContext,
315 mKeyHandle,
316 d,
317 sig,
318 mDigestAlg);
319 }
320 }
321
322 /* this is the one called by CSPFullPluginSession */
323 void SDSignatureContext::final(CssmData &sig)
324 {
325 if(mOutBuf.Data) {
326 /* normal final case in which the actual RPC via SS was done in the
327 * previous outputSize() call. */
328 ssCryptDebug("===final via pre-op and copy");
329 copyOutBuf(sig);
330 return;
331 }
332
333 ssCryptDebug("===final via RPC");
334 sign(sig);
335 }
336
337 /* verify */
338 void
339 SDSignatureContext::final(const CssmData &sig)
340 {
341 /* we have to pass down a modified Context, thus.... */
342 Context tempContext = *mContext;
343 tempContext.AlgorithmType = mSigAlg;
344
345 if(mNullDigest) {
346 CssmData dData(const_cast<void *>(mNullDigest->digestPtr()),
347 mNullDigest->digestSizeInBytes());
348 clientSession().verifySignature(tempContext,
349 mKeyHandle,
350 dData,
351 sig,
352 mDigestAlg);
353 }
354 else {
355 clientSession().verifySignature(tempContext,
356 mKeyHandle,
357 (*mDigest)(),
358 sig,
359 mDigestAlg);
360 }
361 }
362
363
364 //
365 // SDCryptContext -- Context for Encrypt and Decrypt operations
366 //
367 SDCryptContext::SDCryptContext(SDCSPSession &session)
368 : SDContext(session), mKeyHandle(noKey)
369 {
370 /* nothing for now */
371 }
372
373
374 SDCryptContext::~SDCryptContext()
375 {
376 /* nothing for now */
377 }
378
379 void
380 SDCryptContext::init(const Context &context, bool encoding)
381 {
382 ssCryptDebug("===init");
383 SDContext::init(context, encoding);
384
385 /* reusable; reset accumulator */
386 mNullDigest.digestInit();
387
388 const CssmKey &keyInContext =
389 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
390 CSSMERR_CSP_MISSING_ATTR_KEY);
391 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
392 }
393
394 size_t
395 SDCryptContext::inputSize(size_t outSize)
396 {
397 ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize);
398 return UINT_MAX;
399 }
400
401 size_t
402 SDCryptContext::outputSize(bool final, size_t inSize)
403 {
404 ssCryptDebug("===outputSize final %d inSize=%u", final, (unsigned)inSize);
405 if(!final) {
406 /* we buffer until final; no intermediate output */
407 return 0;
408 }
409 size_t inBufSize = mNullDigest.digestSizeInBytes();
410 if(inSize == 0) {
411 /* This is the implied signal to go for it */
412 clearOutBuf();
413 if(inBufSize == 0) {
414 return 0;
415 }
416 const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inBufSize);
417 if (encoding()) {
418 clientSession().encrypt(*mContext, mKeyHandle, in, mOutBuf);
419 }
420 else {
421 clientSession().decrypt(*mContext, mKeyHandle, in, mOutBuf);
422 }
423 /* leave the accumulator as is in case of unexpected sequence */
424 ssCryptDebug(" ===outSize(pre-op) %u", (unsigned)mOutBuf.Length);
425 return mOutBuf.Length;
426 }
427 else {
428 /* out-of-band case, ask CSP via SS */
429 uint32 outSize = clientSession().getOutputSize(*mContext,
430 mKeyHandle,
431 (uint32)(inBufSize + inSize),
432 encoding());
433 ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize);
434 return (size_t)outSize;
435 }
436 }
437
438 void
439 SDCryptContext::minimumProgress(size_t &in, size_t &out)
440 {
441 in = 1;
442 out = 0;
443 }
444
445 void
446 SDCryptContext::update(void *inp, size_t &inSize, void *outp, size_t &outSize)
447 {
448 ssCryptDebug("===update inSize=%u", (unsigned)inSize);
449 /* add incoming data to accumulator */
450 mNullDigest.digestUpdate(inp, inSize);
451 outSize = 0;
452 clearOutBuf();
453 }
454
455 void
456 SDCryptContext::final(CssmData &out)
457 {
458 if(mOutBuf.Data != NULL) {
459 /* normal final case in which the actual RPC via SS was done in the
460 * previous outputSize() call. A memcpy is needed here because
461 * CSPFullPluginSession has just allocated the buf size we need. */
462 ssCryptDebug("===final via pre-op and copy");
463 copyOutBuf(out);
464 return;
465 }
466
467 /* when is this path taken...? */
468 ssCryptDebug("===final via RPC");
469 size_t inSize = mNullDigest.digestSizeInBytes();
470 if(!inSize) return;
471
472 const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inSize);
473 IFDEBUG(size_t origOutSize = out.length());
474 if (encoding()) {
475 clientSession().encrypt(*mContext, mKeyHandle, in, out);
476 }
477 else {
478 clientSession().decrypt(*mContext, mKeyHandle, in, out);
479 }
480 assert(out.length() <= origOutSize);
481 mNullDigest.digestInit();
482 }
483
484 // Digest, using raw CSP
485 SDDigestContext::SDDigestContext(SDCSPSession &session)
486 : SDContext(session), mDigest(NULL)
487 {
488
489 }
490
491 SDDigestContext::~SDDigestContext()
492 {
493 delete mDigest;
494 }
495
496 void SDDigestContext::init(const Context &context, bool encoding)
497 {
498 CSSM_ALGORITHMS alg;
499
500 SDContext::init(context, encoding);
501 alg = context.algorithm();
502 mDigest = new CssmClient::Digest(mSession.mRawCsp, alg);
503 }
504
505 void SDDigestContext::update(const CssmData &data)
506 {
507 mDigest->digest(data);
508 }
509
510 void SDDigestContext::final(CssmData &out)
511 {
512 (*mDigest)(out);
513 }
514
515 size_t SDDigestContext::outputSize(bool final, size_t inSize)
516 {
517 if(!final) {
518 return 0;
519 }
520 else {
521 return (size_t)mDigest->getOutputSize((uint32)inSize);
522 }
523 }
524
525 // MACContext - common class for MAC generate, verify
526 SDMACContext::SDMACContext(SDCSPSession &session)
527 : SDContext(session), mKeyHandle(noKey)
528 {
529
530 }
531
532 void SDMACContext::init(const Context &context, bool encoding)
533 {
534 SDContext::init(context, encoding);
535
536 /* reusable; reset accumulator */
537 mNullDigest.digestInit();
538
539 /* snag key from context */
540 const CssmKey &keyInContext =
541 context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY,
542 CSSMERR_CSP_MISSING_ATTR_KEY);
543 mKeyHandle = mSession.lookupKey(keyInContext).keyHandle();
544 }
545
546 void SDMACContext::update(const CssmData &data)
547 {
548 /* add incoming data to accumulator */
549 mNullDigest.digestUpdate(data.data(), data.length());
550 }
551
552 size_t SDMACContext::outputSize(bool final, size_t inSize)
553 {
554 if(!final) {
555 ssCryptDebug("===mac outputSize !final\n");
556 return 0;
557 }
558 if(!encoding()) {
559 ssCryptDebug("===mac outputSize final, !encoding\n");
560 /* don't see why this is even called... */
561 return 0;
562 }
563 if(inSize == 0) {
564 /*
565 * This is the implied signal to go for it.
566 */
567 clearOutBuf();
568 genMac(mOutBuf);
569 ssCryptDebug("===mac outputSize(pre-op) %u", (unsigned)mOutBuf.Length);
570 return (size_t)mOutBuf.Length;
571 }
572 else {
573 /* out-of-band case, ask CSP via SS */
574 uint32 outSize = clientSession().getOutputSize(*mContext,
575 mKeyHandle,
576 (uint32)(inSize + mNullDigest.digestSizeInBytes()),
577 true);
578 ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize);
579 return (size_t)outSize;
580 }
581 }
582
583 /* generate */
584
585 /* first the common routine used by final() and outputSize() */
586 void SDMACContext::genMac(CssmData &mac)
587 {
588 CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
589 mNullDigest.digestSizeInBytes());
590 clientSession().generateMac(*mContext, mKeyHandle, allData, mac);
591 }
592
593 void SDMACContext::final(CssmData &mac)
594 {
595 genMac(mac);
596 }
597
598 /* verify */
599 void SDMACContext::final(const CssmData &mac)
600 {
601 CssmData allData(const_cast<void *>(mNullDigest.digestPtr()),
602 mNullDigest.digestSizeInBytes());
603 clientSession().verifyMac(*mContext, mKeyHandle, allData, mac);
604 }