2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
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
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.
20 // SSContext - cryptographic contexts for the security server
22 #include "SSContext.h"
24 #include "SSCSPSession.h"
26 #include <security_utilities/debugging.h>
28 #define ssCryptDebug(args...) secdebug("ssCrypt", ## args)
30 using namespace SecurityServer
;
35 SSContext::SSContext(SSCSPSession
&session
)
36 : mSession(session
), mContext(NULL
)
40 void SSContext::clearOutBuf()
43 mSession
.free(mOutBuf
.Data
);
48 void SSContext::copyOutBuf(CssmData
&out
)
50 if(out
.length() < mOutBuf
.length()) {
51 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
53 memmove(out
.Data
, mOutBuf
.Data
, mOutBuf
.Length
);
54 out
.Length
= mOutBuf
.Length
;
59 SSContext::init(const Context
&context
,
60 bool /* encoding */) // @@@ should be removed from API since it's already in mDirection
66 SecurityServer::ClientSession
&
67 SSContext::clientSession()
69 return mSession
.clientSession();
74 // SSRandomContext -- Context for GenerateRandom operations
76 SSRandomContext::SSRandomContext(SSCSPSession
&session
) : SSContext(session
) {}
79 SSRandomContext::init(const Context
&context
, bool encoding
)
81 SSContext::init(context
, encoding
);
83 // set/freeze output size
84 mOutSize
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
);
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
);
96 SSRandomContext::outputSize(bool final
, size_t inSize
)
102 SSRandomContext::final(CssmData
&out
)
104 clientSession().generateRandom(*mContext
, out
);
108 // signature contexts
109 SSSignatureContext::SSSignatureContext(SSCSPSession
&session
)
110 : SSContext(session
),
115 /* nothing else for now */
118 SSSignatureContext::~SSSignatureContext()
124 void SSSignatureContext::init(const Context
&context
, bool signing
)
126 SSContext::init(context
, signing
);
128 /* reusable: skip everything except resetting digest state */
129 if((mNullDigest
!= NULL
) || (mDigest
!= NULL
)) {
130 if(mNullDigest
!= NULL
) {
131 mNullDigest
->digestInit();
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();
142 /* get digest alg and sig alg from Context.algorithm */
143 switch(context
.algorithm()) {
145 case CSSM_ALGID_SHA1WithDSA
:
146 mDigestAlg
= CSSM_ALGID_SHA1
;
147 mSigAlg
= CSSM_ALGID_DSA
;
149 case CSSM_ALGID_DSA
: // Raw
150 mDigestAlg
= CSSM_ALGID_NONE
;
151 mSigAlg
= CSSM_ALGID_DSA
;
154 case CSSM_ALGID_SHA1WithRSA
:
155 mDigestAlg
= CSSM_ALGID_SHA1
;
156 mSigAlg
= CSSM_ALGID_RSA
;
158 case CSSM_ALGID_MD5WithRSA
:
159 mDigestAlg
= CSSM_ALGID_MD5
;
160 mSigAlg
= CSSM_ALGID_RSA
;
162 case CSSM_ALGID_MD2WithRSA
:
163 mDigestAlg
= CSSM_ALGID_MD2
;
164 mSigAlg
= CSSM_ALGID_RSA
;
166 case CSSM_ALGID_SHA256WithRSA
:
167 mDigestAlg
= CSSM_ALGID_SHA256
;
168 mSigAlg
= CSSM_ALGID_RSA
;
170 case CSSM_ALGID_SHA224WithRSA
:
171 mDigestAlg
= CSSM_ALGID_SHA224
;
172 mSigAlg
= CSSM_ALGID_RSA
;
174 case CSSM_ALGID_SHA384WithRSA
:
175 mDigestAlg
= CSSM_ALGID_SHA384
;
176 mSigAlg
= CSSM_ALGID_RSA
;
178 case CSSM_ALGID_SHA512WithRSA
:
179 mDigestAlg
= CSSM_ALGID_SHA512
;
180 mSigAlg
= CSSM_ALGID_RSA
;
182 case CSSM_ALGID_RSA
: // Raw
183 mDigestAlg
= CSSM_ALGID_NONE
;
184 mSigAlg
= CSSM_ALGID_RSA
;
187 case CSSM_ALGID_FEE_SHA1
:
188 mDigestAlg
= CSSM_ALGID_SHA1
;
189 mSigAlg
= CSSM_ALGID_FEE
;
191 case CSSM_ALGID_FEE_MD5
:
192 mDigestAlg
= CSSM_ALGID_MD5
;
193 mSigAlg
= CSSM_ALGID_FEE
;
195 case CSSM_ALGID_FEE
: // Raw
196 mDigestAlg
= CSSM_ALGID_NONE
;
197 mSigAlg
= CSSM_ALGID_FEE
;
200 case CSSM_ALGID_SHA1WithECDSA
:
201 mDigestAlg
= CSSM_ALGID_SHA1
;
202 mSigAlg
= CSSM_ALGID_ECDSA
;
204 case CSSM_ALGID_SHA224WithECDSA
:
205 mDigestAlg
= CSSM_ALGID_SHA224
;
206 mSigAlg
= CSSM_ALGID_ECDSA
;
208 case CSSM_ALGID_SHA256WithECDSA
:
209 mDigestAlg
= CSSM_ALGID_SHA256
;
210 mSigAlg
= CSSM_ALGID_ECDSA
;
212 case CSSM_ALGID_SHA384WithECDSA
:
213 mDigestAlg
= CSSM_ALGID_SHA384
;
214 mSigAlg
= CSSM_ALGID_ECDSA
;
216 case CSSM_ALGID_SHA512WithECDSA
:
217 mDigestAlg
= CSSM_ALGID_SHA512
;
218 mSigAlg
= CSSM_ALGID_ECDSA
;
220 case CSSM_ALGID_ECDSA
: // Raw
221 mDigestAlg
= CSSM_ALGID_NONE
;
222 mSigAlg
= CSSM_ALGID_ECDSA
;
225 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
228 /* set up mNullDigest or mDigest */
229 if(mDigestAlg
== CSSM_ALGID_NONE
) {
230 mNullDigest
= new NullDigest();
233 mDigest
= new CssmClient::Digest(mSession
.mRawCsp
, mDigestAlg
);
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.
243 void SSSignatureContext::setDigestAlgorithm(CSSM_ALGORITHMS digestAlg
)
245 mDigestAlg
= digestAlg
;
248 void SSSignatureContext::update(const CssmData
&data
)
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
);
255 /* add incoming data to digest or accumulator */
257 mNullDigest
->digestUpdate(data
.data(), data
.length());
260 mDigest
->digest(data
);
264 size_t SSSignatureContext::outputSize(bool final
, size_t inSize
)
267 ssCryptDebug("===sig outputSize !final\n");
271 ssCryptDebug("===sig outputSize final, !encoding\n");
272 /* don't see why this is even called... */
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.
285 ssCryptDebug("===sig outputSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
286 return (size_t)mOutBuf
.Length
;
289 /* out-of-band case, ask CSP via SS */
290 uint32 outSize
= clientSession().getOutputSize(*mContext
,
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? */
297 ssCryptDebug("===sig outputSize(RPC) %u", (unsigned)outSize
);
298 return (size_t)outSize
;
304 /* first the common routine shared by final and outputSize */
305 void SSSignatureContext::sign(CssmData
&sig
)
307 /* we have to pass down a modified Context, thus.... */
308 Context tempContext
= *mContext
;
309 tempContext
.AlgorithmType
= mSigAlg
;
312 CssmData
dData(const_cast<void *>(mNullDigest
->digestPtr()),
313 mNullDigest
->digestSizeInBytes());
314 clientSession().generateSignature(tempContext
,
321 CssmAutoData
d (mDigest
->allocator ());
322 d
.set((*mDigest
) ());
324 clientSession().generateSignature(tempContext
,
332 /* this is the one called by CSPFullPluginSession */
333 void SSSignatureContext::final(CssmData
&sig
)
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");
343 ssCryptDebug("===final via RPC");
349 SSSignatureContext::final(const CssmData
&sig
)
351 /* we have to pass down a modified Context, thus.... */
352 Context tempContext
= *mContext
;
353 tempContext
.AlgorithmType
= mSigAlg
;
356 CssmData
dData(const_cast<void *>(mNullDigest
->digestPtr()),
357 mNullDigest
->digestSizeInBytes());
358 clientSession().verifySignature(tempContext
,
365 CssmData digst
= (*mDigest
)();
367 clientSession().verifySignature(tempContext
,
374 mDigest
->allocator().free(digst
.Data
);
377 mDigest
->allocator().free(digst
.Data
);
383 // SSCryptContext -- Context for Encrypt and Decrypt operations
385 SSCryptContext::SSCryptContext(SSCSPSession
&session
)
386 : SSContext(session
), mKeyHandle(noKey
)
388 /* nothing for now */
392 SSCryptContext::~SSCryptContext()
394 /* nothing for now */
398 SSCryptContext::init(const Context
&context
, bool encoding
)
400 ssCryptDebug("===init");
401 SSContext::init(context
, encoding
);
403 /* reusable; reset accumulator */
404 mNullDigest
.digestInit();
406 const CssmKey
&keyInContext
=
407 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
,
408 CSSMERR_CSP_MISSING_ATTR_KEY
);
409 mKeyHandle
= mSession
.lookupKey(keyInContext
).keyHandle();
413 SSCryptContext::inputSize(size_t outSize
)
415 ssCryptDebug("===inputSize outSize=%u", (unsigned)outSize
);
420 SSCryptContext::outputSize(bool final
, size_t inSize
)
422 ssCryptDebug("===outputSize final %d inSize=%u", final
, (unsigned)inSize
);
424 /* we buffer until final; no intermediate output */
427 size_t inBufSize
= mNullDigest
.digestSizeInBytes();
429 /* This is the implied signal to go for it */
434 const CssmData
in(const_cast<void *>(mNullDigest
.digestPtr()), inBufSize
);
436 clientSession().encrypt(*mContext
, mKeyHandle
, in
, mOutBuf
);
439 clientSession().decrypt(*mContext
, mKeyHandle
, in
, mOutBuf
);
441 /* leave the accumulator as is in case of unexpected sequence */
442 ssCryptDebug(" ===outSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
443 return mOutBuf
.Length
;
446 /* out-of-band case, ask CSP via SS */
447 uint32 outSize
= clientSession().getOutputSize(*mContext
,
449 (uint32
)(inBufSize
+ inSize
),
451 ssCryptDebug(" ===outSize(RPC) %u", (unsigned)outSize
);
452 return (size_t)outSize
;
457 SSCryptContext::minimumProgress(size_t &in
, size_t &out
)
464 SSCryptContext::update(void *inp
, size_t &inSize
, void *outp
, size_t &outSize
)
466 ssCryptDebug("===update inSize=%u", (unsigned)inSize
);
467 /* add incoming data to accumulator */
468 mNullDigest
.digestUpdate(inp
, inSize
);
474 SSCryptContext::final(CssmData
&out
)
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");
485 /* when is this path taken...? */
486 ssCryptDebug("===final via RPC");
487 size_t inSize
= mNullDigest
.digestSizeInBytes();
490 const CssmData
in(const_cast<void *>(mNullDigest
.digestPtr()), inSize
);
491 IFDEBUG(size_t origOutSize
= out
.length());
493 clientSession().encrypt(*mContext
, mKeyHandle
, in
, out
);
496 clientSession().decrypt(*mContext
, mKeyHandle
, in
, out
);
498 assert(out
.length() <= origOutSize
);
499 mNullDigest
.digestInit();
502 // Digest, using raw CSP
503 SSDigestContext::SSDigestContext(SSCSPSession
&session
)
504 : SSContext(session
), mDigest(NULL
)
509 SSDigestContext::~SSDigestContext()
514 void SSDigestContext::init(const Context
&context
, bool encoding
)
518 SSContext::init(context
, encoding
);
519 alg
= context
.algorithm();
520 mDigest
= new CssmClient::Digest(mSession
.mRawCsp
, alg
);
523 void SSDigestContext::update(const CssmData
&data
)
525 mDigest
->digest(data
);
528 void SSDigestContext::final(CssmData
&out
)
533 size_t SSDigestContext::outputSize(bool final
, size_t inSize
)
539 return (size_t)mDigest
->getOutputSize((uint32
)inSize
);
543 // MACContext - common class for MAC generate, verify
544 SSMACContext::SSMACContext(SSCSPSession
&session
)
545 : SSContext(session
), mKeyHandle(noKey
)
550 void SSMACContext::init(const Context
&context
, bool encoding
)
552 SSContext::init(context
, encoding
);
554 /* reusable; reset accumulator */
555 mNullDigest
.digestInit();
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();
564 void SSMACContext::update(const CssmData
&data
)
566 /* add incoming data to accumulator */
567 mNullDigest
.digestUpdate(data
.data(), data
.length());
570 size_t SSMACContext::outputSize(bool final
, size_t inSize
)
573 ssCryptDebug("===mac outputSize !final\n");
577 ssCryptDebug("===mac outputSize final, !encoding\n");
578 /* don't see why this is even called... */
583 * This is the implied signal to go for it.
587 ssCryptDebug("===mac outputSize(pre-op) %u", (unsigned)mOutBuf
.Length
);
588 return (size_t)mOutBuf
.Length
;
591 /* out-of-band case, ask CSP via SS */
592 uint32 outSize
= clientSession().getOutputSize(*mContext
,
594 (uint32
)(inSize
+ mNullDigest
.digestSizeInBytes()),
596 ssCryptDebug("===mac outputSize(RPC) %u", (unsigned)outSize
);
597 return (size_t)outSize
;
603 /* first the common routine used by final() and outputSize() */
604 void SSMACContext::genMac(CssmData
&mac
)
606 CssmData
allData(const_cast<void *>(mNullDigest
.digestPtr()),
607 mNullDigest
.digestSizeInBytes());
608 clientSession().generateMac(*mContext
, mKeyHandle
, allData
, mac
);
611 void SSMACContext::final(CssmData
&mac
)
617 void SSMACContext::final(const CssmData
&mac
)
619 CssmData
allData(const_cast<void *>(mNullDigest
.digestPtr()),
620 mNullDigest
.digestSizeInBytes());
621 clientSession().verifyMac(*mContext
, mKeyHandle
, allData
, mac
);