Bug Summary

File:root/firefox-clang/security/nss/lib/pkcs7/p7decode.c
Warning:line 1812, column 9
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name p7decode.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 -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/pkcs7/pkcs7_pkcs7 -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/pkcs7/pkcs7_pkcs7 -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG -D NSS_FIPS_DISABLED -D NSS_NO_INIT_SUPPORT -D NSS_X86_OR_X64 -D NSS_X64 -D NSS_USE_64 -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -D LINUX2_1 -D LINUX -D linux -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D HAVE_STRERROR -D XP_UNIX -D _REENTRANT -D NSS_DISABLE_DBM -D NSS_DISABLE_LIBPKIX -D NSS_USE_PKCS5_PBKD2_PARAMS2_ONLY -D SOFTOKEN_USE_PKCS5_PBKD2_PARAMS2_ONLY -I /root/firefox-clang/security/nss/lib/pkcs7 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/pkcs7/pkcs7_pkcs7 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/private/nss -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-character-conversion -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c /root/firefox-clang/security/nss/lib/pkcs7/p7decode.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 decoding, verification.
7 */
8
9#include "p7local.h"
10
11#include "cert.h"
12/* XXX do not want to have to include */
13#include "certdb.h" /* certdb.h -- the trust stuff needed by */
14 /* the add certificate code needs to get */
15 /* rewritten/abstracted and then this */
16 /* include should be removed! */
17/*#include "cdbhdl.h" */
18#include "cryptohi.h"
19#include "keyhi.h"
20#include "secasn1.h"
21#include "secitem.h"
22#include "secoid.h"
23#include "pk11func.h"
24#include "prtime.h"
25#include "secerr.h"
26#include "sechash.h" /* for HASH_GetHashObject() */
27#include "secder.h"
28#include "secpkcs5.h"
29
30struct sec_pkcs7_decoder_worker {
31 int depth;
32 int digcnt;
33 void **digcxs;
34 const SECHashObject **digobjs;
35 sec_PKCS7CipherObject *decryptobj;
36 PRBool saw_contents;
37};
38
39struct SEC_PKCS7DecoderContextStr {
40 SEC_ASN1DecoderContext *dcx;
41 SEC_PKCS7ContentInfo *cinfo;
42 SEC_PKCS7DecoderContentCallback cb;
43 void *cb_arg;
44 SECKEYGetPasswordKey pwfn;
45 void *pwfn_arg;
46 struct sec_pkcs7_decoder_worker worker;
47 PLArenaPool *tmp_poolp;
48 int error;
49 SEC_PKCS7GetDecryptKeyCallback dkcb;
50 void *dkcb_arg;
51 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb;
52};
53
54/*
55 * Handle one worker, decrypting and digesting the data as necessary.
56 *
57 * XXX If/when we support nested contents, this probably needs to be
58 * revised somewhat to get passed the content-info (which unfortunately
59 * can be two different types depending on whether it is encrypted or not)
60 * corresponding to the given worker.
61 */
62static void
63sec_pkcs7_decoder_work_data(SEC_PKCS7DecoderContext *p7dcx,
64 struct sec_pkcs7_decoder_worker *worker,
65 const unsigned char *data, unsigned long len,
66 PRBool final)
67{
68 unsigned char *buf = NULL((void*)0);
69 PRBool freeBuf = PR_FALSE0;
70 SECStatus rv;
71 int i;
72
73 /*
74 * We should really have data to process, or we should be trying
75 * to finish/flush the last block. (This is an overly paranoid
76 * check since all callers are in this file and simple inspection
77 * proves they do it right. But it could find a bug in future
78 * modifications/development, that is why it is here.)
79 */
80 PORT_Assert((data != NULL && len) || final)(((data != ((void*)0) && len) || final) ? ((void)0) :
PR_Assert("(data != NULL && len) || final", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 80))
;
81
82 /*
83 * Decrypt this chunk.
84 *
85 * XXX If we get an error, we do not want to do the digest or callback,
86 * but we want to keep decoding. Or maybe we want to stop decoding
87 * altogether if there is a callback, because obviously we are not
88 * sending the data back and they want to know that.
89 */
90 if (worker->decryptobj != NULL((void*)0)) {
91 /* XXX the following lengths should all be longs? */
92 unsigned int inlen; /* length of data being decrypted */
93 unsigned int outlen; /* length of decrypted data */
94 unsigned int buflen; /* length available for decrypted data */
95 SECItem *plain;
96
97 inlen = len;
98 buflen = sec_PKCS7DecryptLength(worker->decryptobj, inlen, final);
99 if (buflen == 0) {
100 if (inlen == 0) /* no input and no output */
101 return;
102 /*
103 * No output is expected, but the input data may be buffered
104 * so we still have to call Decrypt.
105 */
106 rv = sec_PKCS7Decrypt(worker->decryptobj, NULL((void*)0), NULL((void*)0), 0,
107 data, inlen, final);
108 if (rv != SECSuccess) {
109 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
110 return; /* XXX indicate error? */
111 }
112 return;
113 }
114
115 if (p7dcx->cb != NULL((void*)0)) {
116 buf = (unsigned char *)PORT_AllocPORT_Alloc_Util(buflen);
117 freeBuf = PR_TRUE1;
118 plain = NULL((void*)0);
119 } else {
120 unsigned long oldlen;
121
122 /*
123 * XXX This assumes one level of content only.
124 * See comment above about nested content types.
125 * XXX Also, it should work for signedAndEnvelopedData, too!
126 */
127 plain = &(p7dcx->cinfo->content.envelopedData->encContentInfo.plainContent);
128
129 oldlen = plain->len;
130 if (oldlen == 0) {
131 buf = (unsigned char *)PORT_ArenaAllocPORT_ArenaAlloc_Util(p7dcx->cinfo->poolp,
132 buflen);
133 plain->data = buf;
134 } else {
135 buf = (unsigned char *)PORT_ArenaGrowPORT_ArenaGrow_Util(p7dcx->cinfo->poolp,
136 plain->data,
137 oldlen, oldlen + buflen);
138 /* Keep plain->data pointing at the start of the (possibly
139 * relocated) buffer so that subsequent grows pass a valid
140 * base pointer/length pair to PORT_ArenaGrow. */
141 plain->data = buf;
142 if (buf != NULL((void*)0))
143 buf += oldlen;
144 }
145 }
146 if (buf == NULL((void*)0)) {
147 p7dcx->error = SEC_ERROR_NO_MEMORY;
148 return; /* XXX indicate error? */
149 }
150 rv = sec_PKCS7Decrypt(worker->decryptobj, buf, &outlen, buflen,
151 data, inlen, final);
152 if (rv != SECSuccess) {
153 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
154 goto cleanup; /* XXX indicate error? */
155 }
156 if (plain != NULL((void*)0)) {
157 PORT_Assert(final || outlen == buflen)((final || outlen == buflen) ? ((void)0) : PR_Assert("final || outlen == buflen"
, "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 157
))
;
158 plain->len += outlen;
159 }
160 data = buf;
161 len = outlen;
162 }
163
164 /*
165 * Update the running digests.
166 */
167 if (len) {
168 for (i = 0; i < worker->digcnt; i++) {
169 if (worker->digobjs[i]) {
170 (*worker->digobjs[i]->update)(worker->digcxs[i], data, len);
171 }
172 }
173 }
174
175 /*
176 * Pass back the contents bytes, and free the temporary buffer.
177 */
178 if (p7dcx->cb != NULL((void*)0)) {
179 if (len)
180 (*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len);
181 }
182
183cleanup:
184 if (freeBuf && buf != NULL((void*)0)) {
185 PORT_FreePORT_Free_Util(buf);
186 }
187}
188
189static void
190sec_pkcs7_decoder_filter(void *arg, const char *data, unsigned long len,
191 int depth, SEC_ASN1EncodingPart data_kind)
192{
193 SEC_PKCS7DecoderContext *p7dcx;
194 struct sec_pkcs7_decoder_worker *worker;
195
196 /*
197 * Since we do not handle any nested contents, the only bytes we
198 * are really interested in are the actual contents bytes (not
199 * the identifier, length, or end-of-contents bytes). If we were
200 * handling nested types we would probably need to do something
201 * smarter based on depth and data_kind.
202 */
203 if (data_kind != SEC_ASN1_Contents)
204 return;
205
206 /*
207 * The ASN.1 decoder should not even call us with a length of 0.
208 * Just being paranoid.
209 */
210 PORT_Assert(len)((len) ? ((void)0) : PR_Assert("len", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 210))
;
211 if (len == 0)
212 return;
213
214 p7dcx = (SEC_PKCS7DecoderContext *)arg;
215
216 /*
217 * Handling nested contents would mean that there is a chain
218 * of workers -- one per each level of content. The following
219 * would start with the first worker and loop over them.
220 */
221 worker = &(p7dcx->worker);
222
223 worker->saw_contents = PR_TRUE1;
224
225 sec_pkcs7_decoder_work_data(p7dcx, worker,
226 (const unsigned char *)data, len, PR_FALSE0);
227}
228
229/*
230 * Create digest contexts for each algorithm in "digestalgs".
231 * No algorithms is not an error, we just do not do anything.
232 * An error (like trouble allocating memory), marks the error
233 * in "p7dcx" and returns SECFailure, which means that our caller
234 * should just give up altogether.
235 */
236static SECStatus
237sec_pkcs7_decoder_start_digests(SEC_PKCS7DecoderContext *p7dcx, int depth,
238 SECAlgorithmID **digestalgs)
239{
240 int i, digcnt;
241
242 p7dcx->worker.digcnt = 0;
243
244 if (digestalgs == NULL((void*)0))
245 return SECSuccess;
246
247 /*
248 * Count the algorithms.
249 */
250 digcnt = 0;
251 while (digestalgs[digcnt] != NULL((void*)0))
252 digcnt++;
253
254 /*
255 * No algorithms means no work to do.
256 * Just act as if there were no algorithms specified.
257 */
258 if (digcnt == 0)
259 return SECSuccess;
260
261 p7dcx->worker.digcxs = (void **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p7dcx->tmp_poolp,
262 digcnt * sizeof(void *));
263 p7dcx->worker.digobjs = (const SECHashObject **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p7dcx->tmp_poolp,
264 digcnt * sizeof(SECHashObject *));
265 if (p7dcx->worker.digcxs == NULL((void*)0) || p7dcx->worker.digobjs == NULL((void*)0)) {
266 p7dcx->error = SEC_ERROR_NO_MEMORY;
267 return SECFailure;
268 }
269
270 p7dcx->worker.depth = depth;
271
272 /*
273 * Create a digest context for each algorithm. Store at the original
274 * index so digcxs/digobjs stay aligned with digestAlgorithms.
275 */
276 PRBool hasDigests = PR_FALSE0;
277 for (i = 0; i < digcnt; i++) {
278 SECAlgorithmID *algid = digestalgs[i];
279 SECOidTag oidTag = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(algid->algorithm));
280 const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
281 void *digcx;
282
283 /*
284 * Skip any algorithm we do not even recognize; obviously,
285 * this could be a problem, but if it is critical then the
286 * result will just be that the signature does not verify.
287 * We do not necessarily want to error out here, because
288 * the particular algorithm may not actually be important,
289 * but we cannot know that until later.
290 */
291 if (digobj == NULL((void*)0)) {
292 continue;
293 }
294
295 digcx = (*digobj->create)();
296 if (digcx != NULL((void*)0)) {
297 (*digobj->begin)(digcx);
298 p7dcx->worker.digobjs[i] = digobj;
299 p7dcx->worker.digcxs[i] = digcx;
300 hasDigests = PR_TRUE1;
301 }
302 }
303 p7dcx->worker.digcnt = digcnt;
304
305 if (hasDigests)
306 SEC_ASN1DecoderSetFilterProcSEC_ASN1DecoderSetFilterProc_Util(p7dcx->dcx,
307 sec_pkcs7_decoder_filter,
308 p7dcx,
309 (PRBool)(p7dcx->cb != NULL((void*)0)));
310 return SECSuccess;
311}
312
313/* destroy any active digest contexts without harvesting results */
314static void
315sec_pkcs7_decoder_abort_digests(struct sec_pkcs7_decoder_worker *worker)
316{
317 int i;
318
319 PORT_Assert(worker)((worker) ? ((void)0) : PR_Assert("worker", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 319))
;
320 if (!worker) {
321 return;
322 }
323
324 if (worker->digcnt <= 0 || !worker->digcxs || !worker->digobjs) {
325 worker->digcnt = 0;
326 return;
327 }
328
329 for (i = 0; i < worker->digcnt; i++) {
330 if (worker->digcxs[i] && worker->digobjs[i]) {
331 (*worker->digobjs[i]->destroy)(worker->digcxs[i], PR_TRUE1);
332 }
333 worker->digcxs[i] = NULL((void*)0);
334 }
335
336 worker->digcnt = 0;
337}
338
339/*
340 * Close out all of the digest contexts, storing the results in "digestsp".
341 */
342static SECStatus
343sec_pkcs7_decoder_finish_digests(SEC_PKCS7DecoderContext *p7dcx,
344 PLArenaPool *poolp,
345 SECItem ***digestsp)
346{
347 /*
348 * XXX Handling nested contents would mean that there is a chain
349 * of workers -- one per each level of content. The following
350 * would want to find the last worker in the chain.
351 */
352 struct sec_pkcs7_decoder_worker *worker = &(p7dcx->worker);
353
354 /*
355 * If no digests, then we have nothing to do.
356 */
357 if (worker->digcnt == 0) {
358 return SECSuccess;
359 }
360
361 /*
362 * No matter what happens after this, we want to stop filtering.
363 * XXX If we handle nested contents, we only want to stop filtering
364 * if we are finishing off the *last* worker.
365 */
366 SEC_ASN1DecoderClearFilterProcSEC_ASN1DecoderClearFilterProc_Util(p7dcx->dcx);
367
368 /*
369 * If we ended up with no contents, just destroy each
370 * digest context -- they are meaningless and potentially
371 * confusing, because their presence would imply some content
372 * was digested.
373 */
374 if (!worker->saw_contents) {
375 sec_pkcs7_decoder_abort_digests(worker);
376 return SECSuccess;
377 }
378
379 void *mark = PORT_ArenaMarkPORT_ArenaMark_Util(poolp);
380
381 /*
382 * Close out each digest context, saving digest away.
383 */
384 SECItem **digests =
385 (SECItem **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(poolp, (worker->digcnt + 1) * sizeof(SECItem *));
386 if (digests == NULL((void*)0)) {
387 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
388 sec_pkcs7_decoder_abort_digests(worker);
389 PORT_ArenaReleasePORT_ArenaRelease_Util(poolp, mark);
390 return SECFailure;
391 }
392
393 for (int i = 0; i < worker->digcnt; i++) {
394 const SECHashObject *digobj = worker->digobjs[i];
395 if (!digobj) {
396 continue;
397 }
398 digests[i] = SECITEM_AllocItemSECITEM_AllocItem_Util(poolp, NULL((void*)0), digobj->length);
399 if (!digests[i]) {
400 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
401 sec_pkcs7_decoder_abort_digests(worker);
402 PORT_ArenaReleasePORT_ArenaRelease_Util(poolp, mark);
403 return SECFailure;
404 }
405 }
406
407 for (int i = 0; i < worker->digcnt; i++) {
408 void *digcx = worker->digcxs[i];
409 const SECHashObject *digobj = worker->digobjs[i];
410
411 if (!digobj) {
412 continue;
413 }
414 (*digobj->end)(digcx, digests[i]->data, &(digests[i]->len), digests[i]->len);
415 (*digobj->destroy)(digcx, PR_TRUE1);
416 worker->digcxs[i] = NULL((void*)0);
417 }
418 worker->digcnt = 0;
419 *digestsp = digests;
420
421 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(poolp, mark);
422 return SECSuccess;
423}
424
425/*
426 * XXX Need comment explaining following helper function (which is used
427 * by sec_pkcs7_decoder_start_decrypt).
428 */
429
430static PK11SymKey *
431sec_pkcs7_decoder_get_recipient_key(SEC_PKCS7DecoderContext *p7dcx,
432 SEC_PKCS7RecipientInfo **recipientinfos,
433 SEC_PKCS7EncryptedContentInfo *enccinfo)
434{
435 SEC_PKCS7RecipientInfo *ri;
436 CERTCertificate *cert = NULL((void*)0);
437 SECKEYPrivateKey *privkey = NULL((void*)0);
438 PK11SymKey *bulkkey = NULL((void*)0);
439 SECOidTag keyalgtag, bulkalgtag, encalgtag;
440 PK11SlotInfo *slot = NULL((void*)0);
441
442 if (recipientinfos == NULL((void*)0) || recipientinfos[0] == NULL((void*)0)) {
443 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
444 goto no_key_found;
445 }
446
447 cert = PK11_FindCertAndKeyByRecipientList(&slot, recipientinfos, &ri,
448 &privkey, p7dcx->pwfn_arg);
449 if (cert == NULL((void*)0)) {
450 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
451 goto no_key_found;
452 }
453
454 ri->cert = cert; /* so we can find it later */
455 PORT_Assert(privkey != NULL)((privkey != ((void*)0)) ? ((void)0) : PR_Assert("privkey != NULL"
, "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 455
))
;
456
457 keyalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(cert->subjectPublicKeyInfo.algorithm));
458 encalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(ri->keyEncAlg));
459 if (keyalgtag != encalgtag) {
460 p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH;
461 goto no_key_found;
462 }
463 bulkalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(enccinfo->contentEncAlg));
464
465 switch (encalgtag) {
466 case SEC_OID_PKCS1_RSA_ENCRYPTION:
467 bulkkey = PK11_PubUnwrapSymKey(privkey, &ri->encKey,
468 PK11_AlgtagToMechanism(bulkalgtag),
469 CKA_DECRYPT0x00000105UL, 0);
470 if (bulkkey == NULL((void*)0)) {
471 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
472 PORT_SetErrorPORT_SetError_Util(0);
473 goto no_key_found;
474 }
475 break;
476 default:
477 p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG;
478 break;
479 }
480
481no_key_found:
482 if (privkey != NULL((void*)0))
483 SECKEY_DestroyPrivateKey(privkey);
484 if (slot != NULL((void*)0))
485 PK11_FreeSlot(slot);
486
487 return bulkkey;
488}
489
490/*
491 * XXX The following comment is old -- the function used to only handle
492 * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData
493 * as well (and it had all of the code of the helper function above
494 * built into it), though the comment was left as is. Fix it...
495 *
496 * We are just about to decode the content of an EnvelopedData.
497 * Set up a decryption context so we can decrypt as we go.
498 * Presumably we are one of the recipients listed in "recipientinfos".
499 * (XXX And if we are not, or if we have trouble, what should we do?
500 * It would be nice to let the decoding still work. Maybe it should
501 * be an error if there is a content callback, but not an error otherwise?)
502 * The encryption key and related information can be found in "enccinfo".
503 */
504static SECStatus
505sec_pkcs7_decoder_start_decrypt(SEC_PKCS7DecoderContext *p7dcx, int depth,
506 SEC_PKCS7RecipientInfo **recipientinfos,
507 SEC_PKCS7EncryptedContentInfo *enccinfo,
508 PK11SymKey **copy_key_for_signature)
509{
510 PK11SymKey *bulkkey = NULL((void*)0);
511 sec_PKCS7CipherObject *decryptobj;
512
513 /*
514 * If a callback is supplied to retrieve the encryption key,
515 * for instance, for Encrypted Content infos, then retrieve
516 * the bulkkey from the callback. Otherwise, assume that
517 * we are processing Enveloped or SignedAndEnveloped data
518 * content infos.
519 *
520 * XXX Put an assert here?
521 */
522 if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) {
523 if (p7dcx->dkcb != NULL((void*)0)) {
524 bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg,
525 &(enccinfo->contentEncAlg));
526 }
527 enccinfo->keysize = 0;
528 } else {
529 bulkkey = sec_pkcs7_decoder_get_recipient_key(p7dcx, recipientinfos,
530 enccinfo);
531 if (bulkkey == NULL((void*)0))
532 goto no_decryption;
533 enccinfo->keysize = PK11_GetKeyStrength(bulkkey,
534 &(enccinfo->contentEncAlg));
535 }
536
537 /*
538 * XXX I think following should set error in p7dcx and clear set error
539 * (as used to be done here, or as is done in get_receipient_key above.
540 */
541 if (bulkkey == NULL((void*)0)) {
542 goto no_decryption;
543 }
544
545 /*
546 * We want to make sure decryption is allowed. This is done via
547 * a callback specified in SEC_PKCS7DecoderStart().
548 */
549 if (p7dcx->decrypt_allowed_cb) {
550 if ((*p7dcx->decrypt_allowed_cb)(&(enccinfo->contentEncAlg),
551 bulkkey) == PR_FALSE0) {
552 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
553 goto no_decryption;
554 }
555 } else {
556 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
557 goto no_decryption;
558 }
559
560 /*
561 * When decrypting a signedAndEnvelopedData, the signature also has
562 * to be decrypted with the bulk encryption key; to avoid having to
563 * get it all over again later (and do another potentially expensive
564 * RSA operation), copy it for later signature verification to use.
565 */
566 if (copy_key_for_signature != NULL((void*)0))
567 *copy_key_for_signature = PK11_ReferenceSymKey(bulkkey);
568
569 /*
570 * Now we have the bulk encryption key (in bulkkey) and the
571 * the algorithm (in enccinfo->contentEncAlg). Using those,
572 * create a decryption context.
573 */
574 decryptobj = sec_PKCS7CreateDecryptObject(bulkkey,
575 &(enccinfo->contentEncAlg));
576
577 /*
578 * We are done with (this) bulkkey now.
579 */
580 PK11_FreeSymKey(bulkkey);
581 bulkkey = NULL((void*)0);
582
583 if (decryptobj == NULL((void*)0)) {
584 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
585 PORT_SetErrorPORT_SetError_Util(0);
586 goto no_decryption;
587 }
588
589 SEC_ASN1DecoderSetFilterProcSEC_ASN1DecoderSetFilterProc_Util(p7dcx->dcx,
590 sec_pkcs7_decoder_filter,
591 p7dcx,
592 (PRBool)(p7dcx->cb != NULL((void*)0)));
593
594 p7dcx->worker.depth = depth;
595 p7dcx->worker.decryptobj = decryptobj;
596
597 return SECSuccess;
598
599no_decryption:
600 PK11_FreeSymKey(bulkkey);
601 /*
602 * For some reason (error set already, if appropriate), we cannot
603 * decrypt the content. I am not sure what exactly is the right
604 * thing to do here; in some cases we want to just stop, and in
605 * others we want to let the decoding finish even though we cannot
606 * decrypt the content. My current thinking is that if the caller
607 * set up a content callback, then they are really interested in
608 * getting (decrypted) content, and if they cannot they will want
609 * to know about it. However, if no callback was specified, then
610 * maybe it is not important that the decryption failed.
611 */
612 if (p7dcx->cb != NULL((void*)0))
613 return SECFailure;
614 else
615 return SECSuccess; /* Let the decoding continue. */
616}
617
618static SECStatus
619sec_pkcs7_decoder_finish_decrypt(SEC_PKCS7DecoderContext *p7dcx,
620 PLArenaPool *poolp,
621 SEC_PKCS7EncryptedContentInfo *enccinfo)
622{
623 struct sec_pkcs7_decoder_worker *worker;
624
625 /*
626 * XXX Handling nested contents would mean that there is a chain
627 * of workers -- one per each level of content. The following
628 * would want to find the last worker in the chain.
629 */
630 worker = &(p7dcx->worker);
631
632 /*
633 * If no decryption context, then we have nothing to do.
634 */
635 if (worker->decryptobj == NULL((void*)0))
636 return SECSuccess;
637
638 /*
639 * No matter what happens after this, we want to stop filtering.
640 * XXX If we handle nested contents, we only want to stop filtering
641 * if we are finishing off the *last* worker.
642 */
643 SEC_ASN1DecoderClearFilterProcSEC_ASN1DecoderClearFilterProc_Util(p7dcx->dcx);
644
645 /*
646 * Handle the last block.
647 */
648 sec_pkcs7_decoder_work_data(p7dcx, worker, NULL((void*)0), 0, PR_TRUE1);
649
650 /*
651 * The callback invoked from work_data may have aborted and already
652 * torn down the decrypt context, so only destroy if it is still set.
653 */
654 if (worker->decryptobj) {
655 sec_PKCS7DestroyDecryptObject(worker->decryptobj);
656 worker->decryptobj = NULL((void*)0);
657 }
658
659 return SECSuccess;
660}
661
662static void
663sec_pkcs7_decoder_notify(void *arg, PRBool before, void *dest, int depth)
664{
665 SEC_PKCS7DecoderContext *p7dcx;
666 SEC_PKCS7ContentInfo *cinfo;
667 SEC_PKCS7SignedData *sigd;
668 SEC_PKCS7EnvelopedData *envd;
669 SEC_PKCS7SignedAndEnvelopedData *saed;
670 SEC_PKCS7EncryptedData *encd;
671 SEC_PKCS7DigestedData *digd;
672 PRBool after;
673 SECStatus rv;
674
675 /*
676 * Just to make the code easier to read, create an "after" variable
677 * that is equivalent to "not before".
678 * (This used to be just the statement "after = !before", but that
679 * causes a warning on the mac; to avoid that, we do it the long way.)
680 */
681 if (before)
682 after = PR_FALSE0;
683 else
684 after = PR_TRUE1;
685
686 p7dcx = (SEC_PKCS7DecoderContext *)arg;
687 if (!p7dcx) {
688 return;
689 }
690
691 cinfo = p7dcx->cinfo;
692
693 if (!cinfo) {
694 return;
695 }
696
697 if (cinfo->contentTypeTag == NULL((void*)0)) {
698 if (after && dest == &(cinfo->contentType))
699 cinfo->contentTypeTag = SECOID_FindOIDSECOID_FindOID_Util(&(cinfo->contentType));
700 return;
701 }
702
703 switch (cinfo->contentTypeTag->offset) {
704 case SEC_OID_PKCS7_SIGNED_DATA:
705 sigd = cinfo->content.signedData;
706 if (sigd == NULL((void*)0))
707 break;
708
709 if (sigd->contentInfo.contentTypeTag == NULL((void*)0)) {
710 if (after && dest == &(sigd->contentInfo.contentType))
711 sigd->contentInfo.contentTypeTag =
712 SECOID_FindOIDSECOID_FindOID_Util(&(sigd->contentInfo.contentType));
713 break;
714 }
715
716 /*
717 * We only set up a filtering digest if the content is
718 * plain DATA; anything else needs more work because a
719 * second pass is required to produce a DER encoding from
720 * an input that can be BER encoded. (This is a requirement
721 * of PKCS7 that is unfortunate, but there you have it.)
722 *
723 * XXX Also, since we stop here if this is not DATA, the
724 * inner content is not getting processed at all. Someday
725 * we may want to fix that.
726 */
727 if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) {
728 /* XXX Set an error in p7dcx->error */
729 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
730 break;
731 }
732
733 /*
734 * Just before the content, we want to set up a digest context
735 * for each digest algorithm listed, and start a filter which
736 * will run all of the contents bytes through that digest.
737 */
738 if (before && dest == &(sigd->contentInfo.content)) {
739 rv = sec_pkcs7_decoder_start_digests(p7dcx, depth,
740 sigd->digestAlgorithms);
741 if (rv != SECSuccess)
742 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
743
744 break;
745 }
746
747 /*
748 * XXX To handle nested types, here is where we would want
749 * to check for inner boundaries that need handling.
750 */
751
752 /*
753 * Are we done?
754 */
755 if (after && dest == &(sigd->contentInfo.content)) {
756 /*
757 * Close out the digest contexts. We ignore any error
758 * because we are stopping anyway; the error status left
759 * behind in p7dcx will be seen by outer functions.
760 */
761 (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp,
762 &(sigd->digests));
763
764 /*
765 * XXX To handle nested contents, we would need to remove
766 * the worker from the chain (and free it).
767 */
768
769 /*
770 * Stop notify.
771 */
772 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
773 }
774 break;
775
776 case SEC_OID_PKCS7_ENVELOPED_DATA:
777 envd = cinfo->content.envelopedData;
778 if (envd == NULL((void*)0))
779 break;
780
781 if (envd->encContentInfo.contentTypeTag == NULL((void*)0)) {
782 if (after && dest == &(envd->encContentInfo.contentType))
783 envd->encContentInfo.contentTypeTag =
784 SECOID_FindOIDSECOID_FindOID_Util(&(envd->encContentInfo.contentType));
785 break;
786 }
787
788 /*
789 * Just before the content, we want to set up a decryption
790 * context, and start a filter which will run all of the
791 * contents bytes through it to determine the plain content.
792 */
793 if (before && dest == &(envd->encContentInfo.encContent)) {
794 rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth,
795 envd->recipientInfos,
796 &(envd->encContentInfo),
797 NULL((void*)0));
798 if (rv != SECSuccess)
799 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
800
801 break;
802 }
803
804 /*
805 * Are we done?
806 */
807 if (after && dest == &(envd->encContentInfo.encContent)) {
808 /*
809 * Close out the decryption context. We ignore any error
810 * because we are stopping anyway; the error status left
811 * behind in p7dcx will be seen by outer functions.
812 */
813 (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp,
814 &(envd->encContentInfo));
815
816 /*
817 * XXX To handle nested contents, we would need to remove
818 * the worker from the chain (and free it).
819 */
820
821 /*
822 * Stop notify.
823 */
824 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
825 }
826 break;
827
828 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
829 saed = cinfo->content.signedAndEnvelopedData;
830 if (saed == NULL((void*)0))
831 break;
832
833 if (saed->encContentInfo.contentTypeTag == NULL((void*)0)) {
834 if (after && dest == &(saed->encContentInfo.contentType))
835 saed->encContentInfo.contentTypeTag =
836 SECOID_FindOIDSECOID_FindOID_Util(&(saed->encContentInfo.contentType));
837 break;
838 }
839
840 /*
841 * Just before the content, we want to set up a decryption
842 * context *and* digest contexts, and start a filter which
843 * will run all of the contents bytes through both.
844 */
845 if (before && dest == &(saed->encContentInfo.encContent)) {
846 rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth,
847 saed->recipientInfos,
848 &(saed->encContentInfo),
849 &(saed->sigKey));
850 if (rv == SECSuccess)
851 rv = sec_pkcs7_decoder_start_digests(p7dcx, depth,
852 saed->digestAlgorithms);
853 if (rv != SECSuccess)
854 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
855
856 break;
857 }
858
859 /*
860 * Are we done?
861 */
862 if (after && dest == &(saed->encContentInfo.encContent)) {
863 /*
864 * Close out the decryption and digests contexts.
865 * We ignore any errors because we are stopping anyway;
866 * the error status left behind in p7dcx will be seen by
867 * outer functions.
868 *
869 * Note that the decrypt stuff must be called first;
870 * it may have a last buffer to do which in turn has
871 * to be added to the digest.
872 */
873 (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp,
874 &(saed->encContentInfo));
875 (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp,
876 &(saed->digests));
877
878 /*
879 * XXX To handle nested contents, we would need to remove
880 * the worker from the chain (and free it).
881 */
882
883 /*
884 * Stop notify.
885 */
886 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
887 }
888 break;
889
890 case SEC_OID_PKCS7_DIGESTED_DATA:
891 digd = cinfo->content.digestedData;
892 if (digd == NULL((void*)0))
893 break;
894
895 /*
896 * XXX Want to do the digest or not? Maybe future enhancement...
897 */
898 if (before && dest == &(digd->contentInfo.content.data)) {
899 SEC_ASN1DecoderSetFilterProcSEC_ASN1DecoderSetFilterProc_Util(p7dcx->dcx, sec_pkcs7_decoder_filter,
900 p7dcx,
901 (PRBool)(p7dcx->cb != NULL((void*)0)));
902 break;
903 }
904
905 /*
906 * Are we done?
907 */
908 if (after && dest == &(digd->contentInfo.content.data)) {
909 SEC_ASN1DecoderClearFilterProcSEC_ASN1DecoderClearFilterProc_Util(p7dcx->dcx);
910 }
911 break;
912
913 case SEC_OID_PKCS7_ENCRYPTED_DATA:
914 encd = cinfo->content.encryptedData;
915
916 if (!encd) {
917 break;
918 }
919
920 /*
921 * XXX If the decryption key callback is set, we want to start
922 * the decryption. If the callback is not set, we will treat the
923 * content as plain data, since we do not have the key.
924 *
925 * Is this the proper thing to do?
926 */
927 if (before && dest == &(encd->encContentInfo.encContent)) {
928 /*
929 * Start the encryption process if the decryption key callback
930 * is present. Otherwise, treat the content like plain data.
931 */
932 rv = SECSuccess;
933 if (p7dcx->dkcb != NULL((void*)0)) {
934 rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, NULL((void*)0),
935 &(encd->encContentInfo),
936 NULL((void*)0));
937 }
938
939 if (rv != SECSuccess)
940 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
941
942 break;
943 }
944
945 /*
946 * Are we done?
947 */
948 if (after && dest == &(encd->encContentInfo.encContent)) {
949 /*
950 * Close out the decryption context. We ignore any error
951 * because we are stopping anyway; the error status left
952 * behind in p7dcx will be seen by outer functions.
953 */
954 (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp,
955 &(encd->encContentInfo));
956
957 /*
958 * Stop notify.
959 */
960 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
961 }
962 break;
963
964 case SEC_OID_PKCS7_DATA:
965 /*
966 * If a output callback has been specified, we want to set the filter
967 * to call the callback. This is taken care of in
968 * sec_pkcs7_decoder_start_decrypt() or
969 * sec_pkcs7_decoder_start_digests() for the other content types.
970 */
971
972 if (before && dest == &(cinfo->content.data)) {
973
974 /*
975 * Set the filter proc up.
976 */
977 SEC_ASN1DecoderSetFilterProcSEC_ASN1DecoderSetFilterProc_Util(p7dcx->dcx,
978 sec_pkcs7_decoder_filter,
979 p7dcx,
980 (PRBool)(p7dcx->cb != NULL((void*)0)));
981 break;
982 }
983
984 if (after && dest == &(cinfo->content.data)) {
985 /*
986 * Time to clean up after ourself, stop the Notify and Filter
987 * procedures.
988 */
989 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
990 SEC_ASN1DecoderClearFilterProcSEC_ASN1DecoderClearFilterProc_Util(p7dcx->dcx);
991 }
992 break;
993
994 default:
995 SEC_ASN1DecoderClearNotifyProcSEC_ASN1DecoderClearNotifyProc_Util(p7dcx->dcx);
996 break;
997 }
998}
999
1000SEC_PKCS7DecoderContext *
1001SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
1002 SECKEYGetPasswordKey pwfn, void *pwfn_arg,
1003 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
1004 void *decrypt_key_cb_arg,
1005 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
1006{
1007 SEC_PKCS7DecoderContext *p7dcx;
1008 SEC_ASN1DecoderContext *dcx;
1009 SEC_PKCS7ContentInfo *cinfo;
1010 PLArenaPool *poolp;
1011
1012 poolp = PORT_NewArenaPORT_NewArena_Util(1024); /* XXX what is right value? */
1013 if (poolp == NULL((void*)0))
1014 return NULL((void*)0);
1015
1016 cinfo = (SEC_PKCS7ContentInfo *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(poolp, sizeof(*cinfo));
1017 if (cinfo == NULL((void*)0)) {
1018 PORT_FreeArenaPORT_FreeArena_Util(poolp, PR_FALSE0);
1019 return NULL((void*)0);
1020 }
1021
1022 cinfo->poolp = poolp;
1023 cinfo->pwfn = pwfn;
1024 cinfo->pwfn_arg = pwfn_arg;
1025 cinfo->created = PR_FALSE0;
1026 cinfo->refCount = 1;
1027
1028 p7dcx =
1029 (SEC_PKCS7DecoderContext *)PORT_ZAllocPORT_ZAlloc_Util(sizeof(SEC_PKCS7DecoderContext));
1030 if (p7dcx == NULL((void*)0)) {
1031 PORT_FreeArenaPORT_FreeArena_Util(poolp, PR_FALSE0);
1032 return NULL((void*)0);
1033 }
1034
1035 p7dcx->tmp_poolp = PORT_NewArenaPORT_NewArena_Util(1024); /* XXX what is right value? */
1036 if (p7dcx->tmp_poolp == NULL((void*)0)) {
1037 PORT_FreePORT_Free_Util(p7dcx);
1038 PORT_FreeArenaPORT_FreeArena_Util(poolp, PR_FALSE0);
1039 return NULL((void*)0);
1040 }
1041
1042 dcx = SEC_ASN1DecoderStartSEC_ASN1DecoderStart_Util(poolp, cinfo, sec_PKCS7ContentInfoTemplate);
1043 if (dcx == NULL((void*)0)) {
1044 PORT_FreeArenaPORT_FreeArena_Util(p7dcx->tmp_poolp, PR_FALSE0);
1045 PORT_FreePORT_Free_Util(p7dcx);
1046 PORT_FreeArenaPORT_FreeArena_Util(poolp, PR_FALSE0);
1047 return NULL((void*)0);
1048 }
1049
1050 SEC_ASN1DecoderSetNotifyProcSEC_ASN1DecoderSetNotifyProc_Util(dcx, sec_pkcs7_decoder_notify, p7dcx);
1051
1052 p7dcx->dcx = dcx;
1053 p7dcx->cinfo = cinfo;
1054 p7dcx->cb = cb;
1055 p7dcx->cb_arg = cb_arg;
1056 p7dcx->pwfn = pwfn;
1057 p7dcx->pwfn_arg = pwfn_arg;
1058 p7dcx->dkcb = decrypt_key_cb;
1059 p7dcx->dkcb_arg = decrypt_key_cb_arg;
1060 p7dcx->decrypt_allowed_cb = decrypt_allowed_cb;
1061
1062 return p7dcx;
1063}
1064
1065SECStatus
1066SEC_PKCS7DecoderSetMaxInputSize(SEC_PKCS7DecoderContext *p7dcx,
1067 unsigned long max_input_size)
1068{
1069 if (!p7dcx || !p7dcx->dcx) {
1070 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1071 return SECFailure;
1072 }
1073 SEC_ASN1DecoderSetMaximumInputSize(p7dcx->dcx, max_input_size);
1074 return SECSuccess;
1075}
1076
1077SECStatus
1078SEC_PKCS7DecoderSetMaxElementLen(SEC_PKCS7DecoderContext *p7dcx,
1079 unsigned long max_element_len)
1080{
1081 if (!p7dcx || !p7dcx->dcx) {
1082 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1083 return SECFailure;
1084 }
1085 SEC_ASN1DecoderSetMaximumElementSize(p7dcx->dcx, max_element_len);
1086 return SECSuccess;
1087}
1088
1089/*
1090 * Do the next chunk of PKCS7 decoding. If there is a problem, set
1091 * an error and return a failure status. Note that in the case of
1092 * an error, this routine is still prepared to be called again and
1093 * again in case that is the easiest route for our caller to take.
1094 * We simply detect it and do not do anything except keep setting
1095 * that error in case our caller has not noticed it yet...
1096 */
1097SECStatus
1098SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
1099 const char *buf, unsigned long len)
1100{
1101 if (!p7dcx) {
1102 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1103 return SECFailure;
1104 }
1105
1106 if (p7dcx->cinfo != NULL((void*)0) && p7dcx->dcx != NULL((void*)0)) {
1107 PORT_Assert(p7dcx->error == 0)((p7dcx->error == 0) ? ((void)0) : PR_Assert("p7dcx->error == 0"
, "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 1107
))
;
1108 if (p7dcx->error == 0) {
1109 if (SEC_ASN1DecoderUpdateSEC_ASN1DecoderUpdate_Util(p7dcx->dcx, buf, len) != SECSuccess) {
1110 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
1111 PORT_Assert(p7dcx->error)((p7dcx->error) ? ((void)0) : PR_Assert("p7dcx->error",
"/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 1111
))
;
1112 if (p7dcx->error == 0)
1113 p7dcx->error = -1;
1114 }
1115 }
1116 }
1117
1118 if (p7dcx->error) {
1119 sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1120 if (p7dcx->worker.decryptobj) {
1121 sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1122 p7dcx->worker.decryptobj = NULL((void*)0);
1123 }
1124 if (p7dcx->dcx != NULL((void*)0)) {
1125 (void)SEC_ASN1DecoderFinishSEC_ASN1DecoderFinish_Util(p7dcx->dcx);
1126 p7dcx->dcx = NULL((void*)0);
1127 }
1128 if (p7dcx->cinfo != NULL((void*)0)) {
1129 SEC_PKCS7DestroyContentInfo(p7dcx->cinfo);
1130 p7dcx->cinfo = NULL((void*)0);
1131 }
1132 PORT_SetErrorPORT_SetError_Util(p7dcx->error);
1133 return SECFailure;
1134 }
1135
1136 return SECSuccess;
1137}
1138
1139SEC_PKCS7ContentInfo *
1140SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
1141{
1142 SEC_PKCS7ContentInfo *cinfo;
1143
1144 sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1145 cinfo = p7dcx->cinfo;
1146 p7dcx->cinfo = NULL((void*)0);
1147 if (p7dcx->dcx != NULL((void*)0)) {
1148 if (SEC_ASN1DecoderFinishSEC_ASN1DecoderFinish_Util(p7dcx->dcx) != SECSuccess) {
1149 SEC_PKCS7DestroyContentInfo(cinfo);
1150 cinfo = NULL((void*)0);
1151 }
1152 p7dcx->dcx = NULL((void*)0);
1153 }
1154 /* SEC_ASN1DecoderFinish reports success for a decoder that stopped on
1155 * an error, so never hand back a message whose decoding was aborted. */
1156 if (cinfo != NULL((void*)0) && p7dcx->error != 0) {
1157 SEC_PKCS7DestroyContentInfo(cinfo);
1158 cinfo = NULL((void*)0);
1159 PORT_SetErrorPORT_SetError_Util(p7dcx->error);
1160 }
1161 /* free any NSS data structures */
1162 if (p7dcx->worker.decryptobj) {
1163 sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1164 p7dcx->worker.decryptobj = NULL((void*)0);
1165 }
1166
1167 PORT_FreeArenaPORT_FreeArena_Util(p7dcx->tmp_poolp, PR_FALSE0);
1168 PORT_FreePORT_Free_Util(p7dcx);
1169 return cinfo;
1170}
1171
1172SEC_PKCS7ContentInfo *
1173SEC_PKCS7DecodeItem(SECItem *p7item,
1174 SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
1175 SECKEYGetPasswordKey pwfn, void *pwfn_arg,
1176 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
1177 void *decrypt_key_cb_arg,
1178 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
1179{
1180 SEC_PKCS7DecoderContext *p7dcx;
1181
1182 p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb,
1183 decrypt_key_cb_arg, decrypt_allowed_cb);
1184 if (!p7dcx) {
1185 /* error code is set */
1186 return NULL((void*)0);
1187 }
1188 (void)SEC_PKCS7DecoderUpdate(p7dcx, (char *)p7item->data, p7item->len);
1189 return SEC_PKCS7DecoderFinish(p7dcx);
1190}
1191
1192/*
1193 * Abort the ASN.1 stream. Used by pkcs 12
1194 */
1195void
1196SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error)
1197{
1198 PORT_Assert(p7dcx)((p7dcx) ? ((void)0) : PR_Assert("p7dcx", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1198))
;
1199 if (!p7dcx) {
1200 return;
1201 }
1202
1203 /* ensure any streaming helpers are torn down */
1204 sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1205 if (p7dcx->worker.decryptobj) {
1206 sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1207 p7dcx->worker.decryptobj = NULL((void*)0);
1208 }
1209
1210 PORT_SetErrorPORT_SetError_Util(error);
1211 p7dcx->error = error ? error : -1;
1212 if (p7dcx->dcx != NULL((void*)0)) {
1213 SEC_ASN1DecoderAbortSEC_ASN1DecoderAbort_Util(p7dcx->dcx, error);
1214 }
1215}
1216
1217/*
1218 * If the thing contains any certs or crls return true; false otherwise.
1219 */
1220PRBool
1221SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo)
1222{
1223 SECOidTag kind;
1224 SECItem **certs;
1225 CERTSignedCrl **crls;
1226
1227 kind = SEC_PKCS7ContentType(cinfo);
1228 switch (kind) {
1229 default:
1230 case SEC_OID_PKCS7_DATA:
1231 case SEC_OID_PKCS7_DIGESTED_DATA:
1232 case SEC_OID_PKCS7_ENVELOPED_DATA:
1233 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1234 return PR_FALSE0;
1235 case SEC_OID_PKCS7_SIGNED_DATA:
1236 certs = cinfo->content.signedData->rawCerts;
1237 crls = cinfo->content.signedData->crls;
1238 break;
1239 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1240 certs = cinfo->content.signedAndEnvelopedData->rawCerts;
1241 crls = cinfo->content.signedAndEnvelopedData->crls;
1242 break;
1243 }
1244
1245 /*
1246 * I know this could be collapsed, but I was in a mood to be explicit.
1247 */
1248 if (certs != NULL((void*)0) && certs[0] != NULL((void*)0))
1249 return PR_TRUE1;
1250 else if (crls != NULL((void*)0) && crls[0] != NULL((void*)0))
1251 return PR_TRUE1;
1252 else
1253 return PR_FALSE0;
1254}
1255
1256/* return the content length...could use GetContent, however we
1257 * need the encrypted content length
1258 */
1259PRBool
1260SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen)
1261{
1262 SECItem *item = NULL((void*)0);
1263
1264 if (cinfo == NULL((void*)0)) {
1265 return PR_TRUE1;
1266 }
1267
1268 switch (SEC_PKCS7ContentType(cinfo)) {
1269 case SEC_OID_PKCS7_DATA:
1270 item = cinfo->content.data;
1271 break;
1272 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1273 item = &cinfo->content.encryptedData->encContentInfo.encContent;
1274 break;
1275 default:
1276 /* add other types */
1277 return PR_FALSE0;
1278 }
1279
1280 if (!item) {
1281 return PR_TRUE1;
1282 } else if (item->len <= minLen) {
1283 return PR_TRUE1;
1284 }
1285
1286 return PR_FALSE0;
1287}
1288
1289PRBool
1290SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo)
1291{
1292 SECOidTag kind;
1293
1294 kind = SEC_PKCS7ContentType(cinfo);
1295 switch (kind) {
1296 default:
1297 case SEC_OID_PKCS7_DATA:
1298 case SEC_OID_PKCS7_DIGESTED_DATA:
1299 case SEC_OID_PKCS7_SIGNED_DATA:
1300 return PR_FALSE0;
1301 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1302 case SEC_OID_PKCS7_ENVELOPED_DATA:
1303 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1304 return PR_TRUE1;
1305 }
1306}
1307
1308/*
1309 * If the PKCS7 content has a signature (not just *could* have a signature)
1310 * return true; false otherwise. This can/should be called before calling
1311 * VerifySignature, which will always indicate failure if no signature is
1312 * present, but that does not mean there even was a signature!
1313 * Note that the content itself can be empty (detached content was sent
1314 * another way); it is the presence of the signature that matters.
1315 */
1316PRBool
1317SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo)
1318{
1319 SECOidTag kind;
1320 SEC_PKCS7SignerInfo **signerinfos;
1321
1322 kind = SEC_PKCS7ContentType(cinfo);
1323 switch (kind) {
1324 default:
1325 case SEC_OID_PKCS7_DATA:
1326 case SEC_OID_PKCS7_DIGESTED_DATA:
1327 case SEC_OID_PKCS7_ENVELOPED_DATA:
1328 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1329 return PR_FALSE0;
1330 case SEC_OID_PKCS7_SIGNED_DATA:
1331 signerinfos = cinfo->content.signedData->signerInfos;
1332 break;
1333 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1334 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
1335 break;
1336 }
1337
1338 /*
1339 * I know this could be collapsed; but I kind of think it will get
1340 * more complicated before I am finished, so...
1341 */
1342 if (signerinfos != NULL((void*)0) && signerinfos[0] != NULL((void*)0))
1343 return PR_TRUE1;
1344 else
1345 return PR_FALSE0;
1346}
1347
1348/*
1349 * sec_pkcs7_verify_signature
1350 *
1351 * Look at a PKCS7 contentInfo and check if the signature is good.
1352 * The digest was either calculated earlier (and is stored in the
1353 * contentInfo itself) or is passed in via "detached_digest".
1354 *
1355 * The verification checks that the signing cert is valid and trusted
1356 * for the purpose specified by "certusage" at
1357 * - "*atTime" if "atTime" is not null, or
1358 * - the signing time if the signing time is available in "cinfo", or
1359 * - the current time (as returned by PR_Now).
1360 *
1361 * In addition, if "keepcerts" is true, add any new certificates found
1362 * into our local database.
1363 *
1364 * XXX Each place which returns PR_FALSE should be sure to have a good
1365 * error set for inspection by the caller. Alternatively, we could create
1366 * an enumeration of success and each type of failure and return that
1367 * instead of a boolean. For now, the default in a bad situation is to
1368 * set the error to SEC_ERROR_PKCS7_BAD_SIGNATURE. But this should be
1369 * reviewed; better (more specific) errors should be possible (to distinguish
1370 * a signature failure from a badly-formed pkcs7 signedData, for example).
1371 * Some of the errors should probably just be SEC_ERROR_BAD_SIGNATURE,
1372 * but that has a less helpful error string associated with it right now;
1373 * if/when that changes, review and change these as needed.
1374 *
1375 * XXX This is broken wrt signedAndEnvelopedData. In that case, the
1376 * message digest is doubly encrypted -- first encrypted with the signer
1377 * private key but then again encrypted with the bulk encryption key used
1378 * to encrypt the content. So before we can pass the digest to VerifyDigest,
1379 * we need to decrypt it with the bulk encryption key. Also, in this case,
1380 * there should be NO authenticatedAttributes (signerinfo->authAttr should
1381 * be NULL).
1382 */
1383static PRBool
1384sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo,
1385 SECCertUsage certusage,
1386 const SECItem *detached_digest,
1387 HASH_HashType digest_type,
1388 PRBool keepcerts,
1389 const PRTime *atTime)
1390{
1391 SECAlgorithmID **digestalgs, *bulkid;
1392 const SECItem *digest;
1393 SECItem **digests;
1394 SECItem **rawcerts;
1395 SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
1396 CERTCertificate *cert, **certs;
1397 PRBool goodsig;
1398 CERTCertDBHandle *certdb, *defaultdb;
1399 SECOidTag encTag, digestTag;
1400 HASH_HashType found_type;
1401 int i, certcount;
1402 SECKEYPublicKey *publickey;
1403 SECItem *content_type;
1404 PK11SymKey *sigkey;
1405 SECItem *encoded_stime;
1406 PRTime stime;
1407 PRTime verificationTime;
1408 SECStatus rv;
1409
1410 /*
1411 * Everything needed in order to "goto done" safely.
1412 */
1413 goodsig = PR_FALSE0;
1414 certcount = 0;
1415 cert = NULL((void*)0);
1416 certs = NULL((void*)0);
1417 certdb = NULL((void*)0);
1418 defaultdb = CERT_GetDefaultCertDB();
1419 publickey = NULL((void*)0);
1420
1421 if (!SEC_PKCS7ContentIsSigned(cinfo)) {
1422 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1423 goto done;
1424 }
1425
1426 PORT_Assert(cinfo->contentTypeTag != NULL)((cinfo->contentTypeTag != ((void*)0)) ? ((void)0) : PR_Assert
("cinfo->contentTypeTag != NULL", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1426))
;
1427
1428 switch (cinfo->contentTypeTag->offset) {
1429 default:
1430 case SEC_OID_PKCS7_DATA:
1431 case SEC_OID_PKCS7_DIGESTED_DATA:
1432 case SEC_OID_PKCS7_ENVELOPED_DATA:
1433 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1434 /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */
1435 PORT_Assert(0)((0) ? ((void)0) : PR_Assert("0", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1435))
;
1436 case SEC_OID_PKCS7_SIGNED_DATA: {
1437 SEC_PKCS7SignedData *sdp;
1438
1439 sdp = cinfo->content.signedData;
1440 digestalgs = sdp->digestAlgorithms;
1441 digests = sdp->digests;
1442 rawcerts = sdp->rawCerts;
1443 signerinfos = sdp->signerInfos;
1444 content_type = &(sdp->contentInfo.contentType);
1445 sigkey = NULL((void*)0);
1446 bulkid = NULL((void*)0);
1447 } break;
1448 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
1449 SEC_PKCS7SignedAndEnvelopedData *saedp;
1450
1451 saedp = cinfo->content.signedAndEnvelopedData;
1452 digestalgs = saedp->digestAlgorithms;
1453 digests = saedp->digests;
1454 rawcerts = saedp->rawCerts;
1455 signerinfos = saedp->signerInfos;
1456 content_type = &(saedp->encContentInfo.contentType);
1457 sigkey = saedp->sigKey;
1458 bulkid = &(saedp->encContentInfo.contentEncAlg);
1459 } break;
1460 }
1461
1462 if ((signerinfos == NULL((void*)0)) || (signerinfos[0] == NULL((void*)0))) {
1463 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1464 goto done;
1465 }
1466
1467 /*
1468 * XXX Need to handle multiple signatures; checking them is easy,
1469 * but what should be the semantics here (like, return value)?
1470 */
1471 if (signerinfos[1] != NULL((void*)0)) {
1472 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1473 goto done;
1474 }
1475
1476 signerinfo = signerinfos[0];
1477
1478 /*
1479 * XXX I would like to just pass the issuerAndSN, along with the rawcerts
1480 * and crls, to some function that did all of this certificate stuff
1481 * (open/close the database if necessary, verifying the certs, etc.)
1482 * and gave me back a cert pointer if all was good.
1483 */
1484 certdb = defaultdb;
1485 if (certdb == NULL((void*)0)) {
1486 goto done;
1487 }
1488
1489 certcount = 0;
1490 if (rawcerts != NULL((void*)0)) {
1491 for (; rawcerts[certcount] != NULL((void*)0); certcount++) {
1492 /* just counting */
1493 }
1494 }
1495
1496 /*
1497 * Note that the result of this is that each cert in "certs"
1498 * needs to be destroyed.
1499 */
1500 rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs,
1501 keepcerts, PR_FALSE0, NULL((void*)0));
1502 if (rv != SECSuccess) {
1503 goto done;
1504 }
1505
1506 /*
1507 * This cert will also need to be freed, but since we save it
1508 * in signerinfo for later, we do not want to destroy it when
1509 * we leave this function -- we let the clean-up of the entire
1510 * cinfo structure later do the destroy of this cert.
1511 */
1512 cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN);
1513 if (cert == NULL((void*)0)) {
1514 goto done;
1515 }
1516
1517 if (signerinfo->cert != NULL((void*)0)) {
1518 CERT_DestroyCertificate(signerinfo->cert);
1519 }
1520 signerinfo->cert = cert;
1521
1522 /*
1523 * Get and convert the signing time; if available, it will be used
1524 * both on the cert verification and for importing the sender
1525 * email profile.
1526 */
1527 encoded_stime = SEC_PKCS7GetSigningTime(cinfo);
1528 if (encoded_stime != NULL((void*)0)) {
1529 if (DER_DecodeTimeChoiceDER_DecodeTimeChoice_Util(&stime, encoded_stime) != SECSuccess)
1530 encoded_stime = NULL((void*)0); /* conversion failed, so pretend none */
1531 }
1532
1533 /*
1534 * XXX This uses the signing time, if available. Additionally, we
1535 * might want to, if there is no signing time, get the message time
1536 * from the mail header itself, and use that. That would require
1537 * a change to our interface though, and for S/MIME callers to pass
1538 * in a time (and for non-S/MIME callers to pass in nothing, or
1539 * maybe make them pass in the current time, always?).
1540 */
1541 if (atTime) {
1542 verificationTime = *atTime;
1543 } else if (encoded_stime != NULL((void*)0)) {
1544 verificationTime = stime;
1545 } else {
1546 verificationTime = PR_Now();
1547 }
1548 if (CERT_VerifyCert(certdb, cert, PR_TRUE1, certusage, verificationTime,
1549 cinfo->pwfn_arg, NULL((void*)0)) != SECSuccess) {
1550 /*
1551 * XXX Give the user an option to check the signature anyway?
1552 * If we want to do this, need to give a way to leave and display
1553 * some dialog and get the answer and come back through (or do
1554 * the rest of what we do below elsewhere, maybe by putting it
1555 * in a function that we call below and could call from a dialog
1556 * finish handler).
1557 */
1558 goto savecert;
1559 }
1560
1561 publickey = CERT_ExtractPublicKey(cert);
1562 if (publickey == NULL((void*)0))
1563 goto done;
1564
1565 /*
1566 * XXX No! If digests is empty, see if we can create it now by
1567 * digesting the contents. This is necessary if we want to allow
1568 * somebody to do a simple decode (without filtering, etc.) and
1569 * then later call us here to do the verification.
1570 * OR, we can just specify that the interface to this routine
1571 * *requires* that the digest(s) be done before calling and either
1572 * stashed in the struct itself or passed in explicitly (as would
1573 * be done for detached contents).
1574 */
1575 if (digests == NULL((void*)0) && (detached_digest == NULL((void*)0) || detached_digest->data == NULL((void*)0)))
1576 goto done;
1577
1578 /*
1579 * Find and confirm digest algorithm.
1580 */
1581 digestTag = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(signerinfo->digestAlg.algorithm));
1582
1583 /* make sure we understand the digest type first */
1584 found_type = HASH_GetHashTypeByOidTagHASH_GetHashTypeByOidTag_Util(digestTag);
1585 if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) {
1586 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1587 goto done;
1588 }
1589
1590 if (detached_digest != NULL((void*)0)) {
1591 unsigned int hashLen = HASH_ResultLen(found_type);
1592
1593 if (digest_type != found_type ||
1594 detached_digest->len != hashLen) {
1595 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1596 goto done;
1597 }
1598 digest = detached_digest;
1599 } else {
1600 PORT_Assert(digestalgs != NULL && digestalgs[0] != NULL)((digestalgs != ((void*)0) && digestalgs[0] != ((void
*)0)) ? ((void)0) : PR_Assert("digestalgs != NULL && digestalgs[0] != NULL"
, "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 1600
))
;
1601 if (digestalgs == NULL((void*)0) || digestalgs[0] == NULL((void*)0)) {
1602 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1603 goto done;
1604 }
1605
1606 /*
1607 * pick digest matching signerinfo->digestAlg from digests
1608 */
1609 for (i = 0; digestalgs[i] != NULL((void*)0); i++) {
1610 if (SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(digestalgs[i]->algorithm)) == digestTag)
1611 break;
1612 }
1613 if (digestalgs[i] == NULL((void*)0)) {
1614 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1615 goto done;
1616 }
1617
1618 digest = digests[i];
1619 if (digest == NULL((void*)0)) {
1620 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1621 goto done;
1622 }
1623 }
1624
1625 encTag = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(signerinfo->digestEncAlg.algorithm));
1626 if (encTag == SEC_OID_UNKNOWN) {
1627 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1628 goto done;
1629 }
1630
1631 if (signerinfo->authAttr != NULL((void*)0)) {
1632 SEC_PKCS7Attribute *attr;
1633 SECItem *value;
1634 SECItem encoded_attrs;
1635
1636 /*
1637 * We have a sigkey only for signedAndEnvelopedData, which is
1638 * not supposed to have any authenticated attributes.
1639 */
1640 if (sigkey != NULL((void*)0)) {
1641 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1642 goto done;
1643 }
1644
1645 /*
1646 * PKCS #7 says that if there are any authenticated attributes,
1647 * then there must be one for content type which matches the
1648 * content type of the content being signed, and there must
1649 * be one for message digest which matches our message digest.
1650 * So check these things first.
1651 * XXX Might be nice to have a compare-attribute-value function
1652 * which could collapse the following nicely.
1653 */
1654 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1655 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE1);
1656 value = sec_PKCS7AttributeValue(attr);
1657 if (value == NULL((void*)0) || value->len != content_type->len) {
1658 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1659 goto done;
1660 }
1661 if (PORT_Memcmpmemcmp(value->data, content_type->data, value->len) != 0) {
1662 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1663 goto done;
1664 }
1665
1666 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1667 SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE1);
1668 value = sec_PKCS7AttributeValue(attr);
1669 if (value == NULL((void*)0) || value->len != digest->len) {
1670 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1671 goto done;
1672 }
1673 if (PORT_Memcmpmemcmp(value->data, digest->data, value->len) != 0) {
1674 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1675 goto done;
1676 }
1677
1678 /*
1679 * Okay, we met the constraints of the basic attributes.
1680 * Now check the signature, which is based on a digest of
1681 * the DER-encoded authenticated attributes. So, first we
1682 * encode and then we digest/verify.
1683 */
1684 encoded_attrs.data = NULL((void*)0);
1685 encoded_attrs.len = 0;
1686 if (sec_PKCS7EncodeAttributes(NULL((void*)0), &encoded_attrs,
1687 &(signerinfo->authAttr)) == NULL((void*)0))
1688 goto done;
1689
1690 if (encoded_attrs.data == NULL((void*)0) || encoded_attrs.len == 0) {
1691 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1692 goto done;
1693 }
1694
1695 goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data,
1696 encoded_attrs.len,
1697 publickey, &(signerinfo->encDigest),
1698 encTag, digestTag, NULL((void*)0),
1699 cinfo->pwfn_arg) == SECSuccess);
1700 PORT_FreePORT_Free_Util(encoded_attrs.data);
1701 } else {
1702 SECItem *sig;
1703 SECItem holder;
1704
1705 /*
1706 * No authenticated attributes.
1707 * The signature is based on the plain message digest.
1708 */
1709
1710 sig = &(signerinfo->encDigest);
1711 if (sig->len == 0) { /* bad signature */
1712 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1713 goto done;
1714 }
1715
1716 if (sigkey != NULL((void*)0)) {
1717 sec_PKCS7CipherObject *decryptobj;
1718 unsigned int buflen;
1719
1720 /*
1721 * For signedAndEnvelopedData, we first must decrypt the encrypted
1722 * digest with the bulk encryption key. The result is the normal
1723 * encrypted digest (aka the signature).
1724 */
1725 decryptobj = sec_PKCS7CreateDecryptObject(sigkey, bulkid);
1726 if (decryptobj == NULL((void*)0))
1727 goto done;
1728
1729 buflen = sec_PKCS7DecryptLength(decryptobj, sig->len, PR_TRUE1);
1730 PORT_Assert(buflen)((buflen) ? ((void)0) : PR_Assert("buflen", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1730))
;
1731 if (buflen == 0) { /* something is wrong */
1732 sec_PKCS7DestroyDecryptObject(decryptobj);
1733 goto done;
1734 }
1735
1736 holder.data = (unsigned char *)PORT_AllocPORT_Alloc_Util(buflen);
1737 if (holder.data == NULL((void*)0)) {
1738 sec_PKCS7DestroyDecryptObject(decryptobj);
1739 goto done;
1740 }
1741
1742 rv = sec_PKCS7Decrypt(decryptobj, holder.data, &holder.len, buflen,
1743 sig->data, sig->len, PR_TRUE1);
1744 sec_PKCS7DestroyDecryptObject(decryptobj);
1745 if (rv != SECSuccess) {
1746 goto done;
1747 }
1748
1749 sig = &holder;
1750 }
1751
1752 goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig,
1753 encTag, digestTag, cinfo->pwfn_arg) == SECSuccess);
1754
1755 if (sigkey != NULL((void*)0)) {
1756 PORT_Assert(sig == &holder)((sig == &holder) ? ((void)0) : PR_Assert("sig == &holder"
, "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 1756
))
;
1757 PORT_ZFreePORT_ZFree_Util(holder.data, holder.len);
1758 }
1759 }
1760
1761 if (!goodsig) {
1762 /*
1763 * XXX Change the generic error into our specific one, because
1764 * in that case we get a better explanation out of the Security
1765 * Advisor. This is really a bug in our error strings (the
1766 * "generic" error has a lousy/wrong message associated with it
1767 * which assumes the signature verification was done for the
1768 * purposes of checking the issuer signature on a certificate)
1769 * but this is at least an easy workaround and/or in the
1770 * Security Advisor, which specifically checks for the error
1771 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
1772 * in that case but does not similarly check for
1773 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
1774 * probably say the wrong thing in the case that it *was* the
1775 * certificate signature check that failed during the cert
1776 * verification done above. Our error handling is really a mess.
1777 */
1778 if (PORT_GetErrorPORT_GetError_Util() == SEC_ERROR_BAD_SIGNATURE)
1779 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1780 }
1781
1782savecert:
1783 /*
1784 * Only save the smime profile if we are checking an email message and
1785 * the cert has an email address in it.
1786 */
1787 if (cert->emailAddr && cert->emailAddr[0] &&
1788 ((certusage == certUsageEmailSigner) ||
1789 (certusage == certUsageEmailRecipient))) {
1790 SECItem *profile = NULL((void*)0);
1791 int save_error;
1792
1793 /*
1794 * Remember the current error set because we do not care about
1795 * anything set by the functions we are about to call.
1796 */
1797 save_error = PORT_GetErrorPORT_GetError_Util();
1798
1799 if (goodsig && (signerinfo->authAttr != NULL((void*)0))) {
1800 /*
1801 * If the signature is good, then we can save the S/MIME profile,
1802 * if we have one.
1803 */
1804 SEC_PKCS7Attribute *attr;
1805
1806 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1807 SEC_OID_PKCS9_SMIME_CAPABILITIES,
1808 PR_TRUE1);
1809 profile = sec_PKCS7AttributeValue(attr);
1810 }
1811
1812 rv = CERT_SaveSMimeProfile(cert, profile, encoded_stime);
Value stored to 'rv' is never read
1813
1814 /*
1815 * Restore the saved error in case the calls above set a new
1816 * one that we do not actually care about.
1817 */
1818 PORT_SetErrorPORT_SetError_Util(save_error);
1819
1820 /*
1821 * XXX Failure is not indicated anywhere -- the signature
1822 * verification itself is unaffected by whether or not the
1823 * profile was successfully saved.
1824 */
1825 }
1826
1827done:
1828
1829 /*
1830 * See comment above about why we do not want to destroy cert
1831 * itself here.
1832 */
1833
1834 if (certs != NULL((void*)0))
1835 CERT_DestroyCertArray(certs, certcount);
1836
1837 if (publickey != NULL((void*)0))
1838 SECKEY_DestroyPublicKey(publickey);
1839
1840 return goodsig;
1841}
1842
1843/*
1844 * SEC_PKCS7VerifySignature
1845 * Look at a PKCS7 contentInfo and check if the signature is good.
1846 * The verification checks that the signing cert is valid and trusted
1847 * for the purpose specified by "certusage".
1848 *
1849 * In addition, if "keepcerts" is true, add any new certificates found
1850 * into our local database.
1851 */
1852PRBool
1853SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
1854 SECCertUsage certusage,
1855 PRBool keepcerts)
1856{
1857 return sec_pkcs7_verify_signature(cinfo, certusage,
1858 NULL((void*)0), HASH_AlgNULL, keepcerts, NULL((void*)0));
1859}
1860
1861/*
1862 * SEC_PKCS7VerifyDetachedSignature
1863 * Look at a PKCS7 contentInfo and check if the signature matches
1864 * a passed-in digest (calculated, supposedly, from detached contents).
1865 * The verification checks that the signing cert is valid and trusted
1866 * for the purpose specified by "certusage".
1867 *
1868 * In addition, if "keepcerts" is true, add any new certificates found
1869 * into our local database.
1870 */
1871PRBool
1872SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
1873 SECCertUsage certusage,
1874 const SECItem *detached_digest,
1875 HASH_HashType digest_type,
1876 PRBool keepcerts)
1877{
1878 return sec_pkcs7_verify_signature(cinfo, certusage,
1879 detached_digest, digest_type,
1880 keepcerts, NULL((void*)0));
1881}
1882
1883/*
1884 * SEC_PKCS7VerifyDetachedSignatureAtTime
1885 * Look at a PKCS7 contentInfo and check if the signature matches
1886 * a passed-in digest (calculated, supposedly, from detached contents).
1887 * The verification checks that the signing cert is valid and trusted
1888 * for the purpose specified by "certusage" at time "atTime".
1889 *
1890 * In addition, if "keepcerts" is true, add any new certificates found
1891 * into our local database.
1892 */
1893PRBool
1894SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
1895 SECCertUsage certusage,
1896 const SECItem *detached_digest,
1897 HASH_HashType digest_type,
1898 PRBool keepcerts,
1899 PRTime atTime)
1900{
1901 return sec_pkcs7_verify_signature(cinfo, certusage,
1902 detached_digest, digest_type,
1903 keepcerts, &atTime);
1904}
1905
1906/*
1907 * Return the asked-for portion of the name of the signer of a PKCS7
1908 * signed object.
1909 *
1910 * Returns a pointer to allocated memory, which must be freed.
1911 * A NULL return value is an error.
1912 */
1913
1914#define sec_common_name1 1
1915#define sec_email_address2 2
1916
1917static char *
1918sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
1919{
1920 SECOidTag kind;
1921 SEC_PKCS7SignerInfo **signerinfos;
1922 CERTCertificate *signercert;
1923 char *container;
1924
1925 kind = SEC_PKCS7ContentType(cinfo);
1926 switch (kind) {
1927 default:
1928 case SEC_OID_PKCS7_DATA:
1929 case SEC_OID_PKCS7_DIGESTED_DATA:
1930 case SEC_OID_PKCS7_ENVELOPED_DATA:
1931 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1932 PORT_Assert(0)((0) ? ((void)0) : PR_Assert("0", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1932))
;
1933 return NULL((void*)0);
1934 case SEC_OID_PKCS7_SIGNED_DATA: {
1935 SEC_PKCS7SignedData *sdp;
1936
1937 sdp = cinfo->content.signedData;
1938 signerinfos = sdp->signerInfos;
1939 } break;
1940 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
1941 SEC_PKCS7SignedAndEnvelopedData *saedp;
1942
1943 saedp = cinfo->content.signedAndEnvelopedData;
1944 signerinfos = saedp->signerInfos;
1945 } break;
1946 }
1947
1948 if (signerinfos == NULL((void*)0) || signerinfos[0] == NULL((void*)0))
1949 return NULL((void*)0);
1950
1951 signercert = signerinfos[0]->cert;
1952
1953 /*
1954 * No cert there; see if we can find one by calling verify ourselves.
1955 */
1956 if (signercert == NULL((void*)0)) {
1957 /*
1958 * The cert usage does not matter in this case, because we do not
1959 * actually care about the verification itself, but we have to pick
1960 * some valid usage to pass in.
1961 */
1962 (void)sec_pkcs7_verify_signature(cinfo, certUsageEmailSigner,
1963 NULL((void*)0), HASH_AlgNULL, PR_FALSE0, NULL((void*)0));
1964 signercert = signerinfos[0]->cert;
1965 if (signercert == NULL((void*)0))
1966 return NULL((void*)0);
1967 }
1968
1969 switch (selector) {
1970 case sec_common_name1:
1971 container = CERT_GetCommonName(&signercert->subject);
1972 break;
1973 case sec_email_address2:
1974 if (signercert->emailAddr && signercert->emailAddr[0]) {
1975 container = PORT_StrdupPORT_Strdup_Util(signercert->emailAddr);
1976 } else {
1977 container = NULL((void*)0);
1978 }
1979 break;
1980 default:
1981 PORT_Assert(0)((0) ? ((void)0) : PR_Assert("0", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1981))
;
1982 container = NULL((void*)0);
1983 break;
1984 }
1985
1986 return container;
1987}
1988
1989char *
1990SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
1991{
1992 return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name1);
1993}
1994
1995char *
1996SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
1997{
1998 return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address2);
1999}
2000
2001/*
2002 * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
2003 */
2004SECItem *
2005SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
2006{
2007 SEC_PKCS7SignerInfo **signerinfos;
2008 SEC_PKCS7Attribute *attr;
2009
2010 if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
2011 return NULL((void*)0);
2012
2013 signerinfos = cinfo->content.signedData->signerInfos;
2014
2015 /*
2016 * No signature, or more than one, means no deal.
2017 */
2018 if (signerinfos == NULL((void*)0) || signerinfos[0] == NULL((void*)0) || signerinfos[1] != NULL((void*)0))
2019 return NULL((void*)0);
2020
2021 attr = sec_PKCS7FindAttribute(signerinfos[0]->authAttr,
2022 SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE1);
2023 return sec_PKCS7AttributeValue(attr);
2024}