Coverage Report

Created: 2025-06-24 06:49

/src/nss/lib/smime/cmscipher.c
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
/*
6
 * Encryption/decryption routines for CMS implementation, none of which are exported.
7
 */
8
9
#include "cmslocal.h"
10
11
#include "secoid.h"
12
#include "secitem.h"
13
#include "pk11func.h"
14
#include "secerr.h"
15
#include "secpkcs5.h"
16
17
/*
18
 * -------------------------------------------------------------------
19
 * Cipher stuff.
20
 */
21
22
typedef SECStatus (*nss_cms_cipher_function)(void *, unsigned char *, unsigned int *,
23
                                             unsigned int, const unsigned char *, unsigned int);
24
typedef SECStatus (*nss_cms_cipher_destroy)(void *, PRBool);
25
26
0
#define BLOCK_SIZE 4096
27
28
struct NSSCMSCipherContextStr {
29
    void *cx; /* PK11 cipher context */
30
    nss_cms_cipher_function doit;
31
    nss_cms_cipher_destroy destroy;
32
    PRBool encrypt; /* encrypt / decrypt switch */
33
    int block_size; /* block & pad sizes for cipher */
34
    int pad_size;
35
    int pending_count;                     /* pending data (not yet en/decrypted */
36
    unsigned char pending_buf[BLOCK_SIZE]; /* because of blocking */
37
};
38
39
/*
40
 * NSS_CMSCipherContext_StartDecrypt - create a cipher context to do decryption
41
 * based on the given bulk encryption key and algorithm identifier (which
42
 * may include an iv).
43
 *
44
 * XXX Once both are working, it might be nice to combine this and the
45
 * function below (for starting up encryption) into one routine, and just
46
 * have two simple cover functions which call it.
47
 */
48
NSSCMSCipherContext *
49
NSS_CMSCipherContext_StartDecrypt(PK11SymKey *key, SECAlgorithmID *algid)
50
0
{
51
0
    NSSCMSCipherContext *cc;
52
0
    void *ciphercx;
53
0
    CK_MECHANISM_TYPE cryptoMechType;
54
0
    PK11SlotInfo *slot;
55
0
    SECOidTag algtag;
56
0
    SECItem *param = NULL;
57
58
0
    algtag = SECOID_GetAlgorithmTag(algid);
59
60
    /* set param and mechanism */
61
0
    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
62
0
        SECItem *pwitem;
63
64
0
        pwitem = PK11_GetSymKeyUserData(key);
65
0
        if (!pwitem)
66
0
            return NULL;
67
68
0
        cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
69
0
        if (cryptoMechType == CKM_INVALID_MECHANISM) {
70
0
            SECITEM_FreeItem(param, PR_TRUE);
71
0
            return NULL;
72
0
        }
73
74
0
    } else {
75
0
        cryptoMechType = PK11_AlgtagToMechanism(algtag);
76
0
        if ((param = PK11_ParamFromAlgid(algid)) == NULL)
77
0
            return NULL;
78
0
    }
79
80
0
    cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext));
81
0
    if (cc == NULL) {
82
0
        SECITEM_FreeItem(param, PR_TRUE);
83
0
        return NULL;
84
0
    }
85
86
    /* figure out pad and block sizes */
87
0
    cc->pad_size = PK11_GetBlockSize(cryptoMechType, param);
88
0
    slot = PK11_GetSlotFromKey(key);
89
0
    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
90
0
    PK11_FreeSlot(slot);
91
92
    /* create PK11 cipher context */
93
0
    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
94
0
                                          key, param);
95
0
    SECITEM_FreeItem(param, PR_TRUE);
96
0
    if (ciphercx == NULL) {
97
0
        PORT_Free(cc);
98
0
        return NULL;
99
0
    }
100
101
0
    cc->cx = ciphercx;
102
0
    cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
103
0
    cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
104
0
    cc->encrypt = PR_FALSE;
105
0
    cc->pending_count = 0;
106
107
0
    return cc;
108
0
}
109
110
/*
111
 * NSS_CMSCipherContext_StartEncrypt - create a cipher object to do encryption,
112
 * based on the given bulk encryption key and algorithm tag.  Fill in the
113
 * algorithm identifier (which may include an iv) appropriately.
114
 *
115
 * XXX Once both are working, it might be nice to combine this and the
116
 * function above (for starting up decryption) into one routine, and just
117
 * have two simple cover functions which call it.
118
 */
119
NSSCMSCipherContext *
120
NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgorithmID *algid)
121
0
{
122
0
    NSSCMSCipherContext *cc;
123
0
    void *ciphercx = NULL;
124
0
    SECStatus rv;
125
0
    CK_MECHANISM_TYPE cryptoMechType;
126
0
    PK11SlotInfo *slot;
127
0
    SECItem *param = NULL;
128
0
    PRBool needToEncodeAlgid = PR_FALSE;
129
0
    SECOidTag algtag = SECOID_GetAlgorithmTag(algid);
130
131
    /* set param and mechanism */
132
0
    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
133
0
        SECItem *pwitem;
134
135
0
        pwitem = PK11_GetSymKeyUserData(key);
136
0
        if (!pwitem)
137
0
            return NULL;
138
139
0
        cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
140
0
        if (cryptoMechType == CKM_INVALID_MECHANISM) {
141
0
            SECITEM_FreeItem(param, PR_TRUE);
142
0
            return NULL;
143
0
        }
144
0
    } else {
145
0
        cryptoMechType = PK11_AlgtagToMechanism(algtag);
146
0
        if ((param = PK11_GenerateNewParam(cryptoMechType, key)) == NULL)
147
0
            return NULL;
148
0
        needToEncodeAlgid = PR_TRUE;
149
0
    }
150
151
0
    cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext));
152
0
    if (cc == NULL) {
153
0
        goto loser;
154
0
    }
155
156
    /* now find pad and block sizes for our mechanism */
157
0
    cc->pad_size = PK11_GetBlockSize(cryptoMechType, param);
158
0
    slot = PK11_GetSlotFromKey(key);
159
0
    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
160
0
    PK11_FreeSlot(slot);
161
162
    /* and here we go, creating a PK11 cipher context */
163
0
    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
164
0
                                          key, param);
165
0
    if (ciphercx == NULL) {
166
0
        PORT_Free(cc);
167
0
        cc = NULL;
168
0
        goto loser;
169
0
    }
170
171
    /*
172
     * These are placed after the CreateContextBySymKey() because some
173
     * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
174
     * Don't move it from here.
175
     * XXX is that right? the purpose of this is to get the correct algid
176
     *     containing the IVs etc. for encoding. this means we need to set this up
177
     *     BEFORE encoding the algid in the contentInfo, right?
178
     */
179
0
    if (needToEncodeAlgid) {
180
0
        rv = PK11_ParamToAlgid(algtag, param, poolp, algid);
181
0
        if (rv != SECSuccess) {
182
0
            PORT_Free(cc);
183
0
            cc = NULL;
184
0
            goto loser;
185
0
        }
186
0
    }
187
188
0
    cc->cx = ciphercx;
189
0
    ciphercx = NULL;
190
0
    cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
191
0
    cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
192
0
    cc->encrypt = PR_TRUE;
193
0
    cc->pending_count = 0;
194
195
0
loser:
196
0
    SECITEM_FreeItem(param, PR_TRUE);
197
0
    if (ciphercx) {
198
0
        PK11_DestroyContext(ciphercx, PR_TRUE);
199
0
    }
200
201
0
    return cc;
202
0
}
203
204
void
205
NSS_CMSCipherContext_Destroy(NSSCMSCipherContext *cc)
206
0
{
207
0
    PORT_Assert(cc != NULL);
208
0
    if (cc == NULL)
209
0
        return;
210
0
    (*cc->destroy)(cc->cx, PR_TRUE);
211
0
    PORT_Free(cc);
212
0
}
213
214
/*
215
 * NSS_CMSCipherContext_DecryptLength - find the output length of the next call to decrypt.
216
 *
217
 * cc - the cipher context
218
 * input_len - number of bytes used as input
219
 * final - true if this is the final chunk of data
220
 *
221
 * Result can be used to perform memory allocations.  Note that the amount
222
 * is exactly accurate only when not doing a block cipher or when final
223
 * is false, otherwise it is an upper bound on the amount because until
224
 * we see the data we do not know how many padding bytes there are
225
 * (always between 1 and bsize).
226
 *
227
 * Note that this can return zero, which does not mean that the decrypt
228
 * operation can be skipped!  (It simply means that there are not enough
229
 * bytes to make up an entire block; the bytes will be reserved until
230
 * there are enough to encrypt/decrypt at least one block.)  However,
231
 * if zero is returned it *does* mean that no output buffer need be
232
 * passed in to the subsequent decrypt operation, as no output bytes
233
 * will be stored.
234
 */
235
unsigned int
236
NSS_CMSCipherContext_DecryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final)
237
0
{
238
0
    int blocks, block_size;
239
240
0
    PORT_Assert(!cc->encrypt);
241
242
0
    block_size = cc->block_size;
243
244
    /*
245
     * If this is not a block cipher, then we always have the same
246
     * number of output bytes as we had input bytes.
247
     */
248
0
    if (block_size == 0)
249
0
        return input_len;
250
251
    /*
252
     * On the final call, we will always use up all of the pending
253
     * bytes plus all of the input bytes, *but*, there will be padding
254
     * at the end and we cannot predict how many bytes of padding we
255
     * will end up removing.  The amount given here is actually known
256
     * to be at least 1 byte too long (because we know we will have
257
     * at least 1 byte of padding), but seemed clearer/better to me.
258
     */
259
0
    if (final)
260
0
        return cc->pending_count + input_len;
261
262
    /*
263
     * Okay, this amount is exactly what we will output on the
264
     * next cipher operation.  We will always hang onto the last
265
     * 1 - block_size bytes for non-final operations.  That is,
266
     * we will do as many complete blocks as we can *except* the
267
     * last block (complete or partial).  (This is because until
268
     * we know we are at the end, we cannot know when to interpret
269
     * and removing the padding byte(s), which are guaranteed to
270
     * be there.)
271
     */
272
0
    blocks = (cc->pending_count + input_len - 1) / block_size;
273
0
    return blocks * block_size;
274
0
}
275
276
/*
277
 * NSS_CMSCipherContext_EncryptLength - find the output length of the next call to encrypt.
278
 *
279
 * cc - the cipher context
280
 * input_len - number of bytes used as input
281
 * final - true if this is the final chunk of data
282
 *
283
 * Result can be used to perform memory allocations.
284
 *
285
 * Note that this can return zero, which does not mean that the encrypt
286
 * operation can be skipped!  (It simply means that there are not enough
287
 * bytes to make up an entire block; the bytes will be reserved until
288
 * there are enough to encrypt/decrypt at least one block.)  However,
289
 * if zero is returned it *does* mean that no output buffer need be
290
 * passed in to the subsequent encrypt operation, as no output bytes
291
 * will be stored.
292
 */
293
unsigned int
294
NSS_CMSCipherContext_EncryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final)
295
0
{
296
0
    int blocks, block_size;
297
0
    int pad_size;
298
299
0
    PORT_Assert(cc->encrypt);
300
301
0
    block_size = cc->block_size;
302
0
    pad_size = cc->pad_size;
303
304
    /*
305
     * If this is not a block cipher, then we always have the same
306
     * number of output bytes as we had input bytes.
307
     */
308
0
    if (block_size == 0)
309
0
        return input_len;
310
311
    /*
312
     * On the final call, we only send out what we need for
313
     * remaining bytes plus the padding.  (There is always padding,
314
     * so even if we have an exact number of blocks as input, we
315
     * will add another full block that is just padding.)
316
     */
317
0
    if (final) {
318
0
        if (pad_size == 0) {
319
0
            return cc->pending_count + input_len;
320
0
        } else {
321
0
            blocks = (cc->pending_count + input_len) / pad_size;
322
0
            blocks++;
323
0
            return blocks * pad_size;
324
0
        }
325
0
    }
326
327
    /*
328
     * Now, count the number of complete blocks of data we have.
329
     */
330
0
    blocks = (cc->pending_count + input_len) / block_size;
331
332
0
    return blocks * block_size;
333
0
}
334
335
/*
336
 * NSS_CMSCipherContext_Decrypt - do the decryption
337
 *
338
 * cc - the cipher context
339
 * output - buffer for decrypted result bytes
340
 * output_len_p - number of bytes in output
341
 * max_output_len - upper bound on bytes to put into output
342
 * input - pointer to input bytes
343
 * input_len - number of input bytes
344
 * final - true if this is the final chunk of data
345
 *
346
 * Decrypts a given length of input buffer (starting at "input" and
347
 * containing "input_len" bytes), placing the decrypted bytes in
348
 * "output" and storing the output length in "*output_len_p".
349
 * "cc" is the return value from NSS_CMSCipher_StartDecrypt.
350
 * When "final" is true, this is the last of the data to be decrypted.
351
 *
352
 * This is much more complicated than it sounds when the cipher is
353
 * a block-type, meaning that the decryption function will only
354
 * operate on whole blocks.  But our caller is operating stream-wise,
355
 * and can pass in any number of bytes.  So we need to keep track
356
 * of block boundaries.  We save excess bytes between calls in "cc".
357
 * We also need to determine which bytes are padding, and remove
358
 * them from the output.  We can only do this step when we know we
359
 * have the final block of data.  PKCS #7 specifies that the padding
360
 * used for a block cipher is a string of bytes, each of whose value is
361
 * the same as the length of the padding, and that all data is padded.
362
 * (Even data that starts out with an exact multiple of blocks gets
363
 * added to it another block, all of which is padding.)
364
 */
365
SECStatus
366
NSS_CMSCipherContext_Decrypt(NSSCMSCipherContext *cc, unsigned char *output,
367
                             unsigned int *output_len_p, unsigned int max_output_len,
368
                             const unsigned char *input, unsigned int input_len,
369
                             PRBool final)
370
0
{
371
0
    unsigned int blocks, bsize, pcount, padsize;
372
0
    unsigned int max_needed, ifraglen, ofraglen, output_len;
373
0
    unsigned char *pbuf;
374
0
    SECStatus rv;
375
376
0
    PORT_Assert(!cc->encrypt);
377
378
    /*
379
     * Check that we have enough room for the output.  Our caller should
380
     * already handle this; failure is really an internal error (i.e. bug).
381
     */
382
0
    max_needed = NSS_CMSCipherContext_DecryptLength(cc, input_len, final);
383
0
    PORT_Assert(max_output_len >= max_needed);
384
0
    if (max_output_len < max_needed) {
385
        /* PORT_SetError (XXX); */
386
0
        return SECFailure;
387
0
    }
388
389
    /*
390
     * hardware encryption does not like small decryption sizes here, so we
391
     * allow both blocking and padding.
392
     */
393
0
    bsize = cc->block_size;
394
0
    padsize = cc->pad_size;
395
396
    /*
397
     * When no blocking or padding work to do, we can simply call the
398
     * cipher function and we are done.
399
     */
400
0
    if (bsize == 0) {
401
0
        return (*cc->doit)(cc->cx, output, output_len_p, max_output_len,
402
0
                           input, input_len);
403
0
    }
404
405
0
    pcount = cc->pending_count;
406
0
    pbuf = cc->pending_buf;
407
408
0
    output_len = 0;
409
410
0
    if (pcount) {
411
        /*
412
         * Try to fill in an entire block, starting with the bytes
413
         * we already have saved away.
414
         */
415
0
        while (input_len && pcount < bsize) {
416
0
            pbuf[pcount++] = *input++;
417
0
            input_len--;
418
0
        }
419
        /*
420
         * If we have at most a whole block and this is not our last call,
421
         * then we are done for now.  (We do not try to decrypt a lone
422
         * single block because we cannot interpret the padding bytes
423
         * until we know we are handling the very last block of all input.)
424
         */
425
0
        if (input_len == 0 && !final) {
426
0
            cc->pending_count = pcount;
427
0
            if (output_len_p)
428
0
                *output_len_p = 0;
429
0
            return SECSuccess;
430
0
        }
431
        /*
432
         * Given the logic above, we expect to have a full block by now.
433
         * If we do not, there is something wrong, either with our own
434
         * logic or with (length of) the data given to us.
435
         */
436
0
        if ((padsize != 0) && (pcount % padsize) != 0) {
437
0
            PORT_Assert(final);
438
0
            PORT_SetError(SEC_ERROR_BAD_DATA);
439
0
            return SECFailure;
440
0
        }
441
        /*
442
         * Decrypt the block.
443
         */
444
0
        rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
445
0
                         pbuf, pcount);
446
0
        if (rv != SECSuccess)
447
0
            return rv;
448
449
        /*
450
         * For now anyway, all of our ciphers have the same number of
451
         * bytes of output as they do input.  If this ever becomes untrue,
452
         * then NSS_CMSCipherContext_DecryptLength needs to be made smarter!
453
         */
454
0
        PORT_Assert(ofraglen == pcount);
455
456
        /*
457
         * Account for the bytes now in output.
458
         */
459
0
        max_output_len -= ofraglen;
460
0
        output_len += ofraglen;
461
0
        output += ofraglen;
462
0
    }
463
464
    /*
465
     * If this is our last call, we expect to have an exact number of
466
     * blocks left to be decrypted; we will decrypt them all.
467
     *
468
     * If not our last call, we always save between 1 and bsize bytes
469
     * until next time.  (We must do this because we cannot be sure
470
     * that none of the decrypted bytes are padding bytes until we
471
     * have at least another whole block of data.  You cannot tell by
472
     * looking -- the data could be anything -- you can only tell by
473
     * context, knowing you are looking at the last block.)  We could
474
     * decrypt a whole block now but it is easier if we just treat it
475
     * the same way we treat partial block bytes.
476
     */
477
0
    if (final) {
478
0
        if (padsize) {
479
0
            blocks = input_len / padsize;
480
0
            ifraglen = blocks * padsize;
481
0
        } else
482
0
            ifraglen = input_len;
483
0
        PORT_Assert(ifraglen == input_len);
484
485
0
        if (ifraglen != input_len) {
486
0
            PORT_SetError(SEC_ERROR_BAD_DATA);
487
0
            return SECFailure;
488
0
        }
489
0
    } else {
490
0
        blocks = (input_len - 1) / bsize;
491
0
        ifraglen = blocks * bsize;
492
0
        PORT_Assert(ifraglen < input_len);
493
494
0
        pcount = input_len - ifraglen;
495
0
        PORT_Memcpy(pbuf, input + ifraglen, pcount);
496
0
        cc->pending_count = pcount;
497
0
    }
498
499
0
    if (ifraglen) {
500
0
        rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
501
0
                         input, ifraglen);
502
0
        if (rv != SECSuccess)
503
0
            return rv;
504
505
        /*
506
         * For now anyway, all of our ciphers have the same number of
507
         * bytes of output as they do input.  If this ever becomes untrue,
508
         * then sec_PKCS7DecryptLength needs to be made smarter!
509
         */
510
0
        PORT_Assert(ifraglen == ofraglen);
511
0
        if (ifraglen != ofraglen) {
512
0
            PORT_SetError(SEC_ERROR_BAD_DATA);
513
0
            return SECFailure;
514
0
        }
515
516
0
        output_len += ofraglen;
517
0
    } else {
518
0
        ofraglen = 0;
519
0
    }
520
521
    /*
522
     * If we just did our very last block, "remove" the padding by
523
     * adjusting the output length.
524
     */
525
0
    if (final && (padsize != 0)) {
526
0
        unsigned int padlen = *(output + ofraglen - 1);
527
528
0
        if (padlen == 0 || padlen > padsize) {
529
0
            PORT_SetError(SEC_ERROR_BAD_DATA);
530
0
            return SECFailure;
531
0
        }
532
0
        output_len -= padlen;
533
0
    }
534
535
0
    PORT_Assert(output_len_p != NULL || output_len == 0);
536
0
    if (output_len_p != NULL)
537
0
        *output_len_p = output_len;
538
539
0
    return SECSuccess;
540
0
}
541
542
/*
543
 * NSS_CMSCipherContext_Encrypt - do the encryption
544
 *
545
 * cc - the cipher context
546
 * output - buffer for decrypted result bytes
547
 * output_len_p - number of bytes in output
548
 * max_output_len - upper bound on bytes to put into output
549
 * input - pointer to input bytes
550
 * input_len - number of input bytes
551
 * final - true if this is the final chunk of data
552
 *
553
 * Encrypts a given length of input buffer (starting at "input" and
554
 * containing "input_len" bytes), placing the encrypted bytes in
555
 * "output" and storing the output length in "*output_len_p".
556
 * "cc" is the return value from NSS_CMSCipher_StartEncrypt.
557
 * When "final" is true, this is the last of the data to be encrypted.
558
 *
559
 * This is much more complicated than it sounds when the cipher is
560
 * a block-type, meaning that the encryption function will only
561
 * operate on whole blocks.  But our caller is operating stream-wise,
562
 * and can pass in any number of bytes.  So we need to keep track
563
 * of block boundaries.  We save excess bytes between calls in "cc".
564
 * We also need to add padding bytes at the end.  PKCS #7 specifies
565
 * that the padding used for a block cipher is a string of bytes,
566
 * each of whose value is the same as the length of the padding,
567
 * and that all data is padded.  (Even data that starts out with
568
 * an exact multiple of blocks gets added to it another block,
569
 * all of which is padding.)
570
 *
571
 * XXX I would kind of like to combine this with the function above
572
 * which does decryption, since they have a lot in common.  But the
573
 * tricky parts about padding and filling blocks would be much
574
 * harder to read that way, so I left them separate.  At least for
575
 * now until it is clear that they are right.
576
 */
577
SECStatus
578
NSS_CMSCipherContext_Encrypt(NSSCMSCipherContext *cc, unsigned char *output,
579
                             unsigned int *output_len_p, unsigned int max_output_len,
580
                             const unsigned char *input, unsigned int input_len,
581
                             PRBool final)
582
0
{
583
0
    int blocks, bsize, padlen, pcount, padsize;
584
0
    unsigned int max_needed, ifraglen, ofraglen, output_len;
585
0
    unsigned char *pbuf;
586
0
    SECStatus rv;
587
588
0
    PORT_Assert(cc->encrypt);
589
590
    /*
591
     * Check that we have enough room for the output.  Our caller should
592
     * already handle this; failure is really an internal error (i.e. bug).
593
     */
594
0
    max_needed = NSS_CMSCipherContext_EncryptLength(cc, input_len, final);
595
0
    PORT_Assert(max_output_len >= max_needed);
596
0
    if (max_output_len < max_needed) {
597
        /* PORT_SetError (XXX); */
598
0
        return SECFailure;
599
0
    }
600
601
0
    bsize = cc->block_size;
602
0
    padsize = cc->pad_size;
603
604
    /*
605
     * When no blocking and padding work to do, we can simply call the
606
     * cipher function and we are done.
607
     */
608
0
    if (bsize == 0) {
609
0
        return (*cc->doit)(cc->cx, output, output_len_p, max_output_len,
610
0
                           input, input_len);
611
0
    }
612
613
0
    pcount = cc->pending_count;
614
0
    pbuf = cc->pending_buf;
615
616
0
    output_len = 0;
617
618
0
    if (pcount) {
619
        /*
620
         * Try to fill in an entire block, starting with the bytes
621
         * we already have saved away.
622
         */
623
0
        while (input_len && pcount < bsize) {
624
0
            pbuf[pcount++] = *input++;
625
0
            input_len--;
626
0
        }
627
        /*
628
         * If we do not have a full block and we know we will be
629
         * called again, then we are done for now.
630
         */
631
0
        if (pcount < bsize && !final) {
632
0
            cc->pending_count = pcount;
633
0
            if (output_len_p != NULL)
634
0
                *output_len_p = 0;
635
0
            return SECSuccess;
636
0
        }
637
        /*
638
         * If we have a whole block available, encrypt it.
639
         */
640
0
        if ((padsize == 0) || (pcount % padsize) == 0) {
641
0
            rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
642
0
                             pbuf, pcount);
643
0
            if (rv != SECSuccess)
644
0
                return rv;
645
646
            /*
647
             * For now anyway, all of our ciphers have the same number of
648
             * bytes of output as they do input.  If this ever becomes untrue,
649
             * then sec_PKCS7EncryptLength needs to be made smarter!
650
             */
651
0
            PORT_Assert(ofraglen == pcount);
652
653
            /*
654
             * Account for the bytes now in output.
655
             */
656
0
            max_output_len -= ofraglen;
657
0
            output_len += ofraglen;
658
0
            output += ofraglen;
659
660
0
            pcount = 0;
661
0
        }
662
0
    }
663
664
0
    if (input_len) {
665
0
        PORT_Assert(pcount == 0);
666
667
0
        blocks = input_len / bsize;
668
0
        ifraglen = blocks * bsize;
669
670
0
        if (ifraglen) {
671
0
            rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
672
0
                             input, ifraglen);
673
0
            if (rv != SECSuccess)
674
0
                return rv;
675
676
            /*
677
             * For now anyway, all of our ciphers have the same number of
678
             * bytes of output as they do input.  If this ever becomes untrue,
679
             * then sec_PKCS7EncryptLength needs to be made smarter!
680
             */
681
0
            PORT_Assert(ifraglen == ofraglen);
682
683
0
            max_output_len -= ofraglen;
684
0
            output_len += ofraglen;
685
0
            output += ofraglen;
686
0
        }
687
688
0
        pcount = input_len - ifraglen;
689
0
        PORT_Assert(pcount < bsize);
690
0
        if (pcount)
691
0
            PORT_Memcpy(pbuf, input + ifraglen, pcount);
692
0
    }
693
694
0
    if (final) {
695
0
        if (padsize <= 0) {
696
0
            padlen = 0;
697
0
        } else {
698
0
            padlen = padsize - (pcount % padsize);
699
0
            PORT_Memset(pbuf + pcount, padlen, padlen);
700
0
        }
701
0
        rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
702
0
                         pbuf, pcount + padlen);
703
0
        if (rv != SECSuccess)
704
0
            return rv;
705
706
        /*
707
         * For now anyway, all of our ciphers have the same number of
708
         * bytes of output as they do input.  If this ever becomes untrue,
709
         * then sec_PKCS7EncryptLength needs to be made smarter!
710
         */
711
0
        PORT_Assert(ofraglen == (pcount + padlen));
712
0
        output_len += ofraglen;
713
0
    } else {
714
0
        cc->pending_count = pcount;
715
0
    }
716
717
0
    PORT_Assert(output_len_p != NULL || output_len == 0);
718
0
    if (output_len_p != NULL)
719
0
        *output_len_p = output_len;
720
721
0
    return SECSuccess;
722
0
}