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