Coverage Report

Created: 2026-06-07 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/pkcs7/p7decode.c
Line
Count
Source
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
30
struct 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
39
struct 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
 */
62
static void
63
sec_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
438k
{
68
438k
    unsigned char *buf = NULL;
69
438k
    PRBool freeBuf = PR_FALSE;
70
438k
    SECStatus rv;
71
438k
    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
438k
    PORT_Assert((data != NULL && len) || final);
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
438k
    if (worker->decryptobj != NULL) {
91
        /* XXX the following lengths should all be longs? */
92
6.17k
        unsigned int inlen;  /* length of data being decrypted */
93
6.17k
        unsigned int outlen; /* length of decrypted data */
94
6.17k
        unsigned int buflen; /* length available for decrypted data */
95
6.17k
        SECItem *plain;
96
97
6.17k
        inlen = len;
98
6.17k
        buflen = sec_PKCS7DecryptLength(worker->decryptobj, inlen, final);
99
6.17k
        if (buflen == 0) {
100
5.78k
            if (inlen == 0) /* no input and no output */
101
5.46k
                return;
102
            /*
103
             * No output is expected, but the input data may be buffered
104
             * so we still have to call Decrypt.
105
             */
106
323
            rv = sec_PKCS7Decrypt(worker->decryptobj, NULL, NULL, 0,
107
323
                                  data, inlen, final);
108
323
            if (rv != SECSuccess) {
109
0
                p7dcx->error = PORT_GetError();
110
0
                return; /* XXX indicate error? */
111
0
            }
112
323
            return;
113
323
        }
114
115
388
        if (p7dcx->cb != NULL) {
116
388
            buf = (unsigned char *)PORT_Alloc(buflen);
117
388
            freeBuf = PR_TRUE;
118
388
            plain = NULL;
119
388
        } else {
120
0
            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
0
            plain = &(p7dcx->cinfo->content.envelopedData->encContentInfo.plainContent);
128
129
0
            oldlen = plain->len;
130
0
            if (oldlen == 0) {
131
0
                buf = (unsigned char *)PORT_ArenaAlloc(p7dcx->cinfo->poolp,
132
0
                                                       buflen);
133
0
                plain->data = buf;
134
0
            } else {
135
0
                buf = (unsigned char *)PORT_ArenaGrow(p7dcx->cinfo->poolp,
136
0
                                                      plain->data,
137
0
                                                      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
0
                plain->data = buf;
142
0
                if (buf != NULL)
143
0
                    buf += oldlen;
144
0
            }
145
0
        }
146
388
        if (buf == NULL) {
147
0
            p7dcx->error = SEC_ERROR_NO_MEMORY;
148
0
            return; /* XXX indicate error? */
149
0
        }
150
388
        rv = sec_PKCS7Decrypt(worker->decryptobj, buf, &outlen, buflen,
151
388
                              data, inlen, final);
152
388
        if (rv != SECSuccess) {
153
0
            p7dcx->error = PORT_GetError();
154
0
            goto cleanup; /* XXX indicate error? */
155
0
        }
156
388
        if (plain != NULL) {
157
0
            PORT_Assert(final || outlen == buflen);
158
0
            plain->len += outlen;
159
0
        }
160
388
        data = buf;
161
388
        len = outlen;
162
388
    }
163
164
    /*
165
     * Update the running digests.
166
     */
167
432k
    if (len) {
168
914k
        for (i = 0; i < worker->digcnt; i++) {
169
481k
            if (worker->digobjs[i]) {
170
474k
                (*worker->digobjs[i]->update)(worker->digcxs[i], data, len);
171
474k
            }
172
481k
        }
173
432k
    }
174
175
    /*
176
     * Pass back the contents bytes, and free the temporary buffer.
177
     */
178
432k
    if (p7dcx->cb != NULL) {
179
432k
        if (len)
180
432k
            (*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len);
181
432k
    }
182
183
432k
cleanup:
184
432k
    if (freeBuf && buf != NULL) {
185
388
        PORT_Free(buf);
186
388
    }
187
432k
}
188
189
static void
190
sec_pkcs7_decoder_filter(void *arg, const char *data, unsigned long len,
191
                         int depth, SEC_ASN1EncodingPart data_kind)
192
1.28M
{
193
1.28M
    SEC_PKCS7DecoderContext *p7dcx;
194
1.28M
    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
1.28M
    if (data_kind != SEC_ASN1_Contents)
204
848k
        return;
205
206
    /*
207
     * The ASN.1 decoder should not even call us with a length of 0.
208
     * Just being paranoid.
209
     */
210
432k
    PORT_Assert(len);
211
432k
    if (len == 0)
212
0
        return;
213
214
432k
    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
432k
    worker = &(p7dcx->worker);
222
223
432k
    worker->saw_contents = PR_TRUE;
224
225
432k
    sec_pkcs7_decoder_work_data(p7dcx, worker,
226
432k
                                (const unsigned char *)data, len, PR_FALSE);
227
432k
}
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
 */
236
static SECStatus
237
sec_pkcs7_decoder_start_digests(SEC_PKCS7DecoderContext *p7dcx, int depth,
238
                                SECAlgorithmID **digestalgs)
239
783
{
240
783
    int i, digcnt;
241
242
783
    p7dcx->worker.digcnt = 0;
243
244
783
    if (digestalgs == NULL)
245
0
        return SECSuccess;
246
247
    /*
248
     * Count the algorithms.
249
     */
250
783
    digcnt = 0;
251
2.36k
    while (digestalgs[digcnt] != NULL)
252
1.57k
        digcnt++;
253
254
    /*
255
     * No algorithms means no work to do.
256
     * Just act as if there were no algorithms specified.
257
     */
258
783
    if (digcnt == 0)
259
0
        return SECSuccess;
260
261
783
    p7dcx->worker.digcxs = (void **)PORT_ArenaZAlloc(p7dcx->tmp_poolp,
262
783
                                                     digcnt * sizeof(void *));
263
783
    p7dcx->worker.digobjs = (const SECHashObject **)PORT_ArenaZAlloc(p7dcx->tmp_poolp,
264
783
                                                                     digcnt * sizeof(SECHashObject *));
265
783
    if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) {
266
0
        p7dcx->error = SEC_ERROR_NO_MEMORY;
267
0
        return SECFailure;
268
0
    }
269
270
783
    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
783
    PRBool hasDigests = PR_FALSE;
277
2.36k
    for (i = 0; i < digcnt; i++) {
278
1.57k
        SECAlgorithmID *algid = digestalgs[i];
279
1.57k
        SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm));
280
1.57k
        const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
281
1.57k
        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
1.57k
        if (digobj == NULL) {
292
81
            continue;
293
81
        }
294
295
1.49k
        digcx = (*digobj->create)();
296
1.49k
        if (digcx != NULL) {
297
1.49k
            (*digobj->begin)(digcx);
298
1.49k
            p7dcx->worker.digobjs[i] = digobj;
299
1.49k
            p7dcx->worker.digcxs[i] = digcx;
300
1.49k
            hasDigests = PR_TRUE;
301
1.49k
        }
302
1.49k
    }
303
783
    p7dcx->worker.digcnt = digcnt;
304
305
783
    if (hasDigests)
306
781
        SEC_ASN1DecoderSetFilterProc(p7dcx->dcx,
307
781
                                     sec_pkcs7_decoder_filter,
308
781
                                     p7dcx,
309
781
                                     (PRBool)(p7dcx->cb != NULL));
310
783
    return SECSuccess;
311
783
}
312
313
/* destroy any active digest contexts without harvesting results */
314
static void
315
sec_pkcs7_decoder_abort_digests(struct sec_pkcs7_decoder_worker *worker)
316
464k
{
317
464k
    int i;
318
319
464k
    PORT_Assert(worker);
320
464k
    if (!worker) {
321
0
        return;
322
0
    }
323
324
464k
    if (worker->digcnt <= 0 || !worker->digcxs || !worker->digobjs) {
325
463k
        worker->digcnt = 0;
326
463k
        return;
327
463k
    }
328
329
1.99k
    for (i = 0; i < worker->digcnt; i++) {
330
1.32k
        if (worker->digcxs[i] && worker->digobjs[i]) {
331
1.27k
            (*worker->digobjs[i]->destroy)(worker->digcxs[i], PR_TRUE);
332
1.27k
        }
333
1.32k
        worker->digcxs[i] = NULL;
334
1.32k
    }
335
336
664
    worker->digcnt = 0;
337
664
}
338
339
/*
340
 * Close out all of the digest contexts, storing the results in "digestsp".
341
 */
342
static SECStatus
343
sec_pkcs7_decoder_finish_digests(SEC_PKCS7DecoderContext *p7dcx,
344
                                 PLArenaPool *poolp,
345
                                 SECItem ***digestsp)
346
119
{
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
119
    struct sec_pkcs7_decoder_worker *worker = &(p7dcx->worker);
353
354
    /*
355
     * If no digests, then we have nothing to do.
356
     */
357
119
    if (worker->digcnt == 0) {
358
0
        return SECSuccess;
359
0
    }
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
119
    SEC_ASN1DecoderClearFilterProc(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
119
    if (!worker->saw_contents) {
375
0
        sec_pkcs7_decoder_abort_digests(worker);
376
0
        return SECSuccess;
377
0
    }
378
379
119
    void *mark = PORT_ArenaMark(poolp);
380
381
    /*
382
     * Close out each digest context, saving digest away.
383
     */
384
119
    SECItem **digests =
385
119
        (SECItem **)PORT_ArenaZAlloc(poolp, (worker->digcnt + 1) * sizeof(SECItem *));
386
119
    if (digests == NULL) {
387
0
        p7dcx->error = PORT_GetError();
388
0
        sec_pkcs7_decoder_abort_digests(worker);
389
0
        PORT_ArenaRelease(poolp, mark);
390
0
        return SECFailure;
391
0
    }
392
393
369
    for (int i = 0; i < worker->digcnt; i++) {
394
250
        const SECHashObject *digobj = worker->digobjs[i];
395
250
        if (!digobj) {
396
24
            continue;
397
24
        }
398
226
        digests[i] = SECITEM_AllocItem(poolp, NULL, digobj->length);
399
226
        if (!digests[i]) {
400
0
            p7dcx->error = PORT_GetError();
401
0
            sec_pkcs7_decoder_abort_digests(worker);
402
0
            PORT_ArenaRelease(poolp, mark);
403
0
            return SECFailure;
404
0
        }
405
226
    }
406
407
369
    for (int i = 0; i < worker->digcnt; i++) {
408
250
        void *digcx = worker->digcxs[i];
409
250
        const SECHashObject *digobj = worker->digobjs[i];
410
411
250
        if (!digobj) {
412
24
            continue;
413
24
        }
414
226
        (*digobj->end)(digcx, digests[i]->data, &(digests[i]->len), digests[i]->len);
415
226
        (*digobj->destroy)(digcx, PR_TRUE);
416
226
        worker->digcxs[i] = NULL;
417
226
    }
418
119
    worker->digcnt = 0;
419
119
    *digestsp = digests;
420
421
119
    PORT_ArenaUnmark(poolp, mark);
422
119
    return SECSuccess;
423
119
}
424
425
/*
426
 * XXX Need comment explaining following helper function (which is used
427
 * by sec_pkcs7_decoder_start_decrypt).
428
 */
429
430
static PK11SymKey *
431
sec_pkcs7_decoder_get_recipient_key(SEC_PKCS7DecoderContext *p7dcx,
432
                                    SEC_PKCS7RecipientInfo **recipientinfos,
433
                                    SEC_PKCS7EncryptedContentInfo *enccinfo)
434
0
{
435
0
    SEC_PKCS7RecipientInfo *ri;
436
0
    CERTCertificate *cert = NULL;
437
0
    SECKEYPrivateKey *privkey = NULL;
438
0
    PK11SymKey *bulkkey = NULL;
439
0
    SECOidTag keyalgtag, bulkalgtag, encalgtag;
440
0
    PK11SlotInfo *slot = NULL;
441
442
0
    if (recipientinfos == NULL || recipientinfos[0] == NULL) {
443
0
        p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
444
0
        goto no_key_found;
445
0
    }
446
447
0
    cert = PK11_FindCertAndKeyByRecipientList(&slot, recipientinfos, &ri,
448
0
                                              &privkey, p7dcx->pwfn_arg);
449
0
    if (cert == NULL) {
450
0
        p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
451
0
        goto no_key_found;
452
0
    }
453
454
0
    ri->cert = cert; /* so we can find it later */
455
0
    PORT_Assert(privkey != NULL);
456
457
0
    keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
458
0
    encalgtag = SECOID_GetAlgorithmTag(&(ri->keyEncAlg));
459
0
    if (keyalgtag != encalgtag) {
460
0
        p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH;
461
0
        goto no_key_found;
462
0
    }
463
0
    bulkalgtag = SECOID_GetAlgorithmTag(&(enccinfo->contentEncAlg));
464
465
0
    switch (encalgtag) {
466
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
467
0
            bulkkey = PK11_PubUnwrapSymKey(privkey, &ri->encKey,
468
0
                                           PK11_AlgtagToMechanism(bulkalgtag),
469
0
                                           CKA_DECRYPT, 0);
470
0
            if (bulkkey == NULL) {
471
0
                p7dcx->error = PORT_GetError();
472
0
                PORT_SetError(0);
473
0
                goto no_key_found;
474
0
            }
475
0
            break;
476
0
        default:
477
0
            p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG;
478
0
            break;
479
0
    }
480
481
0
no_key_found:
482
0
    if (privkey != NULL)
483
0
        SECKEY_DestroyPrivateKey(privkey);
484
0
    if (slot != NULL)
485
0
        PK11_FreeSlot(slot);
486
487
0
    return bulkkey;
488
0
}
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
 */
504
static SECStatus
505
sec_pkcs7_decoder_start_decrypt(SEC_PKCS7DecoderContext *p7dcx, int depth,
506
                                SEC_PKCS7RecipientInfo **recipientinfos,
507
                                SEC_PKCS7EncryptedContentInfo *enccinfo,
508
                                PK11SymKey **copy_key_for_signature)
509
18.6k
{
510
18.6k
    PK11SymKey *bulkkey = NULL;
511
18.6k
    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
18.6k
    if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) {
523
18.6k
        if (p7dcx->dkcb != NULL) {
524
18.6k
            bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg,
525
18.6k
                                     &(enccinfo->contentEncAlg));
526
18.6k
        }
527
18.6k
        enccinfo->keysize = 0;
528
18.6k
    } else {
529
0
        bulkkey = sec_pkcs7_decoder_get_recipient_key(p7dcx, recipientinfos,
530
0
                                                      enccinfo);
531
0
        if (bulkkey == NULL)
532
0
            goto no_decryption;
533
0
        enccinfo->keysize = PK11_GetKeyStrength(bulkkey,
534
0
                                                &(enccinfo->contentEncAlg));
535
0
    }
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
18.6k
    if (bulkkey == NULL) {
542
13.0k
        goto no_decryption;
543
13.0k
    }
544
545
    /*
546
     * We want to make sure decryption is allowed.  This is done via
547
     * a callback specified in SEC_PKCS7DecoderStart().
548
     */
549
5.59k
    if (p7dcx->decrypt_allowed_cb) {
550
5.59k
        if ((*p7dcx->decrypt_allowed_cb)(&(enccinfo->contentEncAlg),
551
5.59k
                                         bulkkey) == PR_FALSE) {
552
18
            p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
553
18
            goto no_decryption;
554
18
        }
555
5.59k
    } else {
556
0
        p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
557
0
        goto no_decryption;
558
0
    }
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
5.58k
    if (copy_key_for_signature != NULL)
567
0
        *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
5.58k
    decryptobj = sec_PKCS7CreateDecryptObject(bulkkey,
575
5.58k
                                              &(enccinfo->contentEncAlg));
576
577
    /*
578
     * We are done with (this) bulkkey now.
579
     */
580
5.58k
    PK11_FreeSymKey(bulkkey);
581
5.58k
    bulkkey = NULL;
582
583
5.58k
    if (decryptobj == NULL) {
584
58
        p7dcx->error = PORT_GetError();
585
58
        PORT_SetError(0);
586
58
        goto no_decryption;
587
58
    }
588
589
5.52k
    SEC_ASN1DecoderSetFilterProc(p7dcx->dcx,
590
5.52k
                                 sec_pkcs7_decoder_filter,
591
5.52k
                                 p7dcx,
592
5.52k
                                 (PRBool)(p7dcx->cb != NULL));
593
594
5.52k
    p7dcx->worker.depth = depth;
595
5.52k
    p7dcx->worker.decryptobj = decryptobj;
596
597
5.52k
    return SECSuccess;
598
599
13.1k
no_decryption:
600
13.1k
    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
13.1k
    if (p7dcx->cb != NULL)
613
13.1k
        return SECFailure;
614
0
    else
615
0
        return SECSuccess; /* Let the decoding continue. */
616
13.1k
}
617
618
static SECStatus
619
sec_pkcs7_decoder_finish_decrypt(SEC_PKCS7DecoderContext *p7dcx,
620
                                 PLArenaPool *poolp,
621
                                 SEC_PKCS7EncryptedContentInfo *enccinfo)
622
5.46k
{
623
5.46k
    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
5.46k
    worker = &(p7dcx->worker);
631
632
    /*
633
     * If no decryption context, then we have nothing to do.
634
     */
635
5.46k
    if (worker->decryptobj == NULL)
636
1
        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
5.46k
    SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);
644
645
    /*
646
     * Handle the last block.
647
     */
648
5.46k
    sec_pkcs7_decoder_work_data(p7dcx, worker, NULL, 0, PR_TRUE);
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
5.46k
    if (worker->decryptobj) {
655
5.46k
        sec_PKCS7DestroyDecryptObject(worker->decryptobj);
656
5.46k
        worker->decryptobj = NULL;
657
5.46k
    }
658
659
5.46k
    return SECSuccess;
660
5.46k
}
661
662
static void
663
sec_pkcs7_decoder_notify(void *arg, PRBool before, void *dest, int depth)
664
477k
{
665
477k
    SEC_PKCS7DecoderContext *p7dcx;
666
477k
    SEC_PKCS7ContentInfo *cinfo;
667
477k
    SEC_PKCS7SignedData *sigd;
668
477k
    SEC_PKCS7EnvelopedData *envd;
669
477k
    SEC_PKCS7SignedAndEnvelopedData *saed;
670
477k
    SEC_PKCS7EncryptedData *encd;
671
477k
    SEC_PKCS7DigestedData *digd;
672
477k
    PRBool after;
673
477k
    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
477k
    if (before)
682
265k
        after = PR_FALSE;
683
211k
    else
684
211k
        after = PR_TRUE;
685
686
477k
    p7dcx = (SEC_PKCS7DecoderContext *)arg;
687
477k
    if (!p7dcx) {
688
0
        return;
689
0
    }
690
691
477k
    cinfo = p7dcx->cinfo;
692
693
477k
    if (!cinfo) {
694
0
        return;
695
0
    }
696
697
477k
    if (cinfo->contentTypeTag == NULL) {
698
158k
        if (after && dest == &(cinfo->contentType))
699
51.8k
            cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
700
158k
        return;
701
158k
    }
702
703
318k
    switch (cinfo->contentTypeTag->offset) {
704
54.1k
        case SEC_OID_PKCS7_SIGNED_DATA:
705
54.1k
            sigd = cinfo->content.signedData;
706
54.1k
            if (sigd == NULL)
707
1.39k
                break;
708
709
52.7k
            if (sigd->contentInfo.contentTypeTag == NULL) {
710
51.7k
                if (after && dest == &(sigd->contentInfo.contentType))
711
870
                    sigd->contentInfo.contentTypeTag =
712
870
                        SECOID_FindOID(&(sigd->contentInfo.contentType));
713
51.7k
                break;
714
51.7k
            }
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
915
            if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) {
728
                /* XXX Set an error in p7dcx->error */
729
13
                SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
730
13
                break;
731
13
            }
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
902
            if (before && dest == &(sigd->contentInfo.content)) {
739
783
                rv = sec_pkcs7_decoder_start_digests(p7dcx, depth,
740
783
                                                     sigd->digestAlgorithms);
741
783
                if (rv != SECSuccess)
742
0
                    SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
743
744
783
                break;
745
783
            }
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
119
            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
119
                (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp,
762
119
                                                       &(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
119
                SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
773
119
            }
774
119
            break;
775
776
720
        case SEC_OID_PKCS7_ENVELOPED_DATA:
777
720
            envd = cinfo->content.envelopedData;
778
720
            if (envd == NULL)
779
720
                break;
780
781
0
            if (envd->encContentInfo.contentTypeTag == NULL) {
782
0
                if (after && dest == &(envd->encContentInfo.contentType))
783
0
                    envd->encContentInfo.contentTypeTag =
784
0
                        SECOID_FindOID(&(envd->encContentInfo.contentType));
785
0
                break;
786
0
            }
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
0
            if (before && dest == &(envd->encContentInfo.encContent)) {
794
0
                rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth,
795
0
                                                     envd->recipientInfos,
796
0
                                                     &(envd->encContentInfo),
797
0
                                                     NULL);
798
0
                if (rv != SECSuccess)
799
0
                    SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
800
801
0
                break;
802
0
            }
803
804
            /*
805
             * Are we done?
806
             */
807
0
            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
0
                (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp,
814
0
                                                       &(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
0
                SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
825
0
            }
826
0
            break;
827
828
1.63k
        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
829
1.63k
            saed = cinfo->content.signedAndEnvelopedData;
830
1.63k
            if (saed == NULL)
831
1.36k
                break;
832
833
267
            if (saed->encContentInfo.contentTypeTag == NULL) {
834
9
                if (after && dest == &(saed->encContentInfo.contentType))
835
1
                    saed->encContentInfo.contentTypeTag =
836
1
                        SECOID_FindOID(&(saed->encContentInfo.contentType));
837
9
                break;
838
9
            }
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
258
            if (before && dest == &(saed->encContentInfo.encContent)) {
846
0
                rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth,
847
0
                                                     saed->recipientInfos,
848
0
                                                     &(saed->encContentInfo),
849
0
                                                     &(saed->sigKey));
850
0
                if (rv == SECSuccess)
851
0
                    rv = sec_pkcs7_decoder_start_digests(p7dcx, depth,
852
0
                                                         saed->digestAlgorithms);
853
0
                if (rv != SECSuccess)
854
0
                    SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
855
856
0
                break;
857
0
            }
858
859
            /*
860
             * Are we done?
861
             */
862
258
            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
0
                (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp,
874
0
                                                       &(saed->encContentInfo));
875
0
                (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp,
876
0
                                                       &(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
0
                SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
887
0
            }
888
258
            break;
889
890
10.8k
        case SEC_OID_PKCS7_DIGESTED_DATA:
891
10.8k
            digd = cinfo->content.digestedData;
892
10.8k
            if (digd == NULL)
893
1.99k
                break;
894
895
            /*
896
             * XXX Want to do the digest or not?  Maybe future enhancement...
897
             */
898
8.88k
            if (before && dest == &(digd->contentInfo.content.data)) {
899
21
                SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, sec_pkcs7_decoder_filter,
900
21
                                             p7dcx,
901
21
                                             (PRBool)(p7dcx->cb != NULL));
902
21
                break;
903
21
            }
904
905
            /*
906
             * Are we done?
907
             */
908
8.86k
            if (after && dest == &(digd->contentInfo.content.data)) {
909
2
                SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);
910
2
            }
911
8.86k
            break;
912
913
248k
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
914
248k
            encd = cinfo->content.encryptedData;
915
916
248k
            if (!encd) {
917
18.7k
                break;
918
18.7k
            }
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
229k
            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
18.6k
                rv = SECSuccess;
933
18.6k
                if (p7dcx->dkcb != NULL) {
934
18.6k
                    rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, NULL,
935
18.6k
                                                         &(encd->encContentInfo),
936
18.6k
                                                         NULL);
937
18.6k
                }
938
939
18.6k
                if (rv != SECSuccess)
940
13.1k
                    SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
941
942
18.6k
                break;
943
18.6k
            }
944
945
            /*
946
             * Are we done?
947
             */
948
210k
            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
5.46k
                (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp,
955
5.46k
                                                       &(encd->encContentInfo));
956
957
                /*
958
                 * Stop notify.
959
                 */
960
5.46k
                SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
961
5.46k
            }
962
210k
            break;
963
964
3.08k
        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
3.08k
            if (before && dest == &(cinfo->content.data)) {
973
974
                /*
975
                 * Set the filter proc up.
976
                 */
977
1.93k
                SEC_ASN1DecoderSetFilterProc(p7dcx->dcx,
978
1.93k
                                             sec_pkcs7_decoder_filter,
979
1.93k
                                             p7dcx,
980
1.93k
                                             (PRBool)(p7dcx->cb != NULL));
981
1.93k
                break;
982
1.93k
            }
983
984
1.15k
            if (after && dest == &(cinfo->content.data)) {
985
                /*
986
                 * Time to clean up after ourself, stop the Notify and Filter
987
                 * procedures.
988
                 */
989
1.15k
                SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
990
1.15k
                SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);
991
1.15k
            }
992
1.15k
            break;
993
994
165
        default:
995
165
            SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx);
996
165
            break;
997
318k
    }
998
318k
}
999
1000
SEC_PKCS7DecoderContext *
1001
SEC_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
52.0k
{
1007
52.0k
    SEC_PKCS7DecoderContext *p7dcx;
1008
52.0k
    SEC_ASN1DecoderContext *dcx;
1009
52.0k
    SEC_PKCS7ContentInfo *cinfo;
1010
52.0k
    PLArenaPool *poolp;
1011
1012
52.0k
    poolp = PORT_NewArena(1024); /* XXX what is right value? */
1013
52.0k
    if (poolp == NULL)
1014
0
        return NULL;
1015
1016
52.0k
    cinfo = (SEC_PKCS7ContentInfo *)PORT_ArenaZAlloc(poolp, sizeof(*cinfo));
1017
52.0k
    if (cinfo == NULL) {
1018
0
        PORT_FreeArena(poolp, PR_FALSE);
1019
0
        return NULL;
1020
0
    }
1021
1022
52.0k
    cinfo->poolp = poolp;
1023
52.0k
    cinfo->pwfn = pwfn;
1024
52.0k
    cinfo->pwfn_arg = pwfn_arg;
1025
52.0k
    cinfo->created = PR_FALSE;
1026
52.0k
    cinfo->refCount = 1;
1027
1028
52.0k
    p7dcx =
1029
52.0k
        (SEC_PKCS7DecoderContext *)PORT_ZAlloc(sizeof(SEC_PKCS7DecoderContext));
1030
52.0k
    if (p7dcx == NULL) {
1031
0
        PORT_FreeArena(poolp, PR_FALSE);
1032
0
        return NULL;
1033
0
    }
1034
1035
52.0k
    p7dcx->tmp_poolp = PORT_NewArena(1024); /* XXX what is right value? */
1036
52.0k
    if (p7dcx->tmp_poolp == NULL) {
1037
0
        PORT_Free(p7dcx);
1038
0
        PORT_FreeArena(poolp, PR_FALSE);
1039
0
        return NULL;
1040
0
    }
1041
1042
52.0k
    dcx = SEC_ASN1DecoderStart(poolp, cinfo, sec_PKCS7ContentInfoTemplate);
1043
52.0k
    if (dcx == NULL) {
1044
0
        PORT_FreeArena(p7dcx->tmp_poolp, PR_FALSE);
1045
0
        PORT_Free(p7dcx);
1046
0
        PORT_FreeArena(poolp, PR_FALSE);
1047
0
        return NULL;
1048
0
    }
1049
1050
52.0k
    SEC_ASN1DecoderSetNotifyProc(dcx, sec_pkcs7_decoder_notify, p7dcx);
1051
1052
52.0k
    p7dcx->dcx = dcx;
1053
52.0k
    p7dcx->cinfo = cinfo;
1054
52.0k
    p7dcx->cb = cb;
1055
52.0k
    p7dcx->cb_arg = cb_arg;
1056
52.0k
    p7dcx->pwfn = pwfn;
1057
52.0k
    p7dcx->pwfn_arg = pwfn_arg;
1058
52.0k
    p7dcx->dkcb = decrypt_key_cb;
1059
52.0k
    p7dcx->dkcb_arg = decrypt_key_cb_arg;
1060
52.0k
    p7dcx->decrypt_allowed_cb = decrypt_allowed_cb;
1061
1062
52.0k
    return p7dcx;
1063
52.0k
}
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
 */
1073
SECStatus
1074
SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
1075
                       const char *buf, unsigned long len)
1076
2.62M
{
1077
2.62M
    if (!p7dcx) {
1078
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1079
0
        return SECFailure;
1080
0
    }
1081
1082
2.62M
    if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) {
1083
2.21M
        PORT_Assert(p7dcx->error == 0);
1084
2.21M
        if (p7dcx->error == 0) {
1085
2.21M
            if (SEC_ASN1DecoderUpdate(p7dcx->dcx, buf, len) != SECSuccess) {
1086
860
                p7dcx->error = PORT_GetError();
1087
860
                PORT_Assert(p7dcx->error);
1088
860
                if (p7dcx->error == 0)
1089
0
                    p7dcx->error = -1;
1090
860
            }
1091
2.21M
        }
1092
2.21M
    }
1093
1094
2.62M
    if (p7dcx->error) {
1095
412k
        sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1096
412k
        if (p7dcx->worker.decryptobj) {
1097
1
            sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1098
1
            p7dcx->worker.decryptobj = NULL;
1099
1
        }
1100
412k
        if (p7dcx->dcx != NULL) {
1101
936
            (void)SEC_ASN1DecoderFinish(p7dcx->dcx);
1102
936
            p7dcx->dcx = NULL;
1103
936
        }
1104
412k
        if (p7dcx->cinfo != NULL) {
1105
936
            SEC_PKCS7DestroyContentInfo(p7dcx->cinfo);
1106
936
            p7dcx->cinfo = NULL;
1107
936
        }
1108
412k
        PORT_SetError(p7dcx->error);
1109
412k
        return SECFailure;
1110
412k
    }
1111
1112
2.21M
    return SECSuccess;
1113
2.62M
}
1114
1115
SEC_PKCS7ContentInfo *
1116
SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
1117
52.0k
{
1118
52.0k
    SEC_PKCS7ContentInfo *cinfo;
1119
1120
52.0k
    sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1121
52.0k
    cinfo = p7dcx->cinfo;
1122
52.0k
    if (p7dcx->dcx != NULL) {
1123
51.1k
        if (SEC_ASN1DecoderFinish(p7dcx->dcx) != SECSuccess) {
1124
1.66k
            SEC_PKCS7DestroyContentInfo(cinfo);
1125
1.66k
            cinfo = NULL;
1126
1.66k
        }
1127
51.1k
    }
1128
    /* free any NSS data structures */
1129
52.0k
    if (p7dcx->worker.decryptobj) {
1130
19
        sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1131
19
        p7dcx->worker.decryptobj = NULL;
1132
19
    }
1133
1134
52.0k
    PORT_FreeArena(p7dcx->tmp_poolp, PR_FALSE);
1135
52.0k
    PORT_Free(p7dcx);
1136
52.0k
    return cinfo;
1137
52.0k
}
1138
1139
SEC_PKCS7ContentInfo *
1140
SEC_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
0
{
1147
0
    SEC_PKCS7DecoderContext *p7dcx;
1148
1149
0
    p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb,
1150
0
                                  decrypt_key_cb_arg, decrypt_allowed_cb);
1151
0
    if (!p7dcx) {
1152
        /* error code is set */
1153
0
        return NULL;
1154
0
    }
1155
0
    (void)SEC_PKCS7DecoderUpdate(p7dcx, (char *)p7item->data, p7item->len);
1156
0
    return SEC_PKCS7DecoderFinish(p7dcx);
1157
0
}
1158
1159
/*
1160
 * Abort the ASN.1 stream. Used by pkcs 12
1161
 */
1162
void
1163
SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error)
1164
87
{
1165
87
    PORT_Assert(p7dcx);
1166
87
    if (!p7dcx) {
1167
0
        return;
1168
0
    }
1169
1170
    /* ensure any streaming helpers are torn down */
1171
87
    sec_pkcs7_decoder_abort_digests(&p7dcx->worker);
1172
87
    if (p7dcx->worker.decryptobj) {
1173
42
        sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
1174
42
        p7dcx->worker.decryptobj = NULL;
1175
42
    }
1176
1177
87
    SEC_ASN1DecoderAbort(p7dcx->dcx, error);
1178
87
}
1179
1180
/*
1181
 * If the thing contains any certs or crls return true; false otherwise.
1182
 */
1183
PRBool
1184
SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo)
1185
0
{
1186
0
    SECOidTag kind;
1187
0
    SECItem **certs;
1188
0
    CERTSignedCrl **crls;
1189
1190
0
    kind = SEC_PKCS7ContentType(cinfo);
1191
0
    switch (kind) {
1192
0
        default:
1193
0
        case SEC_OID_PKCS7_DATA:
1194
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
1195
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
1196
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
1197
0
            return PR_FALSE;
1198
0
        case SEC_OID_PKCS7_SIGNED_DATA:
1199
0
            certs = cinfo->content.signedData->rawCerts;
1200
0
            crls = cinfo->content.signedData->crls;
1201
0
            break;
1202
0
        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1203
0
            certs = cinfo->content.signedAndEnvelopedData->rawCerts;
1204
0
            crls = cinfo->content.signedAndEnvelopedData->crls;
1205
0
            break;
1206
0
    }
1207
1208
    /*
1209
     * I know this could be collapsed, but I was in a mood to be explicit.
1210
     */
1211
0
    if (certs != NULL && certs[0] != NULL)
1212
0
        return PR_TRUE;
1213
0
    else if (crls != NULL && crls[0] != NULL)
1214
0
        return PR_TRUE;
1215
0
    else
1216
0
        return PR_FALSE;
1217
0
}
1218
1219
/* return the content length...could use GetContent, however we
1220
 * need the encrypted content length
1221
 */
1222
PRBool
1223
SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen)
1224
0
{
1225
0
    SECItem *item = NULL;
1226
1227
0
    if (cinfo == NULL) {
1228
0
        return PR_TRUE;
1229
0
    }
1230
1231
0
    switch (SEC_PKCS7ContentType(cinfo)) {
1232
0
        case SEC_OID_PKCS7_DATA:
1233
0
            item = cinfo->content.data;
1234
0
            break;
1235
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
1236
0
            item = &cinfo->content.encryptedData->encContentInfo.encContent;
1237
0
            break;
1238
0
        default:
1239
            /* add other types */
1240
0
            return PR_FALSE;
1241
0
    }
1242
1243
0
    if (!item) {
1244
0
        return PR_TRUE;
1245
0
    } else if (item->len <= minLen) {
1246
0
        return PR_TRUE;
1247
0
    }
1248
1249
0
    return PR_FALSE;
1250
0
}
1251
1252
PRBool
1253
SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo)
1254
0
{
1255
0
    SECOidTag kind;
1256
1257
0
    kind = SEC_PKCS7ContentType(cinfo);
1258
0
    switch (kind) {
1259
0
        default:
1260
0
        case SEC_OID_PKCS7_DATA:
1261
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
1262
0
        case SEC_OID_PKCS7_SIGNED_DATA:
1263
0
            return PR_FALSE;
1264
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
1265
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
1266
0
        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1267
0
            return PR_TRUE;
1268
0
    }
1269
0
}
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
 */
1279
PRBool
1280
SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo)
1281
0
{
1282
0
    SECOidTag kind;
1283
0
    SEC_PKCS7SignerInfo **signerinfos;
1284
1285
0
    kind = SEC_PKCS7ContentType(cinfo);
1286
0
    switch (kind) {
1287
0
        default:
1288
0
        case SEC_OID_PKCS7_DATA:
1289
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
1290
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
1291
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
1292
0
            return PR_FALSE;
1293
0
        case SEC_OID_PKCS7_SIGNED_DATA:
1294
0
            signerinfos = cinfo->content.signedData->signerInfos;
1295
0
            break;
1296
0
        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
1297
0
            signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
1298
0
            break;
1299
0
    }
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
0
    if (signerinfos != NULL && signerinfos[0] != NULL)
1306
0
        return PR_TRUE;
1307
0
    else
1308
0
        return PR_FALSE;
1309
0
}
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
 */
1346
static PRBool
1347
sec_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
0
{
1354
0
    SECAlgorithmID **digestalgs, *bulkid;
1355
0
    const SECItem *digest;
1356
0
    SECItem **digests;
1357
0
    SECItem **rawcerts;
1358
0
    SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
1359
0
    CERTCertificate *cert, **certs;
1360
0
    PRBool goodsig;
1361
0
    CERTCertDBHandle *certdb, *defaultdb;
1362
0
    SECOidTag encTag, digestTag;
1363
0
    HASH_HashType found_type;
1364
0
    int i, certcount;
1365
0
    SECKEYPublicKey *publickey;
1366
0
    SECItem *content_type;
1367
0
    PK11SymKey *sigkey;
1368
0
    SECItem *encoded_stime;
1369
0
    PRTime stime;
1370
0
    PRTime verificationTime;
1371
0
    SECStatus rv;
1372
1373
    /*
1374
     * Everything needed in order to "goto done" safely.
1375
     */
1376
0
    goodsig = PR_FALSE;
1377
0
    certcount = 0;
1378
0
    cert = NULL;
1379
0
    certs = NULL;
1380
0
    certdb = NULL;
1381
0
    defaultdb = CERT_GetDefaultCertDB();
1382
0
    publickey = NULL;
1383
1384
0
    if (!SEC_PKCS7ContentIsSigned(cinfo)) {
1385
0
        PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1386
0
        goto done;
1387
0
    }
1388
1389
0
    PORT_Assert(cinfo->contentTypeTag != NULL);
1390
1391
0
    switch (cinfo->contentTypeTag->offset) {
1392
0
        default:
1393
0
        case SEC_OID_PKCS7_DATA:
1394
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
1395
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
1396
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
1397
            /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */
1398
0
            PORT_Assert(0);
1399
0
        case SEC_OID_PKCS7_SIGNED_DATA: {
1400
0
            SEC_PKCS7SignedData *sdp;
1401
1402
0
            sdp = cinfo->content.signedData;
1403
0
            digestalgs = sdp->digestAlgorithms;
1404
0
            digests = sdp->digests;
1405
0
            rawcerts = sdp->rawCerts;
1406
0
            signerinfos = sdp->signerInfos;
1407
0
            content_type = &(sdp->contentInfo.contentType);
1408
0
            sigkey = NULL;
1409
0
            bulkid = NULL;
1410
0
        } break;
1411
0
        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
1412
0
            SEC_PKCS7SignedAndEnvelopedData *saedp;
1413
1414
0
            saedp = cinfo->content.signedAndEnvelopedData;
1415
0
            digestalgs = saedp->digestAlgorithms;
1416
0
            digests = saedp->digests;
1417
0
            rawcerts = saedp->rawCerts;
1418
0
            signerinfos = saedp->signerInfos;
1419
0
            content_type = &(saedp->encContentInfo.contentType);
1420
0
            sigkey = saedp->sigKey;
1421
0
            bulkid = &(saedp->encContentInfo.contentEncAlg);
1422
0
        } break;
1423
0
    }
1424
1425
0
    if ((signerinfos == NULL) || (signerinfos[0] == NULL)) {
1426
0
        PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1427
0
        goto done;
1428
0
    }
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
0
    if (signerinfos[1] != NULL) {
1435
0
        PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1436
0
        goto done;
1437
0
    }
1438
1439
0
    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
0
    certdb = defaultdb;
1448
0
    if (certdb == NULL) {
1449
0
        goto done;
1450
0
    }
1451
1452
0
    certcount = 0;
1453
0
    if (rawcerts != NULL) {
1454
0
        for (; rawcerts[certcount] != NULL; certcount++) {
1455
            /* just counting */
1456
0
        }
1457
0
    }
1458
1459
    /*
1460
     * Note that the result of this is that each cert in "certs"
1461
     * needs to be destroyed.
1462
     */
1463
0
    rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs,
1464
0
                          keepcerts, PR_FALSE, NULL);
1465
0
    if (rv != SECSuccess) {
1466
0
        goto done;
1467
0
    }
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
0
    cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN);
1476
0
    if (cert == NULL) {
1477
0
        goto done;
1478
0
    }
1479
1480
0
    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
0
    encoded_stime = SEC_PKCS7GetSigningTime(cinfo);
1488
0
    if (encoded_stime != NULL) {
1489
0
        if (DER_DecodeTimeChoice(&stime, encoded_stime) != SECSuccess)
1490
0
            encoded_stime = NULL; /* conversion failed, so pretend none */
1491
0
    }
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
0
    if (atTime) {
1502
0
        verificationTime = *atTime;
1503
0
    } else if (encoded_stime != NULL) {
1504
0
        verificationTime = stime;
1505
0
    } else {
1506
0
        verificationTime = PR_Now();
1507
0
    }
1508
0
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, verificationTime,
1509
0
                        cinfo->pwfn_arg, NULL) != 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
0
        goto savecert;
1519
0
    }
1520
1521
0
    publickey = CERT_ExtractPublicKey(cert);
1522
0
    if (publickey == NULL)
1523
0
        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
0
    if (digests == NULL && (detached_digest == NULL || detached_digest->data == NULL))
1536
0
        goto done;
1537
1538
    /*
1539
     * Find and confirm digest algorithm.
1540
     */
1541
0
    digestTag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm));
1542
1543
    /* make sure we understand the digest type first */
1544
0
    found_type = HASH_GetHashTypeByOidTag(digestTag);
1545
0
    if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) {
1546
0
        PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1547
0
        goto done;
1548
0
    }
1549
1550
0
    if (detached_digest != NULL) {
1551
0
        unsigned int hashLen = HASH_ResultLen(found_type);
1552
1553
0
        if (digest_type != found_type ||
1554
0
            detached_digest->len != hashLen) {
1555
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1556
0
            goto done;
1557
0
        }
1558
0
        digest = detached_digest;
1559
0
    } else {
1560
0
        PORT_Assert(digestalgs != NULL && digestalgs[0] != NULL);
1561
0
        if (digestalgs == NULL || digestalgs[0] == NULL) {
1562
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1563
0
            goto done;
1564
0
        }
1565
1566
        /*
1567
         * pick digest matching signerinfo->digestAlg from digests
1568
         */
1569
0
        for (i = 0; digestalgs[i] != NULL; i++) {
1570
0
            if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag)
1571
0
                break;
1572
0
        }
1573
0
        if (digestalgs[i] == NULL) {
1574
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1575
0
            goto done;
1576
0
        }
1577
1578
0
        digest = digests[i];
1579
0
        if (digest == NULL) {
1580
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1581
0
            goto done;
1582
0
        }
1583
0
    }
1584
1585
0
    encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm));
1586
0
    if (encTag == SEC_OID_UNKNOWN) {
1587
0
        PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1588
0
        goto done;
1589
0
    }
1590
1591
0
    if (signerinfo->authAttr != NULL) {
1592
0
        SEC_PKCS7Attribute *attr;
1593
0
        SECItem *value;
1594
0
        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
0
        if (sigkey != NULL) {
1601
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1602
0
            goto done;
1603
0
        }
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
0
        attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1615
0
                                      SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
1616
0
        value = sec_PKCS7AttributeValue(attr);
1617
0
        if (value == NULL || value->len != content_type->len) {
1618
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1619
0
            goto done;
1620
0
        }
1621
0
        if (PORT_Memcmp(value->data, content_type->data, value->len) != 0) {
1622
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1623
0
            goto done;
1624
0
        }
1625
1626
0
        attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1627
0
                                      SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
1628
0
        value = sec_PKCS7AttributeValue(attr);
1629
0
        if (value == NULL || value->len != digest->len) {
1630
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1631
0
            goto done;
1632
0
        }
1633
0
        if (PORT_Memcmp(value->data, digest->data, value->len) != 0) {
1634
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1635
0
            goto done;
1636
0
        }
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
0
        encoded_attrs.data = NULL;
1645
0
        encoded_attrs.len = 0;
1646
0
        if (sec_PKCS7EncodeAttributes(NULL, &encoded_attrs,
1647
0
                                      &(signerinfo->authAttr)) == NULL)
1648
0
            goto done;
1649
1650
0
        if (encoded_attrs.data == NULL || encoded_attrs.len == 0) {
1651
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1652
0
            goto done;
1653
0
        }
1654
1655
0
        goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data,
1656
0
                                                encoded_attrs.len,
1657
0
                                                publickey, &(signerinfo->encDigest),
1658
0
                                                encTag, digestTag, NULL,
1659
0
                                                cinfo->pwfn_arg) == SECSuccess);
1660
0
        PORT_Free(encoded_attrs.data);
1661
0
    } else {
1662
0
        SECItem *sig;
1663
0
        SECItem holder;
1664
1665
        /*
1666
         * No authenticated attributes.
1667
         * The signature is based on the plain message digest.
1668
         */
1669
1670
0
        sig = &(signerinfo->encDigest);
1671
0
        if (sig->len == 0) { /* bad signature */
1672
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1673
0
            goto done;
1674
0
        }
1675
1676
0
        if (sigkey != NULL) {
1677
0
            sec_PKCS7CipherObject *decryptobj;
1678
0
            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
0
            decryptobj = sec_PKCS7CreateDecryptObject(sigkey, bulkid);
1686
0
            if (decryptobj == NULL)
1687
0
                goto done;
1688
1689
0
            buflen = sec_PKCS7DecryptLength(decryptobj, sig->len, PR_TRUE);
1690
0
            PORT_Assert(buflen);
1691
0
            if (buflen == 0) { /* something is wrong */
1692
0
                sec_PKCS7DestroyDecryptObject(decryptobj);
1693
0
                goto done;
1694
0
            }
1695
1696
0
            holder.data = (unsigned char *)PORT_Alloc(buflen);
1697
0
            if (holder.data == NULL) {
1698
0
                sec_PKCS7DestroyDecryptObject(decryptobj);
1699
0
                goto done;
1700
0
            }
1701
1702
0
            rv = sec_PKCS7Decrypt(decryptobj, holder.data, &holder.len, buflen,
1703
0
                                  sig->data, sig->len, PR_TRUE);
1704
0
            sec_PKCS7DestroyDecryptObject(decryptobj);
1705
0
            if (rv != SECSuccess) {
1706
0
                goto done;
1707
0
            }
1708
1709
0
            sig = &holder;
1710
0
        }
1711
1712
0
        goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig,
1713
0
                                                  encTag, digestTag, cinfo->pwfn_arg) == SECSuccess);
1714
1715
0
        if (sigkey != NULL) {
1716
0
            PORT_Assert(sig == &holder);
1717
0
            PORT_ZFree(holder.data, holder.len);
1718
0
        }
1719
0
    }
1720
1721
0
    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
0
        if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
1739
0
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
1740
0
    }
1741
1742
0
savecert:
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
0
    if (cert->emailAddr && cert->emailAddr[0] &&
1748
0
        ((certusage == certUsageEmailSigner) ||
1749
0
         (certusage == certUsageEmailRecipient))) {
1750
0
        SECItem *profile = NULL;
1751
0
        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
0
        save_error = PORT_GetError();
1758
1759
0
        if (goodsig && (signerinfo->authAttr != NULL)) {
1760
            /*
1761
             * If the signature is good, then we can save the S/MIME profile,
1762
             * if we have one.
1763
             */
1764
0
            SEC_PKCS7Attribute *attr;
1765
1766
0
            attr = sec_PKCS7FindAttribute(signerinfo->authAttr,
1767
0
                                          SEC_OID_PKCS9_SMIME_CAPABILITIES,
1768
0
                                          PR_TRUE);
1769
0
            profile = sec_PKCS7AttributeValue(attr);
1770
0
        }
1771
1772
0
        rv = CERT_SaveSMimeProfile(cert, profile, encoded_stime);
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
0
        PORT_SetError(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
0
    }
1786
1787
0
done:
1788
1789
    /*
1790
     * See comment above about why we do not want to destroy cert
1791
     * itself here.
1792
     */
1793
1794
0
    if (certs != NULL)
1795
0
        CERT_DestroyCertArray(certs, certcount);
1796
1797
0
    if (publickey != NULL)
1798
0
        SECKEY_DestroyPublicKey(publickey);
1799
1800
0
    return goodsig;
1801
0
}
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
 */
1812
PRBool
1813
SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
1814
                         SECCertUsage certusage,
1815
                         PRBool keepcerts)
1816
0
{
1817
0
    return sec_pkcs7_verify_signature(cinfo, certusage,
1818
0
                                      NULL, HASH_AlgNULL, keepcerts, NULL);
1819
0
}
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
 */
1831
PRBool
1832
SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
1833
                                 SECCertUsage certusage,
1834
                                 const SECItem *detached_digest,
1835
                                 HASH_HashType digest_type,
1836
                                 PRBool keepcerts)
1837
0
{
1838
0
    return sec_pkcs7_verify_signature(cinfo, certusage,
1839
0
                                      detached_digest, digest_type,
1840
0
                                      keepcerts, NULL);
1841
0
}
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
 */
1853
PRBool
1854
SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
1855
                                       SECCertUsage certusage,
1856
                                       const SECItem *detached_digest,
1857
                                       HASH_HashType digest_type,
1858
                                       PRBool keepcerts,
1859
                                       PRTime atTime)
1860
0
{
1861
0
    return sec_pkcs7_verify_signature(cinfo, certusage,
1862
0
                                      detached_digest, digest_type,
1863
0
                                      keepcerts, &atTime);
1864
0
}
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
0
#define sec_common_name 1
1875
0
#define sec_email_address 2
1876
1877
static char *
1878
sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
1879
0
{
1880
0
    SECOidTag kind;
1881
0
    SEC_PKCS7SignerInfo **signerinfos;
1882
0
    CERTCertificate *signercert;
1883
0
    char *container;
1884
1885
0
    kind = SEC_PKCS7ContentType(cinfo);
1886
0
    switch (kind) {
1887
0
        default:
1888
0
        case SEC_OID_PKCS7_DATA:
1889
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
1890
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
1891
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
1892
0
            PORT_Assert(0);
1893
0
            return NULL;
1894
0
        case SEC_OID_PKCS7_SIGNED_DATA: {
1895
0
            SEC_PKCS7SignedData *sdp;
1896
1897
0
            sdp = cinfo->content.signedData;
1898
0
            signerinfos = sdp->signerInfos;
1899
0
        } break;
1900
0
        case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: {
1901
0
            SEC_PKCS7SignedAndEnvelopedData *saedp;
1902
1903
0
            saedp = cinfo->content.signedAndEnvelopedData;
1904
0
            signerinfos = saedp->signerInfos;
1905
0
        } break;
1906
0
    }
1907
1908
0
    if (signerinfos == NULL || signerinfos[0] == NULL)
1909
0
        return NULL;
1910
1911
0
    signercert = signerinfos[0]->cert;
1912
1913
    /*
1914
     * No cert there; see if we can find one by calling verify ourselves.
1915
     */
1916
0
    if (signercert == NULL) {
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
0
        (void)sec_pkcs7_verify_signature(cinfo, certUsageEmailSigner,
1923
0
                                         NULL, HASH_AlgNULL, PR_FALSE, NULL);
1924
0
        signercert = signerinfos[0]->cert;
1925
0
        if (signercert == NULL)
1926
0
            return NULL;
1927
0
    }
1928
1929
0
    switch (selector) {
1930
0
        case sec_common_name:
1931
0
            container = CERT_GetCommonName(&signercert->subject);
1932
0
            break;
1933
0
        case sec_email_address:
1934
0
            if (signercert->emailAddr && signercert->emailAddr[0]) {
1935
0
                container = PORT_Strdup(signercert->emailAddr);
1936
0
            } else {
1937
0
                container = NULL;
1938
0
            }
1939
0
            break;
1940
0
        default:
1941
0
            PORT_Assert(0);
1942
0
            container = NULL;
1943
0
            break;
1944
0
    }
1945
1946
0
    return container;
1947
0
}
1948
1949
char *
1950
SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
1951
0
{
1952
0
    return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name);
1953
0
}
1954
1955
char *
1956
SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
1957
0
{
1958
0
    return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address);
1959
0
}
1960
1961
/*
1962
 * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
1963
 */
1964
SECItem *
1965
SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
1966
0
{
1967
0
    SEC_PKCS7SignerInfo **signerinfos;
1968
0
    SEC_PKCS7Attribute *attr;
1969
1970
0
    if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
1971
0
        return NULL;
1972
1973
0
    signerinfos = cinfo->content.signedData->signerInfos;
1974
1975
    /*
1976
     * No signature, or more than one, means no deal.
1977
     */
1978
0
    if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
1979
0
        return NULL;
1980
1981
0
    attr = sec_PKCS7FindAttribute(signerinfos[0]->authAttr,
1982
0
                                  SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
1983
0
    return sec_PKCS7AttributeValue(attr);
1984
0
}