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/. */
19
struct nss_cms_encoder_output {
20
NSSCMSContentCallback outputfn;
22
PLArenaPool *destpoolp;
26
struct NSSCMSEncoderContextStr {
27
SEC_ASN1EncoderContext * ecx; /* ASN.1 encoder context */
28
PRBool ecxupdated; /* true if data was handed in */
29
NSSCMSMessage * cmsg; /* pointer to the root message */
30
SECOidTag type; /* type tag of the current content */
31
NSSCMSContent content; /* pointer to current content */
32
struct nss_cms_encoder_output output; /* output function */
33
int error; /* error code */
34
NSSCMSEncoderContext * childp7ecx; /* link to child encoder context */
37
static SECStatus nss_cms_before_data(NSSCMSEncoderContext *p7ecx);
38
static SECStatus nss_cms_after_data(NSSCMSEncoderContext *p7ecx);
39
static SECStatus nss_cms_encoder_update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned long len);
40
static SECStatus nss_cms_encoder_work_data(NSSCMSEncoderContext *p7ecx, SECItem *dest,
41
const unsigned char *data, unsigned long len,
42
PRBool final, PRBool innermost);
44
extern const SEC_ASN1Template NSSCMSMessageTemplate[];
47
* The little output function that the ASN.1 encoder calls to hand
48
* us bytes which we in turn hand back to our caller (via the callback
52
nss_cms_encoder_out(void *arg, const char *buf, unsigned long len,
53
int depth, SEC_ASN1EncodingPart data_kind)
55
struct nss_cms_encoder_output *output = (struct nss_cms_encoder_output *)arg;
61
const char *data_name = "unknown";
64
case SEC_ASN1_Identifier:
65
data_name = "identifier";
70
case SEC_ASN1_Contents:
71
data_name = "contents";
73
case SEC_ASN1_EndOfContents:
74
data_name = "end-of-contents";
77
fprintf(stderr, "kind = %s, depth = %d, len = %d\n", data_name, depth, len);
78
for (i=0; i < len; i++) {
79
fprintf(stderr, " %02x%s", (unsigned int)buf[i] & 0xff, ((i % 16) == 15) ? "\n" : "");
82
fprintf(stderr, "\n");
85
if (output->outputfn != NULL)
86
/* call output callback with DER data */
87
output->outputfn(output->outputarg, buf, len);
89
if (output->dest != NULL) {
90
/* store DER data in SECItem */
91
offset = output->dest->len;
93
dest = (unsigned char *)PORT_ArenaAlloc(output->destpoolp, len);
95
dest = (unsigned char *)PORT_ArenaGrow(output->destpoolp,
98
output->dest->len + len);
104
output->dest->data = dest;
105
output->dest->len += len;
108
PORT_Memcpy(output->dest->data + offset, buf, len);
113
* nss_cms_encoder_notify - ASN.1 encoder callback
115
* this function is called by the ASN.1 encoder before and after the encoding of
116
* every object. here, it is used to keep track of data structures, set up
117
* encryption and/or digesting and possibly set up child encoders.
120
nss_cms_encoder_notify(void *arg, PRBool before, void *dest, int depth)
122
NSSCMSEncoderContext *p7ecx;
123
NSSCMSContentInfo *rootcinfo, *cinfo;
124
PRBool after = !before;
129
p7ecx = (NSSCMSEncoderContext *)arg;
130
PORT_Assert(p7ecx != NULL);
132
rootcinfo = &(p7ecx->cmsg->contentInfo);
133
poolp = p7ecx->cmsg->poolp;
136
fprintf(stderr, "%6.6s, dest = 0x%08x, depth = %d\n", before ? "before" : "after", dest, depth);
140
* Watch for the content field, at which point we want to instruct
141
* the ASN.1 encoder to start taking bytes from the buffer.
143
if (NSS_CMSType_IsData(p7ecx->type)) {
144
cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);
145
if (before && dest == &(cinfo->rawContent)) {
146
/* just set up encoder to grab from user - no encryption or digesting */
147
if ((item = cinfo->content.data) != NULL)
148
(void)nss_cms_encoder_work_data(p7ecx, NULL, item->data, item->len, PR_TRUE, PR_TRUE);
150
SEC_ASN1EncoderSetTakeFromBuf(p7ecx->ecx);
151
SEC_ASN1EncoderClearNotifyProc(p7ecx->ecx); /* no need to get notified anymore */
153
} else if (NSS_CMSType_IsWrapper(p7ecx->type)) {
154
/* when we know what the content is, we encode happily until we reach the inner content */
155
cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);
156
childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
158
if (after && dest == &(cinfo->contentType)) {
159
/* we're right before encoding the data (if we have some or not) */
160
/* (for encrypted data, we're right before the contentEncAlg which may change */
161
/* in nss_cms_before_data because of IV calculation when setting up encryption) */
162
if (nss_cms_before_data(p7ecx) != SECSuccess)
163
p7ecx->error = PORT_GetError();
165
if (before && dest == &(cinfo->rawContent)) {
166
if (p7ecx->childp7ecx == NULL) {
167
if ((NSS_CMSType_IsData(childtype) && (item = cinfo->content.data) != NULL)) {
168
/* we are the innermost non-data and we have data - feed it in */
169
(void)nss_cms_encoder_work_data(p7ecx, NULL, item->data, item->len, PR_TRUE, PR_TRUE);
171
/* else we'll have to get data from user */
172
SEC_ASN1EncoderSetTakeFromBuf(p7ecx->ecx);
175
/* if we have a nested encoder, wait for its data */
176
SEC_ASN1EncoderSetTakeFromBuf(p7ecx->ecx);
179
if (after && dest == &(cinfo->rawContent)) {
180
if (nss_cms_after_data(p7ecx) != SECSuccess)
181
p7ecx->error = PORT_GetError();
182
SEC_ASN1EncoderClearNotifyProc(p7ecx->ecx); /* no need to get notified anymore */
185
/* we're still in the root message */
186
if (after && dest == &(rootcinfo->contentType)) {
187
/* got the content type OID now - so find out the type tag */
188
p7ecx->type = NSS_CMSContentInfo_GetContentTypeTag(rootcinfo);
189
/* set up a pointer to our current content */
190
p7ecx->content = rootcinfo->content;
196
* nss_cms_before_data - setup the current encoder to receive data
199
nss_cms_before_data(NSSCMSEncoderContext *p7ecx)
203
NSSCMSContentInfo *cinfo;
205
NSSCMSEncoderContext *childp7ecx;
206
const SEC_ASN1Template *template;
208
poolp = p7ecx->cmsg->poolp;
210
/* call _Encode_BeforeData handlers */
211
switch (p7ecx->type) {
212
case SEC_OID_PKCS7_SIGNED_DATA:
213
/* we're encoding a signedData, so set up the digests */
214
rv = NSS_CMSSignedData_Encode_BeforeData(p7ecx->content.signedData);
216
case SEC_OID_PKCS7_DIGESTED_DATA:
217
/* we're encoding a digestedData, so set up the digest */
218
rv = NSS_CMSDigestedData_Encode_BeforeData(p7ecx->content.digestedData);
220
case SEC_OID_PKCS7_ENVELOPED_DATA:
221
rv = NSS_CMSEnvelopedData_Encode_BeforeData(p7ecx->content.envelopedData);
223
case SEC_OID_PKCS7_ENCRYPTED_DATA:
224
rv = NSS_CMSEncryptedData_Encode_BeforeData(p7ecx->content.encryptedData);
227
if (NSS_CMSType_IsWrapper(p7ecx->type)) {
228
rv = NSS_CMSGenericWrapperData_Encode_BeforeData(p7ecx->type, p7ecx->content.genericData);
233
if (rv != SECSuccess)
236
/* ok, now we have a pointer to cinfo */
237
/* find out what kind of data is encapsulated */
239
cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);
240
childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
242
if (NSS_CMSType_IsWrapper(childtype)) {
243
/* in these cases, we need to set up a child encoder! */
244
/* create new encoder context */
245
childp7ecx = PORT_ZAlloc(sizeof(NSSCMSEncoderContext));
246
if (childp7ecx == NULL)
249
/* the CHILD encoder needs to hand its encoded data to the CURRENT encoder
250
* (which will encrypt and/or digest it)
251
* this needs to route back into our update function
252
* which finds the lowest encoding context & encrypts and computes digests */
253
childp7ecx->type = childtype;
254
childp7ecx->content = cinfo->content;
255
/* use the non-recursive update function here, of course */
256
childp7ecx->output.outputfn = (NSSCMSContentCallback)nss_cms_encoder_update;
257
childp7ecx->output.outputarg = p7ecx;
258
childp7ecx->output.destpoolp = NULL;
259
childp7ecx->output.dest = NULL;
260
childp7ecx->cmsg = p7ecx->cmsg;
261
childp7ecx->ecxupdated = PR_FALSE;
262
childp7ecx->childp7ecx = NULL;
264
template = NSS_CMSUtil_GetTemplateByTypeTag(childtype);
265
if (template == NULL)
266
goto loser; /* cannot happen */
268
/* now initialize the data for encoding the first third */
269
switch (childp7ecx->type) {
270
case SEC_OID_PKCS7_SIGNED_DATA:
271
rv = NSS_CMSSignedData_Encode_BeforeStart(cinfo->content.signedData);
273
case SEC_OID_PKCS7_ENVELOPED_DATA:
274
rv = NSS_CMSEnvelopedData_Encode_BeforeStart(cinfo->content.envelopedData);
276
case SEC_OID_PKCS7_DIGESTED_DATA:
277
rv = NSS_CMSDigestedData_Encode_BeforeStart(cinfo->content.digestedData);
279
case SEC_OID_PKCS7_ENCRYPTED_DATA:
280
rv = NSS_CMSEncryptedData_Encode_BeforeStart(cinfo->content.encryptedData);
283
rv = NSS_CMSGenericWrapperData_Encode_BeforeStart(childp7ecx->type, cinfo->content.genericData);
286
if (rv != SECSuccess)
290
* Initialize the BER encoder.
292
childp7ecx->ecx = SEC_ASN1EncoderStart(cinfo->content.pointer, template,
293
nss_cms_encoder_out, &(childp7ecx->output));
294
if (childp7ecx->ecx == NULL)
298
* Indicate that we are streaming. We will be streaming until we
299
* get past the contents bytes.
301
if (!cinfo->privateInfo || !cinfo->privateInfo->dontStream)
302
SEC_ASN1EncoderSetStreaming(childp7ecx->ecx);
305
* The notify function will watch for the contents field.
307
p7ecx->childp7ecx = childp7ecx;
308
SEC_ASN1EncoderSetNotifyProc(childp7ecx->ecx, nss_cms_encoder_notify, childp7ecx);
310
/* please note that we are NOT calling SEC_ASN1EncoderUpdate here to kick off the */
311
/* encoding process - we'll do that from the update function instead */
312
/* otherwise we'd be encoding data from a call of the notify function of the */
313
/* parent encoder (which would not work) */
315
} else if (NSS_CMSType_IsData(childtype)) {
316
p7ecx->childp7ecx = NULL;
318
/* we do not know this type */
319
p7ecx->error = SEC_ERROR_BAD_DER;
327
SEC_ASN1EncoderFinish(childp7ecx->ecx);
328
PORT_Free(childp7ecx);
329
p7ecx->childp7ecx = NULL;
335
nss_cms_after_data(NSSCMSEncoderContext *p7ecx)
337
SECStatus rv = SECFailure;
339
switch (p7ecx->type) {
340
case SEC_OID_PKCS7_SIGNED_DATA:
341
/* this will finish the digests and sign */
342
rv = NSS_CMSSignedData_Encode_AfterData(p7ecx->content.signedData);
344
case SEC_OID_PKCS7_ENVELOPED_DATA:
345
rv = NSS_CMSEnvelopedData_Encode_AfterData(p7ecx->content.envelopedData);
347
case SEC_OID_PKCS7_DIGESTED_DATA:
348
rv = NSS_CMSDigestedData_Encode_AfterData(p7ecx->content.digestedData);
350
case SEC_OID_PKCS7_ENCRYPTED_DATA:
351
rv = NSS_CMSEncryptedData_Encode_AfterData(p7ecx->content.encryptedData);
354
if (NSS_CMSType_IsWrapper(p7ecx->type)) {
355
rv = NSS_CMSGenericWrapperData_Encode_AfterData(p7ecx->type, p7ecx->content.genericData);
365
* nss_cms_encoder_work_data - process incoming data
367
* (from the user or the next encoding layer)
368
* Here, we need to digest and/or encrypt, then pass it on
371
nss_cms_encoder_work_data(NSSCMSEncoderContext *p7ecx, SECItem *dest,
372
const unsigned char *data, unsigned long len,
373
PRBool final, PRBool innermost)
375
unsigned char *buf = NULL;
377
NSSCMSContentInfo *cinfo;
379
rv = SECSuccess; /* may as well be optimistic */
382
* We should really have data to process, or we should be trying
383
* to finish/flush the last block. (This is an overly paranoid
384
* check since all callers are in this file and simple inspection
385
* proves they do it right. But it could find a bug in future
386
* modifications/development, that is why it is here.)
388
PORT_Assert ((data != NULL && len) || final);
390
/* we got data (either from the caller, or from a lower level encoder) */
391
cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);
393
/* The original programmer didn't expect this to happen */
394
p7ecx->error = SEC_ERROR_LIBRARY_FAILURE;
398
/* Update the running digest. */
399
if (len && cinfo->privateInfo && cinfo->privateInfo->digcx != NULL)
400
NSS_CMSDigestContext_Update(cinfo->privateInfo->digcx, data, len);
402
/* Encrypt this chunk. */
403
if (cinfo->privateInfo && cinfo->privateInfo->ciphcx != NULL) {
404
unsigned int inlen; /* length of data being encrypted */
405
unsigned int outlen; /* length of encrypted data */
406
unsigned int buflen; /* length available for encrypted data */
409
buflen = NSS_CMSCipherContext_EncryptLength(cinfo->privateInfo->ciphcx, inlen, final);
412
* No output is expected, but the input data may be buffered
413
* so we still have to call Encrypt.
415
rv = NSS_CMSCipherContext_Encrypt(cinfo->privateInfo->ciphcx, NULL, NULL, 0,
425
buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cmsg->poolp, buflen);
427
buf = (unsigned char*)PORT_Alloc(buflen);
432
rv = NSS_CMSCipherContext_Encrypt(cinfo->privateInfo->ciphcx, buf, &outlen, buflen,
437
if (rv != SECSuccess)
438
/* encryption or malloc failed? */
444
* at this point (data,len) has everything we'd like to give to the CURRENT encoder
445
* (which will encode it, then hand it back to the user or the parent encoder)
446
* We don't encode the data if we're innermost and we're told not to include the data
448
if (p7ecx->ecx != NULL && len && (!innermost || cinfo->rawContent != cinfo->content.pointer))
449
rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, (const char *)data, len);
453
if (cinfo->privateInfo && cinfo->privateInfo->ciphcx != NULL) {
457
} else if (buf != NULL) {
465
* nss_cms_encoder_update - deliver encoded data to the next higher level
467
* no recursion here because we REALLY want to end up at the next higher encoder!
470
nss_cms_encoder_update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned long len)
472
/* XXX Error handling needs help. Return what? Do "Finish" on failure? */
473
return nss_cms_encoder_work_data (p7ecx, NULL, (const unsigned char *)data, len, PR_FALSE, PR_FALSE);
477
* NSS_CMSEncoder_Start - set up encoding of a CMS message
479
* "cmsg" - message to encode
480
* "outputfn", "outputarg" - callback function for delivery of DER-encoded output
481
* will not be called if NULL.
482
* "dest" - if non-NULL, pointer to SECItem that will hold the DER-encoded output
483
* "destpoolp" - pool to allocate DER-encoded output in
484
* "pwfn", pwfn_arg" - callback function for getting token password
485
* "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
486
* "detached_digestalgs", "detached_digests" - digests from detached content
488
NSSCMSEncoderContext *
489
NSS_CMSEncoder_Start(NSSCMSMessage *cmsg,
490
NSSCMSContentCallback outputfn, void *outputarg,
491
SECItem *dest, PLArenaPool *destpoolp,
492
PK11PasswordFunc pwfn, void *pwfn_arg,
493
NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
494
SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
496
NSSCMSEncoderContext *p7ecx;
498
NSSCMSContentInfo *cinfo;
501
NSS_CMSMessage_SetEncodingParams(cmsg, pwfn, pwfn_arg, decrypt_key_cb, decrypt_key_cb_arg,
502
detached_digestalgs, detached_digests);
504
p7ecx = (NSSCMSEncoderContext *)PORT_ZAlloc(sizeof(NSSCMSEncoderContext));
506
PORT_SetError(SEC_ERROR_NO_MEMORY);
511
p7ecx->output.outputfn = outputfn;
512
p7ecx->output.outputarg = outputarg;
513
p7ecx->output.dest = dest;
514
p7ecx->output.destpoolp = destpoolp;
515
p7ecx->type = SEC_OID_UNKNOWN;
517
cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
519
tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
521
case SEC_OID_PKCS7_SIGNED_DATA:
522
rv = NSS_CMSSignedData_Encode_BeforeStart(cinfo->content.signedData);
524
case SEC_OID_PKCS7_ENVELOPED_DATA:
525
rv = NSS_CMSEnvelopedData_Encode_BeforeStart(cinfo->content.envelopedData);
527
case SEC_OID_PKCS7_DIGESTED_DATA:
528
rv = NSS_CMSDigestedData_Encode_BeforeStart(cinfo->content.digestedData);
530
case SEC_OID_PKCS7_ENCRYPTED_DATA:
531
rv = NSS_CMSEncryptedData_Encode_BeforeStart(cinfo->content.encryptedData);
534
if (NSS_CMSType_IsWrapper(tag)) {
535
rv = NSS_CMSGenericWrapperData_Encode_BeforeStart(tag,
536
p7ecx->content.genericData);
542
if (rv != SECSuccess) {
547
/* Initialize the BER encoder.
548
* Note that this will not encode anything until the first call to SEC_ASN1EncoderUpdate */
549
p7ecx->ecx = SEC_ASN1EncoderStart(cmsg, NSSCMSMessageTemplate,
550
nss_cms_encoder_out, &(p7ecx->output));
551
if (p7ecx->ecx == NULL) {
555
p7ecx->ecxupdated = PR_FALSE;
558
* Indicate that we are streaming. We will be streaming until we
559
* get past the contents bytes.
561
if (!cinfo->privateInfo || !cinfo->privateInfo->dontStream)
562
SEC_ASN1EncoderSetStreaming(p7ecx->ecx);
565
* The notify function will watch for the contents field.
567
SEC_ASN1EncoderSetNotifyProc(p7ecx->ecx, nss_cms_encoder_notify, p7ecx);
569
/* this will kick off the encoding process & encode everything up to the content bytes,
570
* at which point the notify function sets streaming mode (and possibly creates
571
* a child encoder). */
572
p7ecx->ecxupdated = PR_TRUE;
573
if (SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0) != SECSuccess) {
582
* NSS_CMSEncoder_Update - take content data delivery from the user
584
* "p7ecx" - encoder context
585
* "data" - content data
586
* "len" - length of content data
588
* need to find the lowest level (and call SEC_ASN1EncoderUpdate on the way down),
589
* then hand the data to the work_data fn
592
NSS_CMSEncoder_Update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned long len)
595
NSSCMSContentInfo *cinfo;
601
/* hand data to the innermost decoder */
602
if (p7ecx->childp7ecx) {
603
/* tell the child to start encoding, up to its first data byte, if it
604
* hasn't started yet */
605
if (!p7ecx->childp7ecx->ecxupdated) {
606
p7ecx->childp7ecx->ecxupdated = PR_TRUE;
607
if (SEC_ASN1EncoderUpdate(p7ecx->childp7ecx->ecx, NULL, 0) != SECSuccess)
611
rv = NSS_CMSEncoder_Update(p7ecx->childp7ecx, data, len);
613
/* we are at innermost decoder */
614
/* find out about our inner content type - must be data */
615
cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);
617
/* The original programmer didn't expect this to happen */
618
p7ecx->error = SEC_ERROR_LIBRARY_FAILURE;
622
childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo);
623
if (!NSS_CMSType_IsData(childtype))
625
/* and we must not have preset data */
626
if (cinfo->content.data != NULL)
629
/* hand it the data so it can encode it (let DER trickle up the chain) */
630
rv = nss_cms_encoder_work_data(p7ecx, NULL, (const unsigned char *)data, len, PR_FALSE, PR_TRUE);
636
* NSS_CMSEncoder_Cancel - stop all encoding
638
* we need to walk down the chain of encoders and the finish them from the innermost out
641
NSS_CMSEncoder_Cancel(NSSCMSEncoderContext *p7ecx)
643
SECStatus rv = SECFailure;
645
/* XXX do this right! */
648
* Finish any inner decoders before us so that all the encoded data is flushed
649
* This basically finishes all the decoders from the innermost to the outermost.
650
* Finishing an inner decoder may result in data being updated to the outer decoder
651
* while we are already in NSS_CMSEncoder_Finish, but that's allright.
653
if (p7ecx->childp7ecx) {
654
rv = NSS_CMSEncoder_Cancel(p7ecx->childp7ecx); /* frees p7ecx->childp7ecx */
655
/* remember rv for now */
659
* On the way back up, there will be no more data (if we had an
660
* inner encoder, it is done now!)
661
* Flush out any remaining data and/or finish digests.
663
rv = nss_cms_encoder_work_data(p7ecx, NULL, NULL, 0, PR_TRUE, (p7ecx->childp7ecx == NULL));
664
if (rv != SECSuccess)
667
p7ecx->childp7ecx = NULL;
669
/* kick the encoder back into working mode again.
670
* We turn off streaming stuff (which will cause the encoder to continue
671
* encoding happily, now that we have all the data (like digests) ready for it).
673
SEC_ASN1EncoderClearTakeFromBuf(p7ecx->ecx);
674
SEC_ASN1EncoderClearStreaming(p7ecx->ecx);
676
/* now that TakeFromBuf is off, this will kick this encoder to finish encoding */
677
rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0);
680
SEC_ASN1EncoderFinish(p7ecx->ecx);
686
* NSS_CMSEncoder_Finish - signal the end of data
688
* we need to walk down the chain of encoders and the finish them from the innermost out
691
NSS_CMSEncoder_Finish(NSSCMSEncoderContext *p7ecx)
693
SECStatus rv = SECFailure;
694
NSSCMSContentInfo *cinfo;
697
* Finish any inner decoders before us so that all the encoded data is flushed
698
* This basically finishes all the decoders from the innermost to the outermost.
699
* Finishing an inner decoder may result in data being updated to the outer decoder
700
* while we are already in NSS_CMSEncoder_Finish, but that's allright.
702
if (p7ecx->childp7ecx) {
703
/* tell the child to start encoding, up to its first data byte, if it
705
if (!p7ecx->childp7ecx->ecxupdated) {
706
p7ecx->childp7ecx->ecxupdated = PR_TRUE;
707
rv = SEC_ASN1EncoderUpdate(p7ecx->childp7ecx->ecx, NULL, 0);
708
if (rv != SECSuccess) {
709
NSS_CMSEncoder_Finish(p7ecx->childp7ecx); /* frees p7ecx->childp7ecx */
713
rv = NSS_CMSEncoder_Finish(p7ecx->childp7ecx); /* frees p7ecx->childp7ecx */
714
if (rv != SECSuccess)
719
* On the way back up, there will be no more data (if we had an
720
* inner encoder, it is done now!)
721
* Flush out any remaining data and/or finish digests.
723
rv = nss_cms_encoder_work_data(p7ecx, NULL, NULL, 0, PR_TRUE, (p7ecx->childp7ecx == NULL));
724
if (rv != SECSuccess)
727
p7ecx->childp7ecx = NULL;
729
cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type);
731
/* The original programmer didn't expect this to happen */
732
p7ecx->error = SEC_ERROR_LIBRARY_FAILURE;
736
SEC_ASN1EncoderClearTakeFromBuf(p7ecx->ecx);
737
SEC_ASN1EncoderClearStreaming(p7ecx->ecx);
738
/* now that TakeFromBuf is off, this will kick this encoder to finish encoding */
739
rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0);
745
SEC_ASN1EncoderFinish(p7ecx->ecx);