~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/pkcs7/p7decode.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

Show diffs side-by-side

added added

removed removed

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