2 * Copyright (c) 2001,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@
27 #include "ascContext.h"
28 #include "ascFactory.h"
29 #include <security_utilities/debugging.h>
30 #include <security_utilities/logging.h>
31 #include <Security/cssmapple.h>
33 #define abprintf(args...) secinfo("ascBuf", ## args) /* buffer sizes */
34 #define aioprintf(args...) secinfo("ascIo", ## args) /* all I/O */
36 static Allocator
*ascAllocator
;
39 * Comcryption-style memory allocator callbacks
41 static void *ccMalloc(unsigned size
)
43 return ascAllocator
->malloc(size
);
45 static void ccFree(void *data
)
47 ascAllocator
->free(data
);
50 /* Given a ComCryption error, throw appropriate CssmError */
51 static void throwComcrypt(
53 const char *op
) /* optional */
55 CSSM_RETURN cerr
= CSSM_OK
;
56 const char *errStr
= "Bad Error String";
60 errStr
= "CCR_SUCCESS";
62 case CCR_OUTBUFFER_TOO_SMALL
:
63 errStr
= "CCR_OUTBUFFER_TOO_SMALL";
64 cerr
= CSSMERR_CSP_OUTPUT_LENGTH_ERROR
;
66 case CCR_MEMORY_ERROR
:
67 errStr
= "CCR_MEMORY_ERROR";
68 cerr
= CSSMERR_CSP_MEMORY_ERROR
;
70 case CCR_WRONG_VERSION
:
71 errStr
= "CCR_WRONG_VERSION";
72 cerr
= CSSMERR_CSP_INVALID_DATA
;
74 case CCR_BAD_CIPHERTEXT
:
75 errStr
= "CCR_BAD_CIPHERTEXT";
76 cerr
= CSSMERR_CSP_INVALID_DATA
;
80 errStr
= "CCR_INTERNAL";
81 cerr
= CSSMERR_CSP_INTERNAL_ERROR
;
85 Security::Syslog::error("Apple CSP %s: %s", op
, errStr
);
88 CssmError::throwMe(cerr
);
96 AscAlgFactory::AscAlgFactory(
100 /* once-per-address-space init */
101 ascAllocator
= privAlloc
;
102 comMallocRegister(ccMalloc
, ccFree
);
105 bool AscAlgFactory::setup(
106 AppleCSPSession
&session
,
107 CSPFullPluginSession::CSPContext
* &cspCtx
,
108 const Context
&context
)
110 if(context
.algorithm() != CSSM_ALGID_ASC
) {
114 /* reusing one of ours; OK */
117 switch(context
.type()) {
118 case CSSM_ALGCLASS_KEYGEN
:
119 cspCtx
= new AppleSymmKeyGenerator(session
,
121 COMCRYPT_MAX_KEYLENGTH
* 8,
122 true); // must be byte size
124 case CSSM_ALGCLASS_SYMMETRIC
:
125 cspCtx
= new ASCContext(session
);
134 ASCContext::~ASCContext()
137 comcryptObjFree(mCcObj
);
142 * Standard CSPContext init, called from CSPFullPluginSession::init().
143 * Reusable, e.g., query followed by en/decrypt.
145 void ASCContext::init(
146 const Context
&context
,
150 uint8
*keyData
= NULL
;
153 /* obtain key from context */
154 symmetricKeyBits(context
, session(), CSSM_ALGID_ASC
,
155 encrypting
? CSSM_KEYUSE_ENCRYPT
: CSSM_KEYUSE_DECRYPT
,
157 if((keyLen
< 1) || (keyLen
> COMCRYPT_MAX_KEYLENGTH
)) {
158 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY
);
160 mDecryptBufValid
= false;
162 /* optional optimization attribute */
163 comcryptOptimize optimize
= CCO_DEFAULT
;
164 uint32 opt
= context
.getInt(CSSM_ATTRIBUTE_ASC_OPTIMIZATION
);
166 case CSSM_ASC_OPTIMIZE_DEFAULT
:
167 optimize
= CCO_DEFAULT
;
169 case CSSM_ASC_OPTIMIZE_SIZE
:
172 case CSSM_ASC_OPTIMIZE_SECURITY
:
173 optimize
= CCO_SECURITY
;
175 case CSSM_ASC_OPTIMIZE_TIME
:
178 case CSSM_ASC_OPTIMIZE_TIME_SIZE
:
179 optimize
= CCO_TIME_SIZE
;
181 case CSSM_ASC_OPTIMIZE_ASCII
:
182 optimize
= CCO_ASCII
;
185 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS
);
188 /* All other context attributes ignored */
189 /* init the low-level state */
191 /* note we allow for context reuse */
192 mCcObj
= comcryptAlloc();
194 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
198 crtn
= comcryptInit(mCcObj
, keyData
, (unsigned)keyLen
, optimize
);
200 throwComcrypt(crtn
, "comcryptInit");
205 * All of these functions are called by CSPFullPluginSession.
207 void ASCContext::update(
209 size_t &inSize
, // in/out
211 size_t &outSize
) // in/out
215 unsigned char *inText
= (unsigned char *)inp
;
216 unsigned char *outText
= (unsigned char *)outp
;
219 outLen
= (unsigned)outSize
;
220 crtn
= comcryptData(mCcObj
,
225 CCE_MORE_TO_COME
); // not used on encrypt
227 throwComcrypt(crtn
, "comcryptData");
232 * Deal with 1-byte buffer hack. First decrypt the existing buffer...
235 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
238 unsigned partialOutLen
= 0;
239 if(mDecryptBufValid
) {
240 thisOutLen
= (unsigned)outSize
;
241 crtn
= deComcryptData(mCcObj
,
247 mDecryptBufValid
= false;
249 throwComcrypt(crtn
, "deComcryptData (1)");
251 partialOutLen
= thisOutLen
;
252 outText
+= thisOutLen
;
256 * Now decrypt remaining, less one byte (which is stored in the
259 thisOutLen
= (unsigned)(outSize
- partialOutLen
);
260 crtn
= deComcryptData(mCcObj
,
262 (unsigned)(inSize
- 1),
267 throwComcrypt(crtn
, "deComcryptData (2)");
269 outLen
= partialOutLen
+ thisOutLen
;
270 mDecryptBuf
= inText
[inSize
- 1];
271 mDecryptBufValid
= true;
274 aioprintf("=== ASC::update encrypt %d inSize %ld outSize %ld",
275 encoding() ? 1 : 0, inSize
, outSize
);
278 void ASCContext::final(
285 /* decrypt buffer hack */
286 if(!mDecryptBufValid
) {
287 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
290 unsigned outLen
= (unsigned)out
.Length
;
291 crtn
= deComcryptData(mCcObj
,
294 (unsigned char *)out
.Data
,
297 mDecryptBufValid
= false;
299 throwComcrypt(crtn
, "deComcryptData (3)");
303 aioprintf("=== ASC::final encrypt %d outSize %ld",
304 encoding() ? 1 : 0, out
.Length
);
307 size_t ASCContext::inputSize(
308 size_t outSize
) // input for given output size
310 size_t rtn
= comcryptMaxInBufSize(mCcObj
,
312 encoding() ? CCOP_COMCRYPT
: CCOP_DECOMCRYPT
);
313 abprintf("--- ASCContext::inputSize inSize %ld outSize %ld",
319 * ComCryption's buffer size calculation really does not lend itself to the
320 * requirements here. For example, there is no guarantee that
321 * inputSize(outputSize(x)) == x. We're just going to fudge it and make
322 * apps (or CSPFullPluginSession) alloc plenty more than they need.
324 #define ASC_OUTSIZE_FUDGE 1
325 #define ASC_OUTSIZE_FUDGE_FACTOR 1.2
327 size_t ASCContext::outputSize(
329 size_t inSize
) // output for given input size
331 unsigned effectiveInSize
= (unsigned)inSize
;
334 rtn
= comcryptMaxOutBufSize(mCcObj
,
338 #if ASC_OUTSIZE_FUDGE
339 float newOutSize
= rtn
;
340 newOutSize
*= ASC_OUTSIZE_FUDGE_FACTOR
;
341 rtn
= static_cast<size_t>(newOutSize
);
342 #endif /* ASC_OUTSIZE_FUDGE */
346 if(mDecryptBufValid
) {
350 else if(inSize
&& !mDecryptBufValid
) {
351 /* not final and nothing buffered yet - lop off one */
354 rtn
= comcryptMaxOutBufSize(mCcObj
,
359 abprintf("--- ASCContext::outputSize inSize %ld outSize %ld final %d ",
364 void ASCContext::minimumProgress(
366 size_t &out
) // minimum progress chunks
370 out
= comcryptMaxOutBufSize(mCcObj
,
376 if(mDecryptBufValid
) {
377 /* use "everything" */
383 out
= comcryptMaxOutBufSize(mCcObj
,
388 abprintf("--- ASCContext::minProgres in %ld out %ld", in
, out
);
391 #endif /* ASC_CSP_ENABLE */