2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // SDContext - cryptographic contexts for the security server
28 #include "SDContext.h"
30 #include "SDCSPSession.h"
32 #include <security_utilities/debugging.h>
34 #define ssCryptDebug(args...) secdebug("ssCrypt", ## args)
36 using namespace SecurityServer
;
41 SDContext::SDContext(SDCSPSession
&session
)
42 : mSession(session
), mContext(NULL
)
46 void SDContext::clearOutBuf()
49 mSession
.free(mOutBuf
.Data
);
54 void SDContext::copyOutBuf(CssmData
&out
)
56 if(out
.length() < mOutBuf
.length()) {
57 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
59 memmove(out
.Data
, mOutBuf
.Data
, mOutBuf
.Length
);
60 out
.Length
= mOutBuf
.Length
;
65 SDContext::init(const Context
&context
,
66 bool /* encoding */) // @@@ should be removed from API since it's already in mDirection
72 SecurityServer::ClientSession
&
73 SDContext::clientSession()
75 return mSession
.clientSession();
80 // SDRandomContext -- Context for GenerateRandom operations
82 SDRandomContext::SDRandomContext(SDCSPSession
&session
) : SDContext(session
) {}
85 SDRandomContext::init(const Context
&context
, bool encoding
)
87 SDContext::init(context
, encoding
);
89 // set/freeze output size
90 mOutSize
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
);
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
);
102 SDRandomContext::outputSize(bool final
, size_t inSize
)
108 SDRandomContext::final(CssmData
&out
)
110 clientSession().generateRandom(*mContext
, out
);
114 // signature contexts
115 SDSignatureContext::SDSignatureContext(SDCSPSession
&session
)
116 : SDContext(session
),
121 /* nothing else for now */
124 SDSignatureContext::~SDSignatureContext()
130 void SDSignatureContext::init(const Context
&context
, bool signing
)
132 SDContext::init(context
, signing
);
134 /* reusable: skip everything except resetting digest state */
135 if((mNullDigest
!= NULL
) || (mDigest
!= NULL
)) {
136 if(mNullDigest
!= NULL
) {
137 mNullDigest
->digestInit();
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();
148 /* get digest alg and sig alg from Context.algorithm */
149 switch(context
.algorithm()) {
151 case CSSM_ALGID_SHA1WithDSA
:
152 mDigestAlg
= CSSM_ALGID_SHA1
;
153 mSigAlg
= CSSM_ALGID_DSA
;
155 case CSSM_ALGID_DSA
: // Raw
156 mDigestAlg
= CSSM_ALGID_NONE
;
157 mSigAlg
= CSSM_ALGID_DSA
;
160 case CSSM_ALGID_SHA1WithRSA
:
161 mDigestAlg
= CSSM_ALGID_SHA1
;
162 mSigAlg
= CSSM_ALGID_RSA
;
164 case CSSM_ALGID_MD5WithRSA
:
165 mDigestAlg
= CSSM_ALGID_MD5
;
166 mSigAlg
= CSSM_ALGID_RSA
;
168 case CSSM_ALGID_MD2WithRSA
:
169 mDigestAlg
= CSSM_ALGID_MD2
;
170 mSigAlg
= CSSM_ALGID_RSA
;
172 case CSSM_ALGID_RSA
: // Raw
173 mDigestAlg
= CSSM_ALGID_NONE
;
174 mSigAlg
= CSSM_ALGID_RSA
;
177 case CSSM_ALGID_FEE_SHA1
:
178 mDigestAlg
= CSSM_ALGID_SHA1
;
179 mSigAlg
= CSSM_ALGID_FEE
;
181 case CSSM_ALGID_FEE_MD5
:
182 mDigestAlg
= CSSM_ALGID_MD5
;
183 mSigAlg
= CSSM_ALGID_FEE
;
185 case CSSM_ALGID_FEE
: // Raw
186 mDigestAlg
= CSSM_ALGID_NONE
;
187 mSigAlg
= CSSM_ALGID_FEE
;
190 case CSSM_ALGID_SHA1WithECDSA
:
191 mDigestAlg
= CSSM_ALGID_SHA1
;
192 mSigAlg
= CSSM_ALGID_ECDSA
;
194 case CSSM_ALGID_SHA224WithECDSA
:
195 mDigestAlg
= CSSM_ALGID_SHA224
;
196 mSigAlg
= CSSM_ALGID_ECDSA
;
198 case CSSM_ALGID_SHA256WithECDSA
:
199 mDigestAlg
= CSSM_ALGID_SHA256
;
200 mSigAlg
= CSSM_ALGID_ECDSA
;
202 case CSSM_ALGID_SHA384WithECDSA
:
203 mDigestAlg
= CSSM_ALGID_SHA384
;
204 mSigAlg
= CSSM_ALGID_ECDSA
;
206 case CSSM_ALGID_SHA512WithECDSA
:
207 mDigestAlg
= CSSM_ALGID_SHA512
;
208 mSigAlg
= CSSM_ALGID_ECDSA
;
210 case CSSM_ALGID_ECDSA
: // Raw
211 mDigestAlg
= CSSM_ALGID_NONE
;
212 mSigAlg
= CSSM_ALGID_ECDSA
;
215 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
218 /* set up mNullDigest or mDigest */
219 if(mDigestAlg
== CSSM_ALGID_NONE
) {
220 mNullDigest
= new NullDigest();
223 mDigest
= new CssmClient::Digest(mSession
.mRawCsp
, mDigestAlg
);
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.
233 void SDSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg
)
235 mDigestAlg
= digestAlg
;
238 void SDSignatureContext::update(const CssmData
&data
)
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
);
245 /* add incoming data to digest or accumulator */
247 mNullDigest
->digestUpdate(data
.data(), data
.length());
250 mDigest
->digest(data
);
254 size_t SDSignatureContext::outputSize(bool final
, size_t inSize
)
257 ssCryptDebug("===sig outputSize !final\n");
261 ssCryptDebug("===sig outputSize final, !encoding\n");
262 /* don't see why this is even called... */
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.
275 ssCryptDebug("===sig outputSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
276 return (size_t)mOutBuf
.Length
;
279 /* out-of-band case, ask CSP via SS */
280 uint32 outSize
= clientSession().getOutputSize(*mContext
,
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? */
287 ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize
);
288 return (size_t)outSize
;
294 /* first the common routine shared by final and outputSize */
295 void SDSignatureContext::sign(CssmData
&sig
)
297 /* we have to pass down a modified Context, thus.... */
298 Context tempContext
= *mContext
;
299 tempContext
.AlgorithmType
= mSigAlg
;
302 CssmData
dData(const_cast<void *>(mNullDigest
->digestPtr()),
303 mNullDigest
->digestSizeInBytes());
304 clientSession().generateSignature(tempContext
,
311 CssmAutoData
d (mDigest
->allocator ());
312 d
.set((*mDigest
) ());
314 clientSession().generateSignature(tempContext
,
322 /* this is the one called by CSPFullPluginSession */
323 void SDSignatureContext::final(CssmData
&sig
)
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");
333 ssCryptDebug("===final via RPC");
339 SDSignatureContext::final(const CssmData
&sig
)
341 /* we have to pass down a modified Context, thus.... */
342 Context tempContext
= *mContext
;
343 tempContext
.AlgorithmType
= mSigAlg
;
346 CssmData
dData(const_cast<void *>(mNullDigest
->digestPtr()),
347 mNullDigest
->digestSizeInBytes());
348 clientSession().verifySignature(tempContext
,
355 clientSession().verifySignature(tempContext
,
365 // SDCryptContext -- Context for Encrypt and Decrypt operations
367 SDCryptContext::SDCryptContext(SDCSPSession
&session
)
368 : SDContext(session
), mKeyHandle(noKey
)
370 /* nothing for now */
374 SDCryptContext::~SDCryptContext()
376 /* nothing for now */
380 SDCryptContext::init(const Context
&context
, bool encoding
)
382 ssCryptDebug("===init");
383 SDContext::init(context
, encoding
);
385 /* reusable; reset accumulator */
386 mNullDigest
.digestInit();
388 const CssmKey
&keyInContext
=
389 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
,
390 CSSMERR_CSP_MISSING_ATTR_KEY
);
391 mKeyHandle
= mSession
.lookupKey(keyInContext
).keyHandle();
395 SDCryptContext::inputSize(size_t outSize
)
397 ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize
);
402 SDCryptContext::outputSize(bool final
, size_t inSize
)
404 ssCryptDebug("===outputSize final %d inSize=%u", final
, (unsigned)inSize
);
406 /* we buffer until final; no intermediate output */
409 size_t inBufSize
= mNullDigest
.digestSizeInBytes();
411 /* This is the implied signal to go for it */
416 const CssmData
in(const_cast<void *>(mNullDigest
.digestPtr()), inBufSize
);
418 clientSession().encrypt(*mContext
, mKeyHandle
, in
, mOutBuf
);
421 clientSession().decrypt(*mContext
, mKeyHandle
, in
, mOutBuf
);
423 /* leave the accumulator as is in case of unexpected sequence */
424 ssCryptDebug(" ===outSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
425 return mOutBuf
.Length
;
428 /* out-of-band case, ask CSP via SS */
429 uint32 outSize
= clientSession().getOutputSize(*mContext
,
433 ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize
);
434 return (size_t)outSize
;
439 SDCryptContext::minimumProgress(size_t &in
, size_t &out
)
446 SDCryptContext::update(void *inp
, size_t &inSize
, void *outp
, size_t &outSize
)
448 ssCryptDebug("===update inSize=%u", (unsigned)inSize
);
449 /* add incoming data to accumulator */
450 mNullDigest
.digestUpdate(inp
, inSize
);
456 SDCryptContext::final(CssmData
&out
)
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");
467 /* when is this path taken...? */
468 ssCryptDebug("===final via RPC");
469 size_t inSize
= mNullDigest
.digestSizeInBytes();
472 const CssmData
in(const_cast<void *>(mNullDigest
.digestPtr()), inSize
);
473 IFDEBUG(unsigned origOutSize
= out
.length());
475 clientSession().encrypt(*mContext
, mKeyHandle
, in
, out
);
478 clientSession().decrypt(*mContext
, mKeyHandle
, in
, out
);
480 assert(out
.length() <= origOutSize
);
481 mNullDigest
.digestInit();
484 // Digest, using raw CSP
485 SDDigestContext::SDDigestContext(SDCSPSession
&session
)
486 : SDContext(session
), mDigest(NULL
)
491 SDDigestContext::~SDDigestContext()
496 void SDDigestContext::init(const Context
&context
, bool encoding
)
500 SDContext::init(context
, encoding
);
501 alg
= context
.algorithm();
502 mDigest
= new CssmClient::Digest(mSession
.mRawCsp
, alg
);
505 void SDDigestContext::update(const CssmData
&data
)
507 mDigest
->digest(data
);
510 void SDDigestContext::final(CssmData
&out
)
515 size_t SDDigestContext::outputSize(bool final
, size_t inSize
)
521 return (size_t)mDigest
->getOutputSize(inSize
);
525 // MACContext - common class for MAC generate, verify
526 SDMACContext::SDMACContext(SDCSPSession
&session
)
527 : SDContext(session
), mKeyHandle(noKey
)
532 void SDMACContext::init(const Context
&context
, bool encoding
)
534 SDContext::init(context
, encoding
);
536 /* reusable; reset accumulator */
537 mNullDigest
.digestInit();
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();
546 void SDMACContext::update(const CssmData
&data
)
548 /* add incoming data to accumulator */
549 mNullDigest
.digestUpdate(data
.data(), data
.length());
552 size_t SDMACContext::outputSize(bool final
, size_t inSize
)
555 ssCryptDebug("===mac outputSize !final\n");
559 ssCryptDebug("===mac outputSize final, !encoding\n");
560 /* don't see why this is even called... */
565 * This is the implied signal to go for it.
569 ssCryptDebug("===mac outputSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
570 return (size_t)mOutBuf
.Length
;
573 /* out-of-band case, ask CSP via SS */
574 uint32 outSize
= clientSession().getOutputSize(*mContext
,
576 inSize
+ mNullDigest
.digestSizeInBytes(),
578 ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize
);
579 return (size_t)outSize
;
585 /* first the common routine used by final() and outputSize() */
586 void SDMACContext::genMac(CssmData
&mac
)
588 CssmData
allData(const_cast<void *>(mNullDigest
.digestPtr()),
589 mNullDigest
.digestSizeInBytes());
590 clientSession().generateMac(*mContext
, mKeyHandle
, allData
, mac
);
593 void SDMACContext::final(CssmData
&mac
)
599 void SDMACContext::final(const CssmData
&mac
)
601 CssmData
allData(const_cast<void *>(mNullDigest
.digestPtr()),
602 mNullDigest
.digestSizeInBytes());
603 clientSession().verifyMac(*mContext
, mKeyHandle
, allData
, mac
);