smimeutil.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:22k
- /*
- * 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, ¶m_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, ¶m_int64, PR_TRUE, PR_TRUE },
- { SMIME_RC2_CBC_128, SEC_OID_RC2_CBC, ¶m_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 int
- smime_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 SECStatus
- nss_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 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;
- }
- PRBool
- NSS_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.
- */
- PRBool
- NSS_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 int
- nss_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 */
- }
- /*
- * 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)
- {
- PRArenaPool *poolp;
- long cipher;
- long chosen_cipher;
- int *cipher_abilities;
- int *cipher_votes;
- int weak_mapi;
- int strong_mapi;
- int rcount, mapi, max, i;
- PRBool scert_is_fortezza = (scert == NULL) ? PR_FALSE : PK11_FortezzaHasKEA(scert);
- 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++) {
- 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_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) */
- SECKEYPublicKey *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) {
- pklen_bits = SECKEY_PublicKeyStrength (key) * 8;
- 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);
- return chosen_cipher;
- }
- /*
- * XXX This is a hack for now to satisfy our current interface.
- * Eventually, with more parameters needing to be specified, just
- * looking up the keysize is not going to be sufficient.
- */
- static int
- smime_keysize_by_cipher (unsigned long which)
- {
- int keysize;
- switch (which) {
- case SMIME_RC2_CBC_40:
- keysize = 40;
- break;
- case SMIME_RC2_CBC_64:
- keysize = 64;
- break;
- case SMIME_RC2_CBC_128:
- keysize = 128;
- break;
- case SMIME_DES_CBC_56:
- case SMIME_DES_EDE3_168:
- case SMIME_FORTEZZA:
- /*
- * These are special; since the key size is fixed, we actually
- * want to *avoid* specifying a key size.
- */
- keysize = 0;
- break;
- default:
- keysize = -1;
- break;
- }
- return keysize;
- }
- /*
- * 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].algtag);
- return SECSuccess;
- }
- /*
- * NSS_SMIMEUtil_CreateSMIMECapabilities - get S/MIME capabilities for this instance of NSS
- *
- * scans the list of allowed and enabled ciphers and construct a PKCS9-compliant
- * S/MIME capabilities attribute value.
- *
- * XXX Please note that, in contradiction to RFC2633 2.5.2, the capabilities only include
- * symmetric ciphers, NO signature algorithms or key encipherment algorithms.
- *
- * "poolp" - arena pool to create the S/MIME capabilities data on
- * "dest" - SECItem to put the data in
- * "includeFortezzaCiphers" - PR_TRUE if fortezza ciphers should be included
- */
- SECStatus
- NSS_SMIMEUtil_CreateSMIMECapabilities(PLArenaPool *poolp, SECItem *dest, PRBool includeFortezzaCiphers)
- {
- NSSSMIMECapability *cap;
- NSSSMIMECapability **smime_capabilities;
- smime_cipher_map_entry *map;
- SECOidData *oiddata;
- SECItem *dummy;
- int i, capIndex;
- /* if we have an old NSSSMIMECapability array, we'll reuse it (has the right size) */
- /* smime_cipher_map_count + 1 is an upper bound - we might end up with less */
- smime_capabilities = (NSSSMIMECapability **)PORT_ZAlloc((smime_cipher_map_count + 1)
- * sizeof(NSSSMIMECapability *));
- if (smime_capabilities == NULL)
- return SECFailure;
- capIndex = 0;
- /* Add all the symmetric ciphers
- * We walk the cipher list backwards, as it is ordered by increasing strength,
- * we prefer the stronger cipher over a weaker one, and we have to list the
- * preferred algorithm first */
- for (i = smime_cipher_map_count - 1; i >= 0; i--) {
- /* Find the corresponding entry in the cipher map. */
- map = &(smime_cipher_map[i]);
- if (!map->enabled)
- continue;
- /* If we're using a non-Fortezza cert, only advertise non-Fortezza
- capabilities. (We advertise all capabilities if we have a
- Fortezza cert.) */
- if ((!includeFortezzaCiphers) && (map->cipher == SMIME_FORTEZZA))
- continue;
- /* get next SMIME capability */
- cap = (NSSSMIMECapability *)PORT_ZAlloc(sizeof(NSSSMIMECapability));
- if (cap == NULL)
- break;
- smime_capabilities[capIndex++] = cap;
- oiddata = SECOID_FindOIDByTag(map->algtag);
- if (oiddata == NULL)
- break;
- cap->capabilityID.data = oiddata->oid.data;
- cap->capabilityID.len = oiddata->oid.len;
- cap->parameters.data = map->parms ? map->parms->data : NULL;
- cap->parameters.len = map->parms ? map->parms->len : 0;
- cap->cipher = smime_cipher_map[i].cipher;
- }
- /* XXX add signature algorithms */
- /* XXX add key encipherment algorithms */
- smime_capabilities[capIndex] = NULL; /* last one - now encode */
- dummy = SEC_ASN1EncodeItem(poolp, dest, &smime_capabilities, NSSSMIMECapabilitiesTemplate);
- /* now that we have the proper encoded SMIMECapabilities (or not),
- * free the work data */
- for (i = 0; smime_capabilities[i] != NULL; i++)
- PORT_Free(smime_capabilities[i]);
- PORT_Free(smime_capabilities);
- return (dummy == NULL) ? SECFailure : SECSuccess;
- }
- /*
- * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferences attr value
- *
- * "poolp" - arena pool to create the attr value on
- * "dest" - SECItem to put the data in
- * "cert" - certificate that should be marked as preferred encryption key
- * cert is expected to have been verified for EmailRecipient usage.
- */
- SECStatus
- NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCertificate *cert)
- {
- NSSSMIMEEncryptionKeyPreference ekp;
- SECItem *dummy = NULL;
- PLArenaPool *tmppoolp;
- if (cert == NULL)
- goto loser;
- tmppoolp = PORT_NewArena(1024);
- if (tmppoolp == NULL)
- goto loser;
- /* XXX hardcoded IssuerSN choice for now */
- ekp.selector = NSSSMIMEEncryptionKeyPref_IssuerSN;
- ekp.id.issuerAndSN = CERT_GetCertIssuerAndSN(tmppoolp, cert);
- if (ekp.id.issuerAndSN == NULL)
- goto loser;
- dummy = SEC_ASN1EncodeItem(poolp, dest, &ekp, smime_encryptionkeypref_template);
- loser:
- if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);
- return (dummy == NULL) ? SECFailure : SECSuccess;
- }
- /*
- * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference -
- * find cert marked by EncryptionKeyPreference attribute
- *
- * "certdb" - handle for the cert database to look in
- * "DERekp" - DER-encoded value of S/MIME Encryption Key Preference attribute
- *
- * if certificate is supposed to be found among the message's included certificates,
- * they are assumed to have been imported already.
- */
- CERTCertificate *
- NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(CERTCertDBHandle *certdb, SECItem *DERekp)
- {
- PLArenaPool *tmppoolp = NULL;
- CERTCertificate *cert = NULL;
- NSSSMIMEEncryptionKeyPreference ekp;
- tmppoolp = PORT_NewArena(1024);
- if (tmppoolp == NULL)
- return NULL;
- /* decode DERekp */
- if (SEC_ASN1DecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, DERekp) != SECSuccess)
- goto loser;
- /* find cert */
- switch (ekp.selector) {
- case NSSSMIMEEncryptionKeyPref_IssuerSN:
- cert = CERT_FindCertByIssuerAndSN(certdb, ekp.id.issuerAndSN);
- break;
- case NSSSMIMEEncryptionKeyPref_RKeyID:
- case NSSSMIMEEncryptionKeyPref_SubjectKeyID:
- /* XXX not supported yet - we need to be able to look up certs by SubjectKeyID */
- break;
- default:
- PORT_Assert(0);
- }
- loser:
- if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);
- return cert;
- }