smimeutil.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 715 行 · 第 1/2 页

C
715
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * Stuff specific to S/MIME policy and interoperability. * * $Id: smimeutil.c,v 1.4 2000/06/20 16:28:57 chrisk%netscape.com Exp $ */#include "secmime.h"#include "secoid.h"#include "pk11func.h"#include "ciferfam.h"	/* for CIPHER_FAMILY symbols */#include "secasn1.h"#include "secitem.h"#include "cert.h"#include "key.h"#include "secerr.h"#include "cms.h"/* various integer's ASN.1 encoding */static unsigned char asn1_int40[] = { SEC_ASN1_INTEGER, 0x01, 0x28 };static unsigned char asn1_int64[] = { SEC_ASN1_INTEGER, 0x01, 0x40 };static unsigned char asn1_int128[] = { SEC_ASN1_INTEGER, 0x02, 0x00, 0x80 };/* RC2 algorithm parameters (used in smime_cipher_map) */static SECItem param_int40 = { siBuffer, asn1_int40, sizeof(asn1_int40) };static SECItem param_int64 = { siBuffer, asn1_int64, sizeof(asn1_int64) };static SECItem param_int128 = { siBuffer, asn1_int128, sizeof(asn1_int128) };/* * XXX Would like the "parameters" field to be a SECItem *, but the * encoder is having trouble with optional pointers to an ANY.  Maybe * once that is fixed, can change this back... */typedef struct {    SECItem capabilityID;    SECItem parameters;    long cipher;		/* optimization */} NSSSMIMECapability;static const SEC_ASN1Template NSSSMIMECapabilityTemplate[] = {    { SEC_ASN1_SEQUENCE,	  0, NULL, sizeof(NSSSMIMECapability) },    { SEC_ASN1_OBJECT_ID,	  offsetof(NSSSMIMECapability,capabilityID), },    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,	  offsetof(NSSSMIMECapability,parameters), },    { 0, }};static const SEC_ASN1Template NSSSMIMECapabilitiesTemplate[] = {    { SEC_ASN1_SEQUENCE_OF, 0, NSSSMIMECapabilityTemplate }};/* * NSSSMIMEEncryptionKeyPreference - if we find one of these, it needs to prompt us *  to store this and only this certificate permanently for the sender email address. */typedef enum {    NSSSMIMEEncryptionKeyPref_IssuerSN,    NSSSMIMEEncryptionKeyPref_RKeyID,    NSSSMIMEEncryptionKeyPref_SubjectKeyID} NSSSMIMEEncryptionKeyPrefSelector;typedef struct {    NSSSMIMEEncryptionKeyPrefSelector selector;    union {	CERTIssuerAndSN			*issuerAndSN;	NSSCMSRecipientKeyIdentifier	*recipientKeyID;	SECItem				*subjectKeyID;    } id;} NSSSMIMEEncryptionKeyPreference;extern const SEC_ASN1Template NSSCMSRecipientKeyIdentifierTemplate[];static const SEC_ASN1Template smime_encryptionkeypref_template[] = {    { SEC_ASN1_CHOICE,	  offsetof(NSSSMIMEEncryptionKeyPreference,selector), NULL,	  sizeof(NSSSMIMEEncryptionKeyPreference) },    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 0,	  offsetof(NSSSMIMEEncryptionKeyPreference,id.issuerAndSN),	  CERT_IssuerAndSNTemplate,	  NSSSMIMEEncryptionKeyPref_IssuerSN },    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 1,	  offsetof(NSSSMIMEEncryptionKeyPreference,id.recipientKeyID),	  NSSCMSRecipientKeyIdentifierTemplate,	  NSSSMIMEEncryptionKeyPref_IssuerSN },    { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 2,	  offsetof(NSSSMIMEEncryptionKeyPreference,id.subjectKeyID),	  SEC_OctetStringTemplate,	  NSSSMIMEEncryptionKeyPref_SubjectKeyID },    { 0, }};/* smime_cipher_map - map of SMIME symmetric "ciphers" to algtag & parameters */typedef struct {    unsigned long cipher;    SECOidTag algtag;    SECItem *parms;    PRBool enabled;	/* in the user's preferences */    PRBool allowed;	/* per export policy */} smime_cipher_map_entry;/* global: list of supported SMIME symmetric ciphers, ordered roughly by increasing strength */static smime_cipher_map_entry smime_cipher_map[] = {/*    cipher			algtag			parms		enabled  allowed *//*    ---------------------------------------------------------------------------------- */    { SMIME_RC2_CBC_40,		SEC_OID_RC2_CBC,	&param_int40,	PR_TRUE, PR_TRUE },    { SMIME_DES_CBC_56,		SEC_OID_DES_CBC,	NULL,		PR_TRUE, PR_TRUE },    { SMIME_RC2_CBC_64,		SEC_OID_RC2_CBC,	&param_int64,	PR_TRUE, PR_TRUE },    { SMIME_RC2_CBC_128,	SEC_OID_RC2_CBC,	&param_int128,	PR_TRUE, PR_TRUE },    { SMIME_DES_EDE3_168,	SEC_OID_DES_EDE3_CBC,	NULL,		PR_TRUE, PR_TRUE },    { SMIME_FORTEZZA,		SEC_OID_FORTEZZA_SKIPJACK, NULL,	PR_TRUE, PR_TRUE }};static const int smime_cipher_map_count = sizeof(smime_cipher_map) / sizeof(smime_cipher_map_entry);/* * smime_mapi_by_cipher - find index into smime_cipher_map by cipher */static intsmime_mapi_by_cipher(unsigned long cipher){    int i;    for (i = 0; i < smime_cipher_map_count; i++) {	if (smime_cipher_map[i].cipher == cipher)	    return i;	/* bingo */    }    return -1;		/* should not happen if we're consistent, right? */}/* * 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;}/* * 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;}/* * Based on the given algorithm (including its parameters, in some cases!) * and the given key (may or may not be inspected, depending on the * algorithm), find the appropriate policy algorithm specification * and return it.  If no match can be made, -1 is returned. */static SECStatusnss_smime_get_cipher_for_alg_and_key(SECAlgorithmID *algid, PK11SymKey *key, unsigned long *cipher){    SECOidTag algtag;    unsigned int keylen_bits;    SECStatus rv = SECSuccess;    unsigned long c;    algtag = SECOID_GetAlgorithmTag(algid);    switch (algtag) {    case SEC_OID_RC2_CBC:	keylen_bits = PK11_GetKeyStrength(key, algid);	switch (keylen_bits) {	case 40:	    c = SMIME_RC2_CBC_40;	case 64:	    c = SMIME_RC2_CBC_64;	case 128:	    c = SMIME_RC2_CBC_128;	default:	    rv = SECFailure;	    break;	}	break;    case SEC_OID_DES_CBC:	c = SMIME_DES_CBC_56;    case SEC_OID_DES_EDE3_CBC:	c = SMIME_DES_EDE3_168;    case SEC_OID_FORTEZZA_SKIPJACK:	c = SMIME_FORTEZZA;    default:	rv = SECFailure;    }    if (rv == SECSuccess)	*cipher = c;    return rv;}static PRBoolnss_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;}PRBoolNSS_SMIMEUtil_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key){    unsigned long which;    if (nss_smime_get_cipher_for_alg_and_key(algid, key, &which) != SECSuccess)	return PR_FALSE;    return nss_smime_cipher_allowed(which);}/* * NSS_SMIME_EncryptionPossible - check if any encryption is allowed * * This tells whether or not *any* S/MIME encryption can be done, * according to policy.  Callers may use this to do nicer user interface * (say, greying out a checkbox so a user does not even try to encrypt * a message when they are not allowed to) or for any reason they want * to check whether S/MIME encryption (or decryption, for that matter) * may be done. * * It takes no arguments.  The return value is a simple boolean: *   PR_TRUE means encryption (or decryption) is *possible* *	(but may still fail due to other reasons, like because we cannot *	find all the necessary certs, etc.; PR_TRUE is *not* a guarantee) *   PR_FALSE means encryption (or decryption) is not permitted * * There are no errors from this routine. */PRBoolNSS_SMIMEUtil_EncryptionPossible(void){    int i;    for (i = 0; i < smime_cipher_map_count; i++) {	if (smime_cipher_map[i].allowed)	    return PR_TRUE;    }    return PR_FALSE;}static intnss_SMIME_FindCipherForSMIMECap(NSSSMIMECapability *cap){    int i;    SECOidTag capIDTag;    /* we need the OIDTag here */    capIDTag = SECOID_FindOIDTag(&(cap->capabilityID));    /* go over all the SMIME ciphers we know and see if we find a match */    for (i = 0; i < smime_cipher_map_count; i++) {	if (smime_cipher_map[i].algtag != capIDTag)	    continue;	/*	 * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing	 * 2 NULLs as equal and NULL and non-NULL as not equal), we could	 * use that here instead of all of the following comparison code.	 */	if (cap->parameters.data == NULL && smime_cipher_map[i].parms == NULL)	    break;	/* both empty: bingo */	if (cap->parameters.data != NULL && smime_cipher_map[i].parms != NULL &&	    cap->parameters.len == smime_cipher_map[i].parms->len &&	    PORT_Memcmp (cap->parameters.data, smime_cipher_map[i].parms->data,			     cap->parameters.len) == 0)	{	    break;	/* both not empty, same length & equal content: bingo */	}    }    if (i == smime_cipher_map_count)	return 0;				/* no match found */    else	return smime_cipher_map[i].cipher;	/* match found, point to cipher */}/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?