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