]>
Commit | Line | Data |
---|---|---|
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 | ||
18 | static Allocator *ascAllocator; | |
19 | ||
20 | /* | |
21 | * Comcryption-style memory allocator callbacks | |
22 | */ | |
23 | static void *ccMalloc(unsigned size) | |
24 | { | |
25 | return ascAllocator->malloc(size); | |
26 | } | |
27 | static void ccFree(void *data) | |
28 | { | |
29 | ascAllocator->free(data); | |
30 | } | |
31 | ||
32 | /* Given a ComCryption error, throw appropriate CssmError */ | |
33 | static 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 | ||
78 | AscAlgFactory::AscAlgFactory( | |
79 | Allocator *normAlloc, | |
80 | Allocator *privAlloc) | |
81 | { | |
82 | /* once-per-address-space init */ | |
83 | ascAllocator = privAlloc; | |
84 | comMallocRegister(ccMalloc, ccFree); | |
85 | } | |
86 | ||
87 | bool 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 | ||
116 | ASCContext::~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 | */ | |
127 | void 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 | */ | |
189 | void 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 | ||
260 | void 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 | ||
289 | size_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 | ||
309 | size_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 | ||
346 | void 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 */ |