]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/ascContext.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / ascContext.cpp
1 /*
2 * Copyright (c) 2001,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #ifdef ASC_CSP_ENABLE
26
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>
32
33 #define abprintf(args...) secinfo("ascBuf", ## args) /* buffer sizes */
34 #define aioprintf(args...) secinfo("ascIo", ## args) /* all I/O */
35
36 static Allocator *ascAllocator;
37
38 /*
39 * Comcryption-style memory allocator callbacks
40 */
41 static void *ccMalloc(unsigned size)
42 {
43 return ascAllocator->malloc(size);
44 }
45 static void ccFree(void *data)
46 {
47 ascAllocator->free(data);
48 }
49
50 /* Given a ComCryption error, throw appropriate CssmError */
51 static void throwComcrypt(
52 comcryptReturn crtn,
53 const char *op) /* optional */
54 {
55 CSSM_RETURN cerr = CSSM_OK;
56 const char *errStr = "Bad Error String";
57
58 switch(crtn) {
59 case CCR_SUCCESS:
60 errStr = "CCR_SUCCESS";
61 break;
62 case CCR_OUTBUFFER_TOO_SMALL:
63 errStr = "CCR_OUTBUFFER_TOO_SMALL";
64 cerr = CSSMERR_CSP_OUTPUT_LENGTH_ERROR;
65 break;
66 case CCR_MEMORY_ERROR:
67 errStr = "CCR_MEMORY_ERROR";
68 cerr = CSSMERR_CSP_MEMORY_ERROR;
69 break;
70 case CCR_WRONG_VERSION:
71 errStr = "CCR_WRONG_VERSION";
72 cerr = CSSMERR_CSP_INVALID_DATA;
73 break;
74 case CCR_BAD_CIPHERTEXT:
75 errStr = "CCR_BAD_CIPHERTEXT";
76 cerr = CSSMERR_CSP_INVALID_DATA;
77 break;
78 case CCR_INTERNAL:
79 default:
80 errStr = "CCR_INTERNAL";
81 cerr = CSSMERR_CSP_INTERNAL_ERROR;
82 break;
83 }
84 if(op) {
85 Security::Syslog::error("Apple CSP %s: %s", op, errStr);
86 }
87 if(cerr) {
88 CssmError::throwMe(cerr);
89 }
90 }
91
92 /*
93 * Algorithm factory.
94 */
95
96 AscAlgFactory::AscAlgFactory(
97 Allocator *normAlloc,
98 Allocator *privAlloc)
99 {
100 /* once-per-address-space init */
101 ascAllocator = privAlloc;
102 comMallocRegister(ccMalloc, ccFree);
103 }
104
105 bool AscAlgFactory::setup(
106 AppleCSPSession &session,
107 CSPFullPluginSession::CSPContext * &cspCtx,
108 const Context &context)
109 {
110 if(context.algorithm() != CSSM_ALGID_ASC) {
111 return false;
112 }
113 if(cspCtx != NULL) {
114 /* reusing one of ours; OK */
115 return true;
116 }
117 switch(context.type()) {
118 case CSSM_ALGCLASS_KEYGEN:
119 cspCtx = new AppleSymmKeyGenerator(session,
120 8,
121 COMCRYPT_MAX_KEYLENGTH * 8,
122 true); // must be byte size
123 return true;
124 case CSSM_ALGCLASS_SYMMETRIC:
125 cspCtx = new ASCContext(session);
126 return true;
127 default:
128 break;
129 }
130 /* not ours */
131 return false;
132 }
133
134 ASCContext::~ASCContext()
135 {
136 if(mCcObj != NULL) {
137 comcryptObjFree(mCcObj);
138 }
139 }
140
141 /*
142 * Standard CSPContext init, called from CSPFullPluginSession::init().
143 * Reusable, e.g., query followed by en/decrypt.
144 */
145 void ASCContext::init(
146 const Context &context,
147 bool encrypting)
148 {
149 CSSM_SIZE keyLen;
150 uint8 *keyData = NULL;
151 comcryptReturn crtn;
152
153 /* obtain key from context */
154 symmetricKeyBits(context, session(), CSSM_ALGID_ASC,
155 encrypting ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT,
156 keyData, keyLen);
157 if((keyLen < 1) || (keyLen > COMCRYPT_MAX_KEYLENGTH)) {
158 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
159 }
160 mDecryptBufValid = false;
161
162 /* optional optimization attribute */
163 comcryptOptimize optimize = CCO_DEFAULT;
164 uint32 opt = context.getInt(CSSM_ATTRIBUTE_ASC_OPTIMIZATION);
165 switch(opt) {
166 case CSSM_ASC_OPTIMIZE_DEFAULT:
167 optimize = CCO_DEFAULT;
168 break;
169 case CSSM_ASC_OPTIMIZE_SIZE:
170 optimize = CCO_SIZE;
171 break;
172 case CSSM_ASC_OPTIMIZE_SECURITY:
173 optimize = CCO_SECURITY;
174 break;
175 case CSSM_ASC_OPTIMIZE_TIME:
176 optimize = CCO_TIME;
177 break;
178 case CSSM_ASC_OPTIMIZE_TIME_SIZE:
179 optimize = CCO_TIME_SIZE;
180 break;
181 case CSSM_ASC_OPTIMIZE_ASCII:
182 optimize = CCO_ASCII;
183 break;
184 default:
185 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS);
186 }
187
188 /* All other context attributes ignored */
189 /* init the low-level state */
190 if(mCcObj == NULL) {
191 /* note we allow for context reuse */
192 mCcObj = comcryptAlloc();
193 if(mCcObj == NULL) {
194 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
195 }
196 }
197
198 crtn = comcryptInit(mCcObj, keyData, (unsigned)keyLen, optimize);
199 if(crtn) {
200 throwComcrypt(crtn, "comcryptInit");
201 }
202 }
203
204 /*
205 * All of these functions are called by CSPFullPluginSession.
206 */
207 void ASCContext::update(
208 void *inp,
209 size_t &inSize, // in/out
210 void *outp,
211 size_t &outSize) // in/out
212 {
213 comcryptReturn crtn;
214 unsigned outLen;
215 unsigned char *inText = (unsigned char *)inp;
216 unsigned char *outText = (unsigned char *)outp;
217
218 if(encoding()) {
219 outLen = (unsigned)outSize;
220 crtn = comcryptData(mCcObj,
221 inText,
222 (unsigned)inSize,
223 outText,
224 &outLen,
225 CCE_MORE_TO_COME); // not used on encrypt
226 if(crtn) {
227 throwComcrypt(crtn, "comcryptData");
228 }
229 }
230 else {
231 /*
232 * Deal with 1-byte buffer hack. First decrypt the existing buffer...
233 */
234 if(inSize == 0) {
235 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
236 }
237 unsigned thisOutLen;
238 unsigned partialOutLen = 0;
239 if(mDecryptBufValid) {
240 thisOutLen = (unsigned)outSize;
241 crtn = deComcryptData(mCcObj,
242 &mDecryptBuf,
243 1,
244 outText,
245 &thisOutLen,
246 CCE_MORE_TO_COME);
247 mDecryptBufValid = false;
248 if(crtn) {
249 throwComcrypt(crtn, "deComcryptData (1)");
250 }
251 partialOutLen = thisOutLen;
252 outText += thisOutLen;
253 }
254
255 /*
256 * Now decrypt remaining, less one byte (which is stored in the
257 * buffer).
258 */
259 thisOutLen = (unsigned)(outSize - partialOutLen);
260 crtn = deComcryptData(mCcObj,
261 inText,
262 (unsigned)(inSize - 1),
263 outText,
264 &thisOutLen,
265 CCE_MORE_TO_COME);
266 if(crtn) {
267 throwComcrypt(crtn, "deComcryptData (2)");
268 }
269 outLen = partialOutLen + thisOutLen;
270 mDecryptBuf = inText[inSize - 1];
271 mDecryptBufValid = true;
272 }
273 outSize = outLen;
274 aioprintf("=== ASC::update encrypt %d inSize %ld outSize %ld",
275 encoding() ? 1 : 0, inSize, outSize);
276 }
277
278 void ASCContext::final(
279 CssmData &out)
280 {
281 if(encoding()) {
282 out.length(0);
283 }
284 else {
285 /* decrypt buffer hack */
286 if(!mDecryptBufValid) {
287 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
288 }
289 comcryptReturn crtn;
290 unsigned outLen = (unsigned)out.Length;
291 crtn = deComcryptData(mCcObj,
292 &mDecryptBuf,
293 1,
294 (unsigned char *)out.Data,
295 &outLen,
296 CCE_END_OF_STREAM);
297 mDecryptBufValid = false;
298 if(crtn) {
299 throwComcrypt(crtn, "deComcryptData (3)");
300 }
301 out.length(outLen);
302 }
303 aioprintf("=== ASC::final encrypt %d outSize %ld",
304 encoding() ? 1 : 0, out.Length);
305 }
306
307 size_t ASCContext::inputSize(
308 size_t outSize) // input for given output size
309 {
310 size_t rtn = comcryptMaxInBufSize(mCcObj,
311 (unsigned)outSize,
312 encoding() ? CCOP_COMCRYPT : CCOP_DECOMCRYPT);
313 abprintf("--- ASCContext::inputSize inSize %ld outSize %ld",
314 rtn, outSize);
315 return rtn;
316 }
317
318 /*
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.
323 */
324 #define ASC_OUTSIZE_FUDGE 1
325 #define ASC_OUTSIZE_FUDGE_FACTOR 1.2
326
327 size_t ASCContext::outputSize(
328 bool final,
329 size_t inSize) // output for given input size
330 {
331 unsigned effectiveInSize = (unsigned)inSize;
332 size_t rtn;
333 if(encoding()) {
334 rtn = comcryptMaxOutBufSize(mCcObj,
335 effectiveInSize,
336 CCOP_COMCRYPT,
337 final);
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 */
343 }
344 else {
345 if(final) {
346 if(mDecryptBufValid) {
347 effectiveInSize++;
348 }
349 }
350 else if(inSize && !mDecryptBufValid) {
351 /* not final and nothing buffered yet - lop off one */
352 effectiveInSize--;
353 }
354 rtn = comcryptMaxOutBufSize(mCcObj,
355 effectiveInSize,
356 CCOP_DECOMCRYPT,
357 final);
358 }
359 abprintf("--- ASCContext::outputSize inSize %ld outSize %ld final %d ",
360 inSize, rtn, final);
361 return rtn;
362 }
363
364 void ASCContext::minimumProgress(
365 size_t &in,
366 size_t &out) // minimum progress chunks
367 {
368 if(encoding()) {
369 in = 1;
370 out = comcryptMaxOutBufSize(mCcObj,
371 1,
372 CCOP_COMCRYPT,
373 0);
374 }
375 else {
376 if(mDecryptBufValid) {
377 /* use "everything" */
378 in = 1;
379 }
380 else {
381 in = 0;
382 }
383 out = comcryptMaxOutBufSize(mCcObj,
384 (unsigned)in,
385 CCOP_DECOMCRYPT,
386 0);
387 }
388 abprintf("--- ASCContext::minProgres in %ld out %ld", in, out);
389 }
390
391 #endif /* ASC_CSP_ENABLE */