Bug Summary

File:s/lib/pkcs7/p7encode.c
Warning:line 864, column 31
Access to field 'len' results in a dereference of a null pointer (loaded from field 'certList')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name p7encode.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/pkcs7 -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/pkcs7 -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/nss -I ../../../dist/private/nss -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c p7encode.c
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 * PKCS7 encoding.
7 */
8
9#include "p7local.h"
10
11#include "cert.h"
12#include "cryptohi.h"
13#include "keyhi.h"
14#include "secasn1.h"
15#include "secoid.h"
16#include "secitem.h"
17#include "pk11func.h"
18#include "secerr.h"
19#include "sechash.h" /* for HASH_GetHashObject() */
20
21struct sec_pkcs7_encoder_output {
22 SEC_PKCS7EncoderOutputCallback outputfn;
23 void *outputarg;
24};
25
26struct SEC_PKCS7EncoderContextStr {
27 SEC_ASN1EncoderContext *ecx;
28 SEC_PKCS7ContentInfo *cinfo;
29 struct sec_pkcs7_encoder_output output;
30 sec_PKCS7CipherObject *encryptobj;
31 const SECHashObject *digestobj;
32 void *digestcx;
33};
34
35/*
36 * The little output function that the ASN.1 encoder calls to hand
37 * us bytes which we in turn hand back to our caller (via the callback
38 * they gave us).
39 */
40static void
41sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len,
42 int depth, SEC_ASN1EncodingPart data_kind)
43{
44 struct sec_pkcs7_encoder_output *output;
45
46 output = (struct sec_pkcs7_encoder_output *)arg;
47 output->outputfn(output->outputarg, buf, len);
48}
49
50static sec_PKCS7CipherObject *
51sec_pkcs7_encoder_start_encrypt(SEC_PKCS7ContentInfo *cinfo,
52 PK11SymKey *orig_bulkkey)
53{
54 SECOidTag kind;
55 sec_PKCS7CipherObject *encryptobj;
56 SEC_PKCS7RecipientInfo **recipientinfos, *ri;
57 SEC_PKCS7EncryptedContentInfo *enccinfo;
58 SECKEYPublicKey *publickey = NULL((void*)0);
59 SECKEYPrivateKey *ourPrivKey = NULL((void*)0);
60 PK11SymKey *bulkkey;
61 void *mark;
62 int i;
63 PLArenaPool *arena = NULL((void*)0);
64
65 kind = SEC_PKCS7ContentType(cinfo);
66 switch (kind) {
67 default:
68 case SEC_OID_PKCS7_DATA:
69 case SEC_OID_PKCS7_DIGESTED_DATA:
70 case SEC_OID_PKCS7_SIGNED_DATA:
71 recipientinfos = NULL((void*)0);
72 enccinfo = NULL((void*)0);
73 break;
74 case SEC_OID_PKCS7_ENCRYPTED_DATA: {
75 SEC_PKCS7EncryptedData *encdp;
76
77 /* To do EncryptedData we *must* be given a bulk key. */
78 PORT_Assert(orig_bulkkey != NULL)((orig_bulkkey != ((void*)0))?((void)0):PR_Assert("orig_bulkkey != NULL"
,"p7encode.c",78))
;
79 if (orig_bulkkey == NULL((void*)0)) {
80 /* XXX error? */
81 return NULL((void*)0);
82 }
83
84 encdp = cinfo->content.encryptedData;
85 recipientinfos = NULL((void*)0);
86 enccinfo = &(encdp->encContentInfo);
87 } break;
88 case SEC_OID_PKCS7_ENVELOPED_DATA: {
89 SEC_PKCS7EnvelopedData *envdp;
90
91 envdp = cinfo->content.envelopedData;
92 recipientinfos = envdp->recipientInfos;
93 enccinfo = &(envdp->encContentInfo);
94 } break;
95 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
96 SEC_PKCS7SignedAndEnvelopedData *saedp;
97
98 saedp = cinfo->content.signedAndEnvelopedData;
99 recipientinfos = saedp->recipientInfos;
100 enccinfo = &(saedp->encContentInfo);
101 } break;
102 }
103
104 if (enccinfo == NULL((void*)0))
105 return NULL((void*)0);
106
107 bulkkey = orig_bulkkey;
108 if (bulkkey == NULL((void*)0)) {
109 CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
110 PK11SlotInfo *slot;
111
112 slot = PK11_GetBestSlot(type, cinfo->pwfn_arg);
113 if (slot == NULL((void*)0)) {
114 return NULL((void*)0);
115 }
116 bulkkey = PK11_KeyGen(slot, type, NULL((void*)0), enccinfo->keysize / 8,
117 cinfo->pwfn_arg);
118 PK11_FreeSlot(slot);
119 if (bulkkey == NULL((void*)0)) {
120 return NULL((void*)0);
121 }
122 }
123
124 encryptobj = NULL((void*)0);
125 mark = PORT_ArenaMarkPORT_ArenaMark_Util(cinfo->poolp);
126
127 /*
128 * Encrypt the bulk key with the public key of each recipient.
129 */
130 for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL((void*)0); i++) {
131 CERTCertificate *cert;
132 SECOidTag certalgtag, encalgtag;
133 SECStatus rv;
134 int data_len;
135 SECItem *params = NULL((void*)0);
136
137 cert = ri->cert;
138 PORT_Assert(cert != NULL)((cert != ((void*)0))?((void)0):PR_Assert("cert != NULL","p7encode.c"
,138))
;
139 if (cert == NULL((void*)0))
140 continue;
141
142 /*
143 * XXX Want an interface that takes a cert and some data and
144 * fills in an algorithmID and encrypts the data with the public
145 * key from the cert. Or, give me two interfaces -- one which
146 * gets the algorithm tag from a cert (I should not have to go
147 * down into the subjectPublicKeyInfo myself) and another which
148 * takes a public key and algorithm tag and data and encrypts
149 * the data. Or something like that. The point is that all
150 * of the following hardwired RSA stuff should be done elsewhere.
151 */
152
153 certalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(cert->subjectPublicKeyInfo.algorithm));
154
155 switch (certalgtag) {
156 case SEC_OID_PKCS1_RSA_ENCRYPTION:
157 encalgtag = certalgtag;
158 publickey = CERT_ExtractPublicKey(cert);
159 if (publickey == NULL((void*)0))
160 goto loser;
161
162 data_len = SECKEY_PublicKeyStrength(publickey);
163 ri->encKey.data =
164 (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(cinfo->poolp, data_len);
165 ri->encKey.len = data_len;
166 if (ri->encKey.data == NULL((void*)0))
167 goto loser;
168
169 rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag), publickey,
170 bulkkey, &ri->encKey);
171
172 SECKEY_DestroyPublicKey(publickey);
173 publickey = NULL((void*)0);
174 if (rv != SECSuccess)
175 goto loser;
176 params = NULL((void*)0); /* paranoia */
177 break;
178 default:
179 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM);
180 goto loser;
181 }
182
183 rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(cinfo->poolp, &ri->keyEncAlg, encalgtag,
184 params);
185 if (rv != SECSuccess)
186 goto loser;
187 if (arena)
188 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
189 arena = NULL((void*)0);
190 }
191
192 encryptobj = sec_PKCS7CreateEncryptObject(cinfo->poolp, bulkkey,
193 enccinfo->encalg,
194 &(enccinfo->contentEncAlg));
195 if (encryptobj != NULL((void*)0)) {
196 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(cinfo->poolp, mark);
197 mark = NULL((void*)0); /* good one; do not want to release */
198 }
199 /* fallthru */
200
201loser:
202 if (arena) {
203 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
204 }
205 if (publickey) {
206 SECKEY_DestroyPublicKey(publickey);
207 }
208 if (ourPrivKey) {
209 SECKEY_DestroyPrivateKey(ourPrivKey);
210 }
211 if (mark != NULL((void*)0)) {
212 PORT_ArenaReleasePORT_ArenaRelease_Util(cinfo->poolp, mark);
213 }
214 if (orig_bulkkey == NULL((void*)0)) {
215 if (bulkkey)
216 PK11_FreeSymKey(bulkkey);
217 }
218
219 return encryptobj;
220}
221
222static void
223sec_pkcs7_encoder_notify(void *arg, PRBool before, void *dest, int depth)
224{
225 SEC_PKCS7EncoderContext *p7ecx;
226 SEC_PKCS7ContentInfo *cinfo;
227 SECOidTag kind;
228 PRBool before_content;
229
230 /*
231 * We want to notice just before the content field. After fields are
232 * not interesting to us.
233 */
234 if (!before)
235 return;
236
237 p7ecx = (SEC_PKCS7EncoderContext *)arg;
238 cinfo = p7ecx->cinfo;
239
240 before_content = PR_FALSE0;
241
242 /*
243 * Watch for the content field, at which point we want to instruct
244 * the ASN.1 encoder to start taking bytes from the buffer.
245 *
246 * XXX The following assumes the inner content type is data;
247 * if/when we want to handle fully nested types, this will have
248 * to recurse until reaching the innermost data content.
249 */
250 kind = SEC_PKCS7ContentType(cinfo);
251 switch (kind) {
252 default:
253 case SEC_OID_PKCS7_DATA:
254 if (dest == &(cinfo->content.data))
255 before_content = PR_TRUE1;
256 break;
257
258 case SEC_OID_PKCS7_DIGESTED_DATA: {
259 SEC_PKCS7DigestedData *digd;
260
261 digd = cinfo->content.digestedData;
262 if (digd == NULL((void*)0))
263 break;
264
265 if (dest == &(digd->contentInfo.content))
266 before_content = PR_TRUE1;
267 } break;
268
269 case SEC_OID_PKCS7_ENCRYPTED_DATA: {
270 SEC_PKCS7EncryptedData *encd;
271
272 encd = cinfo->content.encryptedData;
273 if (encd == NULL((void*)0))
274 break;
275
276 if (dest == &(encd->encContentInfo.encContent))
277 before_content = PR_TRUE1;
278 } break;
279
280 case SEC_OID_PKCS7_ENVELOPED_DATA: {
281 SEC_PKCS7EnvelopedData *envd;
282
283 envd = cinfo->content.envelopedData;
284 if (envd == NULL((void*)0))
285 break;
286
287 if (dest == &(envd->encContentInfo.encContent))
288 before_content = PR_TRUE1;
289 } break;
290
291 case SEC_OID_PKCS7_SIGNED_DATA: {
292 SEC_PKCS7SignedData *sigd;
293
294 sigd = cinfo->content.signedData;
295 if (sigd == NULL((void*)0))
296 break;
297
298 if (dest == &(sigd->contentInfo.content))
299 before_content = PR_TRUE1;
300 } break;
301
302 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
303 SEC_PKCS7SignedAndEnvelopedData *saed;
304
305 saed = cinfo->content.signedAndEnvelopedData;
306 if (saed == NULL((void*)0))
307 break;
308
309 if (dest == &(saed->encContentInfo.encContent))
310 before_content = PR_TRUE1;
311 } break;
312 }
313
314 if (before_content) {
315 /*
316 * This will cause the next SEC_ASN1EncoderUpdate to take the
317 * contents bytes from the passed-in buffer.
318 */
319 SEC_ASN1EncoderSetTakeFromBufSEC_ASN1EncoderSetTakeFromBuf_Util(p7ecx->ecx);
320 /*
321 * And that is all we needed this notify function for.
322 */
323 SEC_ASN1EncoderClearNotifyProcSEC_ASN1EncoderClearNotifyProc_Util(p7ecx->ecx);
324 }
325}
326
327static SEC_PKCS7EncoderContext *
328sec_pkcs7_encoder_start_contexts(SEC_PKCS7ContentInfo *cinfo,
329 PK11SymKey *bulkkey)
330{
331 SEC_PKCS7EncoderContext *p7ecx;
332 SECOidTag kind;
333 PRBool encrypt;
334 SECItem **digests;
335 SECAlgorithmID *digestalg, **digestalgs;
336
337 p7ecx =
338 (SEC_PKCS7EncoderContext *)PORT_ZAllocPORT_ZAlloc_Util(sizeof(SEC_PKCS7EncoderContext));
339 if (p7ecx == NULL((void*)0))
340 return NULL((void*)0);
341
342 digests = NULL((void*)0);
343 digestalg = NULL((void*)0);
344 digestalgs = NULL((void*)0);
345 encrypt = PR_FALSE0;
346
347 kind = SEC_PKCS7ContentType(cinfo);
348 switch (kind) {
349 default:
350 case SEC_OID_PKCS7_DATA:
351 break;
352 case SEC_OID_PKCS7_DIGESTED_DATA:
353 digestalg = &(cinfo->content.digestedData->digestAlg);
354 break;
355 case SEC_OID_PKCS7_SIGNED_DATA:
356 digests = cinfo->content.signedData->digests;
357 digestalgs = cinfo->content.signedData->digestAlgorithms;
358 break;
359 case SEC_OID_PKCS7_ENCRYPTED_DATA:
360 case SEC_OID_PKCS7_ENVELOPED_DATA:
361 encrypt = PR_TRUE1;
362 break;
363 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
364 digests = cinfo->content.signedAndEnvelopedData->digests;
365 digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
366 encrypt = PR_TRUE1;
367 break;
368 }
369
370 if (encrypt) {
371 p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt(cinfo, bulkkey);
372 if (p7ecx->encryptobj == NULL((void*)0)) {
373 PORT_FreePORT_Free_Util(p7ecx);
374 return NULL((void*)0);
375 }
376 }
377
378 if (digestalgs != NULL((void*)0)) {
379 if (digests != NULL((void*)0)) {
380 /* digests already created (probably for detached data) */
381 digestalg = NULL((void*)0);
382 } else {
383 /*
384 * XXX Some day we should handle multiple digests; for now,
385 * assume only one will be done.
386 */
387 PORT_Assert(digestalgs[0] != NULL && digestalgs[1] == NULL)((digestalgs[0] != ((void*)0) && digestalgs[1] == ((void
*)0))?((void)0):PR_Assert("digestalgs[0] != NULL && digestalgs[1] == NULL"
,"p7encode.c",387))
;
388 digestalg = digestalgs[0];
389 }
390 }
391
392 if (digestalg != NULL((void*)0)) {
393 SECOidTag oidTag = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(digestalg->algorithm));
394
395 p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag);
396 if (p7ecx->digestobj != NULL((void*)0)) {
397 p7ecx->digestcx = (*p7ecx->digestobj->create)();
398 if (p7ecx->digestcx == NULL((void*)0))
399 p7ecx->digestobj = NULL((void*)0);
400 else
401 (*p7ecx->digestobj->begin)(p7ecx->digestcx);
402 }
403 if (p7ecx->digestobj == NULL((void*)0)) {
404 if (p7ecx->encryptobj != NULL((void*)0))
405 sec_PKCS7DestroyEncryptObject(p7ecx->encryptobj);
406 PORT_FreePORT_Free_Util(p7ecx);
407 return NULL((void*)0);
408 }
409 }
410
411 p7ecx->cinfo = cinfo;
412 return p7ecx;
413}
414
415SEC_PKCS7EncoderContext *
416SEC_PKCS7EncoderStart(SEC_PKCS7ContentInfo *cinfo,
417 SEC_PKCS7EncoderOutputCallback outputfn,
418 void *outputarg,
419 PK11SymKey *bulkkey)
420{
421 SEC_PKCS7EncoderContext *p7ecx;
422 SECStatus rv;
423
424 p7ecx = sec_pkcs7_encoder_start_contexts(cinfo, bulkkey);
425 if (p7ecx == NULL((void*)0))
426 return NULL((void*)0);
427
428 p7ecx->output.outputfn = outputfn;
429 p7ecx->output.outputarg = outputarg;
430
431 /*
432 * Initialize the BER encoder.
433 */
434 p7ecx->ecx = SEC_ASN1EncoderStartSEC_ASN1EncoderStart_Util(cinfo, sec_PKCS7ContentInfoTemplate,
435 sec_pkcs7_encoder_out, &(p7ecx->output));
436 if (p7ecx->ecx == NULL((void*)0)) {
437 PORT_FreePORT_Free_Util(p7ecx);
438 return NULL((void*)0);
439 }
440
441 /*
442 * Indicate that we are streaming. We will be streaming until we
443 * get past the contents bytes.
444 */
445 SEC_ASN1EncoderSetStreamingSEC_ASN1EncoderSetStreaming_Util(p7ecx->ecx);
446
447 /*
448 * The notify function will watch for the contents field.
449 */
450 SEC_ASN1EncoderSetNotifyProcSEC_ASN1EncoderSetNotifyProc_Util(p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);
451
452 /*
453 * This will encode everything up to the content bytes. (The notify
454 * function will then cause the encoding to stop there.) Then our
455 * caller can start passing contents bytes to our Update, which we
456 * will pass along.
457 */
458 rv = SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(p7ecx->ecx, NULL((void*)0), 0);
459 if (rv != SECSuccess) {
460 PORT_FreePORT_Free_Util(p7ecx);
461 return NULL((void*)0);
462 }
463
464 return p7ecx;
465}
466
467/*
468 * XXX If/when we support nested contents, this needs to be revised.
469 */
470static SECStatus
471sec_pkcs7_encoder_work_data(SEC_PKCS7EncoderContext *p7ecx, SECItem *dest,
472 const unsigned char *data, unsigned long len,
473 PRBool final)
474{
475 unsigned char *buf = NULL((void*)0);
476 SECStatus rv;
477
478 rv = SECSuccess; /* may as well be optimistic */
479
480 /*
481 * We should really have data to process, or we should be trying
482 * to finish/flush the last block. (This is an overly paranoid
483 * check since all callers are in this file and simple inspection
484 * proves they do it right. But it could find a bug in future
485 * modifications/development, that is why it is here.)
486 */
487 PORT_Assert((data != NULL && len) || final)(((data != ((void*)0) && len) || final)?((void)0):PR_Assert
("(data != NULL && len) || final","p7encode.c",487))
;
488
489 /*
490 * Update the running digest.
491 * XXX This needs modification if/when we handle multiple digests.
492 */
493 if (len && p7ecx->digestobj != NULL((void*)0)) {
494 (*p7ecx->digestobj->update)(p7ecx->digestcx, data, len);
495 }
496
497 /*
498 * Encrypt this chunk.
499 */
500 if (p7ecx->encryptobj != NULL((void*)0)) {
501 /* XXX the following lengths should all be longs? */
502 unsigned int inlen; /* length of data being encrypted */
503 unsigned int outlen; /* length of encrypted data */
504 unsigned int buflen; /* length available for encrypted data */
505
506 inlen = len;
507 buflen = sec_PKCS7EncryptLength(p7ecx->encryptobj, inlen, final);
508 if (buflen == 0) {
509 /*
510 * No output is expected, but the input data may be buffered
511 * so we still have to call Encrypt.
512 */
513 rv = sec_PKCS7Encrypt(p7ecx->encryptobj, NULL((void*)0), &outlen, 0,
514 data, inlen, final);
515 if (final) {
516 len = 0;
517 goto done;
518 }
519 return rv;
520 }
521
522 if (dest != NULL((void*)0))
523 buf = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(p7ecx->cinfo->poolp, buflen);
524 else
525 buf = (unsigned char *)PORT_AllocPORT_Alloc_Util(buflen);
526
527 if (buf == NULL((void*)0)) {
528 rv = SECFailure;
529 } else {
530 rv = sec_PKCS7Encrypt(p7ecx->encryptobj, buf, &outlen, buflen,
531 data, inlen, final);
532 data = buf;
533 len = outlen;
534 }
535 if (rv != SECSuccess) {
536 if (final)
537 goto done;
538 return rv;
539 }
540 }
541
542 if (p7ecx->ecx != NULL((void*)0)) {
543 /*
544 * Encode the contents bytes.
545 */
546 if (len) {
547 rv = SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(p7ecx->ecx, (const char *)data, len);
548 }
549 }
550
551done:
552 if (p7ecx->encryptobj != NULL((void*)0)) {
553 if (final)
554 sec_PKCS7DestroyEncryptObject(p7ecx->encryptobj);
555 if (dest != NULL((void*)0)) {
556 dest->data = buf;
557 dest->len = len;
558 } else if (buf != NULL((void*)0)) {
559 PORT_FreePORT_Free_Util(buf);
560 }
561 }
562
563 if (final && p7ecx->digestobj != NULL((void*)0)) {
564 SECItem *digest, **digests, ***digestsp;
565 unsigned char *digdata;
566 SECOidTag kind;
567
568 kind = SEC_PKCS7ContentType(p7ecx->cinfo);
569 switch (kind) {
570 default:
571 PORT_Assert(0)((0)?((void)0):PR_Assert("0","p7encode.c",571));
572 return SECFailure;
573 case SEC_OID_PKCS7_DIGESTED_DATA:
574 digest = &(p7ecx->cinfo->content.digestedData->digest);
575 digestsp = NULL((void*)0);
576 break;
577 case SEC_OID_PKCS7_SIGNED_DATA:
578 digest = NULL((void*)0);
579 digestsp = &(p7ecx->cinfo->content.signedData->digests);
580 break;
581 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
582 digest = NULL((void*)0);
583 digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
584 break;
585 }
586
587 digdata = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(p7ecx->cinfo->poolp,
588 p7ecx->digestobj->length);
589 if (digdata == NULL((void*)0))
590 return SECFailure;
591
592 if (digestsp != NULL((void*)0)) {
593 PORT_Assert(digest == NULL)((digest == ((void*)0))?((void)0):PR_Assert("digest == NULL",
"p7encode.c",593))
;
594
595 digest = (SECItem *)PORT_ArenaAllocPORT_ArenaAlloc_Util(p7ecx->cinfo->poolp,
596 sizeof(SECItem));
597 digests = (SECItem **)PORT_ArenaAllocPORT_ArenaAlloc_Util(p7ecx->cinfo->poolp,
598 2 * sizeof(SECItem *));
599 if (digests == NULL((void*)0) || digest == NULL((void*)0))
600 return SECFailure;
601
602 digests[0] = digest;
603 digests[1] = NULL((void*)0);
604
605 *digestsp = digests;
606 }
607
608 PORT_Assert(digest != NULL)((digest != ((void*)0))?((void)0):PR_Assert("digest != NULL",
"p7encode.c",608))
;
609
610 digest->data = digdata;
611 digest->len = p7ecx->digestobj->length;
612
613 (*p7ecx->digestobj->end)(p7ecx->digestcx, digest->data,
614 &(digest->len), digest->len);
615 (*p7ecx->digestobj->destroy)(p7ecx->digestcx, PR_TRUE1);
616 }
617
618 return rv;
619}
620
621SECStatus
622SEC_PKCS7EncoderUpdate(SEC_PKCS7EncoderContext *p7ecx,
623 const char *data, unsigned long len)
624{
625 /* XXX Error handling needs help. Return what? Do "Finish" on failure? */
626 return sec_pkcs7_encoder_work_data(p7ecx, NULL((void*)0),
627 (const unsigned char *)data, len,
628 PR_FALSE0);
629}
630
631static SECStatus
632sec_pkcs7_encoder_sig_and_certs(SEC_PKCS7ContentInfo *cinfo,
633 SECKEYGetPasswordKey pwfn, void *pwfnarg)
634{
635 SECOidTag kind;
636 CERTCertificate **certs;
637 CERTCertificateList **certlists;
638 SECAlgorithmID **digestalgs;
639 SECItem **digests;
640 SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
641 SECItem **rawcerts, ***rawcertsp;
642 PLArenaPool *poolp;
643 int certcount;
644 int ci, cli, rci, si;
645
646 kind = SEC_PKCS7ContentType(cinfo);
647 switch (kind) {
7
Control jumps to 'case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:' at line 671
648 default:
649 case SEC_OID_PKCS7_DATA:
650 case SEC_OID_PKCS7_DIGESTED_DATA:
651 case SEC_OID_PKCS7_ENCRYPTED_DATA:
652 case SEC_OID_PKCS7_ENVELOPED_DATA:
653 certs = NULL((void*)0);
654 certlists = NULL((void*)0);
655 digestalgs = NULL((void*)0);
656 digests = NULL((void*)0);
657 signerinfos = NULL((void*)0);
658 rawcertsp = NULL((void*)0);
659 break;
660 case SEC_OID_PKCS7_SIGNED_DATA: {
661 SEC_PKCS7SignedData *sdp;
662
663 sdp = cinfo->content.signedData;
664 certs = sdp->certs;
665 certlists = sdp->certLists;
666 digestalgs = sdp->digestAlgorithms;
667 digests = sdp->digests;
668 signerinfos = sdp->signerInfos;
669 rawcertsp = &(sdp->rawCerts);
670 } break;
671 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
672 SEC_PKCS7SignedAndEnvelopedData *saedp;
673
674 saedp = cinfo->content.signedAndEnvelopedData;
675 certs = saedp->certs;
676 certlists = saedp->certLists;
677 digestalgs = saedp->digestAlgorithms;
678 digests = saedp->digests;
679 signerinfos = saedp->signerInfos;
680 rawcertsp = &(saedp->rawCerts);
681 } break;
682 }
683
684 if (certs == NULL((void*)0) && certlists == NULL((void*)0) && signerinfos == NULL((void*)0))
8
Assuming 'certs' is not equal to NULL
685 return SECSuccess; /* nothing for us to do! */
686
687 poolp = cinfo->poolp;
688 certcount = 0;
689
690 if (signerinfos != NULL((void*)0)) {
9
Assuming 'signerinfos' is not equal to NULL
10
Taking true branch
691 SECOidTag digestalgtag;
692 int di;
693 SECStatus rv;
694 CERTCertificate *cert;
695 SECKEYPrivateKey *privkey;
696 SECItem signature;
697 SECOidTag signalgtag;
698
699 PORT_Assert(digestalgs != NULL && digests != NULL)((digestalgs != ((void*)0) && digests != ((void*)0))?
((void)0):PR_Assert("digestalgs != NULL && digests != NULL"
,"p7encode.c",699))
;
11
Assuming 'digestalgs' is not equal to null
12
Assuming 'digests' is not equal to null
13
'?' condition is true
700
701 /*
702 * If one fails, we bail right then. If we want to continue and
703 * try to do subsequent signatures, this loop, and the departures
704 * from it, will need to be reworked.
705 */
706 for (si = 0; signerinfos[si] != NULL((void*)0); si++) {
14
Assuming the condition is true
15
Loop condition is true. Entering loop body
37
Assuming the condition is false
38
Loop condition is false. Execution continues on line 830
707
708 signerinfo = signerinfos[si];
709
710 /* find right digest */
711 digestalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(signerinfo->digestAlg));
712 for (di = 0; digestalgs[di] != NULL((void*)0); di++) {
16
Assuming the condition is true
17
Loop condition is true. Entering loop body
713 /* XXX Should I be comparing more than the tag? */
714 if (digestalgtag == SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(digestalgs[di]))
18
Assuming the condition is true
19
Taking true branch
715 break;
716 }
717 if (digestalgs[di] == NULL((void*)0)) {
20
Execution continues on line 717
718 /* XXX oops; do what? set an error? */
719 return SECFailure;
720 }
721 PORT_Assert(digests[di] != NULL)((digests[di] != ((void*)0))?((void)0):PR_Assert("digests[di] != NULL"
,"p7encode.c",721))
;
21
Taking false branch
22
Assuming the condition is true
23
'?' condition is true
722
723 cert = signerinfo->cert;
724 privkey = PK11_FindKeyByAnyCert(cert, pwfnarg);
725 if (privkey == NULL((void*)0))
24
Assuming 'privkey' is not equal to NULL
25
Taking false branch
726 return SECFailure;
727
728 /*
729 * XXX I think there should be a cert-level interface for this,
730 * so that I do not have to know about subjectPublicKeyInfo...
731 */
732 signalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(cert->subjectPublicKeyInfo.algorithm));
733
734 if (signerinfo->authAttr != NULL((void*)0)) {
26
Assuming field 'authAttr' is equal to NULL
27
Taking false branch
735 SEC_PKCS7Attribute *attr;
736 SECItem encoded_attrs;
737 SECItem *dummy;
738 SECOidTag algid;
739
740 /*
741 * First, find and fill in the message digest attribute.
742 */
743 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
744 SEC_OID_PKCS9_MESSAGE_DIGEST,
745 PR_TRUE1);
746 PORT_Assert(attr != NULL)((attr != ((void*)0))?((void)0):PR_Assert("attr != NULL","p7encode.c"
,746))
;
747 if (attr == NULL((void*)0)) {
748 SECKEY_DestroyPrivateKey(privkey);
749 return SECFailure;
750 }
751
752 /*
753 * XXX The second half of the following assertion prevents
754 * the encoder from being called twice on the same content.
755 * Either just remove the second half the assertion, or
756 * change the code to check if the value already there is
757 * the same as digests[di], whichever seems more right.
758 */
759 PORT_Assert(attr->values != NULL && attr->values[0] == NULL)((attr->values != ((void*)0) && attr->values[0]
== ((void*)0))?((void)0):PR_Assert("attr->values != NULL && attr->values[0] == NULL"
,"p7encode.c",759))
;
760 attr->values[0] = digests[di];
761
762 /*
763 * Before encoding, reorder the attributes so that when they
764 * are encoded, they will be conforming DER, which is required
765 * to have a specific order and that is what must be used for
766 * the hash/signature. We do this here, rather than building
767 * it into EncodeAttributes, because we do not want to do
768 * such reordering on incoming messages (which also uses
769 * EncodeAttributes) or our old signatures (and other "broken"
770 * implementations) will not verify. So, we want to guarantee
771 * that we send out good DER encodings of attributes, but not
772 * to expect to receive them.
773 */
774 rv = sec_PKCS7ReorderAttributes(signerinfo->authAttr);
775 if (rv != SECSuccess) {
776 SECKEY_DestroyPrivateKey(privkey);
777 return SECFailure;
778 }
779
780 encoded_attrs.data = NULL((void*)0);
781 encoded_attrs.len = 0;
782 dummy = sec_PKCS7EncodeAttributes(NULL((void*)0), &encoded_attrs,
783 &(signerinfo->authAttr));
784 if (dummy == NULL((void*)0)) {
785 SECKEY_DestroyPrivateKey(privkey);
786 return SECFailure;
787 }
788
789 algid = SEC_GetSignatureAlgorithmOidTag(privkey->keyType,
790 digestalgtag);
791 if (algid == SEC_OID_UNKNOWN) {
792 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM);
793 SECKEY_DestroyPrivateKey(privkey);
794 return SECFailure;
795 }
796 rv = SEC_SignData(&signature,
797 encoded_attrs.data, encoded_attrs.len,
798 privkey,
799 algid);
800 SECITEM_FreeItemSECITEM_FreeItem_Util(&encoded_attrs, PR_FALSE0);
801 } else {
802 rv = SGN_Digest(privkey, digestalgtag, &signature,
803 digests[di]);
804 }
805
806 SECKEY_DestroyPrivateKey(privkey);
807
808 if (rv != SECSuccess)
28
Assuming 'rv' is equal to SECSuccess
29
Taking false branch
809 return rv;
810
811 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(poolp, &(signerinfo->encDigest), &signature);
812 if (rv != SECSuccess)
30
Assuming 'rv' is equal to SECSuccess
31
Taking false branch
813 return rv;
814
815 SECITEM_FreeItemSECITEM_FreeItem_Util(&signature, PR_FALSE0);
816
817 rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(poolp, &(signerinfo->digestEncAlg),
32
Value assigned to field 'certList'
818 signalgtag, NULL((void*)0));
819 if (rv != SECSuccess)
33
Assuming 'rv' is equal to SECSuccess
34
Taking false branch
820 return SECFailure;
821
822 /*
823 * Count the cert chain for this signer.
824 */
825 if (signerinfo->certList != NULL((void*)0))
35
Assuming field 'certList' is equal to NULL
36
Taking false branch
826 certcount += signerinfo->certList->len;
827 }
828 }
829
830 if (certs
38.1
'certs' is not equal to NULL
!= NULL((void*)0)) {
39
Taking true branch
831 for (ci = 0; certs[ci] != NULL((void*)0); ci++)
40
Assuming the condition is true
41
Loop condition is true. Entering loop body
42
Assuming the condition is false
43
Loop condition is false. Execution continues on line 835
832 certcount++;
833 }
834
835 if (certlists != NULL((void*)0)) {
44
Assuming 'certlists' is equal to NULL
45
Taking false branch
836 for (cli = 0; certlists[cli] != NULL((void*)0); cli++)
837 certcount += certlists[cli]->len;
838 }
839
840 if (certcount
45.1
'certcount' is not equal to 0
== 0)
46
Taking false branch
841 return SECSuccess; /* signing done; no certs */
842
843 /*
844 * Combine all of the certs and cert chains into rawcerts.
845 * Note: certcount is an upper bound; we may not need that many slots
846 * but we will allocate anyway to avoid having to do another pass.
847 * (The temporary space saving is not worth it.)
848 */
849 rawcerts = (SECItem **)PORT_ArenaAllocPORT_ArenaAlloc_Util(poolp,
850 (certcount + 1) * sizeof(SECItem *));
851 if (rawcerts == NULL((void*)0))
47
Assuming 'rawcerts' is not equal to NULL
48
Taking false branch
852 return SECFailure;
853
854 /*
855 * XXX Want to check for duplicates and not add *any* cert that is
856 * already in the set. This will be more important when we start
857 * dealing with larger sets of certs, dual-key certs (signing and
858 * encryption), etc. For the time being we can slide by...
859 */
860 rci = 0;
861 if (signerinfos
48.1
'signerinfos' is not equal to NULL
!= NULL((void*)0)) {
49
Taking true branch
862 for (si = 0; signerinfos[si] != NULL((void*)0); si++) {
50
Loop condition is true. Entering loop body
863 signerinfo = signerinfos[si];
864 for (ci = 0; ci < signerinfo->certList->len; ci++)
51
Access to field 'len' results in a dereference of a null pointer (loaded from field 'certList')
865 rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
866 }
867 }
868
869 if (certs != NULL((void*)0)) {
870 for (ci = 0; certs[ci] != NULL((void*)0); ci++)
871 rawcerts[rci++] = &(certs[ci]->derCert);
872 }
873
874 if (certlists != NULL((void*)0)) {
875 for (cli = 0; certlists[cli] != NULL((void*)0); cli++) {
876 for (ci = 0; ci < certlists[cli]->len; ci++)
877 rawcerts[rci++] = &(certlists[cli]->certs[ci]);
878 }
879 }
880
881 rawcerts[rci] = NULL((void*)0);
882 *rawcertsp = rawcerts;
883
884 return SECSuccess;
885}
886
887SECStatus
888SEC_PKCS7EncoderFinish(SEC_PKCS7EncoderContext *p7ecx,
889 SECKEYGetPasswordKey pwfn, void *pwfnarg)
890{
891 SECStatus rv;
892
893 /*
894 * Flush out any remaining data.
895 */
896 rv = sec_pkcs7_encoder_work_data(p7ecx, NULL((void*)0), NULL((void*)0), 0, PR_TRUE1);
897
898 /*
899 * Turn off streaming stuff.
900 */
901 SEC_ASN1EncoderClearTakeFromBufSEC_ASN1EncoderClearTakeFromBuf_Util(p7ecx->ecx);
902 SEC_ASN1EncoderClearStreamingSEC_ASN1EncoderClearStreaming_Util(p7ecx->ecx);
903
904 if (rv != SECSuccess)
905 goto loser;
906
907 rv = sec_pkcs7_encoder_sig_and_certs(p7ecx->cinfo, pwfn, pwfnarg);
908 if (rv != SECSuccess)
909 goto loser;
910
911 rv = SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(p7ecx->ecx, NULL((void*)0), 0);
912
913loser:
914 SEC_ASN1EncoderFinishSEC_ASN1EncoderFinish_Util(p7ecx->ecx);
915 PORT_FreePORT_Free_Util(p7ecx);
916 return rv;
917}
918
919/*
920 * Abort the ASN.1 stream. Used by pkcs 12
921 */
922void
923SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7ecx, int error)
924{
925 PORT_Assert(p7ecx)((p7ecx)?((void)0):PR_Assert("p7ecx","p7encode.c",925));
926 SEC_ASN1EncoderAbortSEC_ASN1EncoderAbort_Util(p7ecx->ecx, error);
927}
928
929/*
930 * After this routine is called, the entire PKCS7 contentInfo is ready
931 * to be encoded. This is used internally, but can also be called from
932 * elsewhere for those who want to be able to just have pointers to
933 * the ASN1 template for pkcs7 contentInfo built into their own encodings.
934 */
935SECStatus
936SEC_PKCS7PrepareForEncode(SEC_PKCS7ContentInfo *cinfo,
937 PK11SymKey *bulkkey,
938 SECKEYGetPasswordKey pwfn,
939 void *pwfnarg)
940{
941 SEC_PKCS7EncoderContext *p7ecx;
942 SECItem *content, *enc_content;
943 SECStatus rv;
944
945 p7ecx = sec_pkcs7_encoder_start_contexts(cinfo, bulkkey);
946 if (p7ecx
1.1
'p7ecx' is not equal to NULL
== NULL((void*)0))
2
Taking false branch
947 return SECFailure;
948
949 content = SEC_PKCS7GetContent(cinfo);
950
951 if (p7ecx->encryptobj != NULL((void*)0)) {
3
Assuming field 'encryptobj' is equal to NULL
4
Taking false branch
952 SECOidTag kind;
953 SEC_PKCS7EncryptedContentInfo *enccinfo;
954
955 kind = SEC_PKCS7ContentType(p7ecx->cinfo);
956 switch (kind) {
957 default:
958 PORT_Assert(0)((0)?((void)0):PR_Assert("0","p7encode.c",958));
959 rv = SECFailure;
960 goto loser;
961 case SEC_OID_PKCS7_ENCRYPTED_DATA:
962 enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
963 break;
964 case SEC_OID_PKCS7_ENVELOPED_DATA:
965 enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
966 break;
967 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
968 enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);
969 break;
970 }
971 enc_content = &(enccinfo->encContent);
972 } else {
973 enc_content = NULL((void*)0);
974 }
975
976 if (content != NULL((void*)0) && content->data != NULL((void*)0) && content->len) {
5
Assuming 'content' is equal to NULL
977 rv = sec_pkcs7_encoder_work_data(p7ecx, enc_content,
978 content->data, content->len, PR_TRUE1);
979 if (rv != SECSuccess)
980 goto loser;
981 }
982
983 rv = sec_pkcs7_encoder_sig_and_certs(cinfo, pwfn, pwfnarg);
6
Calling 'sec_pkcs7_encoder_sig_and_certs'
984
985loser:
986 PORT_FreePORT_Free_Util(p7ecx);
987 return rv;
988}
989
990/*
991 * Encode a PKCS7 object, in one shot. All necessary components
992 * of the object must already be specified. Either the data has
993 * already been included (via SetContent), or the data is detached,
994 * or there is no data at all (certs-only).
995 *
996 * "cinfo" specifies the object to be encoded.
997 *
998 * "outputfn" is where the encoded bytes will be passed.
999 *
1000 * "outputarg" is an opaque argument to the above callback.
1001 *
1002 * "bulkkey" specifies the bulk encryption key to use. This argument
1003 * can be NULL if no encryption is being done, or if the bulk key should
1004 * be generated internally (usually the case for EnvelopedData but never
1005 * for EncryptedData, which *must* provide a bulk encryption key).
1006 *
1007 * "pwfn" is a callback for getting the password which protects the
1008 * private key of the signer. This argument can be NULL if it is known
1009 * that no signing is going to be done.
1010 *
1011 * "pwfnarg" is an opaque argument to the above callback.
1012 */
1013SECStatus
1014SEC_PKCS7Encode(SEC_PKCS7ContentInfo *cinfo,
1015 SEC_PKCS7EncoderOutputCallback outputfn,
1016 void *outputarg,
1017 PK11SymKey *bulkkey,
1018 SECKEYGetPasswordKey pwfn,
1019 void *pwfnarg)
1020{
1021 SECStatus rv;
1022
1023 rv = SEC_PKCS7PrepareForEncode(cinfo, bulkkey, pwfn, pwfnarg);
1024 if (rv == SECSuccess) {
1025 struct sec_pkcs7_encoder_output outputcx;
1026
1027 outputcx.outputfn = outputfn;
1028 outputcx.outputarg = outputarg;
1029
1030 rv = SEC_ASN1EncodeSEC_ASN1Encode_Util(cinfo, sec_PKCS7ContentInfoTemplate,
1031 sec_pkcs7_encoder_out, &outputcx);
1032 }
1033
1034 return rv;
1035}
1036
1037/*
1038 * Encode a PKCS7 object, in one shot. All necessary components
1039 * of the object must already be specified. Either the data has
1040 * already been included (via SetContent), or the data is detached,
1041 * or there is no data at all (certs-only). The output, rather than
1042 * being passed to an output function as is done above, is all put
1043 * into a SECItem.
1044 *
1045 * "pool" specifies a pool from which to allocate the result.
1046 * It can be NULL, in which case memory is allocated generically.
1047 *
1048 * "dest" specifies a SECItem in which to put the result data.
1049 * It can be NULL, in which case the entire item is allocated, too.
1050 *
1051 * "cinfo" specifies the object to be encoded.
1052 *
1053 * "bulkkey" specifies the bulk encryption key to use. This argument
1054 * can be NULL if no encryption is being done, or if the bulk key should
1055 * be generated internally (usually the case for EnvelopedData but never
1056 * for EncryptedData, which *must* provide a bulk encryption key).
1057 *
1058 * "pwfn" is a callback for getting the password which protects the
1059 * private key of the signer. This argument can be NULL if it is known
1060 * that no signing is going to be done.
1061 *
1062 * "pwfnarg" is an opaque argument to the above callback.
1063 */
1064SECItem *
1065SEC_PKCS7EncodeItem(PLArenaPool *pool,
1066 SECItem *dest,
1067 SEC_PKCS7ContentInfo *cinfo,
1068 PK11SymKey *bulkkey,
1069 SECKEYGetPasswordKey pwfn,
1070 void *pwfnarg)
1071{
1072 SECStatus rv;
1073
1074 rv = SEC_PKCS7PrepareForEncode(cinfo, bulkkey, pwfn, pwfnarg);
1
Calling 'SEC_PKCS7PrepareForEncode'
1075 if (rv != SECSuccess)
1076 return NULL((void*)0);
1077
1078 return SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
1079}