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

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/pkcs7/secmime.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
 *
 
23
 * Alternatively, the contents of this file may be used under the terms of
 
24
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
25
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
26
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
27
 * of those above. If you wish to allow use of your version of this file only
 
28
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
29
 * use your version of this file under the terms of the MPL, indicate your
 
30
 * decision by deleting the provisions above and replace them with the notice
 
31
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
32
 * the provisions above, a recipient may use your version of this file under
 
33
 * the terms of any one of the MPL, the GPL or the LGPL.
 
34
 *
 
35
 * ***** END LICENSE BLOCK ***** */
 
36
 
 
37
/*
 
38
 * Stuff specific to S/MIME policy and interoperability.
 
39
 * Depends on PKCS7, but there should be no dependency the other way around.
 
40
 *
 
41
 * $Id: secmime.c,v 1.4 2004/06/18 00:38:45 jpierre%netscape.com Exp $
 
42
 */
 
43
 
 
44
#include "secmime.h"
 
45
#include "secoid.h"
 
46
#include "pk11func.h"
 
47
#include "ciferfam.h"   /* for CIPHER_FAMILY symbols */
 
48
#include "secasn1.h"
 
49
#include "secitem.h"
 
50
#include "cert.h"
 
51
#include "key.h"
 
52
#include "secerr.h"
 
53
 
 
54
typedef struct smime_cipher_map_struct {
 
55
    unsigned long cipher;
 
56
    SECOidTag algtag;
 
57
    SECItem *parms;
 
58
} smime_cipher_map;
 
59
 
 
60
/*
 
61
 * These are macros because I think some subsequent parameters,
 
62
 * like those for RC5, will want to use them, too, separately.
 
63
 */
 
64
#define SMIME_DER_INTVAL_16     SEC_ASN1_INTEGER, 0x01, 0x10
 
65
#define SMIME_DER_INTVAL_40     SEC_ASN1_INTEGER, 0x01, 0x28
 
66
#define SMIME_DER_INTVAL_64     SEC_ASN1_INTEGER, 0x01, 0x40
 
67
#define SMIME_DER_INTVAL_128    SEC_ASN1_INTEGER, 0x02, 0x00, 0x80
 
68
 
 
69
#ifdef SMIME_DOES_RC5   /* will be needed; quiet unused warning for now */
 
70
static unsigned char smime_int16[] = { SMIME_DER_INTVAL_16 };
 
71
#endif
 
72
static unsigned char smime_int40[] = { SMIME_DER_INTVAL_40 };
 
73
static unsigned char smime_int64[] = { SMIME_DER_INTVAL_64 };
 
74
static unsigned char smime_int128[] = { SMIME_DER_INTVAL_128 };
 
75
 
 
76
static SECItem smime_rc2p40 = { siBuffer, smime_int40, sizeof(smime_int40) };
 
77
static SECItem smime_rc2p64 = { siBuffer, smime_int64, sizeof(smime_int64) };
 
78
static SECItem smime_rc2p128 = { siBuffer, smime_int128, sizeof(smime_int128) };
 
79
 
 
80
static smime_cipher_map smime_cipher_maps[] = {
 
81
    { SMIME_RC2_CBC_40,         SEC_OID_RC2_CBC,        &smime_rc2p40 },
 
82
    { SMIME_RC2_CBC_64,         SEC_OID_RC2_CBC,        &smime_rc2p64 },
 
83
    { SMIME_RC2_CBC_128,        SEC_OID_RC2_CBC,        &smime_rc2p128 },
 
84
#ifdef SMIME_DOES_RC5
 
85
    { SMIME_RC5PAD_64_16_40,    SEC_OID_RC5_CBC_PAD,    &smime_rc5p40 },
 
86
    { SMIME_RC5PAD_64_16_64,    SEC_OID_RC5_CBC_PAD,    &smime_rc5p64 },
 
87
    { SMIME_RC5PAD_64_16_128,   SEC_OID_RC5_CBC_PAD,    &smime_rc5p128 },
 
88
#endif
 
89
    { SMIME_DES_CBC_56,         SEC_OID_DES_CBC,        NULL },
 
90
    { SMIME_DES_EDE3_168,       SEC_OID_DES_EDE3_CBC,   NULL },
 
91
    { SMIME_FORTEZZA,           SEC_OID_FORTEZZA_SKIPJACK, NULL}
 
92
};
 
93
 
 
94
/*
 
95
 * Note, the following value really just needs to be an upper bound
 
96
 * on the ciphers.
 
97
 */
 
98
static const int smime_symmetric_count = sizeof(smime_cipher_maps)
 
99
                                         / sizeof(smime_cipher_map);
 
100
 
 
101
static unsigned long *smime_prefs, *smime_newprefs;
 
102
static int smime_current_pref_index = 0;
 
103
static PRBool smime_prefs_complete = PR_FALSE;
 
104
static PRBool smime_prefs_changed = PR_TRUE;
 
105
 
 
106
static unsigned long smime_policy_bits = 0;
 
107
 
 
108
 
 
109
static int
 
110
smime_mapi_by_cipher (unsigned long cipher)
 
111
{
 
112
    int i;
 
113
 
 
114
    for (i = 0; i < smime_symmetric_count; i++) {
 
115
        if (smime_cipher_maps[i].cipher == cipher)
 
116
            break;
 
117
    }
 
118
 
 
119
    if (i == smime_symmetric_count)
 
120
        return -1;
 
121
 
 
122
    return i;
 
123
}
 
124
 
 
125
 
 
126
/*
 
127
 * this function locally records the user's preference
 
128
 */
 
129
SECStatus 
 
130
SECMIME_EnableCipher(long which, int on)
 
131
{
 
132
    unsigned long mask;
 
133
 
 
134
    if (smime_newprefs == NULL || smime_prefs_complete) {
 
135
        /*
 
136
         * This is either the very first time, or we are starting over.
 
137
         */
 
138
        smime_newprefs = (unsigned long*)PORT_ZAlloc (smime_symmetric_count
 
139
                                      * sizeof(*smime_newprefs));
 
140
        if (smime_newprefs == NULL)
 
141
            return SECFailure;
 
142
        smime_current_pref_index = 0;
 
143
        smime_prefs_complete = PR_FALSE;
 
144
    }
 
145
 
 
146
    mask = which & CIPHER_FAMILYID_MASK;
 
147
    if (mask == CIPHER_FAMILYID_MASK) {
 
148
        /*
 
149
         * This call signifies that all preferences have been set.
 
150
         * Move "newprefs" over, after checking first whether or
 
151
         * not the new ones are different from the old ones.
 
152
         */
 
153
        if (smime_prefs != NULL) {
 
154
            if (PORT_Memcmp (smime_prefs, smime_newprefs,
 
155
                             smime_symmetric_count * sizeof(*smime_prefs)) == 0)
 
156
                smime_prefs_changed = PR_FALSE;
 
157
            else
 
158
                smime_prefs_changed = PR_TRUE;
 
159
            PORT_Free (smime_prefs);
 
160
        }
 
161
 
 
162
        smime_prefs = smime_newprefs;
 
163
        smime_prefs_complete = PR_TRUE;
 
164
        return SECSuccess;
 
165
    }
 
166
 
 
167
    PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
 
168
    if (mask != CIPHER_FAMILYID_SMIME) {
 
169
        /* XXX set an error! */
 
170
        return SECFailure;
 
171
    }
 
172
 
 
173
    if (on) {
 
174
        PORT_Assert (smime_current_pref_index < smime_symmetric_count);
 
175
        if (smime_current_pref_index >= smime_symmetric_count) {
 
176
            /* XXX set an error! */
 
177
            return SECFailure;
 
178
        }
 
179
 
 
180
        smime_newprefs[smime_current_pref_index++] = which;
 
181
    }
 
182
 
 
183
    return SECSuccess;
 
184
}
 
185
 
 
186
 
 
187
/*
 
188
 * this function locally records the export policy
 
189
 */
 
190
SECStatus 
 
191
SECMIME_SetPolicy(long which, int on)
 
192
{
 
193
    unsigned long mask;
 
194
 
 
195
    PORT_Assert ((which & CIPHER_FAMILYID_MASK) == CIPHER_FAMILYID_SMIME);
 
196
    if ((which & CIPHER_FAMILYID_MASK) != CIPHER_FAMILYID_SMIME) {
 
197
        /* XXX set an error! */
 
198
        return SECFailure;
 
199
    }
 
200
 
 
201
    which &= ~CIPHER_FAMILYID_MASK;
 
202
 
 
203
    PORT_Assert (which < 32);   /* bits in the long */
 
204
    if (which >= 32) {
 
205
        /* XXX set an error! */
 
206
        return SECFailure;
 
207
    }
 
208
 
 
209
    mask = 1UL << which;
 
210
 
 
211
    if (on) {
 
212
        smime_policy_bits |= mask;
 
213
    } else {
 
214
        smime_policy_bits &= ~mask;
 
215
    }
 
216
 
 
217
    return SECSuccess;
 
218
}
 
219
 
 
220
 
 
221
/*
 
222
 * Based on the given algorithm (including its parameters, in some cases!)
 
223
 * and the given key (may or may not be inspected, depending on the
 
224
 * algorithm), find the appropriate policy algorithm specification
 
225
 * and return it.  If no match can be made, -1 is returned.
 
226
 */
 
227
static long
 
228
smime_policy_algorithm (SECAlgorithmID *algid, PK11SymKey *key)
 
229
{
 
230
    SECOidTag algtag;
 
231
 
 
232
    algtag = SECOID_GetAlgorithmTag (algid);
 
233
    switch (algtag) {
 
234
      case SEC_OID_RC2_CBC:
 
235
        {
 
236
            unsigned int keylen_bits;
 
237
 
 
238
            keylen_bits = PK11_GetKeyStrength (key, algid);
 
239
            switch (keylen_bits) {
 
240
              case 40:
 
241
                return SMIME_RC2_CBC_40;
 
242
              case 64:
 
243
                return SMIME_RC2_CBC_64;
 
244
              case 128:
 
245
                return SMIME_RC2_CBC_128;
 
246
              default:
 
247
                break;
 
248
            }
 
249
        }
 
250
        break;
 
251
      case SEC_OID_DES_CBC:
 
252
        return SMIME_DES_CBC_56;
 
253
      case SEC_OID_DES_EDE3_CBC:
 
254
        return SMIME_DES_EDE3_168;
 
255
      case SEC_OID_FORTEZZA_SKIPJACK:
 
256
        return SMIME_FORTEZZA;
 
257
#ifdef SMIME_DOES_RC5
 
258
      case SEC_OID_RC5_CBC_PAD:
 
259
        PORT_Assert (0);        /* XXX need to pull out parameters and match */
 
260
        break;
 
261
#endif
 
262
      default:
 
263
        break;
 
264
    }
 
265
 
 
266
    return -1;
 
267
}
 
268
 
 
269
 
 
270
static PRBool
 
271
smime_cipher_allowed (unsigned long which)
 
272
{
 
273
    unsigned long mask;
 
274
 
 
275
    which &= ~CIPHER_FAMILYID_MASK;
 
276
    PORT_Assert (which < 32);   /* bits per long (min) */
 
277
    if (which >= 32)
 
278
        return PR_FALSE;
 
279
 
 
280
    mask = 1UL << which;
 
281
    if ((mask & smime_policy_bits) == 0)
 
282
        return PR_FALSE;
 
283
 
 
284
    return PR_TRUE;
 
285
}
 
286
 
 
287
 
 
288
PRBool
 
289
SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key)
 
290
{
 
291
    long which;
 
292
 
 
293
    which = smime_policy_algorithm (algid, key);
 
294
    if (which < 0)
 
295
        return PR_FALSE;
 
296
 
 
297
    return smime_cipher_allowed ((unsigned long)which);
 
298
}
 
299
 
 
300
 
 
301
/*
 
302
 * Does the current policy allow *any* S/MIME encryption (or decryption)?
 
303
 *
 
304
 * This tells whether or not *any* S/MIME encryption can be done,
 
305
 * according to policy.  Callers may use this to do nicer user interface
 
306
 * (say, greying out a checkbox so a user does not even try to encrypt
 
307
 * a message when they are not allowed to) or for any reason they want
 
308
 * to check whether S/MIME encryption (or decryption, for that matter)
 
309
 * may be done.
 
310
 *
 
311
 * It takes no arguments.  The return value is a simple boolean:
 
312
 *   PR_TRUE means encryption (or decryption) is *possible*
 
313
 *      (but may still fail due to other reasons, like because we cannot
 
314
 *      find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
 
315
 *   PR_FALSE means encryption (or decryption) is not permitted
 
316
 *
 
317
 * There are no errors from this routine.
 
318
 */
 
319
PRBool
 
320
SECMIME_EncryptionPossible (void)
 
321
{
 
322
    if (smime_policy_bits != 0)
 
323
        return PR_TRUE;
 
324
 
 
325
    return PR_FALSE;
 
326
}
 
327
 
 
328
 
 
329
/*
 
330
 * XXX Would like the "parameters" field to be a SECItem *, but the
 
331
 * encoder is having trouble with optional pointers to an ANY.  Maybe
 
332
 * once that is fixed, can change this back...
 
333
 */
 
334
typedef struct smime_capability_struct {
 
335
    unsigned long cipher;       /* local; not part of encoding */
 
336
    SECOidTag capIDTag;         /* local; not part of encoding */
 
337
    SECItem capabilityID;
 
338
    SECItem parameters;
 
339
} smime_capability;
 
340
 
 
341
static const SEC_ASN1Template smime_capability_template[] = {
 
342
    { SEC_ASN1_SEQUENCE,
 
343
          0, NULL, sizeof(smime_capability) },
 
344
    { SEC_ASN1_OBJECT_ID,
 
345
          offsetof(smime_capability,capabilityID), },
 
346
    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
 
347
          offsetof(smime_capability,parameters), },
 
348
    { 0, }
 
349
};
 
350
 
 
351
static const SEC_ASN1Template smime_capabilities_template[] = {
 
352
    { SEC_ASN1_SEQUENCE_OF, 0, smime_capability_template }
 
353
};
 
354
 
 
355
 
 
356
 
 
357
static void
 
358
smime_fill_capability (smime_capability *cap)
 
359
{
 
360
    unsigned long cipher;
 
361
    SECOidTag algtag;
 
362
    int i;
 
363
 
 
364
    algtag = SECOID_FindOIDTag (&(cap->capabilityID));
 
365
 
 
366
    for (i = 0; i < smime_symmetric_count; i++) {
 
367
        if (smime_cipher_maps[i].algtag != algtag)
 
368
            continue;
 
369
        /*
 
370
         * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing
 
371
         * 2 NULLs as equal and NULL and non-NULL as not equal), we could
 
372
         * use that here instead of all of the following comparison code.
 
373
         */
 
374
        if (cap->parameters.data != NULL) {
 
375
            if (smime_cipher_maps[i].parms == NULL)
 
376
                continue;
 
377
            if (cap->parameters.len != smime_cipher_maps[i].parms->len)
 
378
                continue;
 
379
            if (PORT_Memcmp (cap->parameters.data,
 
380
                             smime_cipher_maps[i].parms->data,
 
381
                             cap->parameters.len) == 0)
 
382
                break;
 
383
        } else if (smime_cipher_maps[i].parms == NULL) {
 
384
            break;
 
385
        }
 
386
    }
 
387
 
 
388
    if (i == smime_symmetric_count)
 
389
        cipher = 0;
 
390
    else
 
391
        cipher = smime_cipher_maps[i].cipher;
 
392
 
 
393
    cap->cipher = cipher;
 
394
    cap->capIDTag = algtag;
 
395
}
 
396
 
 
397
 
 
398
static long
 
399
smime_choose_cipher (CERTCertificate *scert, CERTCertificate **rcerts)
 
400
{
 
401
    PRArenaPool *poolp;
 
402
    long chosen_cipher;
 
403
    int *cipher_abilities;
 
404
    int *cipher_votes;
 
405
    int strong_mapi;
 
406
    int rcount, mapi, max, i;
 
407
        PRBool isFortezza = PK11_FortezzaHasKEA(scert);
 
408
 
 
409
    if (smime_policy_bits == 0) {
 
410
        PORT_SetError (SEC_ERROR_BAD_EXPORT_ALGORITHM);
 
411
        return -1;
 
412
    }
 
413
 
 
414
    chosen_cipher = SMIME_RC2_CBC_40;           /* the default, LCD */
 
415
 
 
416
    poolp = PORT_NewArena (1024);               /* XXX what is right value? */
 
417
    if (poolp == NULL)
 
418
        goto done;
 
419
 
 
420
    cipher_abilities = (int*)PORT_ArenaZAlloc (poolp,
 
421
                                         smime_symmetric_count * sizeof(int));
 
422
    if (cipher_abilities == NULL)
 
423
        goto done;
 
424
 
 
425
    cipher_votes = (int*)PORT_ArenaZAlloc (poolp,
 
426
                                     smime_symmetric_count * sizeof(int));
 
427
    if (cipher_votes == NULL)
 
428
        goto done;
 
429
 
 
430
    /*
 
431
     * XXX Should have a #define somewhere which specifies default
 
432
     * strong cipher.  (Or better, a way to configure, which would
 
433
     * take Fortezza into account as well.)
 
434
     */
 
435
 
 
436
    /* If the user has the Fortezza preference turned on, make
 
437
     *  that the strong cipher. Otherwise, use triple-DES. */
 
438
    strong_mapi = -1;
 
439
    if (isFortezza) {
 
440
        for(i=0;i < smime_current_pref_index && strong_mapi < 0;i++)
 
441
        {
 
442
            if (smime_prefs[i] == SMIME_FORTEZZA)
 
443
                strong_mapi = smime_mapi_by_cipher(SMIME_FORTEZZA);
 
444
        }
 
445
    }
 
446
 
 
447
    if (strong_mapi == -1)
 
448
        strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
 
449
 
 
450
    PORT_Assert (strong_mapi >= 0);
 
451
 
 
452
    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
 
453
        SECItem *profile;
 
454
        smime_capability **caps;
 
455
        int capi, pref;
 
456
        SECStatus dstat;
 
457
 
 
458
        pref = smime_symmetric_count;
 
459
        profile = CERT_FindSMimeProfile (rcerts[rcount]);
 
460
        if (profile != NULL && profile->data != NULL && profile->len > 0) {
 
461
            caps = NULL;
 
462
            dstat = SEC_QuickDERDecodeItem (poolp, &caps,
 
463
                                        smime_capabilities_template,
 
464
                                        profile);
 
465
            if (dstat == SECSuccess && caps != NULL) {
 
466
                for (capi = 0; caps[capi] != NULL; capi++) {
 
467
                    smime_fill_capability (caps[capi]);
 
468
                    mapi = smime_mapi_by_cipher (caps[capi]->cipher);
 
469
                    if (mapi >= 0) {
 
470
                        cipher_abilities[mapi]++;
 
471
                        cipher_votes[mapi] += pref;
 
472
                        --pref;
 
473
                    }
 
474
                }
 
475
            }
 
476
        } else {
 
477
            SECKEYPublicKey *key;
 
478
            unsigned int pklen_bits;
 
479
 
 
480
            /*
 
481
             * XXX This is probably only good for RSA keys.  What I would
 
482
             * really like is a function to just say;  Is the public key in
 
483
             * this cert an export-length key?  Then I would not have to
 
484
             * know things like the value 512, or the kind of key, or what
 
485
             * a subjectPublicKeyInfo is, etc.
 
486
             */
 
487
            key = CERT_ExtractPublicKey (rcerts[rcount]);
 
488
            if (key != NULL) {
 
489
                pklen_bits = SECKEY_PublicKeyStrength (key) * 8;
 
490
                SECKEY_DestroyPublicKey (key);
 
491
 
 
492
                if (pklen_bits > 512) {
 
493
                    cipher_abilities[strong_mapi]++;
 
494
                    cipher_votes[strong_mapi] += pref;
 
495
                }
 
496
            }
 
497
        }
 
498
        if (profile != NULL)
 
499
            SECITEM_FreeItem (profile, PR_TRUE);
 
500
    }
 
501
 
 
502
    max = 0;
 
503
    for (mapi = 0; mapi < smime_symmetric_count; mapi++) {
 
504
        if (cipher_abilities[mapi] != rcount)
 
505
            continue;
 
506
        if (! smime_cipher_allowed (smime_cipher_maps[mapi].cipher))
 
507
            continue;
 
508
        if (!isFortezza  && (smime_cipher_maps[mapi].cipher == SMIME_FORTEZZA))
 
509
                continue;
 
510
        if (cipher_votes[mapi] > max) {
 
511
            chosen_cipher = smime_cipher_maps[mapi].cipher;
 
512
            max = cipher_votes[mapi];
 
513
        } /* XXX else if a tie, let scert break it? */
 
514
    }
 
515
 
 
516
done:
 
517
    if (poolp != NULL)
 
518
        PORT_FreeArena (poolp, PR_FALSE);
 
519
 
 
520
    return chosen_cipher;
 
521
}
 
522
 
 
523
 
 
524
/*
 
525
 * XXX This is a hack for now to satisfy our current interface.
 
526
 * Eventually, with more parameters needing to be specified, just
 
527
 * looking up the keysize is not going to be sufficient.
 
528
 */
 
529
static int
 
530
smime_keysize_by_cipher (unsigned long which)
 
531
{
 
532
    int keysize;
 
533
 
 
534
    switch (which) {
 
535
      case SMIME_RC2_CBC_40:
 
536
        keysize = 40;
 
537
        break;
 
538
      case SMIME_RC2_CBC_64:
 
539
        keysize = 64;
 
540
        break;
 
541
      case SMIME_RC2_CBC_128:
 
542
        keysize = 128;
 
543
        break;
 
544
#ifdef SMIME_DOES_RC5
 
545
      case SMIME_RC5PAD_64_16_40:
 
546
      case SMIME_RC5PAD_64_16_64:
 
547
      case SMIME_RC5PAD_64_16_128:
 
548
        /* XXX See comment above; keysize is not enough... */
 
549
        PORT_Assert (0);
 
550
        PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
 
551
        keysize = -1;
 
552
        break;
 
553
#endif
 
554
      case SMIME_DES_CBC_56:
 
555
      case SMIME_DES_EDE3_168:
 
556
      case SMIME_FORTEZZA:
 
557
        /*
 
558
         * These are special; since the key size is fixed, we actually
 
559
         * want to *avoid* specifying a key size.
 
560
         */
 
561
        keysize = 0;
 
562
        break;
 
563
      default:
 
564
        keysize = -1;
 
565
        break;
 
566
    }
 
567
 
 
568
    return keysize;
 
569
}
 
570
 
 
571
 
 
572
/*
 
573
 * Start an S/MIME encrypting context.
 
574
 *
 
575
 * "scert" is the cert for the sender.  It will be checked for validity.
 
576
 * "rcerts" are the certs for the recipients.  They will also be checked.
 
577
 *
 
578
 * "certdb" is the cert database to use for verifying the certs.
 
579
 * It can be NULL if a default database is available (like in the client).
 
580
 *
 
581
 * This function already does all of the stuff specific to S/MIME protocol
 
582
 * and local policy; the return value just needs to be passed to
 
583
 * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
 
584
 * and finally to SEC_PKCS7DestroyContentInfo().
 
585
 *
 
586
 * An error results in a return value of NULL and an error set.
 
587
 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
 
588
 */
 
589
SEC_PKCS7ContentInfo *
 
590
SECMIME_CreateEncrypted(CERTCertificate *scert,
 
591
                        CERTCertificate **rcerts,
 
592
                        CERTCertDBHandle *certdb,
 
593
                        SECKEYGetPasswordKey pwfn,
 
594
                        void *pwfn_arg)
 
595
{
 
596
    SEC_PKCS7ContentInfo *cinfo;
 
597
    long cipher;
 
598
    SECOidTag encalg;
 
599
    int keysize;
 
600
    int mapi, rci;
 
601
 
 
602
    cipher = smime_choose_cipher (scert, rcerts);
 
603
    if (cipher < 0)
 
604
        return NULL;
 
605
 
 
606
    mapi = smime_mapi_by_cipher (cipher);
 
607
    if (mapi < 0)
 
608
        return NULL;
 
609
 
 
610
    /*
 
611
     * XXX This is stretching it -- CreateEnvelopedData should probably
 
612
     * take a cipher itself of some sort, because we cannot know what the
 
613
     * future will bring in terms of parameters for each type of algorithm.
 
614
     * For example, just an algorithm and keysize is *not* sufficient to
 
615
     * fully specify the usage of RC5 (which also needs to know rounds and
 
616
     * block size).  Work this out into a better API!
 
617
     */
 
618
    encalg = smime_cipher_maps[mapi].algtag;
 
619
    keysize = smime_keysize_by_cipher (cipher);
 
620
    if (keysize < 0)
 
621
        return NULL;
 
622
 
 
623
    cinfo = SEC_PKCS7CreateEnvelopedData (scert, certUsageEmailRecipient,
 
624
                                          certdb, encalg, keysize,
 
625
                                          pwfn, pwfn_arg);
 
626
    if (cinfo == NULL)
 
627
        return NULL;
 
628
 
 
629
    for (rci = 0; rcerts[rci] != NULL; rci++) {
 
630
        if (rcerts[rci] == scert)
 
631
            continue;
 
632
        if (SEC_PKCS7AddRecipient (cinfo, rcerts[rci], certUsageEmailRecipient,
 
633
                                   NULL) != SECSuccess) {
 
634
            SEC_PKCS7DestroyContentInfo (cinfo);
 
635
            return NULL;
 
636
        }
 
637
    }
 
638
 
 
639
    return cinfo;
 
640
}
 
641
 
 
642
 
 
643
static smime_capability **smime_capabilities;
 
644
static SECItem *smime_encoded_caps;
 
645
static PRBool lastUsedFortezza;
 
646
 
 
647
 
 
648
static SECStatus
 
649
smime_init_caps (PRBool isFortezza)
 
650
{
 
651
    smime_capability *cap;
 
652
    smime_cipher_map *map;
 
653
    SECOidData *oiddata;
 
654
    SECStatus rv;
 
655
    int i, capIndex;
 
656
 
 
657
    if (smime_encoded_caps != NULL 
 
658
        && (! smime_prefs_changed) 
 
659
        && lastUsedFortezza == isFortezza)
 
660
        return SECSuccess;
 
661
 
 
662
    if (smime_encoded_caps != NULL) {
 
663
        SECITEM_FreeItem (smime_encoded_caps, PR_TRUE);
 
664
        smime_encoded_caps = NULL;
 
665
    }
 
666
 
 
667
    if (smime_capabilities == NULL) {
 
668
        smime_capabilities = (smime_capability**)PORT_ZAlloc (
 
669
                                          (smime_symmetric_count + 1)
 
670
                                          * sizeof(smime_capability *));
 
671
        if (smime_capabilities == NULL)
 
672
            return SECFailure;
 
673
    }
 
674
 
 
675
    rv = SECFailure;
 
676
 
 
677
    /* 
 
678
       The process of creating the encoded PKCS7 cipher capability list
 
679
       involves two basic steps: 
 
680
 
 
681
       (a) Convert our internal representation of cipher preferences 
 
682
           (smime_prefs) into an array containing cipher OIDs and 
 
683
           parameter data (smime_capabilities). This step is
 
684
           performed here.
 
685
 
 
686
       (b) Encode, using ASN.1, the cipher information in 
 
687
           smime_capabilities, leaving the encoded result in 
 
688
           smime_encoded_caps.
 
689
 
 
690
       (In the process of performing (a), Lisa put in some optimizations
 
691
       which allow us to avoid needlessly re-populating elements in 
 
692
       smime_capabilities as we walk through smime_prefs.)
 
693
 
 
694
       We want to use separate loop variables for smime_prefs and
 
695
       smime_capabilities because in the case where the Skipjack cipher 
 
696
       is turned on in the prefs, but where we don't want to include 
 
697
       Skipjack in the encoded capabilities (presumably due to using a 
 
698
       non-fortezza cert when sending a message), we want to avoid creating
 
699
       an empty element in smime_capabilities. This would otherwise cause 
 
700
       the encoding step to produce an empty set, since Skipjack happens 
 
701
       to be the first cipher in smime_prefs, if it is turned on.
 
702
    */
 
703
    for (i = 0, capIndex = 0; i < smime_current_pref_index; i++, capIndex++) {
 
704
        int mapi;
 
705
 
 
706
        /* Get the next cipher preference in smime_prefs. */
 
707
        mapi = smime_mapi_by_cipher (smime_prefs[i]);
 
708
        if (mapi < 0)
 
709
            break;
 
710
 
 
711
        /* Find the corresponding entry in the cipher map. */
 
712
        PORT_Assert (mapi < smime_symmetric_count);
 
713
        map = &(smime_cipher_maps[mapi]);
 
714
 
 
715
        /* If we're using a non-Fortezza cert, only advertise non-Fortezza
 
716
           capabilities. (We advertise all capabilities if we have a 
 
717
           Fortezza cert.) */
 
718
        if ((!isFortezza) && (map->cipher == SMIME_FORTEZZA))
 
719
        {
 
720
            capIndex--; /* we want to visit the same caps index entry next time */
 
721
            continue;
 
722
        }
 
723
 
 
724
        /*
 
725
         * Convert the next preference found in smime_prefs into an
 
726
         * smime_capability.
 
727
         */
 
728
 
 
729
        cap = smime_capabilities[capIndex];
 
730
        if (cap == NULL) {
 
731
            cap = (smime_capability*)PORT_ZAlloc (sizeof(smime_capability));
 
732
            if (cap == NULL)
 
733
                break;
 
734
            smime_capabilities[capIndex] = cap;
 
735
        } else if (cap->cipher == smime_prefs[i]) {
 
736
            continue;           /* no change to this one */
 
737
        }
 
738
 
 
739
        cap->capIDTag = map->algtag;
 
740
        oiddata = SECOID_FindOIDByTag (map->algtag);
 
741
        if (oiddata == NULL)
 
742
            break;
 
743
 
 
744
        if (cap->capabilityID.data != NULL) {
 
745
            SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
 
746
            cap->capabilityID.data = NULL;
 
747
            cap->capabilityID.len = 0;
 
748
        }
 
749
 
 
750
        rv = SECITEM_CopyItem (NULL, &(cap->capabilityID), &(oiddata->oid));
 
751
        if (rv != SECSuccess)
 
752
            break;
 
753
 
 
754
        if (map->parms == NULL) {
 
755
            cap->parameters.data = NULL;
 
756
            cap->parameters.len = 0;
 
757
        } else {
 
758
            cap->parameters.data = map->parms->data;
 
759
            cap->parameters.len = map->parms->len;
 
760
        }
 
761
 
 
762
        cap->cipher = smime_prefs[i];
 
763
    }
 
764
 
 
765
    if (i != smime_current_pref_index)
 
766
        return rv;
 
767
 
 
768
    while (capIndex < smime_symmetric_count) {
 
769
        cap = smime_capabilities[capIndex];
 
770
        if (cap != NULL) {
 
771
            SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
 
772
            PORT_Free (cap);
 
773
        }
 
774
        smime_capabilities[capIndex] = NULL;
 
775
        capIndex++;
 
776
    }
 
777
    smime_capabilities[capIndex] = NULL;
 
778
 
 
779
    smime_encoded_caps = SEC_ASN1EncodeItem (NULL, NULL, &smime_capabilities,
 
780
                                             smime_capabilities_template);
 
781
    if (smime_encoded_caps == NULL)
 
782
        return SECFailure;
 
783
 
 
784
    lastUsedFortezza = isFortezza;
 
785
 
 
786
    return SECSuccess;
 
787
}
 
788
 
 
789
 
 
790
static SECStatus
 
791
smime_add_profile (CERTCertificate *cert, SEC_PKCS7ContentInfo *cinfo)
 
792
{
 
793
    PRBool isFortezza = PR_FALSE;
 
794
 
 
795
    PORT_Assert (smime_prefs_complete);
 
796
    if (! smime_prefs_complete)
 
797
        return SECFailure;
 
798
 
 
799
    /* See if the sender's cert specifies Fortezza key exchange. */
 
800
    if (cert != NULL)
 
801
        isFortezza = PK11_FortezzaHasKEA(cert);
 
802
 
 
803
    /* For that matter, if capabilities haven't been initialized yet,
 
804
       do so now. */
 
805
    if (isFortezza != lastUsedFortezza || smime_encoded_caps == NULL || smime_prefs_changed) {
 
806
        SECStatus rv;
 
807
 
 
808
        rv = smime_init_caps(isFortezza);
 
809
        if (rv != SECSuccess)
 
810
            return rv;
 
811
 
 
812
        PORT_Assert (smime_encoded_caps != NULL);
 
813
    }
 
814
 
 
815
    return SEC_PKCS7AddSignedAttribute (cinfo, SEC_OID_PKCS9_SMIME_CAPABILITIES,
 
816
                                        smime_encoded_caps);
 
817
}
 
818
 
 
819
 
 
820
/*
 
821
 * Start an S/MIME signing context.
 
822
 *
 
823
 * "scert" is the cert that will be used to sign the data.  It will be
 
824
 * checked for validity.
 
825
 *
 
826
 * "ecert" is the signer's encryption cert.  If it is different from
 
827
 * scert, then it will be included in the signed message so that the
 
828
 * recipient can save it for future encryptions.
 
829
 *
 
830
 * "certdb" is the cert database to use for verifying the cert.
 
831
 * It can be NULL if a default database is available (like in the client).
 
832
 * 
 
833
 * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
 
834
 * XXX There should be SECMIME functions for hashing, or the hashing should
 
835
 * be built into this interface, which we would like because we would
 
836
 * support more smartcards that way, and then this argument should go away.)
 
837
 *
 
838
 * "digest" is the actual digest of the data.  It must be provided in
 
839
 * the case of detached data or NULL if the content will be included.
 
840
 *
 
841
 * This function already does all of the stuff specific to S/MIME protocol
 
842
 * and local policy; the return value just needs to be passed to
 
843
 * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
 
844
 * and finally to SEC_PKCS7DestroyContentInfo().
 
845
 *
 
846
 * An error results in a return value of NULL and an error set.
 
847
 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
 
848
 */
 
849
 
 
850
SEC_PKCS7ContentInfo *
 
851
SECMIME_CreateSigned (CERTCertificate *scert,
 
852
                      CERTCertificate *ecert,
 
853
                      CERTCertDBHandle *certdb,
 
854
                      SECOidTag digestalg,
 
855
                      SECItem *digest,
 
856
                      SECKEYGetPasswordKey pwfn,
 
857
                      void *pwfn_arg)
 
858
{
 
859
    SEC_PKCS7ContentInfo *cinfo;
 
860
    SECStatus rv;
 
861
 
 
862
    /* See note in header comment above about digestalg. */
 
863
    /* Doesn't explain this. PORT_Assert (digestalg == SEC_OID_SHA1); */
 
864
 
 
865
    cinfo = SEC_PKCS7CreateSignedData (scert, certUsageEmailSigner,
 
866
                                       certdb, digestalg, digest,
 
867
                                       pwfn, pwfn_arg);
 
868
    if (cinfo == NULL)
 
869
        return NULL;
 
870
 
 
871
    if (SEC_PKCS7IncludeCertChain (cinfo, NULL) != SECSuccess) {
 
872
        SEC_PKCS7DestroyContentInfo (cinfo);
 
873
        return NULL;
 
874
    }
 
875
 
 
876
    /* if the encryption cert and the signing cert differ, then include
 
877
     * the encryption cert too.
 
878
     */
 
879
    /* it is ok to compare the pointers since we ref count, and the same
 
880
     * cert will always have the same pointer
 
881
     */
 
882
    if ( ( ecert != NULL ) && ( ecert != scert ) ) {
 
883
        rv = SEC_PKCS7AddCertificate(cinfo, ecert);
 
884
        if ( rv != SECSuccess ) {
 
885
            SEC_PKCS7DestroyContentInfo (cinfo);
 
886
            return NULL;
 
887
        }
 
888
    }
 
889
    /*
 
890
     * Add the signing time.  But if it fails for some reason,
 
891
     * may as well not give up altogether -- just assert.
 
892
     */
 
893
    rv = SEC_PKCS7AddSigningTime (cinfo);
 
894
    PORT_Assert (rv == SECSuccess);
 
895
 
 
896
    /*
 
897
     * Add the email profile.  Again, if it fails for some reason,
 
898
     * may as well not give up altogether -- just assert.
 
899
     */
 
900
    rv = smime_add_profile (ecert, cinfo);
 
901
    PORT_Assert (rv == SECSuccess);
 
902
 
 
903
    return cinfo;
 
904
}