2 * Copyright (c) 2004,2011-2012,2014 Apple 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...) secinfo("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_SHA224WithRSA
:
173 mDigestAlg
= CSSM_ALGID_SHA224
;
174 mSigAlg
= CSSM_ALGID_RSA
;
176 case CSSM_ALGID_SHA256WithRSA
:
177 mDigestAlg
= CSSM_ALGID_SHA256
;
178 mSigAlg
= CSSM_ALGID_RSA
;
180 case CSSM_ALGID_SHA384WithRSA
:
181 mDigestAlg
= CSSM_ALGID_SHA384
;
182 mSigAlg
= CSSM_ALGID_RSA
;
184 case CSSM_ALGID_SHA512WithRSA
:
185 mDigestAlg
= CSSM_ALGID_SHA512
;
186 mSigAlg
= CSSM_ALGID_RSA
;
188 case CSSM_ALGID_RSA
: // Raw
189 mDigestAlg
= CSSM_ALGID_NONE
;
190 mSigAlg
= CSSM_ALGID_RSA
;
193 case CSSM_ALGID_FEE_SHA1
:
194 mDigestAlg
= CSSM_ALGID_SHA1
;
195 mSigAlg
= CSSM_ALGID_FEE
;
197 case CSSM_ALGID_FEE_MD5
:
198 mDigestAlg
= CSSM_ALGID_MD5
;
199 mSigAlg
= CSSM_ALGID_FEE
;
201 case CSSM_ALGID_FEE
: // Raw
202 mDigestAlg
= CSSM_ALGID_NONE
;
203 mSigAlg
= CSSM_ALGID_FEE
;
206 case CSSM_ALGID_SHA1WithECDSA
:
207 mDigestAlg
= CSSM_ALGID_SHA1
;
208 mSigAlg
= CSSM_ALGID_ECDSA
;
210 case CSSM_ALGID_SHA224WithECDSA
:
211 mDigestAlg
= CSSM_ALGID_SHA224
;
212 mSigAlg
= CSSM_ALGID_ECDSA
;
214 case CSSM_ALGID_SHA256WithECDSA
:
215 mDigestAlg
= CSSM_ALGID_SHA256
;
216 mSigAlg
= CSSM_ALGID_ECDSA
;
218 case CSSM_ALGID_SHA384WithECDSA
:
219 mDigestAlg
= CSSM_ALGID_SHA384
;
220 mSigAlg
= CSSM_ALGID_ECDSA
;
222 case CSSM_ALGID_SHA512WithECDSA
:
223 mDigestAlg
= CSSM_ALGID_SHA512
;
224 mSigAlg
= CSSM_ALGID_ECDSA
;
226 case CSSM_ALGID_ECDSA
: // Raw
227 mDigestAlg
= CSSM_ALGID_NONE
;
228 mSigAlg
= CSSM_ALGID_ECDSA
;
231 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
234 /* set up mNullDigest or mDigest */
235 if(mDigestAlg
== CSSM_ALGID_NONE
) {
236 mNullDigest
= new NullDigest();
239 mDigest
= new CssmClient::Digest(mSession
.mRawCsp
, mDigestAlg
);
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.
249 void SDSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg
)
251 mDigestAlg
= digestAlg
;
254 void SDSignatureContext::update(const CssmData
&data
)
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
);
261 /* add incoming data to digest or accumulator */
263 mNullDigest
->digestUpdate(data
.data(), data
.length());
266 mDigest
->digest(data
);
270 size_t SDSignatureContext::outputSize(bool final
, size_t inSize
)
273 ssCryptDebug("===sig outputSize !final\n");
277 ssCryptDebug("===sig outputSize final, !encoding\n");
278 /* don't see why this is even called... */
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.
291 ssCryptDebug("===sig outputSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
292 return (size_t)mOutBuf
.Length
;
295 /* out-of-band case, ask CSP via SS */
296 uint32 outSize
= clientSession().getOutputSize(*mContext
,
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? */
303 ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize
);
304 return (size_t)outSize
;
310 /* first the common routine shared by final and outputSize */
311 void SDSignatureContext::sign(CssmData
&sig
)
313 /* we have to pass down a modified Context, thus.... */
314 Context tempContext
= *mContext
;
315 tempContext
.AlgorithmType
= mSigAlg
;
318 CssmData
dData(const_cast<void *>(mNullDigest
->digestPtr()),
319 mNullDigest
->digestSizeInBytes());
320 clientSession().generateSignature(tempContext
,
327 CssmAutoData
d (mDigest
->allocator ());
328 d
.set((*mDigest
) ());
330 clientSession().generateSignature(tempContext
,
338 /* this is the one called by CSPFullPluginSession */
339 void SDSignatureContext::final(CssmData
&sig
)
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");
349 ssCryptDebug("===final via RPC");
355 SDSignatureContext::final(const CssmData
&sig
)
357 /* we have to pass down a modified Context, thus.... */
358 Context tempContext
= *mContext
;
359 tempContext
.AlgorithmType
= mSigAlg
;
362 CssmData
dData(const_cast<void *>(mNullDigest
->digestPtr()),
363 mNullDigest
->digestSizeInBytes());
364 clientSession().verifySignature(tempContext
,
371 clientSession().verifySignature(tempContext
,
381 // SDCryptContext -- Context for Encrypt and Decrypt operations
383 SDCryptContext::SDCryptContext(SDCSPSession
&session
)
384 : SDContext(session
), mKeyHandle(noKey
)
386 /* nothing for now */
390 SDCryptContext::~SDCryptContext()
392 /* nothing for now */
396 SDCryptContext::init(const Context
&context
, bool encoding
)
398 ssCryptDebug("===init");
399 SDContext::init(context
, encoding
);
401 /* reusable; reset accumulator */
402 mNullDigest
.digestInit();
404 const CssmKey
&keyInContext
=
405 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
,
406 CSSMERR_CSP_MISSING_ATTR_KEY
);
407 mKeyHandle
= mSession
.lookupKey(keyInContext
).keyHandle();
411 SDCryptContext::inputSize(size_t outSize
)
413 ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize
);
418 SDCryptContext::outputSize(bool final
, size_t inSize
)
420 ssCryptDebug("===outputSize final %d inSize=%u", final
, (unsigned)inSize
);
422 /* we buffer until final; no intermediate output */
425 size_t inBufSize
= mNullDigest
.digestSizeInBytes();
427 /* This is the implied signal to go for it */
432 const CssmData
in(const_cast<void *>(mNullDigest
.digestPtr()), inBufSize
);
434 clientSession().encrypt(*mContext
, mKeyHandle
, in
, mOutBuf
);
437 clientSession().decrypt(*mContext
, mKeyHandle
, in
, mOutBuf
);
439 /* leave the accumulator as is in case of unexpected sequence */
440 ssCryptDebug(" ===outSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
441 return mOutBuf
.Length
;
444 /* out-of-band case, ask CSP via SS */
445 uint32 outSize
= clientSession().getOutputSize(*mContext
,
447 (uint32
)(inBufSize
+ inSize
),
449 ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize
);
450 return (size_t)outSize
;
455 SDCryptContext::minimumProgress(size_t &in
, size_t &out
)
462 SDCryptContext::update(void *inp
, size_t &inSize
, void *outp
, size_t &outSize
)
464 ssCryptDebug("===update inSize=%u", (unsigned)inSize
);
465 /* add incoming data to accumulator */
466 mNullDigest
.digestUpdate(inp
, inSize
);
472 SDCryptContext::final(CssmData
&out
)
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");
483 /* when is this path taken...? */
484 ssCryptDebug("===final via RPC");
485 size_t inSize
= mNullDigest
.digestSizeInBytes();
488 const CssmData
in(const_cast<void *>(mNullDigest
.digestPtr()), inSize
);
489 IFDEBUG(size_t origOutSize
= out
.length());
491 clientSession().encrypt(*mContext
, mKeyHandle
, in
, out
);
494 clientSession().decrypt(*mContext
, mKeyHandle
, in
, out
);
496 assert(out
.length() <= origOutSize
);
497 mNullDigest
.digestInit();
500 // Digest, using raw CSP
501 SDDigestContext::SDDigestContext(SDCSPSession
&session
)
502 : SDContext(session
), mDigest(NULL
)
507 SDDigestContext::~SDDigestContext()
512 void SDDigestContext::init(const Context
&context
, bool encoding
)
516 SDContext::init(context
, encoding
);
517 alg
= context
.algorithm();
518 mDigest
= new CssmClient::Digest(mSession
.mRawCsp
, alg
);
521 void SDDigestContext::update(const CssmData
&data
)
523 mDigest
->digest(data
);
526 void SDDigestContext::final(CssmData
&out
)
531 size_t SDDigestContext::outputSize(bool final
, size_t inSize
)
537 return (size_t)mDigest
->getOutputSize((uint32
)inSize
);
541 // MACContext - common class for MAC generate, verify
542 SDMACContext::SDMACContext(SDCSPSession
&session
)
543 : SDContext(session
), mKeyHandle(noKey
)
548 void SDMACContext::init(const Context
&context
, bool encoding
)
550 SDContext::init(context
, encoding
);
552 /* reusable; reset accumulator */
553 mNullDigest
.digestInit();
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();
562 void SDMACContext::update(const CssmData
&data
)
564 /* add incoming data to accumulator */
565 mNullDigest
.digestUpdate(data
.data(), data
.length());
568 size_t SDMACContext::outputSize(bool final
, size_t inSize
)
571 ssCryptDebug("===mac outputSize !final\n");
575 ssCryptDebug("===mac outputSize final, !encoding\n");
576 /* don't see why this is even called... */
581 * This is the implied signal to go for it.
585 ssCryptDebug("===mac outputSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
586 return (size_t)mOutBuf
.Length
;
589 /* out-of-band case, ask CSP via SS */
590 uint32 outSize
= clientSession().getOutputSize(*mContext
,
592 (uint32
)(inSize
+ mNullDigest
.digestSizeInBytes()),
594 ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize
);
595 return (size_t)outSize
;
601 /* first the common routine used by final() and outputSize() */
602 void SDMACContext::genMac(CssmData
&mac
)
604 CssmData
allData(const_cast<void *>(mNullDigest
.digestPtr()),
605 mNullDigest
.digestSizeInBytes());
606 clientSession().generateMac(*mContext
, mKeyHandle
, allData
, mac
);
609 void SDMACContext::final(CssmData
&mac
)
615 void SDMACContext::final(const CssmData
&mac
)
617 CssmData
allData(const_cast<void *>(mNullDigest
.digestPtr()),
618 mNullDigest
.digestSizeInBytes());
619 clientSession().verifyMac(*mContext
, mKeyHandle
, allData
, mac
);