Esempio n. 1
0
/*
 * NSS_SMIME_EnableCipher - this function locally records the user's preference
 */
SECStatus 
NSS_SMIMEUtil_EnableCipher(unsigned long which, PRBool on)
{
    unsigned long mask;
    int mapi;

    mask = which & CIPHER_FAMILYID_MASK;

    PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
    if (mask != CIPHER_FAMILYID_SMIME)
	/* XXX set an error! */
    	return SECFailure;

    mapi = smime_mapi_by_cipher(which);
    if (mapi < 0)
	/* XXX set an error */
	return SECFailure;

    /* do we try to turn on a forbidden cipher? */
    if (!smime_cipher_map[mapi].allowed && on) {
	PORT_SetError (SEC_ERROR_BAD_EXPORT_ALGORITHM);
	return SECFailure;
    }

    if (smime_cipher_map[mapi].enabled != on)
	smime_cipher_map[mapi].enabled = on;

    return SECSuccess;
}
Esempio n. 2
0
static PRBool
nss_smime_cipher_allowed(unsigned long which)
{
    int mapi;

    mapi = smime_mapi_by_cipher(which);
    if (mapi < 0)
	return PR_FALSE;
    return smime_cipher_map[mapi].allowed;
}
Esempio n. 3
0
/*
 * Start an S/MIME encrypting context.
 *
 * "scert" is the cert for the sender.  It will be checked for validity.
 * "rcerts" are the certs for the recipients.  They will also be checked.
 *
 * "certdb" is the cert database to use for verifying the certs.
 * It can be NULL if a default database is available (like in the client).
 *
 * This function already does all of the stuff specific to S/MIME protocol
 * and local policy; the return value just needs to be passed to
 * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
 * and finally to SEC_PKCS7DestroyContentInfo().
 *
 * An error results in a return value of NULL and an error set.
 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
 */
SEC_PKCS7ContentInfo *
SECMIME_CreateEncrypted(CERTCertificate *scert,
                        CERTCertificate **rcerts,
                        CERTCertDBHandle *certdb,
                        SECKEYGetPasswordKey pwfn,
                        void *pwfn_arg)
{
    SEC_PKCS7ContentInfo *cinfo;
    long cipher;
    SECOidTag encalg;
    int keysize;
    int mapi, rci;

    cipher = smime_choose_cipher(scert, rcerts);
    if (cipher < 0)
        return NULL;

    mapi = smime_mapi_by_cipher(cipher);
    if (mapi < 0)
        return NULL;

    /*
     * XXX This is stretching it -- CreateEnvelopedData should probably
     * take a cipher itself of some sort, because we cannot know what the
     * future will bring in terms of parameters for each type of algorithm.
     * For example, just an algorithm and keysize is *not* sufficient to
     * fully specify the usage of RC5 (which also needs to know rounds and
     * block size).  Work this out into a better API!
     */
    encalg = smime_cipher_maps[mapi].algtag;
    keysize = smime_keysize_by_cipher(cipher);
    if (keysize < 0)
        return NULL;

    cinfo = SEC_PKCS7CreateEnvelopedData(scert, certUsageEmailRecipient,
                                         certdb, encalg, keysize,
                                         pwfn, pwfn_arg);
    if (cinfo == NULL)
        return NULL;

    for (rci = 0; rcerts[rci] != NULL; rci++) {
        if (rcerts[rci] == scert)
            continue;
        if (SEC_PKCS7AddRecipient(cinfo, rcerts[rci], certUsageEmailRecipient,
                                  NULL) != SECSuccess) {
            SEC_PKCS7DestroyContentInfo(cinfo);
            return NULL;
        }
    }

    return cinfo;
}
Esempio n. 4
0
/*
 * NSS_SMIMEUtil_FindBulkAlgForRecipients - find bulk algorithm suitable for all recipients
 *
 * it would be great for UI purposes if there would be a way to find out which recipients
 * prevented a strong cipher from being used...
 */
SECStatus
NSS_SMIMEUtil_FindBulkAlgForRecipients(CERTCertificate **rcerts, SECOidTag *bulkalgtag, int *keysize)
{
    unsigned long cipher;
    int mapi;

    cipher = smime_choose_cipher(NULL, rcerts);
    mapi = smime_mapi_by_cipher(cipher);

    *bulkalgtag = smime_cipher_map[mapi].algtag;
    *keysize = smime_keysize_by_cipher(smime_cipher_map[mapi].cipher);

    return SECSuccess;
}
Esempio n. 5
0
/*
 * SecSMIMEFindBulkAlgForRecipients - find bulk algorithm suitable for all recipients
 *
 * it would be great for UI purposes if there would be a way to find out which recipients
 * prevented a strong cipher from being used...
 */
OSStatus
SecSMIMEFindBulkAlgForRecipients(SecCertificateRef *rcerts, SECOidTag *bulkalgtag, int *keysize)
{
    unsigned long cipher;
    int mapi;

    cipher = smime_choose_cipher(NULL, rcerts);
    mapi = smime_mapi_by_cipher(cipher);
    if (mapi < 0) {
        return SECFailure;
    }

    *bulkalgtag = smime_cipher_map[mapi].algtag;
    *keysize = smime_keysize_by_cipher(smime_cipher_map[mapi].cipher);

    return SECSuccess;
}
Esempio n. 6
0
/*
 * this function locally records the export policy
 */
OSStatus 
SecSMIMEAllowCipher(uint32 which, Boolean on)
{
    unsigned long mask;
    int mapi;

    mask = which & CIPHER_FAMILYID_MASK;

    PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
    if (mask != CIPHER_FAMILYID_SMIME)
	/* XXX set an error! */
    	return SECFailure;

    mapi = smime_mapi_by_cipher(which);
    if (mapi < 0)
	/* XXX set an error */
	return SECFailure;

    smime_cipher_map[mapi].allowed = on;

    return SECSuccess;
}
Esempio n. 7
0
/*
 * this function locally records the export policy
 */
SECStatus 
NSS_SMIMEUtil_AllowCipher(unsigned long which, PRBool on)
{
    unsigned long mask;
    int mapi;

    mask = which & CIPHER_FAMILYID_MASK;

    PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
    if (mask != CIPHER_FAMILYID_SMIME)
	/* XXX set an error! */
    	return SECFailure;

    mapi = smime_mapi_by_cipher(which);
    if (mapi < 0)
	/* XXX set an error */
	return SECFailure;

    if (smime_cipher_map[mapi].allowed != on)
	smime_cipher_map[mapi].allowed = on;

    return SECSuccess;
}
Esempio n. 8
0
static SECStatus
smime_init_caps(void)
{
    smime_capability *cap;
    smime_cipher_map *map;
    SECOidData *oiddata;
    SECStatus rv;
    int i;

    if (smime_encoded_caps != NULL && (!smime_prefs_changed))
        return SECSuccess;

    if (smime_encoded_caps != NULL) {
        SECITEM_FreeItem(smime_encoded_caps, PR_TRUE);
        smime_encoded_caps = NULL;
    }

    if (smime_capabilities == NULL) {
        smime_capabilities = (smime_capability **)PORT_ZAlloc(
            (smime_symmetric_count + 1) * sizeof(smime_capability *));
        if (smime_capabilities == NULL)
            return SECFailure;
    }

    rv = SECFailure;

    /*
       The process of creating the encoded PKCS7 cipher capability list
       involves two basic steps:

       (a) Convert our internal representation of cipher preferences
           (smime_prefs) into an array containing cipher OIDs and
           parameter data (smime_capabilities). This step is
           performed here.

       (b) Encode, using ASN.1, the cipher information in
           smime_capabilities, leaving the encoded result in
           smime_encoded_caps.

       (In the process of performing (a), Lisa put in some optimizations
       which allow us to avoid needlessly re-populating elements in
       smime_capabilities as we walk through smime_prefs.)
    */
    for (i = 0; i < smime_current_pref_index; i++) {
        int mapi;

        /* Get the next cipher preference in smime_prefs. */
        mapi = smime_mapi_by_cipher(smime_prefs[i]);
        if (mapi < 0)
            break;

        /* Find the corresponding entry in the cipher map. */
        PORT_Assert(mapi < smime_symmetric_count);
        map = &(smime_cipher_maps[mapi]);

        /*
         * Convert the next preference found in smime_prefs into an
         * smime_capability.
         */

        cap = smime_capabilities[i];
        if (cap == NULL) {
            cap = (smime_capability *)PORT_ZAlloc(sizeof(smime_capability));
            if (cap == NULL)
                break;
            smime_capabilities[i] = cap;
        } else if (cap->cipher == smime_prefs[i]) {
            continue; /* no change to this one */
        }

        cap->capIDTag = map->algtag;
        oiddata = SECOID_FindOIDByTag(map->algtag);
        if (oiddata == NULL)
            break;

        if (cap->capabilityID.data != NULL) {
            SECITEM_FreeItem(&(cap->capabilityID), PR_FALSE);
            cap->capabilityID.data = NULL;
            cap->capabilityID.len = 0;
        }

        rv = SECITEM_CopyItem(NULL, &(cap->capabilityID), &(oiddata->oid));
        if (rv != SECSuccess)
            break;

        if (map->parms == NULL) {
            cap->parameters.data = NULL;
            cap->parameters.len = 0;
        } else {
            cap->parameters.data = map->parms->data;
            cap->parameters.len = map->parms->len;
        }

        cap->cipher = smime_prefs[i];
    }

    if (i != smime_current_pref_index)
        return rv;

    while (i < smime_symmetric_count) {
        cap = smime_capabilities[i];
        if (cap != NULL) {
            SECITEM_FreeItem(&(cap->capabilityID), PR_FALSE);
            PORT_Free(cap);
        }
        smime_capabilities[i] = NULL;
        i++;
    }
    smime_capabilities[i] = NULL;

    smime_encoded_caps = SEC_ASN1EncodeItem(NULL, NULL, &smime_capabilities,
                                            smime_capabilities_template);
    if (smime_encoded_caps == NULL)
        return SECFailure;

    return SECSuccess;
}
Esempio n. 9
0
static long
smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts)
{
    PLArenaPool *poolp;
    long chosen_cipher;
    int *cipher_abilities;
    int *cipher_votes;
    int strong_mapi;
    int rcount, mapi, max;

    if (smime_policy_bits == 0) {
        PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
        return -1;
    }

    chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */

    poolp = PORT_NewArena(1024); /* XXX what is right value? */
    if (poolp == NULL)
        goto done;

    cipher_abilities = (int *)PORT_ArenaZAlloc(poolp,
                                               smime_symmetric_count * sizeof(int));
    if (cipher_abilities == NULL)
        goto done;

    cipher_votes = (int *)PORT_ArenaZAlloc(poolp,
                                           smime_symmetric_count * sizeof(int));
    if (cipher_votes == NULL)
        goto done;

    /*
     * XXX Should have a #define somewhere which specifies default
     * strong cipher.  (Or better, a way to configure.)
     */

    /* Make triple-DES the strong cipher. */
    strong_mapi = smime_mapi_by_cipher(SMIME_DES_EDE3_168);

    PORT_Assert(strong_mapi >= 0);

    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
        SECItem *profile;
        smime_capability **caps;
        int capi, pref;
        SECStatus dstat;

        pref = smime_symmetric_count;
        profile = CERT_FindSMimeProfile(rcerts[rcount]);
        if (profile != NULL && profile->data != NULL && profile->len > 0) {
            caps = NULL;
            dstat = SEC_QuickDERDecodeItem(poolp, &caps,
                                           smime_capabilities_template,
                                           profile);
            if (dstat == SECSuccess && caps != NULL) {
                for (capi = 0; caps[capi] != NULL; capi++) {
                    smime_fill_capability(caps[capi]);
                    mapi = smime_mapi_by_cipher(caps[capi]->cipher);
                    if (mapi >= 0) {
                        cipher_abilities[mapi]++;
                        cipher_votes[mapi] += pref;
                        --pref;
                    }
                }
            }
        } else {
            SECKEYPublicKey *key;
            unsigned int pklen_bits;

            /*
             * XXX This is probably only good for RSA keys.  What I would
             * really like is a function to just say;  Is the public key in
             * this cert an export-length key?  Then I would not have to
             * know things like the value 512, or the kind of key, or what
             * a subjectPublicKeyInfo is, etc.
             */
            key = CERT_ExtractPublicKey(rcerts[rcount]);
            if (key != NULL) {
                pklen_bits = SECKEY_PublicKeyStrength(key) * 8;
                SECKEY_DestroyPublicKey(key);

                if (pklen_bits > 512) {
                    cipher_abilities[strong_mapi]++;
                    cipher_votes[strong_mapi] += pref;
                }
            }
        }
        if (profile != NULL)
            SECITEM_FreeItem(profile, PR_TRUE);
    }

    max = 0;
    for (mapi = 0; mapi < smime_symmetric_count; mapi++) {
        if (cipher_abilities[mapi] != rcount)
            continue;
        if (!smime_cipher_allowed(smime_cipher_maps[mapi].cipher))
            continue;
        if (cipher_votes[mapi] > max) {
            chosen_cipher = smime_cipher_maps[mapi].cipher;
            max = cipher_votes[mapi];
        } /* XXX else if a tie, let scert break it? */
    }

done:
    if (poolp != NULL)
        PORT_FreeArena(poolp, PR_FALSE);

    return chosen_cipher;
}
Esempio n. 10
0
/*
 * smime_choose_cipher - choose a cipher that works for all the recipients
 *
 * "scert"  - sender's certificate
 * "rcerts" - recipient's certificates
 */
static long
smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts)
{
    PLArenaPool *poolp;
    long cipher;
    long chosen_cipher;
    int *cipher_abilities;
    int *cipher_votes;
    int weak_mapi;
    int strong_mapi;
    int aes128_mapi;
    int aes256_mapi;
    int rcount, mapi, max, i;

    chosen_cipher = SMIME_RC2_CBC_40;		/* the default, LCD */
    weak_mapi = smime_mapi_by_cipher(chosen_cipher);
    aes128_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_128);
    aes256_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_256);

    poolp = PORT_NewArena (1024);		/* XXX what is right value? */
    if (poolp == NULL)
	goto done;

    cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    cipher_votes     = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    if (cipher_votes == NULL || cipher_abilities == NULL)
	goto done;

    /* Make triple-DES the strong cipher. */
    strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);

    /* walk all the recipient's certs */
    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
	SECItem *profile;
	NSSSMIMECapability **caps;
	int pref;

	/* the first cipher that matches in the user's SMIME profile gets
	 * "smime_cipher_map_count" votes; the next one gets "smime_cipher_map_count" - 1
	 * and so on. If every cipher matches, the last one gets 1 (one) vote */
	pref = smime_cipher_map_count;

	/* find recipient's SMIME profile */
	profile = CERT_FindSMimeProfile(rcerts[rcount]);

	if (profile != NULL && profile->data != NULL && profile->len > 0) {
	    /* we have a profile (still DER-encoded) */
	    caps = NULL;
	    /* decode it */
	    if (SEC_QuickDERDecodeItem(poolp, &caps,
                    NSSSMIMECapabilitiesTemplate, profile) == SECSuccess &&
		    caps != NULL)
	    {
		/* walk the SMIME capabilities for this recipient */
		for (i = 0; caps[i] != NULL; i++) {
		    cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]);
		    mapi = smime_mapi_by_cipher(cipher);
		    if (mapi >= 0) {
			/* found the cipher */
			cipher_abilities[mapi]++;
			cipher_votes[mapi] += pref;
			--pref;
		    }
		}
	    }
	} else {
	    /* no profile found - so we can only assume that the user can do
	     * the mandatory algorithms which are RC2-40 (weak crypto) and
	     * 3DES (strong crypto), unless the user has an elliptic curve
	     * key.  For elliptic curve keys, RFC 5753 mandates support
	     * for AES 128 CBC. */
	    SECKEYPublicKey *key;
	    unsigned int pklen_bits;
	    KeyType key_type;

	    /*
	     * if recipient's public key length is > 512, vote for a strong cipher
	     * please not that the side effect of this is that if only one recipient
	     * has an export-level public key, the strong cipher is disabled.
	     *
	     * XXX This is probably only good for RSA keys.  What I would
	     * really like is a function to just say;  Is the public key in
	     * this cert an export-length key?  Then I would not have to
	     * know things like the value 512, or the kind of key, or what
	     * a subjectPublicKeyInfo is, etc.
	     */
	    key = CERT_ExtractPublicKey(rcerts[rcount]);
	    pklen_bits = 0;
	    key_type = nullKey;
	    if (key != NULL) {
		pklen_bits = SECKEY_PublicKeyStrengthInBits (key);
		key_type = SECKEY_GetPublicKeyType(key);
		SECKEY_DestroyPublicKey (key);
		key = NULL;
	    }

	    if (key_type == ecKey) {
		/* While RFC 5753 mandates support for AES-128 CBC, should use
		 * AES 256 if user's key provides more than 128 bits of
		 * security strength so that symmetric key is not weak link. */

		/* RC2-40 is not compatible with elliptic curve keys. */
		chosen_cipher = SMIME_DES_EDE3_168;
		if (pklen_bits > 256) {
		    cipher_abilities[aes256_mapi]++;
		    cipher_votes[aes256_mapi] += pref;
		    pref--;
		}
		cipher_abilities[aes128_mapi]++;
		cipher_votes[aes128_mapi] += pref;
		pref--;
		cipher_abilities[strong_mapi]++;
		cipher_votes[strong_mapi] += pref;
		pref--;
	    } else {
		if (pklen_bits > 512) {
		    /* cast votes for the strong algorithm */
		    cipher_abilities[strong_mapi]++;
		    cipher_votes[strong_mapi] += pref;
		    pref--;
		}

		/* always cast (possibly less) votes for the weak algorithm */
		cipher_abilities[weak_mapi]++;
		cipher_votes[weak_mapi] += pref;
	    } 
	}
	if (profile != NULL)
	    SECITEM_FreeItem(profile, PR_TRUE);
    }

    /* find cipher that is agreeable by all recipients and that has the most votes */
    max = 0;
    for (mapi = 0; mapi < smime_cipher_map_count; mapi++) {
	/* if not all of the recipients can do this, forget it */
	if (cipher_abilities[mapi] != rcount)
	    continue;
	/* if cipher is not enabled or not allowed by policy, forget it */
	if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed)
	    continue;
	/* now see if this one has more votes than the last best one */
	if (cipher_votes[mapi] >= max) {
	    /* if equal number of votes, prefer the ones further down in the list */
	    /* with the expectation that these are higher rated ciphers */
	    chosen_cipher = smime_cipher_map[mapi].cipher;
	    max = cipher_votes[mapi];
	}
    }
    /* if no common cipher was found, chosen_cipher stays at the default */

done:
    if (poolp != NULL)
	PORT_FreeArena (poolp, PR_FALSE);

    return chosen_cipher;
}
Esempio n. 11
0
/*
 * smime_choose_cipher - choose a cipher that works for all the recipients
 *
 * "scert"  - sender's certificate
 * "rcerts" - recipient's certificates
 */
static long
smime_choose_cipher(SecCertificateRef scert, SecCertificateRef *rcerts)
{
    PRArenaPool *poolp;
    long cipher;
    long chosen_cipher;
    int *cipher_abilities;
    int *cipher_votes;
    int weak_mapi;
    int strong_mapi;
    int rcount, mapi, max, i;
#if 1
    // @@@ We Don't support Fortezza yet.
    Boolean scert_is_fortezza  = PR_FALSE;
#else
    Boolean scert_is_fortezza = (scert == NULL) ? PR_FALSE : PK11_FortezzaHasKEA(scert);
#endif

    chosen_cipher = SMIME_RC2_CBC_40;		/* the default, LCD */
    weak_mapi = smime_mapi_by_cipher(chosen_cipher);

    poolp = PORT_NewArena (1024);		/* XXX what is right value? */
    if (poolp == NULL)
	goto done;

    cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    cipher_votes     = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    if (cipher_votes == NULL || cipher_abilities == NULL)
	goto done;

    /* If the user has the Fortezza preference turned on, make
     *  that the strong cipher. Otherwise, use triple-DES. */
    strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
    if (scert_is_fortezza) {
	mapi = smime_mapi_by_cipher(SMIME_FORTEZZA);
	if (mapi >= 0 && smime_cipher_map[mapi].enabled)
	    strong_mapi = mapi;
    }

    /* walk all the recipient's certs */
    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
	CSSM_DATA_PTR profile;
	NSSSMIMECapability **caps;
	int pref;

	/* the first cipher that matches in the user's SMIME profile gets
	 * "smime_cipher_map_count" votes; the next one gets "smime_cipher_map_count" - 1
	 * and so on. If every cipher matches, the last one gets 1 (one) vote */
	pref = smime_cipher_map_count;

	/* find recipient's SMIME profile */
	profile = CERT_FindSMimeProfile(rcerts[rcount]);

	if (profile != NULL && profile->Data != NULL && profile->Length > 0) {
	    /* we have a profile (still DER-encoded) */
	    caps = NULL;
	    /* decode it */
	    if (SEC_ASN1DecodeItem(poolp, &caps, NSSSMIMECapabilitiesTemplate, profile) == SECSuccess &&
		    caps != NULL)
	    {
		/* walk the SMIME capabilities for this recipient */
		for (i = 0; caps[i] != NULL; i++) {
		    cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]);
		    mapi = smime_mapi_by_cipher(cipher);
		    if (mapi >= 0) {
			/* found the cipher */
			cipher_abilities[mapi]++;
			cipher_votes[mapi] += pref;
			--pref;
		    }
		}
	    }
	} else {
	    /* no profile found - so we can only assume that the user can do
	     * the mandatory algorithms which is RC2-40 (weak crypto) and 3DES (strong crypto) */
	    SecPublicKeyRef key;
	    unsigned int pklen_bits;

	    /*
	     * if recipient's public key length is > 512, vote for a strong cipher
	     * please not that the side effect of this is that if only one recipient
	     * has an export-level public key, the strong cipher is disabled.
	     *
	     * XXX This is probably only good for RSA keys.  What I would
	     * really like is a function to just say;  Is the public key in
	     * this cert an export-length key?  Then I would not have to
	     * know things like the value 512, or the kind of key, or what
	     * a subjectPublicKeyInfo is, etc.
	     */
	    key = CERT_ExtractPublicKey(rcerts[rcount]);
	    pklen_bits = 0;
	    if (key != NULL) {
		SecKeyGetStrengthInBits(key, NULL, &pklen_bits);
		SECKEY_DestroyPublicKey (key);
	    }

	    if (pklen_bits > 512) {
		/* cast votes for the strong algorithm */
		cipher_abilities[strong_mapi]++;
		cipher_votes[strong_mapi] += pref;
		pref--;
	    } 

	    /* always cast (possibly less) votes for the weak algorithm */
	    cipher_abilities[weak_mapi]++;
	    cipher_votes[weak_mapi] += pref;
	}
	if (profile != NULL)
	    SECITEM_FreeItem(profile, PR_TRUE);
    }

    /* find cipher that is agreeable by all recipients and that has the most votes */
    max = 0;
    for (mapi = 0; mapi < smime_cipher_map_count; mapi++) {
	/* if not all of the recipients can do this, forget it */
	if (cipher_abilities[mapi] != rcount)
	    continue;
	/* if cipher is not enabled or not allowed by policy, forget it */
	if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed)
	    continue;
	/* if we're not doing fortezza, but the cipher is fortezza, forget it */
	if (!scert_is_fortezza  && (smime_cipher_map[mapi].cipher == SMIME_FORTEZZA))
	    continue;
	/* now see if this one has more votes than the last best one */
	if (cipher_votes[mapi] >= max) {
	    /* if equal number of votes, prefer the ones further down in the list */
	    /* with the expectation that these are higher rated ciphers */
	    chosen_cipher = smime_cipher_map[mapi].cipher;
	    max = cipher_votes[mapi];
	}
    }
    /* if no common cipher was found, chosen_cipher stays at the default */

done:
    if (poolp != NULL)
	PORT_FreeArena (poolp, PR_FALSE);

    if (smime_keysize_by_cipher(chosen_cipher) < 128) {
        /* you're going to use strong(er) crypto whether you like it or not */
        chosen_cipher = SMIME_DES_EDE3_168;
    }
    return chosen_cipher;
}
Esempio n. 12
0
static SECStatus
smime_init_caps (PRBool isFortezza)
{
    smime_capability *cap;
    smime_cipher_map *map;
    SECOidData *oiddata;
    SECStatus rv;
    int i, capIndex;

    if (smime_encoded_caps != NULL 
	&& (! smime_prefs_changed) 
	&& lastUsedFortezza == isFortezza)
	return SECSuccess;

    if (smime_encoded_caps != NULL) {
	SECITEM_FreeItem (smime_encoded_caps, PR_TRUE);
	smime_encoded_caps = NULL;
    }

    if (smime_capabilities == NULL) {
	smime_capabilities = (smime_capability**)PORT_ZAlloc (
					  (smime_symmetric_count + 1)
					  * sizeof(smime_capability *));
	if (smime_capabilities == NULL)
	    return SECFailure;
    }

    rv = SECFailure;

    /* 
       The process of creating the encoded PKCS7 cipher capability list
       involves two basic steps: 

       (a) Convert our internal representation of cipher preferences 
           (smime_prefs) into an array containing cipher OIDs and 
	   parameter data (smime_capabilities). This step is
	   performed here.

       (b) Encode, using ASN.1, the cipher information in 
           smime_capabilities, leaving the encoded result in 
	   smime_encoded_caps.

       (In the process of performing (a), Lisa put in some optimizations
       which allow us to avoid needlessly re-populating elements in 
       smime_capabilities as we walk through smime_prefs.)

       We want to use separate loop variables for smime_prefs and
       smime_capabilities because in the case where the Skipjack cipher 
       is turned on in the prefs, but where we don't want to include 
       Skipjack in the encoded capabilities (presumably due to using a 
       non-fortezza cert when sending a message), we want to avoid creating
       an empty element in smime_capabilities. This would otherwise cause 
       the encoding step to produce an empty set, since Skipjack happens 
       to be the first cipher in smime_prefs, if it is turned on.
    */
    for (i = 0, capIndex = 0; i < smime_current_pref_index; i++, capIndex++) {
	int mapi;

	/* Get the next cipher preference in smime_prefs. */
	mapi = smime_mapi_by_cipher (smime_prefs[i]);
	if (mapi < 0)
	    break;

	/* Find the corresponding entry in the cipher map. */
	PORT_Assert (mapi < smime_symmetric_count);
	map = &(smime_cipher_maps[mapi]);

	/* If we're using a non-Fortezza cert, only advertise non-Fortezza
	   capabilities. (We advertise all capabilities if we have a 
	   Fortezza cert.) */
	if ((!isFortezza) && (map->cipher == SMIME_FORTEZZA))
	{
	    capIndex--; /* we want to visit the same caps index entry next time */
	    continue;
	}

	/*
	 * Convert the next preference found in smime_prefs into an
	 * smime_capability.
	 */

	cap = smime_capabilities[capIndex];
	if (cap == NULL) {
	    cap = (smime_capability*)PORT_ZAlloc (sizeof(smime_capability));
	    if (cap == NULL)
		break;
	    smime_capabilities[capIndex] = cap;
	} else if (cap->cipher == smime_prefs[i]) {
	    continue;		/* no change to this one */
	}

	cap->capIDTag = map->algtag;
	oiddata = SECOID_FindOIDByTag (map->algtag);
	if (oiddata == NULL)
	    break;

	if (cap->capabilityID.data != NULL) {
	    SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
	    cap->capabilityID.data = NULL;
	    cap->capabilityID.len = 0;
	}

	rv = SECITEM_CopyItem (NULL, &(cap->capabilityID), &(oiddata->oid));
	if (rv != SECSuccess)
	    break;

	if (map->parms == NULL) {
	    cap->parameters.data = NULL;
	    cap->parameters.len = 0;
	} else {
	    cap->parameters.data = map->parms->data;
	    cap->parameters.len = map->parms->len;
	}

	cap->cipher = smime_prefs[i];
    }

    if (i != smime_current_pref_index)
	return rv;

    while (capIndex < smime_symmetric_count) {
	cap = smime_capabilities[capIndex];
	if (cap != NULL) {
	    SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
	    PORT_Free (cap);
	}
	smime_capabilities[capIndex] = NULL;
	capIndex++;
    }
    smime_capabilities[capIndex] = NULL;

    smime_encoded_caps = SEC_ASN1EncodeItem (NULL, NULL, &smime_capabilities,
					     smime_capabilities_template);
    if (smime_encoded_caps == NULL)
	return SECFailure;

    lastUsedFortezza = isFortezza;

    return SECSuccess;
}