Bug Summary

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