]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * The contents of this file are subject to the Mozilla Public | |
3 | * License Version 1.1 (the "License"); you may not use this file | |
4 | * except in compliance with the License. You may obtain a copy of | |
5 | * the License at http://www.mozilla.org/MPL/ | |
6 | * | |
7 | * Software distributed under the License is distributed on an "AS | |
8 | * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | |
9 | * implied. See the License for the specific language governing | |
10 | * rights and limitations under the License. | |
11 | * | |
12 | * The Original Code is the Netscape security libraries. | |
13 | * | |
14 | * The Initial Developer of the Original Code is Netscape | |
15 | * Communications Corporation. Portions created by Netscape are | |
16 | * Copyright (C) 1994-2000 Netscape Communications Corporation. All | |
17 | * Rights Reserved. | |
18 | * | |
19 | * Contributor(s): | |
20 | * | |
21 | * Alternatively, the contents of this file may be used under the | |
22 | * terms of the GNU General Public License Version 2 or later (the | |
23 | * "GPL"), in which case the provisions of the GPL are applicable | |
24 | * instead of those above. If you wish to allow use of your | |
25 | * version of this file only under the terms of the GPL and not to | |
26 | * allow others to use your version of this file under the MPL, | |
27 | * indicate your decision by deleting the provisions above and | |
28 | * replace them with the notice and other provisions required by | |
29 | * the GPL. If you do not delete the provisions above, a recipient | |
30 | * may use your version of this file under either the MPL or the | |
31 | * GPL. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * Encryption/decryption routines for CMS implementation, none of which are exported. | |
36 | * | |
37 | */ | |
38 | ||
39 | #include "cmslocal.h" | |
40 | ||
41 | #include "secoid.h" | |
42 | #include <security_asn1/secerr.h> | |
43 | #include <security_asn1/secasn1.h> | |
44 | #include <Security/SecAsn1Templates.h> | |
45 | #include <Security/cssmapi.h> | |
46 | #include <Security/cssmapple.h> | |
47 | #include <Security/SecKeyPriv.h> | |
48 | ||
49 | /* | |
50 | * ------------------------------------------------------------------- | |
51 | * Cipher stuff. | |
52 | */ | |
53 | ||
54 | #if 0 | |
55 | typedef OSStatus (*nss_cms_cipher_function) (void *, unsigned char *, unsigned int *, | |
56 | unsigned int, const unsigned char *, unsigned int); | |
57 | typedef OSStatus (*nss_cms_cipher_destroy) (void *, Boolean); | |
58 | #endif | |
59 | ||
60 | #define BLOCK_SIZE 4096 | |
61 | ||
62 | struct SecCmsCipherContextStr { | |
63 | #if 1 | |
64 | CSSM_CC_HANDLE cc; /* CSP CONTEXT */ | |
65 | Boolean encrypt; /* encrypt / decrypt switch */ | |
66 | #else | |
67 | void * cx; /* PK11 cipher context */ | |
68 | nss_cms_cipher_function doit; | |
69 | nss_cms_cipher_destroy destroy; | |
70 | Boolean encrypt; /* encrypt / decrypt switch */ | |
71 | int block_size; /* block & pad sizes for cipher */ | |
72 | int pad_size; | |
73 | int pending_count; /* pending data (not yet en/decrypted */ | |
74 | unsigned char pending_buf[BLOCK_SIZE];/* because of blocking */ | |
75 | #endif | |
76 | }; | |
77 | ||
78 | typedef struct sec_rc2cbcParameterStr { | |
79 | SECItem rc2ParameterVersion; | |
80 | SECItem iv; | |
81 | } sec_rc2cbcParameter; | |
82 | ||
83 | static const SecAsn1Template sec_rc2cbc_parameter_template[] = { | |
84 | { SEC_ASN1_SEQUENCE, | |
85 | 0, NULL, sizeof(sec_rc2cbcParameter) }, | |
86 | { SEC_ASN1_INTEGER | SEC_ASN1_SIGNED_INT, | |
87 | offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, | |
88 | { SEC_ASN1_OCTET_STRING, | |
89 | offsetof(sec_rc2cbcParameter,iv) }, | |
90 | { 0 } | |
91 | }; | |
92 | ||
93 | /* | |
94 | ** Convert a der encoded *signed* integer into a machine integral value. | |
95 | ** If an underflow/overflow occurs, sets error code and returns min/max. | |
96 | */ | |
97 | static long | |
98 | DER_GetInteger(SECItem *it) | |
99 | { | |
100 | long ival = 0; | |
101 | CSSM_SIZE len = it->Length; | |
102 | unsigned char *cp = it->Data; | |
103 | unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1); | |
104 | unsigned long ofloinit; | |
105 | ||
106 | if (*cp & 0x80) | |
107 | ival = -1L; | |
108 | ofloinit = ival & overflow; | |
109 | ||
110 | while (len) { | |
111 | if ((ival & overflow) != ofloinit) { | |
112 | PORT_SetError(SEC_ERROR_BAD_DER); | |
113 | if (ival < 0) { | |
114 | return LONG_MIN; | |
115 | } | |
116 | return LONG_MAX; | |
117 | } | |
118 | ival = ival << 8; | |
119 | ival |= *cp++; | |
120 | --len; | |
121 | } | |
122 | return ival; | |
123 | } | |
124 | ||
125 | /* S/MIME picked id values to represent differnt keysizes */ | |
126 | /* I do have a formula, but it ain't pretty, and it only works because you | |
127 | * can always match three points to a parabola:) */ | |
128 | static unsigned char rc2_map(SECItem *version) | |
129 | { | |
130 | long x; | |
131 | ||
132 | x = DER_GetInteger(version); | |
133 | ||
134 | switch (x) { | |
135 | case 58: return 128; | |
136 | case 120: return 64; | |
137 | case 160: return 40; | |
138 | } | |
139 | return 128; | |
140 | } | |
141 | ||
142 | static unsigned long rc2_unmap(unsigned long x) | |
143 | { | |
144 | switch (x) { | |
145 | case 128: return 58; | |
146 | case 64: return 120; | |
147 | case 40: return 160; | |
148 | } | |
149 | return 58; | |
150 | } | |
151 | ||
152 | /* default IV size in bytes */ | |
153 | #define DEFAULT_IV_SIZE 8 | |
154 | /* IV/block size for AES */ | |
155 | #define AES_BLOCK_SIZE 16 | |
156 | /* max IV size in bytes */ | |
157 | #define MAX_IV_SIZE AES_BLOCK_SIZE | |
158 | ||
159 | static SecCmsCipherContextRef | |
160 | SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid, Boolean encrypt) | |
161 | { | |
162 | SecCmsCipherContextRef cc; | |
163 | CSSM_CC_HANDLE ciphercc = 0; | |
164 | SECOidData *oidData; | |
165 | SECOidTag algtag; | |
166 | CSSM_ALGORITHMS algorithm; | |
167 | CSSM_PADDING padding = CSSM_PADDING_PKCS7; | |
168 | CSSM_ENCRYPT_MODE mode; | |
169 | CSSM_CSP_HANDLE cspHandle; | |
170 | const CSSM_KEY *cssmKey; | |
171 | OSStatus rv; | |
172 | uint8 ivbuf[MAX_IV_SIZE]; | |
173 | CSSM_DATA initVector = { DEFAULT_IV_SIZE, ivbuf }; | |
174 | //CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_ALG_PARAMS, sizeof(CSSM_DATA_PTR) }; | |
175 | ||
176 | rv = SecKeyGetCSPHandle(key, &cspHandle); | |
177 | if (rv) | |
178 | goto loser; | |
179 | rv = SecKeyGetCSSMKey(key, &cssmKey); | |
180 | if (rv) | |
181 | goto loser; | |
182 | ||
183 | // @@@ Add support for PBE based stuff | |
184 | ||
185 | oidData = SECOID_FindOID(&algid->algorithm); | |
186 | if (!oidData) | |
187 | goto loser; | |
188 | algtag = oidData->offset; | |
189 | algorithm = oidData->cssmAlgorithm; | |
190 | if (!algorithm) | |
191 | goto loser; | |
192 | ||
193 | switch (algtag) | |
194 | { | |
195 | case SEC_OID_RC2_CBC: | |
196 | case SEC_OID_RC4: | |
197 | case SEC_OID_DES_EDE3_CBC: | |
198 | case SEC_OID_DES_EDE: | |
199 | case SEC_OID_DES_CBC: | |
200 | case SEC_OID_RC5_CBC_PAD: | |
201 | case SEC_OID_FORTEZZA_SKIPJACK: | |
202 | mode = CSSM_ALGMODE_CBCPadIV8; | |
203 | break; | |
204 | ||
205 | /* RFC 3565 says that these sizes refer to key size, NOT block size */ | |
206 | case SEC_OID_AES_128_CBC: | |
207 | case SEC_OID_AES_192_CBC: | |
208 | case SEC_OID_AES_256_CBC: | |
209 | initVector.Length = AES_BLOCK_SIZE; | |
210 | mode = CSSM_ALGMODE_CBCPadIV8; | |
211 | break; | |
212 | ||
213 | case SEC_OID_DES_ECB: | |
214 | case SEC_OID_AES_128_ECB: | |
215 | case SEC_OID_AES_192_ECB: | |
216 | case SEC_OID_AES_256_ECB: | |
217 | mode = CSSM_ALGMODE_ECBPad; | |
218 | break; | |
219 | ||
220 | case SEC_OID_DES_OFB: | |
221 | mode = CSSM_ALGMODE_OFBPadIV8; | |
222 | break; | |
223 | ||
224 | case SEC_OID_DES_CFB: | |
225 | mode = CSSM_ALGMODE_CFBPadIV8; | |
226 | break; | |
227 | ||
228 | default: | |
229 | goto loser; | |
230 | } | |
231 | ||
232 | if (encrypt) | |
233 | { | |
234 | CSSM_CC_HANDLE randomcc; | |
235 | //SECItem *parameters; | |
236 | ||
237 | // Generate random initVector | |
238 | if (CSSM_CSP_CreateRandomGenContext(cspHandle, | |
239 | CSSM_ALGID_APPLE_YARROW, | |
240 | NULL, /* seed*/ | |
241 | initVector.Length, | |
242 | &randomcc)) | |
243 | goto loser; | |
244 | ||
245 | if (CSSM_GenerateRandom(randomcc, &initVector)) | |
246 | goto loser; | |
247 | CSSM_DeleteContext(randomcc); | |
248 | ||
249 | // Put IV into algid.parameters | |
250 | switch (algtag) | |
251 | { | |
252 | case SEC_OID_RC4: | |
253 | case SEC_OID_DES_EDE3_CBC: | |
254 | case SEC_OID_DES_EDE: | |
255 | case SEC_OID_DES_CBC: | |
256 | case SEC_OID_AES_128_CBC: | |
257 | case SEC_OID_AES_192_CBC: | |
258 | case SEC_OID_AES_256_CBC: | |
259 | case SEC_OID_FORTEZZA_SKIPJACK: | |
260 | case SEC_OID_DES_ECB: | |
261 | case SEC_OID_AES_128_ECB: | |
262 | case SEC_OID_AES_192_ECB: | |
263 | case SEC_OID_AES_256_ECB: | |
264 | case SEC_OID_DES_OFB: | |
265 | case SEC_OID_DES_CFB: | |
266 | /* Just encode the initVector as an octet string. */ | |
267 | if (!SEC_ASN1EncodeItem(poolp, &algid->parameters, | |
268 | &initVector, kSecAsn1OctetStringTemplate)) | |
269 | goto loser; | |
270 | break; | |
271 | ||
272 | case SEC_OID_RC2_CBC: | |
273 | { | |
274 | sec_rc2cbcParameter rc2 = {}; | |
275 | unsigned long rc2version; | |
276 | SECItem *newParams; | |
277 | ||
278 | rc2.iv = initVector; | |
279 | rc2version = rc2_unmap(cssmKey->KeyHeader.LogicalKeySizeInBits); | |
280 | if (!SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion), | |
281 | rc2version)) | |
282 | goto loser; | |
283 | newParams = SEC_ASN1EncodeItem (poolp, &algid->parameters, &rc2, | |
284 | sec_rc2cbc_parameter_template); | |
285 | PORT_Free(rc2.rc2ParameterVersion.Data); | |
286 | if (newParams == NULL) | |
287 | goto loser; | |
288 | break; | |
289 | } | |
290 | case SEC_OID_RC5_CBC_PAD: | |
291 | default: | |
292 | // @@@ Implement rc5 params stuff. | |
293 | goto loser; | |
294 | break; | |
295 | } | |
296 | } | |
297 | else | |
298 | { | |
299 | // Extract IV from algid.parameters | |
300 | // Put IV into algid.parameters | |
301 | switch (algtag) | |
302 | { | |
303 | case SEC_OID_RC4: | |
304 | case SEC_OID_DES_EDE3_CBC: | |
305 | case SEC_OID_DES_EDE: | |
306 | case SEC_OID_DES_CBC: | |
307 | case SEC_OID_AES_128_CBC: | |
308 | case SEC_OID_AES_192_CBC: | |
309 | case SEC_OID_AES_256_CBC: | |
310 | case SEC_OID_FORTEZZA_SKIPJACK: | |
311 | case SEC_OID_DES_ECB: | |
312 | case SEC_OID_AES_128_ECB: | |
313 | case SEC_OID_AES_192_ECB: | |
314 | case SEC_OID_AES_256_ECB: | |
315 | case SEC_OID_DES_OFB: | |
316 | case SEC_OID_DES_CFB: | |
317 | { | |
318 | CSSM_DATA iv = {}; | |
319 | /* Just decode the initVector from an octet string. */ | |
320 | rv = SEC_ASN1DecodeItem(NULL, &iv, kSecAsn1OctetStringTemplate, &(algid->parameters)); | |
321 | if (rv) | |
322 | goto loser; | |
323 | if (initVector.Length != iv.Length) { | |
324 | PORT_Free(iv.Data); | |
325 | goto loser; | |
326 | } | |
327 | memcpy(initVector.Data, iv.Data, initVector.Length); | |
328 | PORT_Free(iv.Data); | |
329 | break; | |
330 | } | |
331 | case SEC_OID_RC2_CBC: | |
332 | { | |
333 | sec_rc2cbcParameter rc2 = {}; | |
334 | unsigned long ulEffectiveBits; | |
335 | ||
336 | rv = SEC_ASN1DecodeItem(NULL, &rc2 ,sec_rc2cbc_parameter_template, | |
337 | &(algid->parameters)); | |
338 | if (rv) | |
339 | goto loser; | |
340 | ||
341 | if (initVector.Length != rc2.iv.Length) { | |
342 | PORT_Free(rc2.iv.Data); | |
343 | PORT_Free(rc2.rc2ParameterVersion.Data); | |
344 | goto loser; | |
345 | } | |
346 | memcpy(initVector.Data, rc2.iv.Data, initVector.Length); | |
347 | PORT_Free(rc2.iv.Data); | |
348 | ||
349 | ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion); | |
350 | PORT_Free(rc2.rc2ParameterVersion.Data); | |
351 | if (ulEffectiveBits != cssmKey->KeyHeader.LogicalKeySizeInBits) | |
352 | goto loser; | |
353 | break; | |
354 | } | |
355 | case SEC_OID_RC5_CBC_PAD: | |
356 | default: | |
357 | // @@@ Implement rc5 params stuff. | |
358 | goto loser; | |
359 | break; | |
360 | } | |
361 | } | |
362 | ||
363 | if (CSSM_CSP_CreateSymmetricContext(cspHandle, | |
364 | algorithm, | |
365 | mode, | |
366 | NULL, /* accessCred */ | |
367 | cssmKey, | |
368 | &initVector, | |
369 | padding, | |
370 | NULL, /* reserved */ | |
371 | &ciphercc)) | |
372 | goto loser; | |
373 | ||
374 | if (encrypt) | |
375 | rv = CSSM_EncryptDataInit(ciphercc); | |
376 | else | |
377 | rv = CSSM_DecryptDataInit(ciphercc); | |
378 | if (rv) | |
379 | goto loser; | |
380 | ||
381 | cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext)); | |
382 | if (cc == NULL) | |
383 | goto loser; | |
384 | ||
385 | cc->cc = ciphercc; | |
386 | cc->encrypt = encrypt; | |
387 | ||
388 | return cc; | |
389 | loser: | |
390 | if (ciphercc) | |
391 | CSSM_DeleteContext(ciphercc); | |
392 | ||
393 | return NULL; | |
394 | } | |
395 | ||
396 | /* | |
397 | * SecCmsCipherContextStartDecrypt - create a cipher context to do decryption | |
398 | * based on the given bulk * encryption key and algorithm identifier (which may include an iv). | |
399 | * | |
400 | * XXX Once both are working, it might be nice to combine this and the | |
401 | * function below (for starting up encryption) into one routine, and just | |
402 | * have two simple cover functions which call it. | |
403 | */ | |
404 | SecCmsCipherContextRef | |
405 | SecCmsCipherContextStartDecrypt(SecSymmetricKeyRef key, SECAlgorithmID *algid) | |
406 | { | |
407 | return SecCmsCipherContextStart(NULL, key, algid, PR_FALSE); | |
408 | #if 0 | |
409 | SecCmsCipherContextRef cc; | |
410 | void *ciphercx; | |
411 | CK_MECHANISM_TYPE mechanism; | |
412 | CSSM_DATA_PTR param; | |
413 | PK11SlotInfo *slot; | |
414 | SECOidTag algtag; | |
415 | ||
416 | algtag = SECOID_GetAlgorithmTag(algid); | |
417 | ||
418 | /* set param and mechanism */ | |
419 | if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { | |
420 | CK_MECHANISM pbeMech, cryptoMech; | |
421 | CSSM_DATA_PTR pbeParams; | |
422 | SEC_PKCS5KeyAndPassword *keyPwd; | |
423 | ||
424 | PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM)); | |
425 | PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM)); | |
426 | ||
427 | /* HACK ALERT! | |
428 | * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword * | |
429 | */ | |
430 | keyPwd = (SEC_PKCS5KeyAndPassword *)key; | |
431 | key = keyPwd->key; | |
432 | ||
433 | /* find correct PK11 mechanism and parameters to initialize pbeMech */ | |
434 | pbeMech.mechanism = PK11_AlgtagToMechanism(algtag); | |
435 | pbeParams = PK11_ParamFromAlgid(algid); | |
436 | if (!pbeParams) | |
437 | return NULL; | |
438 | pbeMech.pParameter = pbeParams->Data; | |
439 | pbeMech.ulParameterLen = pbeParams->Length; | |
440 | ||
441 | /* now map pbeMech to cryptoMech */ | |
442 | if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem, | |
443 | PR_FALSE) != CKR_OK) { | |
444 | SECITEM_ZfreeItem(pbeParams, PR_TRUE); | |
445 | return NULL; | |
446 | } | |
447 | SECITEM_ZfreeItem(pbeParams, PR_TRUE); | |
448 | ||
449 | /* and use it to initialize param & mechanism */ | |
450 | if ((param = (CSSM_DATA_PTR)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL) | |
451 | return NULL; | |
452 | ||
453 | param->Data = (unsigned char *)cryptoMech.pParameter; | |
454 | param->Length = cryptoMech.ulParameterLen; | |
455 | mechanism = cryptoMech.mechanism; | |
456 | } else { | |
457 | mechanism = PK11_AlgtagToMechanism(algtag); | |
458 | if ((param = PK11_ParamFromAlgid(algid)) == NULL) | |
459 | return NULL; | |
460 | } | |
461 | ||
462 | cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext)); | |
463 | if (cc == NULL) { | |
464 | SECITEM_FreeItem(param,PR_TRUE); | |
465 | return NULL; | |
466 | } | |
467 | ||
468 | /* figure out pad and block sizes */ | |
469 | cc->pad_size = PK11_GetBlockSize(mechanism, param); | |
470 | slot = PK11_GetSlotFromKey(key); | |
471 | cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; | |
472 | PK11_FreeSlot(slot); | |
473 | ||
474 | /* create PK11 cipher context */ | |
475 | ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param); | |
476 | SECITEM_FreeItem(param, PR_TRUE); | |
477 | if (ciphercx == NULL) { | |
478 | PORT_Free (cc); | |
479 | return NULL; | |
480 | } | |
481 | ||
482 | cc->cx = ciphercx; | |
483 | cc->doit = (nss_cms_cipher_function) PK11_CipherOp; | |
484 | cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext; | |
485 | cc->encrypt = PR_FALSE; | |
486 | cc->pending_count = 0; | |
487 | ||
488 | return cc; | |
489 | #endif | |
490 | } | |
491 | ||
492 | /* | |
493 | * SecCmsCipherContextStartEncrypt - create a cipher object to do encryption, | |
494 | * based on the given bulk encryption key and algorithm tag. Fill in the algorithm | |
495 | * identifier (which may include an iv) appropriately. | |
496 | * | |
497 | * XXX Once both are working, it might be nice to combine this and the | |
498 | * function above (for starting up decryption) into one routine, and just | |
499 | * have two simple cover functions which call it. | |
500 | */ | |
501 | SecCmsCipherContextRef | |
502 | SecCmsCipherContextStartEncrypt(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid) | |
503 | { | |
504 | return SecCmsCipherContextStart(poolp, key, algid, PR_TRUE); | |
505 | #if 0 | |
506 | SecCmsCipherContextRef cc; | |
507 | void *ciphercx; | |
508 | CSSM_DATA_PTR param; | |
509 | OSStatus rv; | |
510 | CK_MECHANISM_TYPE mechanism; | |
511 | PK11SlotInfo *slot; | |
512 | Boolean needToEncodeAlgid = PR_FALSE; | |
513 | SECOidTag algtag = SECOID_GetAlgorithmTag(algid); | |
514 | ||
515 | /* set param and mechanism */ | |
516 | if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { | |
517 | CK_MECHANISM pbeMech, cryptoMech; | |
518 | CSSM_DATA_PTR pbeParams; | |
519 | SEC_PKCS5KeyAndPassword *keyPwd; | |
520 | ||
521 | PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM)); | |
522 | PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM)); | |
523 | ||
524 | /* HACK ALERT! | |
525 | * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword * | |
526 | */ | |
527 | keyPwd = (SEC_PKCS5KeyAndPassword *)key; | |
528 | key = keyPwd->key; | |
529 | ||
530 | /* find correct PK11 mechanism and parameters to initialize pbeMech */ | |
531 | pbeMech.mechanism = PK11_AlgtagToMechanism(algtag); | |
532 | pbeParams = PK11_ParamFromAlgid(algid); | |
533 | if (!pbeParams) | |
534 | return NULL; | |
535 | pbeMech.pParameter = pbeParams->Data; | |
536 | pbeMech.ulParameterLen = pbeParams->Length; | |
537 | ||
538 | /* now map pbeMech to cryptoMech */ | |
539 | if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem, | |
540 | PR_FALSE) != CKR_OK) { | |
541 | SECITEM_ZfreeItem(pbeParams, PR_TRUE); | |
542 | return NULL; | |
543 | } | |
544 | SECITEM_ZfreeItem(pbeParams, PR_TRUE); | |
545 | ||
546 | /* and use it to initialize param & mechanism */ | |
547 | if ((param = (CSSM_DATA_PTR)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL) | |
548 | return NULL; | |
549 | ||
550 | param->Data = (unsigned char *)cryptoMech.pParameter; | |
551 | param->Length = cryptoMech.ulParameterLen; | |
552 | mechanism = cryptoMech.mechanism; | |
553 | } else { | |
554 | mechanism = PK11_AlgtagToMechanism(algtag); | |
555 | if ((param = PK11_GenerateNewParam(mechanism, key)) == NULL) | |
556 | return NULL; | |
557 | needToEncodeAlgid = PR_TRUE; | |
558 | } | |
559 | ||
560 | cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext)); | |
561 | if (cc == NULL) | |
562 | return NULL; | |
563 | ||
564 | /* now find pad and block sizes for our mechanism */ | |
565 | cc->pad_size = PK11_GetBlockSize(mechanism,param); | |
566 | slot = PK11_GetSlotFromKey(key); | |
567 | cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; | |
568 | PK11_FreeSlot(slot); | |
569 | ||
570 | /* and here we go, creating a PK11 cipher context */ | |
571 | ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, key, param); | |
572 | if (ciphercx == NULL) { | |
573 | PORT_Free(cc); | |
574 | cc = NULL; | |
575 | goto loser; | |
576 | } | |
577 | ||
578 | /* | |
579 | * These are placed after the CreateContextBySymKey() because some | |
580 | * mechanisms have to generate their IVs from their card (i.e. FORTEZZA). | |
581 | * Don't move it from here. | |
582 | * XXX is that right? the purpose of this is to get the correct algid | |
583 | * containing the IVs etc. for encoding. this means we need to set this up | |
584 | * BEFORE encoding the algid in the contentInfo, right? | |
585 | */ | |
586 | if (needToEncodeAlgid) { | |
587 | rv = PK11_ParamToAlgid(algtag, param, poolp, algid); | |
588 | if(rv != SECSuccess) { | |
589 | PORT_Free(cc); | |
590 | cc = NULL; | |
591 | goto loser; | |
592 | } | |
593 | } | |
594 | ||
595 | cc->cx = ciphercx; | |
596 | cc->doit = (nss_cms_cipher_function)PK11_CipherOp; | |
597 | cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext; | |
598 | cc->encrypt = PR_TRUE; | |
599 | cc->pending_count = 0; | |
600 | ||
601 | loser: | |
602 | SECITEM_FreeItem(param, PR_TRUE); | |
603 | ||
604 | return cc; | |
605 | #endif | |
606 | } | |
607 | ||
608 | void | |
609 | SecCmsCipherContextDestroy(SecCmsCipherContextRef cc) | |
610 | { | |
611 | PORT_Assert(cc != NULL); | |
612 | if (cc == NULL) | |
613 | return; | |
614 | CSSM_DeleteContext(cc->cc); | |
615 | PORT_Free(cc); | |
616 | } | |
617 | ||
618 | static unsigned int | |
619 | SecCmsCipherContextLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final, Boolean encrypt) | |
620 | { | |
621 | CSSM_QUERY_SIZE_DATA dataBlockSize[2] = { { input_len, 0 }, { input_len, 0 } }; | |
622 | /* Hack CDSA treats the last block as the final one. So unless we are being asked to report the final size we ask for 2 block and ignore the second (final) one. */ | |
623 | OSStatus rv = CSSM_QuerySize(cc->cc, cc->encrypt, final ? 1 : 2, dataBlockSize); | |
624 | if (rv) | |
625 | { | |
626 | PORT_SetError(rv); | |
627 | return 0; | |
628 | } | |
629 | ||
630 | return dataBlockSize[0].SizeOutputBlock; | |
631 | } | |
632 | ||
633 | /* | |
634 | * SecCmsCipherContextDecryptLength - find the output length of the next call to decrypt. | |
635 | * | |
636 | * cc - the cipher context | |
637 | * input_len - number of bytes used as input | |
638 | * final - true if this is the final chunk of data | |
639 | * | |
640 | * Result can be used to perform memory allocations. Note that the amount | |
641 | * is exactly accurate only when not doing a block cipher or when final | |
642 | * is false, otherwise it is an upper bound on the amount because until | |
643 | * we see the data we do not know how many padding bytes there are | |
644 | * (always between 1 and bsize). | |
645 | * | |
646 | * Note that this can return zero, which does not mean that the decrypt | |
647 | * operation can be skipped! (It simply means that there are not enough | |
648 | * bytes to make up an entire block; the bytes will be reserved until | |
649 | * there are enough to encrypt/decrypt at least one block.) However, | |
650 | * if zero is returned it *does* mean that no output buffer need be | |
651 | * passed in to the subsequent decrypt operation, as no output bytes | |
652 | * will be stored. | |
653 | */ | |
654 | size_t | |
655 | SecCmsCipherContextDecryptLength(SecCmsCipherContextRef cc, size_t input_len, Boolean final) | |
656 | { | |
657 | #if 1 | |
658 | return SecCmsCipherContextLength(cc, (unsigned int)input_len, final, PR_FALSE); | |
659 | #else | |
660 | int blocks, block_size; | |
661 | ||
662 | PORT_Assert (! cc->encrypt); | |
663 | ||
664 | block_size = cc->block_size; | |
665 | ||
666 | /* | |
667 | * If this is not a block cipher, then we always have the same | |
668 | * number of output bytes as we had input bytes. | |
669 | */ | |
670 | if (block_size == 0) | |
671 | return input_len; | |
672 | ||
673 | /* | |
674 | * On the final call, we will always use up all of the pending | |
675 | * bytes plus all of the input bytes, *but*, there will be padding | |
676 | * at the end and we cannot predict how many bytes of padding we | |
677 | * will end up removing. The amount given here is actually known | |
678 | * to be at least 1 byte too long (because we know we will have | |
679 | * at least 1 byte of padding), but seemed clearer/better to me. | |
680 | */ | |
681 | if (final) | |
682 | return cc->pending_count + input_len; | |
683 | ||
684 | /* | |
685 | * Okay, this amount is exactly what we will output on the | |
686 | * next cipher operation. We will always hang onto the last | |
687 | * 1 - block_size bytes for non-final operations. That is, | |
688 | * we will do as many complete blocks as we can *except* the | |
689 | * last block (complete or partial). (This is because until | |
690 | * we know we are at the end, we cannot know when to interpret | |
691 | * and removing the padding byte(s), which are guaranteed to | |
692 | * be there.) | |
693 | */ | |
694 | blocks = (cc->pending_count + input_len - 1) / block_size; | |
695 | return blocks * block_size; | |
696 | #endif | |
697 | } | |
698 | ||
699 | /* | |
700 | * SecCmsCipherContextEncryptLength - find the output length of the next call to encrypt. | |
701 | * | |
702 | * cc - the cipher context | |
703 | * input_len - number of bytes used as input | |
704 | * final - true if this is the final chunk of data | |
705 | * | |
706 | * Result can be used to perform memory allocations. | |
707 | * | |
708 | * Note that this can return zero, which does not mean that the encrypt | |
709 | * operation can be skipped! (It simply means that there are not enough | |
710 | * bytes to make up an entire block; the bytes will be reserved until | |
711 | * there are enough to encrypt/decrypt at least one block.) However, | |
712 | * if zero is returned it *does* mean that no output buffer need be | |
713 | * passed in to the subsequent encrypt operation, as no output bytes | |
714 | * will be stored. | |
715 | */ | |
716 | size_t | |
717 | SecCmsCipherContextEncryptLength(SecCmsCipherContextRef cc, size_t input_len, Boolean final) | |
718 | { | |
719 | #if 1 | |
720 | return SecCmsCipherContextLength(cc, (unsigned int)input_len, final, PR_TRUE); | |
721 | #else | |
722 | int blocks, block_size; | |
723 | int pad_size; | |
724 | ||
725 | PORT_Assert (cc->encrypt); | |
726 | ||
727 | block_size = cc->block_size; | |
728 | pad_size = cc->pad_size; | |
729 | ||
730 | /* | |
731 | * If this is not a block cipher, then we always have the same | |
732 | * number of output bytes as we had input bytes. | |
733 | */ | |
734 | if (block_size == 0) | |
735 | return input_len; | |
736 | ||
737 | /* | |
738 | * On the final call, we only send out what we need for | |
739 | * remaining bytes plus the padding. (There is always padding, | |
740 | * so even if we have an exact number of blocks as input, we | |
741 | * will add another full block that is just padding.) | |
742 | */ | |
743 | if (final) { | |
744 | if (pad_size == 0) { | |
745 | return cc->pending_count + input_len; | |
746 | } else { | |
747 | blocks = (cc->pending_count + input_len) / pad_size; | |
748 | blocks++; | |
749 | return blocks*pad_size; | |
750 | } | |
751 | } | |
752 | ||
753 | /* | |
754 | * Now, count the number of complete blocks of data we have. | |
755 | */ | |
756 | blocks = (cc->pending_count + input_len) / block_size; | |
757 | ||
758 | ||
759 | return blocks * block_size; | |
760 | #endif | |
761 | } | |
762 | ||
763 | ||
764 | static OSStatus | |
765 | SecCmsCipherContextCrypt(SecCmsCipherContextRef cc, unsigned char *output, | |
766 | size_t *output_len_p, size_t max_output_len, | |
767 | const unsigned char *input, size_t input_len, | |
768 | Boolean final, Boolean encrypt) | |
769 | { | |
770 | CSSM_DATA outputBuf = { max_output_len, output }; | |
771 | CSSM_SIZE bytes_output = 0; | |
772 | OSStatus rv = 0; | |
773 | ||
774 | if (input_len) | |
775 | { | |
776 | CSSM_DATA inputBuf = { input_len, (uint8 *)input }; | |
777 | ||
778 | if (encrypt) | |
779 | rv = CSSM_EncryptDataUpdate(cc->cc, &inputBuf, 1, &outputBuf, 1, &bytes_output); | |
780 | else | |
781 | rv = CSSM_DecryptDataUpdate(cc->cc, &inputBuf, 1, &outputBuf, 1, &bytes_output); | |
782 | } | |
783 | ||
784 | if (!rv && final) | |
785 | { | |
786 | CSSM_DATA remainderBuf = { max_output_len - bytes_output, output + bytes_output }; | |
787 | if (encrypt) | |
788 | rv = CSSM_EncryptDataFinal(cc->cc, &remainderBuf); | |
789 | else | |
790 | rv = CSSM_DecryptDataFinal(cc->cc, &remainderBuf); | |
791 | ||
792 | bytes_output += remainderBuf.Length; | |
793 | } | |
794 | ||
795 | if (rv) | |
796 | PORT_SetError(SEC_ERROR_BAD_DATA); | |
797 | else if (output_len_p) | |
798 | *output_len_p = bytes_output; | |
799 | ||
800 | return rv; | |
801 | } | |
802 | ||
803 | /* | |
804 | * SecCmsCipherContextDecrypt - do the decryption | |
805 | * | |
806 | * cc - the cipher context | |
807 | * output - buffer for decrypted result bytes | |
808 | * output_len_p - number of bytes in output | |
809 | * max_output_len - upper bound on bytes to put into output | |
810 | * input - pointer to input bytes | |
811 | * input_len - number of input bytes | |
812 | * final - true if this is the final chunk of data | |
813 | * | |
814 | * Decrypts a given length of input buffer (starting at "input" and | |
815 | * containing "input_len" bytes), placing the decrypted bytes in | |
816 | * "output" and storing the output length in "*output_len_p". | |
817 | * "cc" is the return value from SecCmsCipherStartDecrypt. | |
818 | * When "final" is true, this is the last of the data to be decrypted. | |
819 | * | |
820 | * This is much more complicated than it sounds when the cipher is | |
821 | * a block-type, meaning that the decryption function will only | |
822 | * operate on whole blocks. But our caller is operating stream-wise, | |
823 | * and can pass in any number of bytes. So we need to keep track | |
824 | * of block boundaries. We save excess bytes between calls in "cc". | |
825 | * We also need to determine which bytes are padding, and remove | |
826 | * them from the output. We can only do this step when we know we | |
827 | * have the final block of data. PKCS #7 specifies that the padding | |
828 | * used for a block cipher is a string of bytes, each of whose value is | |
829 | * the same as the length of the padding, and that all data is padded. | |
830 | * (Even data that starts out with an exact multiple of blocks gets | |
831 | * added to it another block, all of which is padding.) | |
832 | */ | |
833 | OSStatus | |
834 | SecCmsCipherContextDecrypt(SecCmsCipherContextRef cc, unsigned char *output, | |
835 | size_t *output_len_p, size_t max_output_len, | |
836 | const unsigned char *input, size_t input_len, | |
837 | Boolean final) | |
838 | { | |
839 | #if 1 | |
840 | return SecCmsCipherContextCrypt(cc, output, | |
841 | output_len_p, max_output_len, | |
842 | input, input_len, | |
843 | final, PR_FALSE); | |
844 | #else | |
845 | int blocks, bsize, pcount, padsize; | |
846 | unsigned int max_needed, ifraglen, ofraglen, output_len; | |
847 | unsigned char *pbuf; | |
848 | OSStatus rv; | |
849 | ||
850 | PORT_Assert (! cc->encrypt); | |
851 | ||
852 | /* | |
853 | * Check that we have enough room for the output. Our caller should | |
854 | * already handle this; failure is really an internal error (i.e. bug). | |
855 | */ | |
856 | max_needed = SecCmsCipherContextDecryptLength(cc, input_len, final); | |
857 | PORT_Assert (max_output_len >= max_needed); | |
858 | if (max_output_len < max_needed) { | |
859 | /* PORT_SetError (XXX); */ | |
860 | return SECFailure; | |
861 | } | |
862 | ||
863 | /* | |
864 | * hardware encryption does not like small decryption sizes here, so we | |
865 | * allow both blocking and padding. | |
866 | */ | |
867 | bsize = cc->block_size; | |
868 | padsize = cc->pad_size; | |
869 | ||
870 | /* | |
871 | * When no blocking or padding work to do, we can simply call the | |
872 | * cipher function and we are done. | |
873 | */ | |
874 | if (bsize == 0) { | |
875 | return (* cc->doit) (cc->cx, output, output_len_p, max_output_len, | |
876 | input, input_len); | |
877 | } | |
878 | ||
879 | pcount = cc->pending_count; | |
880 | pbuf = cc->pending_buf; | |
881 | ||
882 | output_len = 0; | |
883 | ||
884 | if (pcount) { | |
885 | /* | |
886 | * Try to fill in an entire block, starting with the bytes | |
887 | * we already have saved away. | |
888 | */ | |
889 | while (input_len && pcount < bsize) { | |
890 | pbuf[pcount++] = *input++; | |
891 | input_len--; | |
892 | } | |
893 | /* | |
894 | * If we have at most a whole block and this is not our last call, | |
895 | * then we are done for now. (We do not try to decrypt a lone | |
896 | * single block because we cannot interpret the padding bytes | |
897 | * until we know we are handling the very last block of all input.) | |
898 | */ | |
899 | if (input_len == 0 && !final) { | |
900 | cc->pending_count = pcount; | |
901 | if (output_len_p) | |
902 | *output_len_p = 0; | |
903 | return SECSuccess; | |
904 | } | |
905 | /* | |
906 | * Given the logic above, we expect to have a full block by now. | |
907 | * If we do not, there is something wrong, either with our own | |
908 | * logic or with (length of) the data given to us. | |
909 | */ | |
910 | if ((padsize != 0) && (pcount % padsize) != 0) { | |
911 | PORT_Assert (final); | |
912 | PORT_SetError (SEC_ERROR_BAD_DATA); | |
913 | return SECFailure; | |
914 | } | |
915 | /* | |
916 | * Decrypt the block. | |
917 | */ | |
918 | rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len, | |
919 | pbuf, pcount); | |
920 | if (rv != SECSuccess) | |
921 | return rv; | |
922 | ||
923 | /* | |
924 | * For now anyway, all of our ciphers have the same number of | |
925 | * bytes of output as they do input. If this ever becomes untrue, | |
926 | * then SecCmsCipherContextDecryptLength needs to be made smarter! | |
927 | */ | |
928 | PORT_Assert(ofraglen == pcount); | |
929 | ||
930 | /* | |
931 | * Account for the bytes now in output. | |
932 | */ | |
933 | max_output_len -= ofraglen; | |
934 | output_len += ofraglen; | |
935 | output += ofraglen; | |
936 | } | |
937 | ||
938 | /* | |
939 | * If this is our last call, we expect to have an exact number of | |
940 | * blocks left to be decrypted; we will decrypt them all. | |
941 | * | |
942 | * If not our last call, we always save between 1 and bsize bytes | |
943 | * until next time. (We must do this because we cannot be sure | |
944 | * that none of the decrypted bytes are padding bytes until we | |
945 | * have at least another whole block of data. You cannot tell by | |
946 | * looking -- the data could be anything -- you can only tell by | |
947 | * context, knowing you are looking at the last block.) We could | |
948 | * decrypt a whole block now but it is easier if we just treat it | |
949 | * the same way we treat partial block bytes. | |
950 | */ | |
951 | if (final) { | |
952 | if (padsize) { | |
953 | blocks = input_len / padsize; | |
954 | ifraglen = blocks * padsize; | |
955 | } else ifraglen = input_len; | |
956 | PORT_Assert (ifraglen == input_len); | |
957 | ||
958 | if (ifraglen != input_len) { | |
959 | PORT_SetError(SEC_ERROR_BAD_DATA); | |
960 | return SECFailure; | |
961 | } | |
962 | } else { | |
963 | blocks = (input_len - 1) / bsize; | |
964 | ifraglen = blocks * bsize; | |
965 | PORT_Assert (ifraglen < input_len); | |
966 | ||
967 | pcount = input_len - ifraglen; | |
968 | PORT_Memcpy (pbuf, input + ifraglen, pcount); | |
969 | cc->pending_count = pcount; | |
970 | } | |
971 | ||
972 | if (ifraglen) { | |
973 | rv = (* cc->doit)(cc->cx, output, &ofraglen, max_output_len, | |
974 | input, ifraglen); | |
975 | if (rv != SECSuccess) | |
976 | return rv; | |
977 | ||
978 | /* | |
979 | * For now anyway, all of our ciphers have the same number of | |
980 | * bytes of output as they do input. If this ever becomes untrue, | |
981 | * then sec_PKCS7DecryptLength needs to be made smarter! | |
982 | */ | |
983 | PORT_Assert (ifraglen == ofraglen); | |
984 | if (ifraglen != ofraglen) { | |
985 | PORT_SetError(SEC_ERROR_BAD_DATA); | |
986 | return SECFailure; | |
987 | } | |
988 | ||
989 | output_len += ofraglen; | |
990 | } else { | |
991 | ofraglen = 0; | |
992 | } | |
993 | ||
994 | /* | |
995 | * If we just did our very last block, "remove" the padding by | |
996 | * adjusting the output length. | |
997 | */ | |
998 | if (final && (padsize != 0)) { | |
999 | unsigned int padlen = *(output + ofraglen - 1); | |
1000 | ||
1001 | if (padlen == 0 || padlen > padsize) { | |
1002 | PORT_SetError(SEC_ERROR_BAD_DATA); | |
1003 | return SECFailure; | |
1004 | } | |
1005 | output_len -= padlen; | |
1006 | } | |
1007 | ||
1008 | PORT_Assert (output_len_p != NULL || output_len == 0); | |
1009 | if (output_len_p != NULL) | |
1010 | *output_len_p = output_len; | |
1011 | ||
1012 | return SECSuccess; | |
1013 | #endif | |
1014 | } | |
1015 | ||
1016 | /* | |
1017 | * SecCmsCipherContextEncrypt - do the encryption | |
1018 | * | |
1019 | * cc - the cipher context | |
1020 | * output - buffer for decrypted result bytes | |
1021 | * output_len_p - number of bytes in output | |
1022 | * max_output_len - upper bound on bytes to put into output | |
1023 | * input - pointer to input bytes | |
1024 | * input_len - number of input bytes | |
1025 | * final - true if this is the final chunk of data | |
1026 | * | |
1027 | * Encrypts a given length of input buffer (starting at "input" and | |
1028 | * containing "input_len" bytes), placing the encrypted bytes in | |
1029 | * "output" and storing the output length in "*output_len_p". | |
1030 | * "cc" is the return value from SecCmsCipherStartEncrypt. | |
1031 | * When "final" is true, this is the last of the data to be encrypted. | |
1032 | * | |
1033 | * This is much more complicated than it sounds when the cipher is | |
1034 | * a block-type, meaning that the encryption function will only | |
1035 | * operate on whole blocks. But our caller is operating stream-wise, | |
1036 | * and can pass in any number of bytes. So we need to keep track | |
1037 | * of block boundaries. We save excess bytes between calls in "cc". | |
1038 | * We also need to add padding bytes at the end. PKCS #7 specifies | |
1039 | * that the padding used for a block cipher is a string of bytes, | |
1040 | * each of whose value is the same as the length of the padding, | |
1041 | * and that all data is padded. (Even data that starts out with | |
1042 | * an exact multiple of blocks gets added to it another block, | |
1043 | * all of which is padding.) | |
1044 | * | |
1045 | * XXX I would kind of like to combine this with the function above | |
1046 | * which does decryption, since they have a lot in common. But the | |
1047 | * tricky parts about padding and filling blocks would be much | |
1048 | * harder to read that way, so I left them separate. At least for | |
1049 | * now until it is clear that they are right. | |
1050 | */ | |
1051 | OSStatus | |
1052 | SecCmsCipherContextEncrypt(SecCmsCipherContextRef cc, unsigned char *output, | |
1053 | size_t *output_len_p, size_t max_output_len, | |
1054 | const unsigned char *input, size_t input_len, | |
1055 | Boolean final) | |
1056 | { | |
1057 | #if 1 | |
1058 | return SecCmsCipherContextCrypt(cc, output, | |
1059 | output_len_p, max_output_len, | |
1060 | input, input_len, | |
1061 | final, PR_TRUE); | |
1062 | #else | |
1063 | int blocks, bsize, padlen, pcount, padsize; | |
1064 | unsigned int max_needed, ifraglen, ofraglen, output_len; | |
1065 | unsigned char *pbuf; | |
1066 | OSStatus rv; | |
1067 | ||
1068 | PORT_Assert (cc->encrypt); | |
1069 | ||
1070 | /* | |
1071 | * Check that we have enough room for the output. Our caller should | |
1072 | * already handle this; failure is really an internal error (i.e. bug). | |
1073 | */ | |
1074 | max_needed = SecCmsCipherContextEncryptLength (cc, input_len, final); | |
1075 | PORT_Assert (max_output_len >= max_needed); | |
1076 | if (max_output_len < max_needed) { | |
1077 | /* PORT_SetError (XXX); */ | |
1078 | return SECFailure; | |
1079 | } | |
1080 | ||
1081 | bsize = cc->block_size; | |
1082 | padsize = cc->pad_size; | |
1083 | ||
1084 | /* | |
1085 | * When no blocking and padding work to do, we can simply call the | |
1086 | * cipher function and we are done. | |
1087 | */ | |
1088 | if (bsize == 0) { | |
1089 | return (*cc->doit)(cc->cx, output, output_len_p, max_output_len, | |
1090 | input, input_len); | |
1091 | } | |
1092 | ||
1093 | pcount = cc->pending_count; | |
1094 | pbuf = cc->pending_buf; | |
1095 | ||
1096 | output_len = 0; | |
1097 | ||
1098 | if (pcount) { | |
1099 | /* | |
1100 | * Try to fill in an entire block, starting with the bytes | |
1101 | * we already have saved away. | |
1102 | */ | |
1103 | while (input_len && pcount < bsize) { | |
1104 | pbuf[pcount++] = *input++; | |
1105 | input_len--; | |
1106 | } | |
1107 | /* | |
1108 | * If we do not have a full block and we know we will be | |
1109 | * called again, then we are done for now. | |
1110 | */ | |
1111 | if (pcount < bsize && !final) { | |
1112 | cc->pending_count = pcount; | |
1113 | if (output_len_p != NULL) | |
1114 | *output_len_p = 0; | |
1115 | return SECSuccess; | |
1116 | } | |
1117 | /* | |
1118 | * If we have a whole block available, encrypt it. | |
1119 | */ | |
1120 | if ((padsize == 0) || (pcount % padsize) == 0) { | |
1121 | rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, | |
1122 | pbuf, pcount); | |
1123 | if (rv != SECSuccess) | |
1124 | return rv; | |
1125 | ||
1126 | /* | |
1127 | * For now anyway, all of our ciphers have the same number of | |
1128 | * bytes of output as they do input. If this ever becomes untrue, | |
1129 | * then sec_PKCS7EncryptLength needs to be made smarter! | |
1130 | */ | |
1131 | PORT_Assert (ofraglen == pcount); | |
1132 | ||
1133 | /* | |
1134 | * Account for the bytes now in output. | |
1135 | */ | |
1136 | max_output_len -= ofraglen; | |
1137 | output_len += ofraglen; | |
1138 | output += ofraglen; | |
1139 | ||
1140 | pcount = 0; | |
1141 | } | |
1142 | } | |
1143 | ||
1144 | if (input_len) { | |
1145 | PORT_Assert (pcount == 0); | |
1146 | ||
1147 | blocks = input_len / bsize; | |
1148 | ifraglen = blocks * bsize; | |
1149 | ||
1150 | if (ifraglen) { | |
1151 | rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, | |
1152 | input, ifraglen); | |
1153 | if (rv != SECSuccess) | |
1154 | return rv; | |
1155 | ||
1156 | /* | |
1157 | * For now anyway, all of our ciphers have the same number of | |
1158 | * bytes of output as they do input. If this ever becomes untrue, | |
1159 | * then sec_PKCS7EncryptLength needs to be made smarter! | |
1160 | */ | |
1161 | PORT_Assert (ifraglen == ofraglen); | |
1162 | ||
1163 | max_output_len -= ofraglen; | |
1164 | output_len += ofraglen; | |
1165 | output += ofraglen; | |
1166 | } | |
1167 | ||
1168 | pcount = input_len - ifraglen; | |
1169 | PORT_Assert (pcount < bsize); | |
1170 | if (pcount) | |
1171 | PORT_Memcpy (pbuf, input + ifraglen, pcount); | |
1172 | } | |
1173 | ||
1174 | if (final) { | |
1175 | padlen = padsize - (pcount % padsize); | |
1176 | PORT_Memset (pbuf + pcount, padlen, padlen); | |
1177 | rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, | |
1178 | pbuf, pcount+padlen); | |
1179 | if (rv != SECSuccess) | |
1180 | return rv; | |
1181 | ||
1182 | /* | |
1183 | * For now anyway, all of our ciphers have the same number of | |
1184 | * bytes of output as they do input. If this ever becomes untrue, | |
1185 | * then sec_PKCS7EncryptLength needs to be made smarter! | |
1186 | */ | |
1187 | PORT_Assert (ofraglen == (pcount+padlen)); | |
1188 | output_len += ofraglen; | |
1189 | } else { | |
1190 | cc->pending_count = pcount; | |
1191 | } | |
1192 | ||
1193 | PORT_Assert (output_len_p != NULL || output_len == 0); | |
1194 | if (output_len_p != NULL) | |
1195 | *output_len_p = output_len; | |
1196 | ||
1197 | return SECSuccess; | |
1198 | #endif | |
1199 | } |