~ubuntu-branches/ubuntu/quantal/nss/quantal-updates

« back to all changes in this revision

Viewing changes to nss/lib/smime/smimeutil.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2013-11-14 14:58:07 UTC
  • mfrom: (1.1.19)
  • Revision ID: package-import@ubuntu.com-20131114145807-vj6v4erz8xj6kwz3
Tags: 3.15.3-0ubuntu0.12.10.1
* SECURITY UPDATE: New upstream release to fix multiple security issues
  and add TLSv1.2 support.
  - CVE-2013-1739
  - CVE-2013-1741
  - CVE-2013-5605
  - CVE-2013-5606
* Adjusted packaging for 3.15.3:
  - debian/patches/*: refreshed.
  - debian/patches/lower-dhe-priority.patch: removed, no longer needed,
    was a workaround for an old version of firefox.
  - debian/libnss3.symbols: added new symbols.
  - debian/rules: updated for new source layout.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This Source Code Form is subject to the terms of the Mozilla Public
 
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
4
 
 
5
/*
 
6
 * Stuff specific to S/MIME policy and interoperability.
 
7
 */
 
8
 
 
9
#include "secmime.h"
 
10
#include "secoid.h"
 
11
#include "pk11func.h"
 
12
#include "ciferfam.h"   /* for CIPHER_FAMILY symbols */
 
13
#include "secasn1.h"
 
14
#include "secitem.h"
 
15
#include "cert.h"
 
16
#include "key.h"
 
17
#include "secerr.h"
 
18
#include "cms.h"
 
19
#include "nss.h"
 
20
 
 
21
SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
 
22
SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
 
23
SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate)
 
24
 
 
25
/* various integer's ASN.1 encoding */
 
26
static unsigned char asn1_int40[] = { SEC_ASN1_INTEGER, 0x01, 0x28 };
 
27
static unsigned char asn1_int64[] = { SEC_ASN1_INTEGER, 0x01, 0x40 };
 
28
static unsigned char asn1_int128[] = { SEC_ASN1_INTEGER, 0x02, 0x00, 0x80 };
 
29
 
 
30
/* RC2 algorithm parameters (used in smime_cipher_map) */
 
31
static SECItem param_int40 = { siBuffer, asn1_int40, sizeof(asn1_int40) };
 
32
static SECItem param_int64 = { siBuffer, asn1_int64, sizeof(asn1_int64) };
 
33
static SECItem param_int128 = { siBuffer, asn1_int128, sizeof(asn1_int128) };
 
34
 
 
35
/*
 
36
 * XXX Would like the "parameters" field to be a SECItem *, but the
 
37
 * encoder is having trouble with optional pointers to an ANY.  Maybe
 
38
 * once that is fixed, can change this back...
 
39
 */
 
40
typedef struct {
 
41
    SECItem capabilityID;
 
42
    SECItem parameters;
 
43
    long cipher;                /* optimization */
 
44
} NSSSMIMECapability;
 
45
 
 
46
static const SEC_ASN1Template NSSSMIMECapabilityTemplate[] = {
 
47
    { SEC_ASN1_SEQUENCE,
 
48
          0, NULL, sizeof(NSSSMIMECapability) },
 
49
    { SEC_ASN1_OBJECT_ID,
 
50
          offsetof(NSSSMIMECapability,capabilityID), },
 
51
    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
 
52
          offsetof(NSSSMIMECapability,parameters), },
 
53
    { 0, }
 
54
};
 
55
 
 
56
static const SEC_ASN1Template NSSSMIMECapabilitiesTemplate[] = {
 
57
    { SEC_ASN1_SEQUENCE_OF, 0, NSSSMIMECapabilityTemplate }
 
58
};
 
59
 
 
60
/*
 
61
 * NSSSMIMEEncryptionKeyPreference - if we find one of these, it needs to prompt us
 
62
 *  to store this and only this certificate permanently for the sender email address.
 
63
 */
 
64
typedef enum {
 
65
    NSSSMIMEEncryptionKeyPref_IssuerSN,
 
66
    NSSSMIMEEncryptionKeyPref_RKeyID,
 
67
    NSSSMIMEEncryptionKeyPref_SubjectKeyID
 
68
} NSSSMIMEEncryptionKeyPrefSelector;
 
69
 
 
70
typedef struct {
 
71
    NSSSMIMEEncryptionKeyPrefSelector selector;
 
72
    union {
 
73
        CERTIssuerAndSN                 *issuerAndSN;
 
74
        NSSCMSRecipientKeyIdentifier    *recipientKeyID;
 
75
        SECItem                         *subjectKeyID;
 
76
    } id;
 
77
} NSSSMIMEEncryptionKeyPreference;
 
78
 
 
79
extern const SEC_ASN1Template NSSCMSRecipientKeyIdentifierTemplate[];
 
80
 
 
81
static const SEC_ASN1Template smime_encryptionkeypref_template[] = {
 
82
    { SEC_ASN1_CHOICE,
 
83
          offsetof(NSSSMIMEEncryptionKeyPreference,selector), NULL,
 
84
          sizeof(NSSSMIMEEncryptionKeyPreference) },
 
85
    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0
 
86
          | SEC_ASN1_CONSTRUCTED,
 
87
          offsetof(NSSSMIMEEncryptionKeyPreference,id.issuerAndSN),
 
88
          SEC_ASN1_SUB(CERT_IssuerAndSNTemplate),
 
89
          NSSSMIMEEncryptionKeyPref_IssuerSN },
 
90
    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 1
 
91
          | SEC_ASN1_CONSTRUCTED,
 
92
          offsetof(NSSSMIMEEncryptionKeyPreference,id.recipientKeyID),
 
93
          NSSCMSRecipientKeyIdentifierTemplate,
 
94
          NSSSMIMEEncryptionKeyPref_RKeyID },
 
95
    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2
 
96
          | SEC_ASN1_CONSTRUCTED,
 
97
          offsetof(NSSSMIMEEncryptionKeyPreference,id.subjectKeyID),
 
98
          SEC_ASN1_SUB(SEC_OctetStringTemplate),
 
99
          NSSSMIMEEncryptionKeyPref_SubjectKeyID },
 
100
    { 0, }
 
101
};
 
102
 
 
103
/* smime_cipher_map - map of SMIME symmetric "ciphers" to algtag & parameters */
 
104
typedef struct {
 
105
    unsigned long cipher;
 
106
    SECOidTag algtag;
 
107
    SECItem *parms;
 
108
    PRBool enabled;     /* in the user's preferences */
 
109
    PRBool allowed;     /* per export policy */
 
110
} smime_cipher_map_entry;
 
111
 
 
112
/* global: list of supported SMIME symmetric ciphers, ordered roughly by increasing strength */
 
113
static smime_cipher_map_entry smime_cipher_map[] = {
 
114
/*    cipher                    algtag                  parms           enabled  allowed */
 
115
/*    ---------------------------------------------------------------------------------- */
 
116
    { SMIME_RC2_CBC_40,         SEC_OID_RC2_CBC,        &param_int40,   PR_TRUE, PR_TRUE },
 
117
    { SMIME_DES_CBC_56,         SEC_OID_DES_CBC,        NULL,           PR_TRUE, PR_TRUE },
 
118
    { SMIME_RC2_CBC_64,         SEC_OID_RC2_CBC,        &param_int64,   PR_TRUE, PR_TRUE },
 
119
    { SMIME_RC2_CBC_128,        SEC_OID_RC2_CBC,        &param_int128,  PR_TRUE, PR_TRUE },
 
120
    { SMIME_DES_EDE3_168,       SEC_OID_DES_EDE3_CBC,   NULL,           PR_TRUE, PR_TRUE },
 
121
    { SMIME_AES_CBC_128,        SEC_OID_AES_128_CBC,    NULL,           PR_TRUE, PR_TRUE },
 
122
    { SMIME_AES_CBC_256,        SEC_OID_AES_256_CBC,    NULL,           PR_TRUE, PR_TRUE }
 
123
};
 
124
static const int smime_cipher_map_count = sizeof(smime_cipher_map) / sizeof(smime_cipher_map_entry);
 
125
 
 
126
/*
 
127
 * smime_mapi_by_cipher - find index into smime_cipher_map by cipher
 
128
 */
 
129
static int
 
130
smime_mapi_by_cipher(unsigned long cipher)
 
131
{
 
132
    int i;
 
133
 
 
134
    for (i = 0; i < smime_cipher_map_count; i++) {
 
135
        if (smime_cipher_map[i].cipher == cipher)
 
136
            return i;   /* bingo */
 
137
    }
 
138
    return -1;          /* should not happen if we're consistent, right? */
 
139
}
 
140
 
 
141
/*
 
142
 * NSS_SMIME_EnableCipher - this function locally records the user's preference
 
143
 */
 
144
SECStatus 
 
145
NSS_SMIMEUtil_EnableCipher(unsigned long which, PRBool on)
 
146
{
 
147
    unsigned long mask;
 
148
    int mapi;
 
149
 
 
150
    mask = which & CIPHER_FAMILYID_MASK;
 
151
 
 
152
    PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
 
153
    if (mask != CIPHER_FAMILYID_SMIME)
 
154
        /* XXX set an error! */
 
155
        return SECFailure;
 
156
 
 
157
    mapi = smime_mapi_by_cipher(which);
 
158
    if (mapi < 0)
 
159
        /* XXX set an error */
 
160
        return SECFailure;
 
161
 
 
162
    /* do we try to turn on a forbidden cipher? */
 
163
    if (!smime_cipher_map[mapi].allowed && on) {
 
164
        PORT_SetError (SEC_ERROR_BAD_EXPORT_ALGORITHM);
 
165
        return SECFailure;
 
166
    }
 
167
 
 
168
    if (smime_cipher_map[mapi].enabled != on)
 
169
        smime_cipher_map[mapi].enabled = on;
 
170
 
 
171
    return SECSuccess;
 
172
}
 
173
 
 
174
 
 
175
/*
 
176
 * this function locally records the export policy
 
177
 */
 
178
SECStatus 
 
179
NSS_SMIMEUtil_AllowCipher(unsigned long which, PRBool on)
 
180
{
 
181
    unsigned long mask;
 
182
    int mapi;
 
183
 
 
184
    mask = which & CIPHER_FAMILYID_MASK;
 
185
 
 
186
    PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
 
187
    if (mask != CIPHER_FAMILYID_SMIME)
 
188
        /* XXX set an error! */
 
189
        return SECFailure;
 
190
 
 
191
    mapi = smime_mapi_by_cipher(which);
 
192
    if (mapi < 0)
 
193
        /* XXX set an error */
 
194
        return SECFailure;
 
195
 
 
196
    if (smime_cipher_map[mapi].allowed != on)
 
197
        smime_cipher_map[mapi].allowed = on;
 
198
 
 
199
    return SECSuccess;
 
200
}
 
201
 
 
202
/*
 
203
 * Based on the given algorithm (including its parameters, in some cases!)
 
204
 * and the given key (may or may not be inspected, depending on the
 
205
 * algorithm), find the appropriate policy algorithm specification
 
206
 * and return it.  If no match can be made, -1 is returned.
 
207
 */
 
208
static SECStatus
 
209
nss_smime_get_cipher_for_alg_and_key(SECAlgorithmID *algid, PK11SymKey *key, unsigned long *cipher)
 
210
{
 
211
    SECOidTag algtag;
 
212
    unsigned int keylen_bits;
 
213
    unsigned long c;
 
214
 
 
215
    algtag = SECOID_GetAlgorithmTag(algid);
 
216
    switch (algtag) {
 
217
    case SEC_OID_RC2_CBC:
 
218
        keylen_bits = PK11_GetKeyStrength(key, algid);
 
219
        switch (keylen_bits) {
 
220
        case 40:
 
221
            c = SMIME_RC2_CBC_40;
 
222
            break;
 
223
        case 64:
 
224
            c = SMIME_RC2_CBC_64;
 
225
            break;
 
226
        case 128:
 
227
            c = SMIME_RC2_CBC_128;
 
228
            break;
 
229
        default:
 
230
            return SECFailure;
 
231
        }
 
232
        break;
 
233
    case SEC_OID_DES_CBC:
 
234
        c = SMIME_DES_CBC_56;
 
235
        break;
 
236
    case SEC_OID_DES_EDE3_CBC:
 
237
        c = SMIME_DES_EDE3_168;
 
238
        break;
 
239
    case SEC_OID_AES_128_CBC:
 
240
        c = SMIME_AES_CBC_128;
 
241
        break;
 
242
    case SEC_OID_AES_256_CBC:
 
243
        c = SMIME_AES_CBC_256;
 
244
        break;
 
245
    default:
 
246
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
 
247
        return SECFailure;
 
248
    }
 
249
    *cipher = c;
 
250
    return SECSuccess;
 
251
}
 
252
 
 
253
static PRBool
 
254
nss_smime_cipher_allowed(unsigned long which)
 
255
{
 
256
    int mapi;
 
257
 
 
258
    mapi = smime_mapi_by_cipher(which);
 
259
    if (mapi < 0)
 
260
        return PR_FALSE;
 
261
    return smime_cipher_map[mapi].allowed;
 
262
}
 
263
 
 
264
PRBool
 
265
NSS_SMIMEUtil_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key)
 
266
{
 
267
    unsigned long which;
 
268
 
 
269
    if (nss_smime_get_cipher_for_alg_and_key(algid, key, &which) != SECSuccess)
 
270
        return PR_FALSE;
 
271
 
 
272
    return nss_smime_cipher_allowed(which);
 
273
}
 
274
 
 
275
 
 
276
/*
 
277
 * NSS_SMIME_EncryptionPossible - check if any encryption is allowed
 
278
 *
 
279
 * This tells whether or not *any* S/MIME encryption can be done,
 
280
 * according to policy.  Callers may use this to do nicer user interface
 
281
 * (say, greying out a checkbox so a user does not even try to encrypt
 
282
 * a message when they are not allowed to) or for any reason they want
 
283
 * to check whether S/MIME encryption (or decryption, for that matter)
 
284
 * may be done.
 
285
 *
 
286
 * It takes no arguments.  The return value is a simple boolean:
 
287
 *   PR_TRUE means encryption (or decryption) is *possible*
 
288
 *      (but may still fail due to other reasons, like because we cannot
 
289
 *      find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
 
290
 *   PR_FALSE means encryption (or decryption) is not permitted
 
291
 *
 
292
 * There are no errors from this routine.
 
293
 */
 
294
PRBool
 
295
NSS_SMIMEUtil_EncryptionPossible(void)
 
296
{
 
297
    int i;
 
298
 
 
299
    for (i = 0; i < smime_cipher_map_count; i++) {
 
300
        if (smime_cipher_map[i].allowed)
 
301
            return PR_TRUE;
 
302
    }
 
303
    return PR_FALSE;
 
304
}
 
305
 
 
306
 
 
307
static int
 
308
nss_SMIME_FindCipherForSMIMECap(NSSSMIMECapability *cap)
 
309
{
 
310
    int i;
 
311
    SECOidTag capIDTag;
 
312
 
 
313
    /* we need the OIDTag here */
 
314
    capIDTag = SECOID_FindOIDTag(&(cap->capabilityID));
 
315
 
 
316
    /* go over all the SMIME ciphers we know and see if we find a match */
 
317
    for (i = 0; i < smime_cipher_map_count; i++) {
 
318
        if (smime_cipher_map[i].algtag != capIDTag)
 
319
            continue;
 
320
        /*
 
321
         * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing
 
322
         * 2 NULLs as equal and NULL and non-NULL as not equal), we could
 
323
         * use that here instead of all of the following comparison code.
 
324
         */
 
325
        if (!smime_cipher_map[i].parms) { 
 
326
            if (!cap->parameters.data || !cap->parameters.len)
 
327
                break;  /* both empty: bingo */
 
328
            if (cap->parameters.len     == 2  &&
 
329
                cap->parameters.data[0] == SEC_ASN1_NULL &&
 
330
                cap->parameters.data[1] == 0) 
 
331
                break;  /* DER NULL == NULL, bingo */
 
332
        } else if (cap->parameters.data != NULL && 
 
333
            cap->parameters.len == smime_cipher_map[i].parms->len &&
 
334
            PORT_Memcmp (cap->parameters.data, smime_cipher_map[i].parms->data,
 
335
                             cap->parameters.len) == 0)
 
336
        {
 
337
            break;      /* both not empty, same length & equal content: bingo */
 
338
        }
 
339
    }
 
340
 
 
341
    if (i == smime_cipher_map_count)
 
342
        return 0;                               /* no match found */
 
343
    return smime_cipher_map[i].cipher;  /* match found, point to cipher */
 
344
}
 
345
 
 
346
/*
 
347
 * smime_choose_cipher - choose a cipher that works for all the recipients
 
348
 *
 
349
 * "scert"  - sender's certificate
 
350
 * "rcerts" - recipient's certificates
 
351
 */
 
352
static long
 
353
smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts)
 
354
{
 
355
    PLArenaPool *poolp;
 
356
    long cipher;
 
357
    long chosen_cipher;
 
358
    int *cipher_abilities;
 
359
    int *cipher_votes;
 
360
    int weak_mapi;
 
361
    int strong_mapi;
 
362
    int aes128_mapi;
 
363
    int aes256_mapi;
 
364
    int rcount, mapi, max, i;
 
365
 
 
366
    chosen_cipher = SMIME_RC2_CBC_40;           /* the default, LCD */
 
367
    weak_mapi = smime_mapi_by_cipher(chosen_cipher);
 
368
    aes128_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_128);
 
369
    aes256_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_256);
 
370
 
 
371
    poolp = PORT_NewArena (1024);               /* XXX what is right value? */
 
372
    if (poolp == NULL)
 
373
        goto done;
 
374
 
 
375
    cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
 
376
    cipher_votes     = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
 
377
    if (cipher_votes == NULL || cipher_abilities == NULL)
 
378
        goto done;
 
379
 
 
380
    /* Make triple-DES the strong cipher. */
 
381
    strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
 
382
 
 
383
    /* walk all the recipient's certs */
 
384
    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
 
385
        SECItem *profile;
 
386
        NSSSMIMECapability **caps;
 
387
        int pref;
 
388
 
 
389
        /* the first cipher that matches in the user's SMIME profile gets
 
390
         * "smime_cipher_map_count" votes; the next one gets "smime_cipher_map_count" - 1
 
391
         * and so on. If every cipher matches, the last one gets 1 (one) vote */
 
392
        pref = smime_cipher_map_count;
 
393
 
 
394
        /* find recipient's SMIME profile */
 
395
        profile = CERT_FindSMimeProfile(rcerts[rcount]);
 
396
 
 
397
        if (profile != NULL && profile->data != NULL && profile->len > 0) {
 
398
            /* we have a profile (still DER-encoded) */
 
399
            caps = NULL;
 
400
            /* decode it */
 
401
            if (SEC_QuickDERDecodeItem(poolp, &caps,
 
402
                    NSSSMIMECapabilitiesTemplate, profile) == SECSuccess &&
 
403
                    caps != NULL)
 
404
            {
 
405
                /* walk the SMIME capabilities for this recipient */
 
406
                for (i = 0; caps[i] != NULL; i++) {
 
407
                    cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]);
 
408
                    mapi = smime_mapi_by_cipher(cipher);
 
409
                    if (mapi >= 0) {
 
410
                        /* found the cipher */
 
411
                        cipher_abilities[mapi]++;
 
412
                        cipher_votes[mapi] += pref;
 
413
                        --pref;
 
414
                    }
 
415
                }
 
416
            }
 
417
        } else {
 
418
            /* no profile found - so we can only assume that the user can do
 
419
             * the mandatory algorithms which are RC2-40 (weak crypto) and
 
420
             * 3DES (strong crypto), unless the user has an elliptic curve
 
421
             * key.  For elliptic curve keys, RFC 5753 mandates support
 
422
             * for AES 128 CBC. */
 
423
            SECKEYPublicKey *key;
 
424
            unsigned int pklen_bits;
 
425
            KeyType key_type;
 
426
 
 
427
            /*
 
428
             * if recipient's public key length is > 512, vote for a strong cipher
 
429
             * please not that the side effect of this is that if only one recipient
 
430
             * has an export-level public key, the strong cipher is disabled.
 
431
             *
 
432
             * XXX This is probably only good for RSA keys.  What I would
 
433
             * really like is a function to just say;  Is the public key in
 
434
             * this cert an export-length key?  Then I would not have to
 
435
             * know things like the value 512, or the kind of key, or what
 
436
             * a subjectPublicKeyInfo is, etc.
 
437
             */
 
438
            key = CERT_ExtractPublicKey(rcerts[rcount]);
 
439
            pklen_bits = 0;
 
440
            if (key != NULL) {
 
441
                pklen_bits = SECKEY_PublicKeyStrengthInBits (key);
 
442
                key_type = SECKEY_GetPublicKeyType(key);
 
443
                SECKEY_DestroyPublicKey (key);
 
444
            }
 
445
 
 
446
            if (key_type == ecKey) {
 
447
                /* While RFC 5753 mandates support for AES-128 CBC, should use
 
448
                 * AES 256 if user's key provides more than 128 bits of
 
449
                 * security strength so that symmetric key is not weak link. */
 
450
 
 
451
                /* RC2-40 is not compatible with elliptic curve keys. */
 
452
                chosen_cipher = SMIME_DES_EDE3_168;
 
453
                if (pklen_bits > 256) {
 
454
                    cipher_abilities[aes256_mapi]++;
 
455
                    cipher_votes[aes256_mapi] += pref;
 
456
                    pref--;
 
457
                }
 
458
                cipher_abilities[aes128_mapi]++;
 
459
                cipher_votes[aes128_mapi] += pref;
 
460
                pref--;
 
461
                cipher_abilities[strong_mapi]++;
 
462
                cipher_votes[strong_mapi] += pref;
 
463
                pref--;
 
464
            } else {
 
465
                if (pklen_bits > 512) {
 
466
                    /* cast votes for the strong algorithm */
 
467
                    cipher_abilities[strong_mapi]++;
 
468
                    cipher_votes[strong_mapi] += pref;
 
469
                    pref--;
 
470
                }
 
471
 
 
472
                /* always cast (possibly less) votes for the weak algorithm */
 
473
                cipher_abilities[weak_mapi]++;
 
474
                cipher_votes[weak_mapi] += pref;
 
475
            } 
 
476
        }
 
477
        if (profile != NULL)
 
478
            SECITEM_FreeItem(profile, PR_TRUE);
 
479
    }
 
480
 
 
481
    /* find cipher that is agreeable by all recipients and that has the most votes */
 
482
    max = 0;
 
483
    for (mapi = 0; mapi < smime_cipher_map_count; mapi++) {
 
484
        /* if not all of the recipients can do this, forget it */
 
485
        if (cipher_abilities[mapi] != rcount)
 
486
            continue;
 
487
        /* if cipher is not enabled or not allowed by policy, forget it */
 
488
        if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed)
 
489
            continue;
 
490
        /* now see if this one has more votes than the last best one */
 
491
        if (cipher_votes[mapi] >= max) {
 
492
            /* if equal number of votes, prefer the ones further down in the list */
 
493
            /* with the expectation that these are higher rated ciphers */
 
494
            chosen_cipher = smime_cipher_map[mapi].cipher;
 
495
            max = cipher_votes[mapi];
 
496
        }
 
497
    }
 
498
    /* if no common cipher was found, chosen_cipher stays at the default */
 
499
 
 
500
done:
 
501
    if (poolp != NULL)
 
502
        PORT_FreeArena (poolp, PR_FALSE);
 
503
 
 
504
    return chosen_cipher;
 
505
}
 
506
 
 
507
/*
 
508
 * XXX This is a hack for now to satisfy our current interface.
 
509
 * Eventually, with more parameters needing to be specified, just
 
510
 * looking up the keysize is not going to be sufficient.
 
511
 */
 
512
static int
 
513
smime_keysize_by_cipher (unsigned long which)
 
514
{
 
515
    int keysize;
 
516
 
 
517
    switch (which) {
 
518
      case SMIME_RC2_CBC_40:
 
519
        keysize = 40;
 
520
        break;
 
521
      case SMIME_RC2_CBC_64:
 
522
        keysize = 64;
 
523
        break;
 
524
      case SMIME_RC2_CBC_128:
 
525
      case SMIME_AES_CBC_128:
 
526
        keysize = 128;
 
527
        break;
 
528
      case SMIME_AES_CBC_256:
 
529
        keysize = 256;
 
530
        break;
 
531
      case SMIME_DES_CBC_56:
 
532
      case SMIME_DES_EDE3_168:
 
533
        /*
 
534
         * These are special; since the key size is fixed, we actually
 
535
         * want to *avoid* specifying a key size.
 
536
         */
 
537
        keysize = 0;
 
538
        break;
 
539
      default:
 
540
        keysize = -1;
 
541
        break;
 
542
    }
 
543
 
 
544
    return keysize;
 
545
}
 
546
 
 
547
/*
 
548
 * NSS_SMIMEUtil_FindBulkAlgForRecipients - find bulk algorithm suitable for all recipients
 
549
 *
 
550
 * it would be great for UI purposes if there would be a way to find out which recipients
 
551
 * prevented a strong cipher from being used...
 
552
 */
 
553
SECStatus
 
554
NSS_SMIMEUtil_FindBulkAlgForRecipients(CERTCertificate **rcerts, SECOidTag *bulkalgtag, int *keysize)
 
555
{
 
556
    unsigned long cipher;
 
557
    int mapi;
 
558
 
 
559
    cipher = smime_choose_cipher(NULL, rcerts);
 
560
    mapi = smime_mapi_by_cipher(cipher);
 
561
 
 
562
    *bulkalgtag = smime_cipher_map[mapi].algtag;
 
563
    *keysize = smime_keysize_by_cipher(smime_cipher_map[mapi].cipher);
 
564
 
 
565
    return SECSuccess;
 
566
}
 
567
 
 
568
/*
 
569
 * NSS_SMIMEUtil_CreateSMIMECapabilities - get S/MIME capabilities for this instance of NSS
 
570
 *
 
571
 * scans the list of allowed and enabled ciphers and construct a PKCS9-compliant
 
572
 * S/MIME capabilities attribute value.
 
573
 *
 
574
 * XXX Please note that, in contradiction to RFC2633 2.5.2, the capabilities only include
 
575
 * symmetric ciphers, NO signature algorithms or key encipherment algorithms.
 
576
 *
 
577
 * "poolp" - arena pool to create the S/MIME capabilities data on
 
578
 * "dest" - SECItem to put the data in
 
579
 */
 
580
SECStatus
 
581
NSS_SMIMEUtil_CreateSMIMECapabilities(PLArenaPool *poolp, SECItem *dest)
 
582
{
 
583
    NSSSMIMECapability *cap;
 
584
    NSSSMIMECapability **smime_capabilities;
 
585
    smime_cipher_map_entry *map;
 
586
    SECOidData *oiddata;
 
587
    SECItem *dummy;
 
588
    int i, capIndex;
 
589
 
 
590
    /* if we have an old NSSSMIMECapability array, we'll reuse it (has the right size) */
 
591
    /* smime_cipher_map_count + 1 is an upper bound - we might end up with less */
 
592
    smime_capabilities = (NSSSMIMECapability **)PORT_ZAlloc((smime_cipher_map_count + 1)
 
593
                                      * sizeof(NSSSMIMECapability *));
 
594
    if (smime_capabilities == NULL)
 
595
        return SECFailure;
 
596
 
 
597
    capIndex = 0;
 
598
 
 
599
    /* Add all the symmetric ciphers
 
600
     * We walk the cipher list backwards, as it is ordered by increasing strength,
 
601
     * we prefer the stronger cipher over a weaker one, and we have to list the
 
602
     * preferred algorithm first */
 
603
    for (i = smime_cipher_map_count - 1; i >= 0; i--) {
 
604
        /* Find the corresponding entry in the cipher map. */
 
605
        map = &(smime_cipher_map[i]);
 
606
        if (!map->enabled)
 
607
            continue;
 
608
 
 
609
        /* get next SMIME capability */
 
610
        cap = (NSSSMIMECapability *)PORT_ZAlloc(sizeof(NSSSMIMECapability));
 
611
        if (cap == NULL)
 
612
            break;
 
613
        smime_capabilities[capIndex++] = cap;
 
614
 
 
615
        oiddata = SECOID_FindOIDByTag(map->algtag);
 
616
        if (oiddata == NULL)
 
617
            break;
 
618
 
 
619
        cap->capabilityID.data = oiddata->oid.data;
 
620
        cap->capabilityID.len = oiddata->oid.len;
 
621
        cap->parameters.data = map->parms ? map->parms->data : NULL;
 
622
        cap->parameters.len = map->parms ? map->parms->len : 0;
 
623
        cap->cipher = smime_cipher_map[i].cipher;
 
624
    }
 
625
 
 
626
    /* XXX add signature algorithms */
 
627
    /* XXX add key encipherment algorithms */
 
628
 
 
629
    smime_capabilities[capIndex] = NULL;        /* last one - now encode */
 
630
    dummy = SEC_ASN1EncodeItem(poolp, dest, &smime_capabilities, NSSSMIMECapabilitiesTemplate);
 
631
 
 
632
    /* now that we have the proper encoded SMIMECapabilities (or not),
 
633
     * free the work data */
 
634
    for (i = 0; smime_capabilities[i] != NULL; i++)
 
635
        PORT_Free(smime_capabilities[i]);
 
636
    PORT_Free(smime_capabilities);
 
637
 
 
638
    return (dummy == NULL) ? SECFailure : SECSuccess;
 
639
}
 
640
 
 
641
/*
 
642
 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferences attr value
 
643
 *
 
644
 * "poolp" - arena pool to create the attr value on
 
645
 * "dest" - SECItem to put the data in
 
646
 * "cert" - certificate that should be marked as preferred encryption key
 
647
 *          cert is expected to have been verified for EmailRecipient usage.
 
648
 */
 
649
SECStatus
 
650
NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCertificate *cert)
 
651
{
 
652
    NSSSMIMEEncryptionKeyPreference ekp;
 
653
    SECItem *dummy = NULL;
 
654
    PLArenaPool *tmppoolp = NULL;
 
655
 
 
656
    if (cert == NULL)
 
657
        goto loser;
 
658
 
 
659
    tmppoolp = PORT_NewArena(1024);
 
660
    if (tmppoolp == NULL)
 
661
        goto loser;
 
662
 
 
663
    /* XXX hardcoded IssuerSN choice for now */
 
664
    ekp.selector = NSSSMIMEEncryptionKeyPref_IssuerSN;
 
665
    ekp.id.issuerAndSN = CERT_GetCertIssuerAndSN(tmppoolp, cert);
 
666
    if (ekp.id.issuerAndSN == NULL)
 
667
        goto loser;
 
668
 
 
669
    dummy = SEC_ASN1EncodeItem(poolp, dest, &ekp, smime_encryptionkeypref_template);
 
670
 
 
671
loser:
 
672
    if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);
 
673
 
 
674
    return (dummy == NULL) ? SECFailure : SECSuccess;
 
675
}
 
676
 
 
677
/*
 
678
 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferences attr value using MS oid
 
679
 *
 
680
 * "poolp" - arena pool to create the attr value on
 
681
 * "dest" - SECItem to put the data in
 
682
 * "cert" - certificate that should be marked as preferred encryption key
 
683
 *          cert is expected to have been verified for EmailRecipient usage.
 
684
 */
 
685
SECStatus
 
686
NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCertificate *cert)
 
687
{
 
688
    SECItem *dummy = NULL;
 
689
    PLArenaPool *tmppoolp = NULL;
 
690
    CERTIssuerAndSN *isn;
 
691
 
 
692
    if (cert == NULL)
 
693
        goto loser;
 
694
 
 
695
    tmppoolp = PORT_NewArena(1024);
 
696
    if (tmppoolp == NULL)
 
697
        goto loser;
 
698
 
 
699
    isn = CERT_GetCertIssuerAndSN(tmppoolp, cert);
 
700
    if (isn == NULL)
 
701
        goto loser;
 
702
 
 
703
    dummy = SEC_ASN1EncodeItem(poolp, dest, isn, SEC_ASN1_GET(CERT_IssuerAndSNTemplate));
 
704
 
 
705
loser:
 
706
    if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);
 
707
 
 
708
    return (dummy == NULL) ? SECFailure : SECSuccess;
 
709
}
 
710
 
 
711
/*
 
712
 * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference -
 
713
 *                              find cert marked by EncryptionKeyPreference attribute
 
714
 *
 
715
 * "certdb" - handle for the cert database to look in
 
716
 * "DERekp" - DER-encoded value of S/MIME Encryption Key Preference attribute
 
717
 *
 
718
 * if certificate is supposed to be found among the message's included certificates,
 
719
 * they are assumed to have been imported already.
 
720
 */
 
721
CERTCertificate *
 
722
NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(CERTCertDBHandle *certdb, SECItem *DERekp)
 
723
{
 
724
    PLArenaPool *tmppoolp = NULL;
 
725
    CERTCertificate *cert = NULL;
 
726
    NSSSMIMEEncryptionKeyPreference ekp;
 
727
 
 
728
    tmppoolp = PORT_NewArena(1024);
 
729
    if (tmppoolp == NULL)
 
730
        return NULL;
 
731
 
 
732
    /* decode DERekp */
 
733
    if (SEC_QuickDERDecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template,
 
734
                               DERekp) != SECSuccess)
 
735
        goto loser;
 
736
 
 
737
    /* find cert */
 
738
    switch (ekp.selector) {
 
739
    case NSSSMIMEEncryptionKeyPref_IssuerSN:
 
740
        cert = CERT_FindCertByIssuerAndSN(certdb, ekp.id.issuerAndSN);
 
741
        break;
 
742
    case NSSSMIMEEncryptionKeyPref_RKeyID:
 
743
    case NSSSMIMEEncryptionKeyPref_SubjectKeyID:
 
744
        /* XXX not supported yet - we need to be able to look up certs by SubjectKeyID */
 
745
        break;
 
746
    default:
 
747
        PORT_Assert(0);
 
748
    }
 
749
loser:
 
750
    if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);
 
751
 
 
752
    return cert;
 
753
}
 
754
 
 
755
extern const char __nss_smime_rcsid[];
 
756
extern const char __nss_smime_sccsid[];
 
757
 
 
758
PRBool
 
759
NSSSMIME_VersionCheck(const char *importedVersion)
 
760
{
 
761
    /*
 
762
     * This is the secret handshake algorithm.
 
763
     *
 
764
     * This release has a simple version compatibility
 
765
     * check algorithm.  This release is not backward
 
766
     * compatible with previous major releases.  It is
 
767
     * not compatible with future major, minor, or
 
768
     * patch releases.
 
769
     */
 
770
    volatile char c; /* force a reference that won't get optimized away */
 
771
 
 
772
    c = __nss_smime_rcsid[0] + __nss_smime_sccsid[0]; 
 
773
 
 
774
    return NSS_VersionCheck(importedVersion);
 
775
}
 
776
 
 
777
const char *
 
778
NSSSMIME_GetVersion(void)
 
779
{
 
780
    return NSS_VERSION;
 
781
}