Bug Summary

File:root/firefox-clang/security/nss/lib/pkcs7/p7decode.c
Warning:line 1772, 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-09-01-224014-2642839-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
1065/*
1066 * Do the next chunk of PKCS7 decoding. If there is a problem, set
1067 * an error and return a failure status. Note that in the case of
1068 * an error, this routine is still prepared to be called again and
1069 * again in case that is the easiest route for our caller to take.
1070 * We simply detect it and do not do anything except keep setting
1071 * that error in case our caller has not noticed it yet...
1072 */
1073SECStatus
1074SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
1075 const char *buf, unsigned long len)
1076{
1077 if (!p7dcx) {
1078 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1079 return SECFailure;
1080 }
1081
1082 if (p7dcx->cinfo != NULL((void*)0) && p7dcx->dcx != NULL((void*)0)) {
1083 PORT_Assert(p7dcx->error == 0)((p7dcx->error == 0) ? ((void)0) : PR_Assert("p7dcx->error == 0"
, "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 1083
))
;
1084 if (p7dcx->error == 0) {
1085 if (SEC_ASN1DecoderUpdateSEC_ASN1DecoderUpdate_Util(p7dcx->dcx, buf, len) != SECSuccess) {
1086 p7dcx->error = PORT_GetErrorPORT_GetError_Util();
1087 PORT_Assert(p7dcx->error)((p7dcx->error) ? ((void)0) : PR_Assert("p7dcx->error",
"/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 1087
))
;
1088 if (p7dcx->error == 0)
1089 p7dcx->error = -1;
1090 }
1091 }
1092 }
1093
1094 if (p7dcx->error) {
1095 sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1096 if (p7dcx->worker.decryptobj) {
1097 sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1098 p7dcx->worker.decryptobj = NULL((void*)0);
1099 }
1100 if (p7dcx->dcx != NULL((void*)0)) {
1101 (void)SEC_ASN1DecoderFinishSEC_ASN1DecoderFinish_Util(p7dcx->dcx);
1102 p7dcx->dcx = NULL((void*)0);
1103 }
1104 if (p7dcx->cinfo != NULL((void*)0)) {
1105 SEC_PKCS7DestroyContentInfo(p7dcx->cinfo);
1106 p7dcx->cinfo = NULL((void*)0);
1107 }
1108 PORT_SetErrorPORT_SetError_Util(p7dcx->error);
1109 return SECFailure;
1110 }
1111
1112 return SECSuccess;
1113}
1114
1115SEC_PKCS7ContentInfo *
1116SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
1117{
1118 SEC_PKCS7ContentInfo *cinfo;
1119
1120 sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1121 cinfo = p7dcx->cinfo;
1122 if (p7dcx->dcx != NULL((void*)0)) {
1123 if (SEC_ASN1DecoderFinishSEC_ASN1DecoderFinish_Util(p7dcx->dcx) != SECSuccess) {
1124 SEC_PKCS7DestroyContentInfo(cinfo);
1125 cinfo = NULL((void*)0);
1126 }
1127 }
1128 /* free any NSS data structures */
1129 if (p7dcx->worker.decryptobj) {
1130 sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1131 p7dcx->worker.decryptobj = NULL((void*)0);
1132 }
1133
1134 PORT_FreeArenaPORT_FreeArena_Util(p7dcx->tmp_poolp, PR_FALSE0);
1135 PORT_FreePORT_Free_Util(p7dcx);
1136 return cinfo;
1137}
1138
1139SEC_PKCS7ContentInfo *
1140SEC_PKCS7DecodeItem(SECItem *p7item,
1141 SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
1142 SECKEYGetPasswordKey pwfn, void *pwfn_arg,
1143 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,
1144 void *decrypt_key_cb_arg,
1145 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
1146{
1147 SEC_PKCS7DecoderContext *p7dcx;
1148
1149 p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb,
1150 decrypt_key_cb_arg, decrypt_allowed_cb);
1151 if (!p7dcx) {
1152 /* error code is set */
1153 return NULL((void*)0);
1154 }
1155 (void)SEC_PKCS7DecoderUpdate(p7dcx, (char *)p7item->data, p7item->len);
1156 return SEC_PKCS7DecoderFinish(p7dcx);
1157}
1158
1159/*
1160 * Abort the ASN.1 stream. Used by pkcs 12
1161 */
1162void
1163SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error)
1164{
1165 PORT_Assert(p7dcx)((p7dcx) ? ((void)0) : PR_Assert("p7dcx", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1165))
;
1166 if (!p7dcx) {
1167 return;
1168 }
1169
1170 /* ensure any streaming helpers are torn down */
1171 sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1172 if (p7dcx->worker.decryptobj) {
1173 sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1174 p7dcx->worker.decryptobj = NULL((void*)0);
1175 }
1176
1177 SEC_ASN1DecoderAbortSEC_ASN1DecoderAbort_Util(p7dcx->dcx, error);
1178}
1179
1180/*
1181 * If the thing contains any certs or crls return true; false otherwise.
1182 */
1183PRBool
1184SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo)
1185{
1186 SECOidTag kind;
1187 SECItem **certs;
1188 CERTSignedCrl **crls;
1189
1190 kind = SEC_PKCS7ContentType(cinfo);
1191 switch (kind) {
1192 default:
1193 case SEC_OID_PKCS7_DATA:
1194 case SEC_OID_PKCS7_DIGESTED_DATA:
1195 case SEC_OID_PKCS7_ENVELOPED_DATA:
1196 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1197 return PR_FALSE0;
1198 case SEC_OID_PKCS7_SIGNED_DATA:
1199 certs = cinfo->content.signedData->rawCerts;
1200 crls = cinfo->content.signedData->crls;
1201 break;
1202 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1203 certs = cinfo->content.signedAndEnvelopedData->rawCerts;
1204 crls = cinfo->content.signedAndEnvelopedData->crls;
1205 break;
1206 }
1207
1208 /*
1209 * I know this could be collapsed, but I was in a mood to be explicit.
1210 */
1211 if (certs != NULL((void*)0) && certs[0] != NULL((void*)0))
1212 return PR_TRUE1;
1213 else if (crls != NULL((void*)0) && crls[0] != NULL((void*)0))
1214 return PR_TRUE1;
1215 else
1216 return PR_FALSE0;
1217}
1218
1219/* return the content length...could use GetContent, however we
1220 * need the encrypted content length
1221 */
1222PRBool
1223SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen)
1224{
1225 SECItem *item = NULL((void*)0);
1226
1227 if (cinfo == NULL((void*)0)) {
1228 return PR_TRUE1;
1229 }
1230
1231 switch (SEC_PKCS7ContentType(cinfo)) {
1232 case SEC_OID_PKCS7_DATA:
1233 item = cinfo->content.data;
1234 break;
1235 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1236 item = &cinfo->content.encryptedData->encContentInfo.encContent;
1237 break;
1238 default:
1239 /* add other types */
1240 return PR_FALSE0;
1241 }
1242
1243 if (!item) {
1244 return PR_TRUE1;
1245 } else if (item->len <= minLen) {
1246 return PR_TRUE1;
1247 }
1248
1249 return PR_FALSE0;
1250}
1251
1252PRBool
1253SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo)
1254{
1255 SECOidTag kind;
1256
1257 kind = SEC_PKCS7ContentType(cinfo);
1258 switch (kind) {
1259 default:
1260 case SEC_OID_PKCS7_DATA:
1261 case SEC_OID_PKCS7_DIGESTED_DATA:
1262 case SEC_OID_PKCS7_SIGNED_DATA:
1263 return PR_FALSE0;
1264 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1265 case SEC_OID_PKCS7_ENVELOPED_DATA:
1266 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1267 return PR_TRUE1;
1268 }
1269}
1270
1271/*
1272 * If the PKCS7 content has a signature (not just *could* have a signature)
1273 * return true; false otherwise. This can/should be called before calling
1274 * VerifySignature, which will always indicate failure if no signature is
1275 * present, but that does not mean there even was a signature!
1276 * Note that the content itself can be empty (detached content was sent
1277 * another way); it is the presence of the signature that matters.
1278 */
1279PRBool
1280SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo)
1281{
1282 SECOidTag kind;
1283 SEC_PKCS7SignerInfo **signerinfos;
1284
1285 kind = SEC_PKCS7ContentType(cinfo);
1286 switch (kind) {
1287 default:
1288 case SEC_OID_PKCS7_DATA:
1289 case SEC_OID_PKCS7_DIGESTED_DATA:
1290 case SEC_OID_PKCS7_ENVELOPED_DATA:
1291 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1292 return PR_FALSE0;
1293 case SEC_OID_PKCS7_SIGNED_DATA:
1294 signerinfos = cinfo->content.signedData->signerInfos;
1295 break;
1296 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1297 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
1298 break;
1299 }
1300
1301 /*
1302 * I know this could be collapsed; but I kind of think it will get
1303 * more complicated before I am finished, so...
1304 */
1305 if (signerinfos != NULL((void*)0) && signerinfos[0] != NULL((void*)0))
1306 return PR_TRUE1;
1307 else
1308 return PR_FALSE0;
1309}
1310
1311/*
1312 * sec_pkcs7_verify_signature
1313 *
1314 * Look at a PKCS7 contentInfo and check if the signature is good.
1315 * The digest was either calculated earlier (and is stored in the
1316 * contentInfo itself) or is passed in via "detached_digest".
1317 *
1318 * The verification checks that the signing cert is valid and trusted
1319 * for the purpose specified by "certusage" at
1320 * - "*atTime" if "atTime" is not null, or
1321 * - the signing time if the signing time is available in "cinfo", or
1322 * - the current time (as returned by PR_Now).
1323 *
1324 * In addition, if "keepcerts" is true, add any new certificates found
1325 * into our local database.
1326 *
1327 * XXX Each place which returns PR_FALSE should be sure to have a good
1328 * error set for inspection by the caller. Alternatively, we could create
1329 * an enumeration of success and each type of failure and return that
1330 * instead of a boolean. For now, the default in a bad situation is to
1331 * set the error to SEC_ERROR_PKCS7_BAD_SIGNATURE. But this should be
1332 * reviewed; better (more specific) errors should be possible (to distinguish
1333 * a signature failure from a badly-formed pkcs7 signedData, for example).
1334 * Some of the errors should probably just be SEC_ERROR_BAD_SIGNATURE,
1335 * but that has a less helpful error string associated with it right now;
1336 * if/when that changes, review and change these as needed.
1337 *
1338 * XXX This is broken wrt signedAndEnvelopedData. In that case, the
1339 * message digest is doubly encrypted -- first encrypted with the signer
1340 * private key but then again encrypted with the bulk encryption key used
1341 * to encrypt the content. So before we can pass the digest to VerifyDigest,
1342 * we need to decrypt it with the bulk encryption key. Also, in this case,
1343 * there should be NO authenticatedAttributes (signerinfo->authAttr should
1344 * be NULL).
1345 */
1346static PRBool
1347sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo,
1348 SECCertUsage certusage,
1349 const SECItem *detached_digest,
1350 HASH_HashType digest_type,
1351 PRBool keepcerts,
1352 const PRTime *atTime)
1353{
1354 SECAlgorithmID **digestalgs, *bulkid;
1355 const SECItem *digest;
1356 SECItem **digests;
1357 SECItem **rawcerts;
1358 SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
1359 CERTCertificate *cert, **certs;
1360 PRBool goodsig;
1361 CERTCertDBHandle *certdb, *defaultdb;
1362 SECOidTag encTag, digestTag;
1363 HASH_HashType found_type;
1364 int i, certcount;
1365 SECKEYPublicKey *publickey;
1366 SECItem *content_type;
1367 PK11SymKey *sigkey;
1368 SECItem *encoded_stime;
1369 PRTime stime;
1370 PRTime verificationTime;
1371 SECStatus rv;
1372
1373 /*
1374 * Everything needed in order to "goto done" safely.
1375 */
1376 goodsig = PR_FALSE0;
1377 certcount = 0;
1378 cert = NULL((void*)0);
1379 certs = NULL((void*)0);
1380 certdb = NULL((void*)0);
1381 defaultdb = CERT_GetDefaultCertDB();
1382 publickey = NULL((void*)0);
1383
1384 if (!SEC_PKCS7ContentIsSigned(cinfo)) {
1385 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1386 goto done;
1387 }
1388
1389 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"
, 1389))
;
1390
1391 switch (cinfo->contentTypeTag->offset) {
1392 default:
1393 case SEC_OID_PKCS7_DATA:
1394 case SEC_OID_PKCS7_DIGESTED_DATA:
1395 case SEC_OID_PKCS7_ENVELOPED_DATA:
1396 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1397 /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */
1398 PORT_Assert(0)((0) ? ((void)0) : PR_Assert("0", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1398))
;
1399 case SEC_OID_PKCS7_SIGNED_DATA: {
1400 SEC_PKCS7SignedData *sdp;
1401
1402 sdp = cinfo->content.signedData;
1403 digestalgs = sdp->digestAlgorithms;
1404 digests = sdp->digests;
1405 rawcerts = sdp->rawCerts;
1406 signerinfos = sdp->signerInfos;
1407 content_type = &(sdp->contentInfo.contentType);
1408 sigkey = NULL((void*)0);
1409 bulkid = NULL((void*)0);
1410 } break;
1411 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
1412 SEC_PKCS7SignedAndEnvelopedData *saedp;
1413
1414 saedp = cinfo->content.signedAndEnvelopedData;
1415 digestalgs = saedp->digestAlgorithms;
1416 digests = saedp->digests;
1417 rawcerts = saedp->rawCerts;
1418 signerinfos = saedp->signerInfos;
1419 content_type = &(saedp->encContentInfo.contentType);
1420 sigkey = saedp->sigKey;
1421 bulkid = &(saedp->encContentInfo.contentEncAlg);
1422 } break;
1423 }
1424
1425 if ((signerinfos == NULL((void*)0)) || (signerinfos[0] == NULL((void*)0))) {
1426 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1427 goto done;
1428 }
1429
1430 /*
1431 * XXX Need to handle multiple signatures; checking them is easy,
1432 * but what should be the semantics here (like, return value)?
1433 */
1434 if (signerinfos[1] != NULL((void*)0)) {
1435 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1436 goto done;
1437 }
1438
1439 signerinfo = signerinfos[0];
1440
1441 /*
1442 * XXX I would like to just pass the issuerAndSN, along with the rawcerts
1443 * and crls, to some function that did all of this certificate stuff
1444 * (open/close the database if necessary, verifying the certs, etc.)
1445 * and gave me back a cert pointer if all was good.
1446 */
1447 certdb = defaultdb;
1448 if (certdb == NULL((void*)0)) {
1449 goto done;
1450 }
1451
1452 certcount = 0;
1453 if (rawcerts != NULL((void*)0)) {
1454 for (; rawcerts[certcount] != NULL((void*)0); certcount++) {
1455 /* just counting */
1456 }
1457 }
1458
1459 /*
1460 * Note that the result of this is that each cert in "certs"
1461 * needs to be destroyed.
1462 */
1463 rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs,
1464 keepcerts, PR_FALSE0, NULL((void*)0));
1465 if (rv != SECSuccess) {
1466 goto done;
1467 }
1468
1469 /*
1470 * This cert will also need to be freed, but since we save it
1471 * in signerinfo for later, we do not want to destroy it when
1472 * we leave this function -- we let the clean-up of the entire
1473 * cinfo structure later do the destroy of this cert.
1474 */
1475 cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN);
1476 if (cert == NULL((void*)0)) {
1477 goto done;
1478 }
1479
1480 signerinfo->cert = cert;
1481
1482 /*
1483 * Get and convert the signing time; if available, it will be used
1484 * both on the cert verification and for importing the sender
1485 * email profile.
1486 */
1487 encoded_stime = SEC_PKCS7GetSigningTime(cinfo);
1488 if (encoded_stime != NULL((void*)0)) {
1489 if (DER_DecodeTimeChoiceDER_DecodeTimeChoice_Util(&stime, encoded_stime) != SECSuccess)
1490 encoded_stime = NULL((void*)0); /* conversion failed, so pretend none */
1491 }
1492
1493 /*
1494 * XXX This uses the signing time, if available. Additionally, we
1495 * might want to, if there is no signing time, get the message time
1496 * from the mail header itself, and use that. That would require
1497 * a change to our interface though, and for S/MIME callers to pass
1498 * in a time (and for non-S/MIME callers to pass in nothing, or
1499 * maybe make them pass in the current time, always?).
1500 */
1501 if (atTime) {
1502 verificationTime = *atTime;
1503 } else if (encoded_stime != NULL((void*)0)) {
1504 verificationTime = stime;
1505 } else {
1506 verificationTime = PR_Now();
1507 }
1508 if (CERT_VerifyCert(certdb, cert, PR_TRUE1, certusage, verificationTime,
1509 cinfo->pwfn_arg, NULL((void*)0)) != SECSuccess) {
1510 /*
1511 * XXX Give the user an option to check the signature anyway?
1512 * If we want to do this, need to give a way to leave and display
1513 * some dialog and get the answer and come back through (or do
1514 * the rest of what we do below elsewhere, maybe by putting it
1515 * in a function that we call below and could call from a dialog
1516 * finish handler).
1517 */
1518 goto savecert;
1519 }
1520
1521 publickey = CERT_ExtractPublicKey(cert);
1522 if (publickey == NULL((void*)0))
1523 goto done;
1524
1525 /*
1526 * XXX No! If digests is empty, see if we can create it now by
1527 * digesting the contents. This is necessary if we want to allow
1528 * somebody to do a simple decode (without filtering, etc.) and
1529 * then later call us here to do the verification.
1530 * OR, we can just specify that the interface to this routine
1531 * *requires* that the digest(s) be done before calling and either
1532 * stashed in the struct itself or passed in explicitly (as would
1533 * be done for detached contents).
1534 */
1535 if (digests == NULL((void*)0) && (detached_digest == NULL((void*)0) || detached_digest->data == NULL((void*)0)))
1536 goto done;
1537
1538 /*
1539 * Find and confirm digest algorithm.
1540 */
1541 digestTag = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(signerinfo->digestAlg.algorithm));
1542
1543 /* make sure we understand the digest type first */
1544 found_type = HASH_GetHashTypeByOidTagHASH_GetHashTypeByOidTag_Util(digestTag);
1545 if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) {
1546 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1547 goto done;
1548 }
1549
1550 if (detached_digest != NULL((void*)0)) {
1551 unsigned int hashLen = HASH_ResultLen(found_type);
1552
1553 if (digest_type != found_type ||
1554 detached_digest->len != hashLen) {
1555 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1556 goto done;
1557 }
1558 digest = detached_digest;
1559 } else {
1560 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", 1560
))
;
1561 if (digestalgs == NULL((void*)0) || digestalgs[0] == NULL((void*)0)) {
1562 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1563 goto done;
1564 }
1565
1566 /*
1567 * pick digest matching signerinfo->digestAlg from digests
1568 */
1569 for (i = 0; digestalgs[i] != NULL((void*)0); i++) {
1570 if (SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(digestalgs[i]->algorithm)) == digestTag)
1571 break;
1572 }
1573 if (digestalgs[i] == NULL((void*)0)) {
1574 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1575 goto done;
1576 }
1577
1578 digest = digests[i];
1579 if (digest == NULL((void*)0)) {
1580 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1581 goto done;
1582 }
1583 }
1584
1585 encTag = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&(signerinfo->digestEncAlg.algorithm));
1586 if (encTag == SEC_OID_UNKNOWN) {
1587 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1588 goto done;
1589 }
1590
1591 if (signerinfo->authAttr != NULL((void*)0)) {
1592 SEC_PKCS7Attribute *attr;
1593 SECItem *value;
1594 SECItem encoded_attrs;
1595
1596 /*
1597 * We have a sigkey only for signedAndEnvelopedData, which is
1598 * not supposed to have any authenticated attributes.
1599 */
1600 if (sigkey != NULL((void*)0)) {
1601 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1602 goto done;
1603 }
1604
1605 /*
1606 * PKCS #7 says that if there are any authenticated attributes,
1607 * then there must be one for content type which matches the
1608 * content type of the content being signed, and there must
1609 * be one for message digest which matches our message digest.
1610 * So check these things first.
1611 * XXX Might be nice to have a compare-attribute-value function
1612 * which could collapse the following nicely.
1613 */
1614 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1615 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE1);
1616 value = sec_PKCS7AttributeValue(attr);
1617 if (value == NULL((void*)0) || value->len != content_type->len) {
1618 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1619 goto done;
1620 }
1621 if (PORT_Memcmpmemcmp(value->data, content_type->data, value->len) != 0) {
1622 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1623 goto done;
1624 }
1625
1626 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1627 SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE1);
1628 value = sec_PKCS7AttributeValue(attr);
1629 if (value == NULL((void*)0) || value->len != digest->len) {
1630 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1631 goto done;
1632 }
1633 if (PORT_Memcmpmemcmp(value->data, digest->data, value->len) != 0) {
1634 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1635 goto done;
1636 }
1637
1638 /*
1639 * Okay, we met the constraints of the basic attributes.
1640 * Now check the signature, which is based on a digest of
1641 * the DER-encoded authenticated attributes. So, first we
1642 * encode and then we digest/verify.
1643 */
1644 encoded_attrs.data = NULL((void*)0);
1645 encoded_attrs.len = 0;
1646 if (sec_PKCS7EncodeAttributes(NULL((void*)0), &encoded_attrs,
1647 &(signerinfo->authAttr)) == NULL((void*)0))
1648 goto done;
1649
1650 if (encoded_attrs.data == NULL((void*)0) || encoded_attrs.len == 0) {
1651 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1652 goto done;
1653 }
1654
1655 goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data,
1656 encoded_attrs.len,
1657 publickey, &(signerinfo->encDigest),
1658 encTag, digestTag, NULL((void*)0),
1659 cinfo->pwfn_arg) == SECSuccess);
1660 PORT_FreePORT_Free_Util(encoded_attrs.data);
1661 } else {
1662 SECItem *sig;
1663 SECItem holder;
1664
1665 /*
1666 * No authenticated attributes.
1667 * The signature is based on the plain message digest.
1668 */
1669
1670 sig = &(signerinfo->encDigest);
1671 if (sig->len == 0) { /* bad signature */
1672 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1673 goto done;
1674 }
1675
1676 if (sigkey != NULL((void*)0)) {
1677 sec_PKCS7CipherObject *decryptobj;
1678 unsigned int buflen;
1679
1680 /*
1681 * For signedAndEnvelopedData, we first must decrypt the encrypted
1682 * digest with the bulk encryption key. The result is the normal
1683 * encrypted digest (aka the signature).
1684 */
1685 decryptobj = sec_PKCS7CreateDecryptObject(sigkey, bulkid);
1686 if (decryptobj == NULL((void*)0))
1687 goto done;
1688
1689 buflen = sec_PKCS7DecryptLength(decryptobj, sig->len, PR_TRUE1);
1690 PORT_Assert(buflen)((buflen) ? ((void)0) : PR_Assert("buflen", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1690))
;
1691 if (buflen == 0) { /* something is wrong */
1692 sec_PKCS7DestroyDecryptObject(decryptobj);
1693 goto done;
1694 }
1695
1696 holder.data = (unsigned char *)PORT_AllocPORT_Alloc_Util(buflen);
1697 if (holder.data == NULL((void*)0)) {
1698 sec_PKCS7DestroyDecryptObject(decryptobj);
1699 goto done;
1700 }
1701
1702 rv = sec_PKCS7Decrypt(decryptobj, holder.data, &holder.len, buflen,
1703 sig->data, sig->len, PR_TRUE1);
1704 sec_PKCS7DestroyDecryptObject(decryptobj);
1705 if (rv != SECSuccess) {
1706 goto done;
1707 }
1708
1709 sig = &holder;
1710 }
1711
1712 goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig,
1713 encTag, digestTag, cinfo->pwfn_arg) == SECSuccess);
1714
1715 if (sigkey != NULL((void*)0)) {
1716 PORT_Assert(sig == &holder)((sig == &holder) ? ((void)0) : PR_Assert("sig == &holder"
, "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c", 1716
))
;
1717 PORT_ZFreePORT_ZFree_Util(holder.data, holder.len);
1718 }
1719 }
1720
1721 if (!goodsig) {
1722 /*
1723 * XXX Change the generic error into our specific one, because
1724 * in that case we get a better explanation out of the Security
1725 * Advisor. This is really a bug in our error strings (the
1726 * "generic" error has a lousy/wrong message associated with it
1727 * which assumes the signature verification was done for the
1728 * purposes of checking the issuer signature on a certificate)
1729 * but this is at least an easy workaround and/or in the
1730 * Security Advisor, which specifically checks for the error
1731 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
1732 * in that case but does not similarly check for
1733 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
1734 * probably say the wrong thing in the case that it *was* the
1735 * certificate signature check that failed during the cert
1736 * verification done above. Our error handling is really a mess.
1737 */
1738 if (PORT_GetErrorPORT_GetError_Util() == SEC_ERROR_BAD_SIGNATURE)
1739 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1740 }
1741
1742savecert:
1743 /*
1744 * Only save the smime profile if we are checking an email message and
1745 * the cert has an email address in it.
1746 */
1747 if (cert->emailAddr && cert->emailAddr[0] &&
1748 ((certusage == certUsageEmailSigner) ||
1749 (certusage == certUsageEmailRecipient))) {
1750 SECItem *profile = NULL((void*)0);
1751 int save_error;
1752
1753 /*
1754 * Remember the current error set because we do not care about
1755 * anything set by the functions we are about to call.
1756 */
1757 save_error = PORT_GetErrorPORT_GetError_Util();
1758
1759 if (goodsig && (signerinfo->authAttr != NULL((void*)0))) {
1760 /*
1761 * If the signature is good, then we can save the S/MIME profile,
1762 * if we have one.
1763 */
1764 SEC_PKCS7Attribute *attr;
1765
1766 attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1767 SEC_OID_PKCS9_SMIME_CAPABILITIES,
1768 PR_TRUE1);
1769 profile = sec_PKCS7AttributeValue(attr);
1770 }
1771
1772 rv = CERT_SaveSMimeProfile(cert, profile, encoded_stime);
Value stored to 'rv' is never read
1773
1774 /*
1775 * Restore the saved error in case the calls above set a new
1776 * one that we do not actually care about.
1777 */
1778 PORT_SetErrorPORT_SetError_Util(save_error);
1779
1780 /*
1781 * XXX Failure is not indicated anywhere -- the signature
1782 * verification itself is unaffected by whether or not the
1783 * profile was successfully saved.
1784 */
1785 }
1786
1787done:
1788
1789 /*
1790 * See comment above about why we do not want to destroy cert
1791 * itself here.
1792 */
1793
1794 if (certs != NULL((void*)0))
1795 CERT_DestroyCertArray(certs, certcount);
1796
1797 if (publickey != NULL((void*)0))
1798 SECKEY_DestroyPublicKey(publickey);
1799
1800 return goodsig;
1801}
1802
1803/*
1804 * SEC_PKCS7VerifySignature
1805 * Look at a PKCS7 contentInfo and check if the signature is good.
1806 * The verification checks that the signing cert is valid and trusted
1807 * for the purpose specified by "certusage".
1808 *
1809 * In addition, if "keepcerts" is true, add any new certificates found
1810 * into our local database.
1811 */
1812PRBool
1813SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
1814 SECCertUsage certusage,
1815 PRBool keepcerts)
1816{
1817 return sec_pkcs7_verify_signature(cinfo, certusage,
1818 NULL((void*)0), HASH_AlgNULL, keepcerts, NULL((void*)0));
1819}
1820
1821/*
1822 * SEC_PKCS7VerifyDetachedSignature
1823 * Look at a PKCS7 contentInfo and check if the signature matches
1824 * a passed-in digest (calculated, supposedly, from detached contents).
1825 * The verification checks that the signing cert is valid and trusted
1826 * for the purpose specified by "certusage".
1827 *
1828 * In addition, if "keepcerts" is true, add any new certificates found
1829 * into our local database.
1830 */
1831PRBool
1832SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
1833 SECCertUsage certusage,
1834 const SECItem *detached_digest,
1835 HASH_HashType digest_type,
1836 PRBool keepcerts)
1837{
1838 return sec_pkcs7_verify_signature(cinfo, certusage,
1839 detached_digest, digest_type,
1840 keepcerts, NULL((void*)0));
1841}
1842
1843/*
1844 * SEC_PKCS7VerifyDetachedSignatureAtTime
1845 * Look at a PKCS7 contentInfo and check if the signature matches
1846 * a passed-in digest (calculated, supposedly, from detached contents).
1847 * The verification checks that the signing cert is valid and trusted
1848 * for the purpose specified by "certusage" at time "atTime".
1849 *
1850 * In addition, if "keepcerts" is true, add any new certificates found
1851 * into our local database.
1852 */
1853PRBool
1854SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
1855 SECCertUsage certusage,
1856 const SECItem *detached_digest,
1857 HASH_HashType digest_type,
1858 PRBool keepcerts,
1859 PRTime atTime)
1860{
1861 return sec_pkcs7_verify_signature(cinfo, certusage,
1862 detached_digest, digest_type,
1863 keepcerts, &atTime);
1864}
1865
1866/*
1867 * Return the asked-for portion of the name of the signer of a PKCS7
1868 * signed object.
1869 *
1870 * Returns a pointer to allocated memory, which must be freed.
1871 * A NULL return value is an error.
1872 */
1873
1874#define sec_common_name1 1
1875#define sec_email_address2 2
1876
1877static char *
1878sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
1879{
1880 SECOidTag kind;
1881 SEC_PKCS7SignerInfo **signerinfos;
1882 CERTCertificate *signercert;
1883 char *container;
1884
1885 kind = SEC_PKCS7ContentType(cinfo);
1886 switch (kind) {
1887 default:
1888 case SEC_OID_PKCS7_DATA:
1889 case SEC_OID_PKCS7_DIGESTED_DATA:
1890 case SEC_OID_PKCS7_ENVELOPED_DATA:
1891 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1892 PORT_Assert(0)((0) ? ((void)0) : PR_Assert("0", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1892))
;
1893 return NULL((void*)0);
1894 case SEC_OID_PKCS7_SIGNED_DATA: {
1895 SEC_PKCS7SignedData *sdp;
1896
1897 sdp = cinfo->content.signedData;
1898 signerinfos = sdp->signerInfos;
1899 } break;
1900 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
1901 SEC_PKCS7SignedAndEnvelopedData *saedp;
1902
1903 saedp = cinfo->content.signedAndEnvelopedData;
1904 signerinfos = saedp->signerInfos;
1905 } break;
1906 }
1907
1908 if (signerinfos == NULL((void*)0) || signerinfos[0] == NULL((void*)0))
1909 return NULL((void*)0);
1910
1911 signercert = signerinfos[0]->cert;
1912
1913 /*
1914 * No cert there; see if we can find one by calling verify ourselves.
1915 */
1916 if (signercert == NULL((void*)0)) {
1917 /*
1918 * The cert usage does not matter in this case, because we do not
1919 * actually care about the verification itself, but we have to pick
1920 * some valid usage to pass in.
1921 */
1922 (void)sec_pkcs7_verify_signature(cinfo, certUsageEmailSigner,
1923 NULL((void*)0), HASH_AlgNULL, PR_FALSE0, NULL((void*)0));
1924 signercert = signerinfos[0]->cert;
1925 if (signercert == NULL((void*)0))
1926 return NULL((void*)0);
1927 }
1928
1929 switch (selector) {
1930 case sec_common_name1:
1931 container = CERT_GetCommonName(&signercert->subject);
1932 break;
1933 case sec_email_address2:
1934 if (signercert->emailAddr && signercert->emailAddr[0]) {
1935 container = PORT_StrdupPORT_Strdup_Util(signercert->emailAddr);
1936 } else {
1937 container = NULL((void*)0);
1938 }
1939 break;
1940 default:
1941 PORT_Assert(0)((0) ? ((void)0) : PR_Assert("0", "/root/firefox-clang/security/nss/lib/pkcs7/p7decode.c"
, 1941))
;
1942 container = NULL((void*)0);
1943 break;
1944 }
1945
1946 return container;
1947}
1948
1949char *
1950SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
1951{
1952 return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name1);
1953}
1954
1955char *
1956SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
1957{
1958 return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address2);
1959}
1960
1961/*
1962 * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
1963 */
1964SECItem *
1965SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
1966{
1967 SEC_PKCS7SignerInfo **signerinfos;
1968 SEC_PKCS7Attribute *attr;
1969
1970 if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
1971 return NULL((void*)0);
1972
1973 signerinfos = cinfo->content.signedData->signerInfos;
1974
1975 /*
1976 * No signature, or more than one, means no deal.
1977 */
1978 if (signerinfos == NULL((void*)0) || signerinfos[0] == NULL((void*)0) || signerinfos[1] != NULL((void*)0))
1979 return NULL((void*)0);
1980
1981 attr = sec_PKCS7FindAttribute(signerinfos[0]->authAttr,
1982 SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE1);
1983 return sec_PKCS7AttributeValue(attr);
1984}