Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions
p7encode.c File Reference
#include "nssrenam.h"
#include "p7local.h"
#include "cert.h"
#include "cryptohi.h"
#include "keyhi.h"
#include "secasn1.h"
#include "secoid.h"
#include "secitem.h"
#include "pk11func.h"
#include "secerr.h"
#include "sechash.h"

Go to the source code of this file.

Classes

struct  sec_pkcs7_encoder_output
struct  SEC_PKCS7EncoderContextStr

Defines

#define SMIME_FORTEZZA_RA_LENGTH   128
#define SMIME_FORTEZZA_IV_LENGTH   24
#define SMIME_FORTEZZA_MAX_KEY_SIZE   256

Functions

static void sec_pkcs7_encoder_out (void *arg, const char *buf, unsigned long len, int depth, SEC_ASN1EncodingPart data_kind)
static sec_PKCS7CipherObject * sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo, PK11SymKey *orig_bulkkey)
static void sec_pkcs7_encoder_notify (void *arg, PRBool before, void *dest, int depth)
static SEC_PKCS7EncoderContext * sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo, PK11SymKey *bulkkey)
SEC_PKCS7EncoderContext * SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo, SEC_PKCS7EncoderOutputCallback outputfn, void *outputarg, PK11SymKey *bulkkey)
static SECStatus sec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest, const unsigned char *data, unsigned long len, PRBool final)
SECStatus SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx, const char *data, unsigned long len)
static SECOidTag sec_pkcs7_pick_sign_alg (SECOidTag hashalg, SECOidTag encalg)
static SECStatus sec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo, SECKEYGetPasswordKey pwfn, void *pwfnarg)
SECStatus SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx, SECKEYGetPasswordKey pwfn, void *pwfnarg)
void SEC_PKCS7EncoderAbort (SEC_PKCS7EncoderContext *p7ecx, int error)
SECStatus SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo, PK11SymKey *bulkkey, SECKEYGetPasswordKey pwfn, void *pwfnarg)
SECStatus SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo, SEC_PKCS7EncoderOutputCallback outputfn, void *outputarg, PK11SymKey *bulkkey, SECKEYGetPasswordKey pwfn, void *pwfnarg)
SECItem * SEC_PKCS7EncodeItem (PRArenaPool *pool, SECItem *dest, SEC_PKCS7ContentInfo *cinfo, PK11SymKey *bulkkey, SECKEYGetPasswordKey pwfn, void *pwfnarg)

Class Documentation

struct sec_pkcs7_encoder_output

Definition at line 58 of file p7encode.c.

Class Members
void * outputarg
SEC_PKCS7EncoderOutputCallback outputfn
struct SEC_PKCS7EncoderContextStr

Definition at line 63 of file p7encode.c.

Class Members
SEC_PKCS7ContentInfo * cinfo
void * digestcx
const SECHashObject * digestobj
SEC_ASN1EncoderContext * ecx
sec_PKCS7CipherObject * encryptobj

Define Documentation


Function Documentation

static void sec_pkcs7_encoder_notify ( void arg,
PRBool  before,
void dest,
int  depth 
) [static]

Definition at line 415 of file p7encode.c.

{
    SEC_PKCS7EncoderContext *p7ecx;
    SEC_PKCS7ContentInfo *cinfo;
    SECOidTag kind;
    PRBool before_content;

    /*
     * We want to notice just before the content field.  After fields are
     * not interesting to us.
     */
    if (!before)
       return;

    p7ecx = (SEC_PKCS7EncoderContext*)arg;
    cinfo = p7ecx->cinfo;

    before_content = PR_FALSE;

    /*
     * Watch for the content field, at which point we want to instruct
     * the ASN.1 encoder to start taking bytes from the buffer.
     *
     * XXX The following assumes the inner content type is data;
     * if/when we want to handle fully nested types, this will have
     * to recurse until reaching the innermost data content.
     */
    kind = SEC_PKCS7ContentType (cinfo);
    switch (kind) {
      default:
      case SEC_OID_PKCS7_DATA:
       if (dest == &(cinfo->content.data))
           before_content = PR_TRUE;
       break;

      case SEC_OID_PKCS7_DIGESTED_DATA:
       {
           SEC_PKCS7DigestedData *digd;

           digd = cinfo->content.digestedData;
           if (digd == NULL)
              break;

           if (dest == &(digd->contentInfo.content))
              before_content = PR_TRUE;
       }
       break;

      case SEC_OID_PKCS7_ENCRYPTED_DATA:
       {
           SEC_PKCS7EncryptedData *encd;

           encd = cinfo->content.encryptedData;
           if (encd == NULL)
              break;

           if (dest == &(encd->encContentInfo.encContent))
              before_content = PR_TRUE;
       }
       break;

      case SEC_OID_PKCS7_ENVELOPED_DATA:
       {
           SEC_PKCS7EnvelopedData *envd;

           envd = cinfo->content.envelopedData;
           if (envd == NULL)
              break;

           if (dest == &(envd->encContentInfo.encContent))
              before_content = PR_TRUE;
       }
       break;

      case SEC_OID_PKCS7_SIGNED_DATA:
       {
           SEC_PKCS7SignedData *sigd;

           sigd = cinfo->content.signedData;
           if (sigd == NULL)
              break;

           if (dest == &(sigd->contentInfo.content))
              before_content = PR_TRUE;
       }
       break;

      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
       {
           SEC_PKCS7SignedAndEnvelopedData *saed;

           saed = cinfo->content.signedAndEnvelopedData;
           if (saed == NULL)
              break;

           if (dest == &(saed->encContentInfo.encContent))
              before_content = PR_TRUE;
       }
       break;
    }

    if (before_content) {
       /*
        * This will cause the next SEC_ASN1EncoderUpdate to take the
        * contents bytes from the passed-in buffer.
        */
       SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx);
       /*
        * And that is all we needed this notify function for.
        */
       SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_pkcs7_encoder_out ( void arg,
const char *  buf,
unsigned long  len,
int  depth,
SEC_ASN1EncodingPart  data_kind 
) [static]

Definition at line 79 of file p7encode.c.

{
    struct sec_pkcs7_encoder_output *output;

    output = (struct sec_pkcs7_encoder_output*)arg;
    output->outputfn (output->outputarg, buf, len);
}

Here is the caller graph for this function:

static SECStatus sec_pkcs7_encoder_sig_and_certs ( SEC_PKCS7ContentInfo *  cinfo,
SECKEYGetPasswordKey  pwfn,
void pwfnarg 
) [static]

Definition at line 889 of file p7encode.c.

{
    SECOidTag kind;
    CERTCertificate **certs;
    CERTCertificateList **certlists;
    SECAlgorithmID **digestalgs;
    SECItem **digests;
    SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
    SECItem **rawcerts, ***rawcertsp;
    PRArenaPool *poolp;
    int certcount;
    int ci, cli, rci, si;

    kind = SEC_PKCS7ContentType (cinfo);
    switch (kind) {
      default:
      case SEC_OID_PKCS7_DATA:
      case SEC_OID_PKCS7_DIGESTED_DATA:
      case SEC_OID_PKCS7_ENCRYPTED_DATA:
      case SEC_OID_PKCS7_ENVELOPED_DATA:
       certs = NULL;
       certlists = NULL;
       digestalgs = NULL;
       digests = NULL;
       signerinfos = NULL;
       rawcertsp = NULL;
       break;
      case SEC_OID_PKCS7_SIGNED_DATA:
       {
           SEC_PKCS7SignedData *sdp;

           sdp = cinfo->content.signedData;
           certs = sdp->certs;
           certlists = sdp->certLists;
           digestalgs = sdp->digestAlgorithms;
           digests = sdp->digests;
           signerinfos = sdp->signerInfos;
           rawcertsp = &(sdp->rawCerts);
       }
       break;
      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
       {
           SEC_PKCS7SignedAndEnvelopedData *saedp;

           saedp = cinfo->content.signedAndEnvelopedData;
           certs = saedp->certs;
           certlists = saedp->certLists;
           digestalgs = saedp->digestAlgorithms;
           digests = saedp->digests;
           signerinfos = saedp->signerInfos;
           rawcertsp = &(saedp->rawCerts);
       }
       break;
    }

    if (certs == NULL && certlists == NULL && signerinfos == NULL)
       return SECSuccess;          /* nothing for us to do! */

    poolp = cinfo->poolp;
    certcount = 0;

    if (signerinfos != NULL) {
       SECOidTag digestalgtag;
       int di;
       SECStatus rv;
       CERTCertificate *cert;
       SECKEYPrivateKey *privkey;
       SECItem signature;
       SECOidTag signalgtag;

       PORT_Assert (digestalgs != NULL && digests != NULL);

       /*
        * If one fails, we bail right then.  If we want to continue and
        * try to do subsequent signatures, this loop, and the departures
        * from it, will need to be reworked.
        */
       for (si = 0; signerinfos[si] != NULL; si++) {

           signerinfo = signerinfos[si];

           /* find right digest */
           digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg));
           for (di = 0; digestalgs[di] != NULL; di++) {
              /* XXX Should I be comparing more than the tag? */
              if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di]))
                  break;
           }
           if (digestalgs[di] == NULL) {
              /* XXX oops; do what? set an error? */
              return SECFailure;
           }
           PORT_Assert (digests[di] != NULL);

           cert = signerinfo->cert;
           privkey = PK11_FindKeyByAnyCert (cert, pwfnarg);
           if (privkey == NULL)
              return SECFailure;

           /*
            * XXX I think there should be a cert-level interface for this,
            * so that I do not have to know about subjectPublicKeyInfo...
            */
           signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.algorithm));

           /* Fortezza MISSI have weird signature formats.  Map them
            * to standard DSA formats */
           signalgtag = PK11_FortezzaMapSig(signalgtag);

           if (signerinfo->authAttr != NULL) {
              SEC_PKCS7Attribute *attr;
              SECItem encoded_attrs;
              SECItem *dummy;

              /*
               * First, find and fill in the message digest attribute.
               */
              attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
                                          SEC_OID_PKCS9_MESSAGE_DIGEST,
                                          PR_TRUE);
              PORT_Assert (attr != NULL);
              if (attr == NULL) {
                  SECKEY_DestroyPrivateKey (privkey);
                  return SECFailure;
              }

              /*
               * XXX The second half of the following assertion prevents
               * the encoder from being called twice on the same content.
               * Either just remove the second half the assertion, or
               * change the code to check if the value already there is
               * the same as digests[di], whichever seems more right.
               */
              PORT_Assert (attr->values != NULL && attr->values[0] == NULL);
              attr->values[0] = digests[di];

              /*
               * Before encoding, reorder the attributes so that when they
               * are encoded, they will be conforming DER, which is required
               * to have a specific order and that is what must be used for
               * the hash/signature.  We do this here, rather than building
               * it into EncodeAttributes, because we do not want to do
               * such reordering on incoming messages (which also uses
               * EncodeAttributes) or our old signatures (and other "broken"
               * implementations) will not verify.  So, we want to guarantee
               * that we send out good DER encodings of attributes, but not
               * to expect to receive them.
               */
              rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr);
              if (rv != SECSuccess) {
                  SECKEY_DestroyPrivateKey (privkey);
                  return SECFailure;
              }

              encoded_attrs.data = NULL;
              encoded_attrs.len = 0;
              dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
                                             &(signerinfo->authAttr));
              if (dummy == NULL) {
                  SECKEY_DestroyPrivateKey (privkey);
                  return SECFailure;
              }

              rv = SEC_SignData (&signature,
                               encoded_attrs.data, encoded_attrs.len,
                               privkey,
                               sec_pkcs7_pick_sign_alg (digestalgtag,
                                                     signalgtag));
              SECITEM_FreeItem (&encoded_attrs, PR_FALSE);
           } else {
              rv = SGN_Digest (privkey, digestalgtag, &signature,
                             digests[di]);
           }

           SECKEY_DestroyPrivateKey (privkey);

           if (rv != SECSuccess)
              return rv;

           rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature);
           if (rv != SECSuccess)
              return rv;

           SECITEM_FreeItem (&signature, PR_FALSE);

           rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg),
                                   signalgtag, NULL);
           if (rv != SECSuccess)
              return SECFailure;

           /*
            * Count the cert chain for this signer.
            */
           if (signerinfo->certList != NULL)
              certcount += signerinfo->certList->len;
       }
    }

    if (certs != NULL) {
       for (ci = 0; certs[ci] != NULL; ci++)
           certcount++;
    }

    if (certlists != NULL) {
       for (cli = 0; certlists[cli] != NULL; cli++)
           certcount += certlists[cli]->len;
    }

    if (certcount == 0)
       return SECSuccess;          /* signing done; no certs */

    /*
     * Combine all of the certs and cert chains into rawcerts.
     * Note: certcount is an upper bound; we may not need that many slots
     * but we will allocate anyway to avoid having to do another pass.
     * (The temporary space saving is not worth it.)
     */
    rawcerts = (SECItem**)PORT_ArenaAlloc (poolp, 
                                   (certcount + 1) * sizeof(SECItem *));
    if (rawcerts == NULL)
       return SECFailure;

    /*
     * XXX Want to check for duplicates and not add *any* cert that is
     * already in the set.  This will be more important when we start
     * dealing with larger sets of certs, dual-key certs (signing and
     * encryption), etc.  For the time being we can slide by...
     */
    rci = 0;
    if (signerinfos != NULL) {
       for (si = 0; signerinfos[si] != NULL; si++) {
           signerinfo = signerinfos[si];
           for (ci = 0; ci < signerinfo->certList->len; ci++)
              rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
       }

    }

    if (certs != NULL) {
       for (ci = 0; certs[ci] != NULL; ci++)
           rawcerts[rci++] = &(certs[ci]->derCert);
    }

    if (certlists != NULL) {
       for (cli = 0; certlists[cli] != NULL; cli++) {
           for (ci = 0; ci < certlists[cli]->len; ci++)
              rawcerts[rci++] = &(certlists[cli]->certs[ci]);
       }
    }

    rawcerts[rci] = NULL;
    *rawcertsp = rawcerts;

    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SEC_PKCS7EncoderContext* sec_pkcs7_encoder_start_contexts ( SEC_PKCS7ContentInfo *  cinfo,
PK11SymKey *  bulkkey 
) [static]

Definition at line 531 of file p7encode.c.

{
    SEC_PKCS7EncoderContext *p7ecx;
    SECOidTag kind;
    PRBool encrypt;
    SECItem **digests;
    SECAlgorithmID *digestalg, **digestalgs;

    p7ecx = 
      (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext));
    if (p7ecx == NULL)
       return NULL;

    digests = NULL;
    digestalg = NULL;
    digestalgs = NULL;
    encrypt = PR_FALSE;

    kind = SEC_PKCS7ContentType (cinfo);
    switch (kind) {
      default:
      case SEC_OID_PKCS7_DATA:
       break;
      case SEC_OID_PKCS7_DIGESTED_DATA:
       digestalg = &(cinfo->content.digestedData->digestAlg);
       break;
      case SEC_OID_PKCS7_SIGNED_DATA:
       digests = cinfo->content.signedData->digests;
       digestalgs = cinfo->content.signedData->digestAlgorithms;
       break;
      case SEC_OID_PKCS7_ENCRYPTED_DATA:
      case SEC_OID_PKCS7_ENVELOPED_DATA:
       encrypt = PR_TRUE;
       break;
      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
       digests = cinfo->content.signedAndEnvelopedData->digests;
       digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
       encrypt = PR_TRUE;
       break;
    }

    if (encrypt) {
       p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey);
       if (p7ecx->encryptobj == NULL) {
           PORT_Free (p7ecx);
           return NULL;
       }
    }

    if (digestalgs != NULL) {
       if (digests != NULL) {
           /* digests already created (probably for detached data) */
           digestalg = NULL;
       } else {
           /*
            * XXX Some day we should handle multiple digests; for now,
            * assume only one will be done.
            */
           PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL);
           digestalg = digestalgs[0];
       }
    }

    if (digestalg != NULL) {
       SECOidTag  oidTag = SECOID_FindOIDTag(&(digestalg->algorithm));

       p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag);
       if (p7ecx->digestobj != NULL) {
           p7ecx->digestcx = (* p7ecx->digestobj->create) ();
           if (p7ecx->digestcx == NULL)
              p7ecx->digestobj = NULL;
           else
              (* p7ecx->digestobj->begin) (p7ecx->digestcx);
       }
       if (p7ecx->digestobj == NULL) {
           if (p7ecx->encryptobj != NULL)
              sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
           PORT_Free (p7ecx);
           return NULL;
       }
    }

    p7ecx->cinfo = cinfo;
    return p7ecx;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static sec_PKCS7CipherObject* sec_pkcs7_encoder_start_encrypt ( SEC_PKCS7ContentInfo *  cinfo,
PK11SymKey *  orig_bulkkey 
) [static]

Definition at line 89 of file p7encode.c.

{
    SECOidTag kind;
    sec_PKCS7CipherObject *encryptobj;
    SEC_PKCS7RecipientInfo **recipientinfos, *ri;
    SEC_PKCS7EncryptedContentInfo *enccinfo;
    SEC_PKCS7SMIMEKEAParameters   keaParams;
    SECKEYPublicKey *publickey = NULL;
    SECKEYPrivateKey *ourPrivKey = NULL;
    PK11SymKey  *bulkkey;
    void *mark, *wincx;
    int i;
    PRArenaPool *arena = NULL;

    /* Get the context in case we need it below. */
    wincx = cinfo->pwfn_arg;

    /* Clear keaParams, since cleanup code checks the lengths */
    (void) memset(&keaParams, 0, sizeof(keaParams));

    kind = SEC_PKCS7ContentType (cinfo);
    switch (kind) {
      default:
      case SEC_OID_PKCS7_DATA:
      case SEC_OID_PKCS7_DIGESTED_DATA:
      case SEC_OID_PKCS7_SIGNED_DATA:
       recipientinfos = NULL;
       enccinfo = NULL;
       break;
      case SEC_OID_PKCS7_ENCRYPTED_DATA:
       {
           SEC_PKCS7EncryptedData *encdp;

           /* To do EncryptedData we *must* be given a bulk key. */
           PORT_Assert (orig_bulkkey != NULL);
           if (orig_bulkkey == NULL) {
              /* XXX error? */
              return NULL;
           }

           encdp = cinfo->content.encryptedData;
           recipientinfos = NULL;
           enccinfo = &(encdp->encContentInfo);
       }
       break;
      case SEC_OID_PKCS7_ENVELOPED_DATA:
       {
           SEC_PKCS7EnvelopedData *envdp;

           envdp = cinfo->content.envelopedData;
           recipientinfos = envdp->recipientInfos;
           enccinfo = &(envdp->encContentInfo);
       }
       break;
      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
       {
           SEC_PKCS7SignedAndEnvelopedData *saedp;

           saedp = cinfo->content.signedAndEnvelopedData;
           recipientinfos = saedp->recipientInfos;
           enccinfo = &(saedp->encContentInfo);
       }
       break;
    }

    if (enccinfo == NULL)
       return NULL;

    bulkkey = orig_bulkkey;
    if (bulkkey == NULL) {
       CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
       PK11SlotInfo *slot;


       slot = PK11_GetBestSlot(type,cinfo->pwfn_arg);
       if (slot == NULL) {
           return NULL;
       }
       bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8,
                           cinfo->pwfn_arg);
       PK11_FreeSlot(slot);
       if (bulkkey == NULL) {
           return NULL;
       }
    }

    encryptobj = NULL;
    mark = PORT_ArenaMark (cinfo->poolp);

    /*
     * Encrypt the bulk key with the public key of each recipient.
     */
    for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
       CERTCertificate *cert;
       SECOidTag certalgtag, encalgtag;
       SECStatus rv;
       int data_len;
       SECItem *params = NULL;

       cert = ri->cert;
       PORT_Assert (cert != NULL);
       if (cert == NULL)
           continue;

       /*
        * XXX Want an interface that takes a cert and some data and
        * fills in an algorithmID and encrypts the data with the public
        * key from the cert.  Or, give me two interfaces -- one which
        * gets the algorithm tag from a cert (I should not have to go
        * down into the subjectPublicKeyInfo myself) and another which
        * takes a public key and algorithm tag and data and encrypts
        * the data.  Or something like that.  The point is that all
        * of the following hardwired RSA and KEA stuff should be done
        * elsewhere.
        */

       certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));

       switch (certalgtag) {
       case SEC_OID_PKCS1_RSA_ENCRYPTION:
           encalgtag = certalgtag;
           publickey = CERT_ExtractPublicKey (cert);
           if (publickey == NULL) goto loser;
              
           data_len = SECKEY_PublicKeyStrength(publickey);
           ri->encKey.data = 
               (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len);
           ri->encKey.len = data_len;
           if (ri->encKey.data == NULL) goto loser;

           rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey,
                            bulkkey,&ri->encKey);

           SECKEY_DestroyPublicKey(publickey);
           publickey = NULL;
           if (rv != SECSuccess) goto loser;
           params = NULL; /* paranoia */
           break;
       /* ### mwelch -- KEA */ 
      case SEC_OID_MISSI_KEA_DSS_OLD:
      case SEC_OID_MISSI_KEA_DSS:
      case SEC_OID_MISSI_KEA:
           {
#define SMIME_FORTEZZA_RA_LENGTH 128
#define SMIME_FORTEZZA_IV_LENGTH 24
#define SMIME_FORTEZZA_MAX_KEY_SIZE 256
              SECStatus err;
              PK11SymKey *tek;
              CERTCertificate *ourCert;
              SECKEYPublicKey *ourPubKey;
              SECKEATemplateSelector whichKEA = SECKEAInvalid;

              /* We really want to show our KEA tag as the
                 key exchange algorithm tag. */
              encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;

              /* Get the public key of the recipient. */
              publickey = CERT_ExtractPublicKey(cert);
              if (publickey == NULL) goto loser;

              /* Find our own cert, and extract its keys. */
              ourCert = PK11_FindBestKEAMatch(cert,wincx);
              if (ourCert == NULL) goto loser;

              arena = PORT_NewArena(1024);
              if (arena == NULL) goto loser;

              ourPubKey = CERT_ExtractPublicKey(ourCert);
              if (ourPubKey == NULL)
              {
                  CERT_DestroyCertificate(ourCert);
                  goto loser;
              }

              /* While we're here, copy the public key into the outgoing
               * KEA parameters. */
              SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey),
                             &(ourPubKey->u.fortezza.KEAKey));
              SECKEY_DestroyPublicKey(ourPubKey);
              ourPubKey = NULL;

              /* Extract our private key in order to derive the 
               * KEA key. */
              ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
              CERT_DestroyCertificate(ourCert); /* we're done with this */
              if (!ourPrivKey) goto loser;

              /* Prepare raItem with 128 bytes (filled with zeros). */
              keaParams.originatorRA.data = 
                (unsigned char*)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
              keaParams.originatorRA.len = SMIME_FORTEZZA_RA_LENGTH;


              /* Generate the TEK (token exchange key) which we use
               * to wrap the bulk encryption key. (raItem) will be
               * filled with a random seed which we need to send to
               * the recipient. */
              tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
                                 &keaParams.originatorRA, NULL,
                                 CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
                                 CKA_WRAP, 0, wincx);

                  SECKEY_DestroyPublicKey(publickey);
                  SECKEY_DestroyPrivateKey(ourPrivKey);
                  publickey = NULL;
                  ourPrivKey = NULL;
              
              if (!tek)
                  goto loser;

              ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp,
                                            SMIME_FORTEZZA_MAX_KEY_SIZE);
              ri->encKey.len = SMIME_FORTEZZA_MAX_KEY_SIZE;

              if (ri->encKey.data == NULL)
              {
                  PK11_FreeSymKey(tek);
                  goto loser;
              }

              /* Wrap the bulk key. What we do with the resulting data
                 depends on whether we're using Skipjack to wrap the key. */
              switch(PK11_AlgtagToMechanism(enccinfo->encalg))
              {
              case CKM_SKIPJACK_CBC64:
              case CKM_SKIPJACK_ECB64:
              case CKM_SKIPJACK_OFB64:
              case CKM_SKIPJACK_CFB64:
              case CKM_SKIPJACK_CFB32:
              case CKM_SKIPJACK_CFB16:
              case CKM_SKIPJACK_CFB8:
                  /* do SKIPJACK, we use the wrap mechanism */
                  err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, 
                                  tek, bulkkey, &ri->encKey);
                  whichKEA = SECKEAUsesSkipjack;
                  break;
              default:
                  /* Not SKIPJACK, we encrypt the raw key data */
                  keaParams.nonSkipjackIV .data = 
                    (unsigned char*)PORT_ArenaAlloc(arena,
                                               SMIME_FORTEZZA_IV_LENGTH);
                  keaParams.nonSkipjackIV.len = SMIME_FORTEZZA_IV_LENGTH;
                  err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64,
                                     &keaParams.nonSkipjackIV, 
                                      tek, bulkkey, &ri->encKey);
                  if (err != SECSuccess)
                     goto loser;

                  if (ri->encKey.len != PK11_GetKeyLength(bulkkey))
                  {
                     /* The size of the encrypted key is not the same as
                        that of the original bulk key, presumably due to
                        padding. Encode and store the real size of the
                        bulk key. */
                     if (SEC_ASN1EncodeInteger(arena, 
                                            &keaParams.bulkKeySize,
                                            PK11_GetKeyLength(bulkkey))
                         == NULL)
                         err = (SECStatus)PORT_GetError();
                     else
                         /* use full template for encoding */
                         whichKEA = SECKEAUsesNonSkipjackWithPaddedEncKey;
                  }
                  else
                     /* enc key length == bulk key length */
                     whichKEA = SECKEAUsesNonSkipjack; 
                  break;
              }

              PK11_FreeSymKey(tek);
              if (err != SECSuccess)
                  goto loser;

              PORT_Assert( whichKEA != SECKEAInvalid);

              /* Encode the KEA parameters into the recipient info. */
              params = SEC_ASN1EncodeItem(arena,NULL, &keaParams, 
                                  sec_pkcs7_get_kea_template(whichKEA));
              if (params == NULL) goto loser;
              break;
           }
       default:
           PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
           goto loser;
       }

       rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, 
                     params);
       if (rv != SECSuccess)
           goto loser;
       if (arena) PORT_FreeArena(arena,PR_FALSE);
       arena = NULL;
    }

    encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey,
                                          enccinfo->encalg,
                                          &(enccinfo->contentEncAlg));
    if (encryptobj != NULL) {
       PORT_ArenaUnmark (cinfo->poolp, mark);
       mark = NULL;         /* good one; do not want to release */
    }
    /* fallthru */

loser:
    if (arena) {
       PORT_FreeArena(arena, PR_FALSE);
    }
    if (publickey) {
        SECKEY_DestroyPublicKey(publickey);
    }
    if (ourPrivKey) {
        SECKEY_DestroyPrivateKey(ourPrivKey);
    }
    if (mark != NULL) {
       PORT_ArenaRelease (cinfo->poolp, mark);
    }
    if (orig_bulkkey == NULL) {
       if (bulkkey) PK11_FreeSymKey(bulkkey);
    }

    return encryptobj;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus sec_pkcs7_encoder_work_data ( SEC_PKCS7EncoderContext *  p7ecx,
SECItem *  dest,
const unsigned char *  data,
unsigned long  len,
PRBool  final 
) [static]

Definition at line 676 of file p7encode.c.

{
    unsigned char *buf = NULL;
    SECStatus rv;


    rv = SECSuccess;        /* may as well be optimistic */

    /*
     * We should really have data to process, or we should be trying
     * to finish/flush the last block.  (This is an overly paranoid
     * check since all callers are in this file and simple inspection
     * proves they do it right.  But it could find a bug in future
     * modifications/development, that is why it is here.)
     */
    PORT_Assert ((data != NULL && len) || final);

    /*
     * Update the running digest.
     * XXX This needs modification if/when we handle multiple digests.
     */
    if (len && p7ecx->digestobj != NULL) {
       (* p7ecx->digestobj->update) (p7ecx->digestcx, data, len);
    }

    /*
     * Encrypt this chunk.
     */
    if (p7ecx->encryptobj != NULL) {
       /* XXX the following lengths should all be longs? */
       unsigned int inlen;  /* length of data being encrypted */
       unsigned int outlen; /* length of encrypted data */
       unsigned int buflen; /* length available for encrypted data */

       inlen = len;
       buflen = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final);
       if (buflen == 0) {
           /*
            * No output is expected, but the input data may be buffered
            * so we still have to call Encrypt.
            */
           rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0,
                               data, inlen, final);
           if (final) {
              len = 0;
              goto done;
           }
           return rv;
       }

       if (dest != NULL)
           buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen);
       else
           buf = (unsigned char*)PORT_Alloc (buflen);

       if (buf == NULL) {
           rv = SECFailure;
       } else {
           rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen,
                               data, inlen, final);
           data = buf;
           len = outlen;
       }
       if (rv != SECSuccess) {
           if (final)
              goto done;
           return rv;
       }
    }

    if (p7ecx->ecx != NULL) {
       /*
        * Encode the contents bytes.
        */
       if(len) {
           rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len);
       }
    }

done:
    if (p7ecx->encryptobj != NULL) {
       if (final)
           sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
       if (dest != NULL) {
           dest->data = buf;
           dest->len = len;
       } else if (buf != NULL) {
           PORT_Free (buf);
       }
    }

    if (final && p7ecx->digestobj != NULL) {
       SECItem *digest, **digests, ***digestsp;
       unsigned char *digdata;
       SECOidTag kind;

       kind = SEC_PKCS7ContentType (p7ecx->cinfo);
       switch (kind) {
         default:
           PORT_Assert (0);
           return SECFailure;
         case SEC_OID_PKCS7_DIGESTED_DATA:
           digest = &(p7ecx->cinfo->content.digestedData->digest);
           digestsp = NULL;
           break;
         case SEC_OID_PKCS7_SIGNED_DATA:
           digest = NULL;
           digestsp = &(p7ecx->cinfo->content.signedData->digests);
           break;
         case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
           digest = NULL;
           digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
           break;
       }

       digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
                               p7ecx->digestobj->length);
       if (digdata == NULL)
           return SECFailure;

       if (digestsp != NULL) {
           PORT_Assert (digest == NULL);

           digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, 
                                          sizeof(SECItem));
           digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
                                   2 * sizeof(SECItem *));
           if (digests == NULL || digest == NULL)
              return SECFailure;

           digests[0] = digest;
           digests[1] = NULL;

           *digestsp = digests;
       }

       PORT_Assert (digest != NULL);

       digest->data = digdata;
       digest->len = p7ecx->digestobj->length;

       (* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data,
                               &(digest->len), digest->len);
       (* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE);
    }

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECOidTag sec_pkcs7_pick_sign_alg ( SECOidTag  hashalg,
SECOidTag  encalg 
) [static]

Definition at line 844 of file p7encode.c.

Here is the caller graph for this function:

SECStatus SEC_PKCS7Encode ( SEC_PKCS7ContentInfo *  cinfo,
SEC_PKCS7EncoderOutputCallback  outputfn,
void outputarg,
PK11SymKey *  bulkkey,
SECKEYGetPasswordKey  pwfn,
void pwfnarg 
)

Definition at line 1275 of file p7encode.c.

{
    SECStatus rv;

    rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
    if (rv == SECSuccess) {
       struct sec_pkcs7_encoder_output outputcx;

       outputcx.outputfn = outputfn;
       outputcx.outputarg = outputarg;

       rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate,
                          sec_pkcs7_encoder_out, &outputcx);
    }

    return rv;
}

Here is the caller graph for this function:

SECItem* SEC_PKCS7EncodeItem ( PRArenaPool pool,
SECItem *  dest,
SEC_PKCS7ContentInfo *  cinfo,
PK11SymKey *  bulkkey,
SECKEYGetPasswordKey  pwfn,
void pwfnarg 
)

Definition at line 1327 of file p7encode.c.

{
    SECStatus rv;

    rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
    if (rv != SECSuccess)
       return NULL;

    return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
}

Here is the caller graph for this function:

void SEC_PKCS7EncoderAbort ( SEC_PKCS7EncoderContext *  p7ecx,
int  error 
)

Definition at line 1183 of file p7encode.c.

{
    PORT_Assert(p7ecx);
    SEC_ASN1EncoderAbort(p7ecx->ecx, error);
}
SECStatus SEC_PKCS7EncoderFinish ( SEC_PKCS7EncoderContext *  p7ecx,
SECKEYGetPasswordKey  pwfn,
void pwfnarg 
)

Definition at line 1148 of file p7encode.c.

{
    SECStatus rv;

    /*
     * Flush out any remaining data.
     */
    rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE);

    /*
     * Turn off streaming stuff.
     */
    SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx);
    SEC_ASN1EncoderClearStreaming (p7ecx->ecx);

    if (rv != SECSuccess)
       goto loser;

    rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg);
    if (rv != SECSuccess)
       goto loser;

    rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);

loser:
    SEC_ASN1EncoderFinish (p7ecx->ecx);
    PORT_Free (p7ecx);
    return rv;
}

Here is the caller graph for this function:

SEC_PKCS7EncoderContext* SEC_PKCS7EncoderStart ( SEC_PKCS7ContentInfo *  cinfo,
SEC_PKCS7EncoderOutputCallback  outputfn,
void outputarg,
PK11SymKey *  bulkkey 
)

Definition at line 620 of file p7encode.c.

{
    SEC_PKCS7EncoderContext *p7ecx;
    SECStatus rv;

    p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
    if (p7ecx == NULL)
       return NULL;

    p7ecx->output.outputfn = outputfn;
    p7ecx->output.outputarg = outputarg;

    /*
     * Initialize the BER encoder.
     */
    p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate,
                                   sec_pkcs7_encoder_out, &(p7ecx->output));
    if (p7ecx->ecx == NULL) {
       PORT_Free (p7ecx);
       return NULL;
    }

    /*
     * Indicate that we are streaming.  We will be streaming until we
     * get past the contents bytes.
     */
    SEC_ASN1EncoderSetStreaming (p7ecx->ecx);

    /*
     * The notify function will watch for the contents field.
     */
    SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);

    /*
     * This will encode everything up to the content bytes.  (The notify
     * function will then cause the encoding to stop there.)  Then our
     * caller can start passing contents bytes to our Update, which we
     * will pass along.
     */
    rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
    if (rv != SECSuccess) {
       PORT_Free (p7ecx);
       return NULL;
    }

    return p7ecx;
}

Here is the caller graph for this function:

SECStatus SEC_PKCS7EncoderUpdate ( SEC_PKCS7EncoderContext *  p7ecx,
const char *  data,
unsigned long  len 
)

Definition at line 829 of file p7encode.c.

{
    /* XXX Error handling needs help.  Return what?  Do "Finish" on failure? */
    return sec_pkcs7_encoder_work_data (p7ecx, NULL,
                                   (const unsigned char *)data, len,
                                   PR_FALSE);
}

Here is the caller graph for this function:

SECStatus SEC_PKCS7PrepareForEncode ( SEC_PKCS7ContentInfo *  cinfo,
PK11SymKey *  bulkkey,
SECKEYGetPasswordKey  pwfn,
void pwfnarg 
)

Definition at line 1196 of file p7encode.c.

{
    SEC_PKCS7EncoderContext *p7ecx;
    SECItem *content, *enc_content;
    SECStatus rv;

    p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
    if (p7ecx == NULL)
       return SECFailure;

    content = SEC_PKCS7GetContent (cinfo);

    if (p7ecx->encryptobj != NULL) {
       SECOidTag kind;
       SEC_PKCS7EncryptedContentInfo *enccinfo;

       kind = SEC_PKCS7ContentType (p7ecx->cinfo);
       switch (kind) {
         default:
           PORT_Assert (0);
           rv = SECFailure;
           goto loser;
         case SEC_OID_PKCS7_ENCRYPTED_DATA:
           enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
           break;
         case SEC_OID_PKCS7_ENVELOPED_DATA:
           enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
           break;
         case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
           enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);
           break;
       }
       enc_content = &(enccinfo->encContent);
    } else {
       enc_content = NULL;
    }

    if (content != NULL && content->data != NULL && content->len) {
       rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content,
                                     content->data, content->len, PR_TRUE);
       if (rv != SECSuccess)
           goto loser;
    }

    rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg);

loser:
    PORT_Free (p7ecx);
    return rv;
}

Here is the caller graph for this function: