security/nss/lib/smime/smimeutil.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     5 /*
     6  * Stuff specific to S/MIME policy and interoperability.
     7  */
     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"
    21 SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
    22 SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
    23 SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate)
    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 };
    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) };
    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;
    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 };
    56 static const SEC_ASN1Template NSSSMIMECapabilitiesTemplate[] = {
    57     { SEC_ASN1_SEQUENCE_OF, 0, NSSSMIMECapabilityTemplate }
    58 };
    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;
    70 typedef struct {
    71     NSSSMIMEEncryptionKeyPrefSelector selector;
    72     union {
    73 	CERTIssuerAndSN			*issuerAndSN;
    74 	NSSCMSRecipientKeyIdentifier	*recipientKeyID;
    75 	SECItem				*subjectKeyID;
    76     } id;
    77 } NSSSMIMEEncryptionKeyPreference;
    79 extern const SEC_ASN1Template NSSCMSRecipientKeyIdentifierTemplate[];
    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 };
   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;
   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);
   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;
   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 }
   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;
   150     mask = which & CIPHER_FAMILYID_MASK;
   152     PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
   153     if (mask != CIPHER_FAMILYID_SMIME)
   154 	/* XXX set an error! */
   155     	return SECFailure;
   157     mapi = smime_mapi_by_cipher(which);
   158     if (mapi < 0)
   159 	/* XXX set an error */
   160 	return SECFailure;
   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     }
   168     if (smime_cipher_map[mapi].enabled != on)
   169 	smime_cipher_map[mapi].enabled = on;
   171     return SECSuccess;
   172 }
   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;
   184     mask = which & CIPHER_FAMILYID_MASK;
   186     PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
   187     if (mask != CIPHER_FAMILYID_SMIME)
   188 	/* XXX set an error! */
   189     	return SECFailure;
   191     mapi = smime_mapi_by_cipher(which);
   192     if (mapi < 0)
   193 	/* XXX set an error */
   194 	return SECFailure;
   196     if (smime_cipher_map[mapi].allowed != on)
   197 	smime_cipher_map[mapi].allowed = on;
   199     return SECSuccess;
   200 }
   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;
   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 }
   253 static PRBool
   254 nss_smime_cipher_allowed(unsigned long which)
   255 {
   256     int mapi;
   258     mapi = smime_mapi_by_cipher(which);
   259     if (mapi < 0)
   260 	return PR_FALSE;
   261     return smime_cipher_map[mapi].allowed;
   262 }
   264 PRBool
   265 NSS_SMIMEUtil_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key)
   266 {
   267     unsigned long which;
   269     if (nss_smime_get_cipher_for_alg_and_key(algid, key, &which) != SECSuccess)
   270 	return PR_FALSE;
   272     return nss_smime_cipher_allowed(which);
   273 }
   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;
   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 }
   307 static int
   308 nss_SMIME_FindCipherForSMIMECap(NSSSMIMECapability *cap)
   309 {
   310     int i;
   311     SECOidTag capIDTag;
   313     /* we need the OIDTag here */
   314     capIDTag = SECOID_FindOIDTag(&(cap->capabilityID));
   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     }
   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 }
   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;
   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);
   371     poolp = PORT_NewArena (1024);		/* XXX what is right value? */
   372     if (poolp == NULL)
   373 	goto done;
   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;
   380     /* Make triple-DES the strong cipher. */
   381     strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
   383     /* walk all the recipient's certs */
   384     for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
   385 	SECItem *profile;
   386 	NSSSMIMECapability **caps;
   387 	int pref;
   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;
   394 	/* find recipient's SMIME profile */
   395 	profile = CERT_FindSMimeProfile(rcerts[rcount]);
   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;
   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 	    }
   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. */
   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 		}
   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     }
   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 */
   500 done:
   501     if (poolp != NULL)
   502 	PORT_FreeArena (poolp, PR_FALSE);
   504     return chosen_cipher;
   505 }
   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;
   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     }
   544     return keysize;
   545 }
   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;
   559     cipher = smime_choose_cipher(NULL, rcerts);
   560     mapi = smime_mapi_by_cipher(cipher);
   562     *bulkalgtag = smime_cipher_map[mapi].algtag;
   563     *keysize = smime_keysize_by_cipher(smime_cipher_map[mapi].cipher);
   565     return SECSuccess;
   566 }
   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;
   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;
   597     capIndex = 0;
   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;
   609 	/* get next SMIME capability */
   610 	cap = (NSSSMIMECapability *)PORT_ZAlloc(sizeof(NSSSMIMECapability));
   611 	if (cap == NULL)
   612 	    break;
   613 	smime_capabilities[capIndex++] = cap;
   615 	oiddata = SECOID_FindOIDByTag(map->algtag);
   616 	if (oiddata == NULL)
   617 	    break;
   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     }
   626     /* XXX add signature algorithms */
   627     /* XXX add key encipherment algorithms */
   629     smime_capabilities[capIndex] = NULL;	/* last one - now encode */
   630     dummy = SEC_ASN1EncodeItem(poolp, dest, &smime_capabilities, NSSSMIMECapabilitiesTemplate);
   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);
   638     return (dummy == NULL) ? SECFailure : SECSuccess;
   639 }
   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;
   656     if (cert == NULL)
   657 	goto loser;
   659     tmppoolp = PORT_NewArena(1024);
   660     if (tmppoolp == NULL)
   661 	goto loser;
   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;
   669     dummy = SEC_ASN1EncodeItem(poolp, dest, &ekp, smime_encryptionkeypref_template);
   671 loser:
   672     if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);
   674     return (dummy == NULL) ? SECFailure : SECSuccess;
   675 }
   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;
   692     if (cert == NULL)
   693 	goto loser;
   695     tmppoolp = PORT_NewArena(1024);
   696     if (tmppoolp == NULL)
   697 	goto loser;
   699     isn = CERT_GetCertIssuerAndSN(tmppoolp, cert);
   700     if (isn == NULL)
   701 	goto loser;
   703     dummy = SEC_ASN1EncodeItem(poolp, dest, isn, SEC_ASN1_GET(CERT_IssuerAndSNTemplate));
   705 loser:
   706     if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);
   708     return (dummy == NULL) ? SECFailure : SECSuccess;
   709 }
   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;
   728     tmppoolp = PORT_NewArena(1024);
   729     if (tmppoolp == NULL)
   730 	return NULL;
   732     /* decode DERekp */
   733     if (SEC_QuickDERDecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template,
   734                                DERekp) != SECSuccess)
   735 	goto loser;
   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);
   752     return cert;
   753 }
   755 extern const char __nss_smime_rcsid[];
   756 extern const char __nss_smime_sccsid[];
   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 */
   772     c = __nss_smime_rcsid[0] + __nss_smime_sccsid[0]; 
   774     return NSS_VersionCheck(importedVersion);
   775 }
   777 const char *
   778 NSSSMIME_GetVersion(void)
   779 {
   780     return NSS_VERSION;
   781 }

mercurial