Back to index

lightning-sunbird  0.9+nobinonly
p7encode.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * PKCS7 encoding.
00040  *
00041  * $Id: p7encode.c,v 1.11 2005/09/02 01:24:56 wtchang%redhat.com Exp $
00042  */
00043 
00044 #include "nssrenam.h"
00045 
00046 #include "p7local.h"
00047 
00048 #include "cert.h"
00049 #include "cryptohi.h"
00050 #include "keyhi.h"
00051 #include "secasn1.h"
00052 #include "secoid.h"
00053 #include "secitem.h"
00054 #include "pk11func.h"
00055 #include "secerr.h"
00056 #include "sechash.h" /* for HASH_GetHashObject() */
00057 
00058 struct sec_pkcs7_encoder_output {
00059     SEC_PKCS7EncoderOutputCallback outputfn;
00060     void *outputarg;
00061 };
00062 
00063 struct SEC_PKCS7EncoderContextStr {
00064     SEC_ASN1EncoderContext *ecx;
00065     SEC_PKCS7ContentInfo *cinfo;
00066     struct sec_pkcs7_encoder_output output;
00067     sec_PKCS7CipherObject *encryptobj;
00068     const SECHashObject *digestobj;
00069     void *digestcx;
00070 };
00071 
00072 
00073 /*
00074  * The little output function that the ASN.1 encoder calls to hand
00075  * us bytes which we in turn hand back to our caller (via the callback
00076  * they gave us).
00077  */
00078 static void
00079 sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len,
00080                     int depth, SEC_ASN1EncodingPart data_kind)
00081 {
00082     struct sec_pkcs7_encoder_output *output;
00083 
00084     output = (struct sec_pkcs7_encoder_output*)arg;
00085     output->outputfn (output->outputarg, buf, len);
00086 }
00087 
00088 static sec_PKCS7CipherObject *
00089 sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo,
00090                                            PK11SymKey *orig_bulkkey)
00091 {
00092     SECOidTag kind;
00093     sec_PKCS7CipherObject *encryptobj;
00094     SEC_PKCS7RecipientInfo **recipientinfos, *ri;
00095     SEC_PKCS7EncryptedContentInfo *enccinfo;
00096     SEC_PKCS7SMIMEKEAParameters   keaParams;
00097     SECKEYPublicKey *publickey = NULL;
00098     SECKEYPrivateKey *ourPrivKey = NULL;
00099     PK11SymKey  *bulkkey;
00100     void *mark, *wincx;
00101     int i;
00102     PRArenaPool *arena = NULL;
00103 
00104     /* Get the context in case we need it below. */
00105     wincx = cinfo->pwfn_arg;
00106 
00107     /* Clear keaParams, since cleanup code checks the lengths */
00108     (void) memset(&keaParams, 0, sizeof(keaParams));
00109 
00110     kind = SEC_PKCS7ContentType (cinfo);
00111     switch (kind) {
00112       default:
00113       case SEC_OID_PKCS7_DATA:
00114       case SEC_OID_PKCS7_DIGESTED_DATA:
00115       case SEC_OID_PKCS7_SIGNED_DATA:
00116        recipientinfos = NULL;
00117        enccinfo = NULL;
00118        break;
00119       case SEC_OID_PKCS7_ENCRYPTED_DATA:
00120        {
00121            SEC_PKCS7EncryptedData *encdp;
00122 
00123            /* To do EncryptedData we *must* be given a bulk key. */
00124            PORT_Assert (orig_bulkkey != NULL);
00125            if (orig_bulkkey == NULL) {
00126               /* XXX error? */
00127               return NULL;
00128            }
00129 
00130            encdp = cinfo->content.encryptedData;
00131            recipientinfos = NULL;
00132            enccinfo = &(encdp->encContentInfo);
00133        }
00134        break;
00135       case SEC_OID_PKCS7_ENVELOPED_DATA:
00136        {
00137            SEC_PKCS7EnvelopedData *envdp;
00138 
00139            envdp = cinfo->content.envelopedData;
00140            recipientinfos = envdp->recipientInfos;
00141            enccinfo = &(envdp->encContentInfo);
00142        }
00143        break;
00144       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
00145        {
00146            SEC_PKCS7SignedAndEnvelopedData *saedp;
00147 
00148            saedp = cinfo->content.signedAndEnvelopedData;
00149            recipientinfos = saedp->recipientInfos;
00150            enccinfo = &(saedp->encContentInfo);
00151        }
00152        break;
00153     }
00154 
00155     if (enccinfo == NULL)
00156        return NULL;
00157 
00158     bulkkey = orig_bulkkey;
00159     if (bulkkey == NULL) {
00160        CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
00161        PK11SlotInfo *slot;
00162 
00163 
00164        slot = PK11_GetBestSlot(type,cinfo->pwfn_arg);
00165        if (slot == NULL) {
00166            return NULL;
00167        }
00168        bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8,
00169                            cinfo->pwfn_arg);
00170        PK11_FreeSlot(slot);
00171        if (bulkkey == NULL) {
00172            return NULL;
00173        }
00174     }
00175 
00176     encryptobj = NULL;
00177     mark = PORT_ArenaMark (cinfo->poolp);
00178 
00179     /*
00180      * Encrypt the bulk key with the public key of each recipient.
00181      */
00182     for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
00183        CERTCertificate *cert;
00184        SECOidTag certalgtag, encalgtag;
00185        SECStatus rv;
00186        int data_len;
00187        SECItem *params = NULL;
00188 
00189        cert = ri->cert;
00190        PORT_Assert (cert != NULL);
00191        if (cert == NULL)
00192            continue;
00193 
00194        /*
00195         * XXX Want an interface that takes a cert and some data and
00196         * fills in an algorithmID and encrypts the data with the public
00197         * key from the cert.  Or, give me two interfaces -- one which
00198         * gets the algorithm tag from a cert (I should not have to go
00199         * down into the subjectPublicKeyInfo myself) and another which
00200         * takes a public key and algorithm tag and data and encrypts
00201         * the data.  Or something like that.  The point is that all
00202         * of the following hardwired RSA and KEA stuff should be done
00203         * elsewhere.
00204         */
00205 
00206        certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
00207 
00208        switch (certalgtag) {
00209        case SEC_OID_PKCS1_RSA_ENCRYPTION:
00210            encalgtag = certalgtag;
00211            publickey = CERT_ExtractPublicKey (cert);
00212            if (publickey == NULL) goto loser;
00213               
00214            data_len = SECKEY_PublicKeyStrength(publickey);
00215            ri->encKey.data = 
00216                (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len);
00217            ri->encKey.len = data_len;
00218            if (ri->encKey.data == NULL) goto loser;
00219 
00220            rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey,
00221                             bulkkey,&ri->encKey);
00222 
00223            SECKEY_DestroyPublicKey(publickey);
00224            publickey = NULL;
00225            if (rv != SECSuccess) goto loser;
00226            params = NULL; /* paranoia */
00227            break;
00228        /* ### mwelch -- KEA */ 
00229       case SEC_OID_MISSI_KEA_DSS_OLD:
00230       case SEC_OID_MISSI_KEA_DSS:
00231       case SEC_OID_MISSI_KEA:
00232            {
00233 #define SMIME_FORTEZZA_RA_LENGTH 128
00234 #define SMIME_FORTEZZA_IV_LENGTH 24
00235 #define SMIME_FORTEZZA_MAX_KEY_SIZE 256
00236               SECStatus err;
00237               PK11SymKey *tek;
00238               CERTCertificate *ourCert;
00239               SECKEYPublicKey *ourPubKey;
00240               SECKEATemplateSelector whichKEA = SECKEAInvalid;
00241 
00242               /* We really want to show our KEA tag as the
00243                  key exchange algorithm tag. */
00244               encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
00245 
00246               /* Get the public key of the recipient. */
00247               publickey = CERT_ExtractPublicKey(cert);
00248               if (publickey == NULL) goto loser;
00249 
00250               /* Find our own cert, and extract its keys. */
00251               ourCert = PK11_FindBestKEAMatch(cert,wincx);
00252               if (ourCert == NULL) goto loser;
00253 
00254               arena = PORT_NewArena(1024);
00255               if (arena == NULL) goto loser;
00256 
00257               ourPubKey = CERT_ExtractPublicKey(ourCert);
00258               if (ourPubKey == NULL)
00259               {
00260                   CERT_DestroyCertificate(ourCert);
00261                   goto loser;
00262               }
00263 
00264               /* While we're here, copy the public key into the outgoing
00265                * KEA parameters. */
00266               SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey),
00267                              &(ourPubKey->u.fortezza.KEAKey));
00268               SECKEY_DestroyPublicKey(ourPubKey);
00269               ourPubKey = NULL;
00270 
00271               /* Extract our private key in order to derive the 
00272                * KEA key. */
00273               ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
00274               CERT_DestroyCertificate(ourCert); /* we're done with this */
00275               if (!ourPrivKey) goto loser;
00276 
00277               /* Prepare raItem with 128 bytes (filled with zeros). */
00278               keaParams.originatorRA.data = 
00279                 (unsigned char*)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
00280               keaParams.originatorRA.len = SMIME_FORTEZZA_RA_LENGTH;
00281 
00282 
00283               /* Generate the TEK (token exchange key) which we use
00284                * to wrap the bulk encryption key. (raItem) will be
00285                * filled with a random seed which we need to send to
00286                * the recipient. */
00287               tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
00288                                  &keaParams.originatorRA, NULL,
00289                                  CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
00290                                  CKA_WRAP, 0, wincx);
00291 
00292                   SECKEY_DestroyPublicKey(publickey);
00293                   SECKEY_DestroyPrivateKey(ourPrivKey);
00294                   publickey = NULL;
00295                   ourPrivKey = NULL;
00296               
00297               if (!tek)
00298                   goto loser;
00299 
00300               ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp,
00301                                             SMIME_FORTEZZA_MAX_KEY_SIZE);
00302               ri->encKey.len = SMIME_FORTEZZA_MAX_KEY_SIZE;
00303 
00304               if (ri->encKey.data == NULL)
00305               {
00306                   PK11_FreeSymKey(tek);
00307                   goto loser;
00308               }
00309 
00310               /* Wrap the bulk key. What we do with the resulting data
00311                  depends on whether we're using Skipjack to wrap the key. */
00312               switch(PK11_AlgtagToMechanism(enccinfo->encalg))
00313               {
00314               case CKM_SKIPJACK_CBC64:
00315               case CKM_SKIPJACK_ECB64:
00316               case CKM_SKIPJACK_OFB64:
00317               case CKM_SKIPJACK_CFB64:
00318               case CKM_SKIPJACK_CFB32:
00319               case CKM_SKIPJACK_CFB16:
00320               case CKM_SKIPJACK_CFB8:
00321                   /* do SKIPJACK, we use the wrap mechanism */
00322                   err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, 
00323                                   tek, bulkkey, &ri->encKey);
00324                   whichKEA = SECKEAUsesSkipjack;
00325                   break;
00326               default:
00327                   /* Not SKIPJACK, we encrypt the raw key data */
00328                   keaParams.nonSkipjackIV .data = 
00329                     (unsigned char*)PORT_ArenaAlloc(arena,
00330                                                SMIME_FORTEZZA_IV_LENGTH);
00331                   keaParams.nonSkipjackIV.len = SMIME_FORTEZZA_IV_LENGTH;
00332                   err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64,
00333                                      &keaParams.nonSkipjackIV, 
00334                                       tek, bulkkey, &ri->encKey);
00335                   if (err != SECSuccess)
00336                      goto loser;
00337 
00338                   if (ri->encKey.len != PK11_GetKeyLength(bulkkey))
00339                   {
00340                      /* The size of the encrypted key is not the same as
00341                         that of the original bulk key, presumably due to
00342                         padding. Encode and store the real size of the
00343                         bulk key. */
00344                      if (SEC_ASN1EncodeInteger(arena, 
00345                                             &keaParams.bulkKeySize,
00346                                             PK11_GetKeyLength(bulkkey))
00347                          == NULL)
00348                          err = (SECStatus)PORT_GetError();
00349                      else
00350                          /* use full template for encoding */
00351                          whichKEA = SECKEAUsesNonSkipjackWithPaddedEncKey;
00352                   }
00353                   else
00354                      /* enc key length == bulk key length */
00355                      whichKEA = SECKEAUsesNonSkipjack; 
00356                   break;
00357               }
00358 
00359               PK11_FreeSymKey(tek);
00360               if (err != SECSuccess)
00361                   goto loser;
00362 
00363               PORT_Assert( whichKEA != SECKEAInvalid);
00364 
00365               /* Encode the KEA parameters into the recipient info. */
00366               params = SEC_ASN1EncodeItem(arena,NULL, &keaParams, 
00367                                   sec_pkcs7_get_kea_template(whichKEA));
00368               if (params == NULL) goto loser;
00369               break;
00370            }
00371        default:
00372            PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
00373            goto loser;
00374        }
00375 
00376        rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, 
00377                      params);
00378        if (rv != SECSuccess)
00379            goto loser;
00380        if (arena) PORT_FreeArena(arena,PR_FALSE);
00381        arena = NULL;
00382     }
00383 
00384     encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey,
00385                                           enccinfo->encalg,
00386                                           &(enccinfo->contentEncAlg));
00387     if (encryptobj != NULL) {
00388        PORT_ArenaUnmark (cinfo->poolp, mark);
00389        mark = NULL;         /* good one; do not want to release */
00390     }
00391     /* fallthru */
00392 
00393 loser:
00394     if (arena) {
00395        PORT_FreeArena(arena, PR_FALSE);
00396     }
00397     if (publickey) {
00398         SECKEY_DestroyPublicKey(publickey);
00399     }
00400     if (ourPrivKey) {
00401         SECKEY_DestroyPrivateKey(ourPrivKey);
00402     }
00403     if (mark != NULL) {
00404        PORT_ArenaRelease (cinfo->poolp, mark);
00405     }
00406     if (orig_bulkkey == NULL) {
00407        if (bulkkey) PK11_FreeSymKey(bulkkey);
00408     }
00409 
00410     return encryptobj;
00411 }
00412 
00413 
00414 static void
00415 sec_pkcs7_encoder_notify (void *arg, PRBool before, void *dest, int depth)
00416 {
00417     SEC_PKCS7EncoderContext *p7ecx;
00418     SEC_PKCS7ContentInfo *cinfo;
00419     SECOidTag kind;
00420     PRBool before_content;
00421 
00422     /*
00423      * We want to notice just before the content field.  After fields are
00424      * not interesting to us.
00425      */
00426     if (!before)
00427        return;
00428 
00429     p7ecx = (SEC_PKCS7EncoderContext*)arg;
00430     cinfo = p7ecx->cinfo;
00431 
00432     before_content = PR_FALSE;
00433 
00434     /*
00435      * Watch for the content field, at which point we want to instruct
00436      * the ASN.1 encoder to start taking bytes from the buffer.
00437      *
00438      * XXX The following assumes the inner content type is data;
00439      * if/when we want to handle fully nested types, this will have
00440      * to recurse until reaching the innermost data content.
00441      */
00442     kind = SEC_PKCS7ContentType (cinfo);
00443     switch (kind) {
00444       default:
00445       case SEC_OID_PKCS7_DATA:
00446        if (dest == &(cinfo->content.data))
00447            before_content = PR_TRUE;
00448        break;
00449 
00450       case SEC_OID_PKCS7_DIGESTED_DATA:
00451        {
00452            SEC_PKCS7DigestedData *digd;
00453 
00454            digd = cinfo->content.digestedData;
00455            if (digd == NULL)
00456               break;
00457 
00458            if (dest == &(digd->contentInfo.content))
00459               before_content = PR_TRUE;
00460        }
00461        break;
00462 
00463       case SEC_OID_PKCS7_ENCRYPTED_DATA:
00464        {
00465            SEC_PKCS7EncryptedData *encd;
00466 
00467            encd = cinfo->content.encryptedData;
00468            if (encd == NULL)
00469               break;
00470 
00471            if (dest == &(encd->encContentInfo.encContent))
00472               before_content = PR_TRUE;
00473        }
00474        break;
00475 
00476       case SEC_OID_PKCS7_ENVELOPED_DATA:
00477        {
00478            SEC_PKCS7EnvelopedData *envd;
00479 
00480            envd = cinfo->content.envelopedData;
00481            if (envd == NULL)
00482               break;
00483 
00484            if (dest == &(envd->encContentInfo.encContent))
00485               before_content = PR_TRUE;
00486        }
00487        break;
00488 
00489       case SEC_OID_PKCS7_SIGNED_DATA:
00490        {
00491            SEC_PKCS7SignedData *sigd;
00492 
00493            sigd = cinfo->content.signedData;
00494            if (sigd == NULL)
00495               break;
00496 
00497            if (dest == &(sigd->contentInfo.content))
00498               before_content = PR_TRUE;
00499        }
00500        break;
00501 
00502       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
00503        {
00504            SEC_PKCS7SignedAndEnvelopedData *saed;
00505 
00506            saed = cinfo->content.signedAndEnvelopedData;
00507            if (saed == NULL)
00508               break;
00509 
00510            if (dest == &(saed->encContentInfo.encContent))
00511               before_content = PR_TRUE;
00512        }
00513        break;
00514     }
00515 
00516     if (before_content) {
00517        /*
00518         * This will cause the next SEC_ASN1EncoderUpdate to take the
00519         * contents bytes from the passed-in buffer.
00520         */
00521        SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx);
00522        /*
00523         * And that is all we needed this notify function for.
00524         */
00525        SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx);
00526     }
00527 }
00528 
00529 
00530 static SEC_PKCS7EncoderContext *
00531 sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo,
00532                               PK11SymKey *bulkkey)
00533 {
00534     SEC_PKCS7EncoderContext *p7ecx;
00535     SECOidTag kind;
00536     PRBool encrypt;
00537     SECItem **digests;
00538     SECAlgorithmID *digestalg, **digestalgs;
00539 
00540     p7ecx = 
00541       (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext));
00542     if (p7ecx == NULL)
00543        return NULL;
00544 
00545     digests = NULL;
00546     digestalg = NULL;
00547     digestalgs = NULL;
00548     encrypt = PR_FALSE;
00549 
00550     kind = SEC_PKCS7ContentType (cinfo);
00551     switch (kind) {
00552       default:
00553       case SEC_OID_PKCS7_DATA:
00554        break;
00555       case SEC_OID_PKCS7_DIGESTED_DATA:
00556        digestalg = &(cinfo->content.digestedData->digestAlg);
00557        break;
00558       case SEC_OID_PKCS7_SIGNED_DATA:
00559        digests = cinfo->content.signedData->digests;
00560        digestalgs = cinfo->content.signedData->digestAlgorithms;
00561        break;
00562       case SEC_OID_PKCS7_ENCRYPTED_DATA:
00563       case SEC_OID_PKCS7_ENVELOPED_DATA:
00564        encrypt = PR_TRUE;
00565        break;
00566       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
00567        digests = cinfo->content.signedAndEnvelopedData->digests;
00568        digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms;
00569        encrypt = PR_TRUE;
00570        break;
00571     }
00572 
00573     if (encrypt) {
00574        p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey);
00575        if (p7ecx->encryptobj == NULL) {
00576            PORT_Free (p7ecx);
00577            return NULL;
00578        }
00579     }
00580 
00581     if (digestalgs != NULL) {
00582        if (digests != NULL) {
00583            /* digests already created (probably for detached data) */
00584            digestalg = NULL;
00585        } else {
00586            /*
00587             * XXX Some day we should handle multiple digests; for now,
00588             * assume only one will be done.
00589             */
00590            PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL);
00591            digestalg = digestalgs[0];
00592        }
00593     }
00594 
00595     if (digestalg != NULL) {
00596        SECOidTag  oidTag = SECOID_FindOIDTag(&(digestalg->algorithm));
00597 
00598        p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag);
00599        if (p7ecx->digestobj != NULL) {
00600            p7ecx->digestcx = (* p7ecx->digestobj->create) ();
00601            if (p7ecx->digestcx == NULL)
00602               p7ecx->digestobj = NULL;
00603            else
00604               (* p7ecx->digestobj->begin) (p7ecx->digestcx);
00605        }
00606        if (p7ecx->digestobj == NULL) {
00607            if (p7ecx->encryptobj != NULL)
00608               sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
00609            PORT_Free (p7ecx);
00610            return NULL;
00611        }
00612     }
00613 
00614     p7ecx->cinfo = cinfo;
00615     return p7ecx;
00616 }
00617 
00618 
00619 SEC_PKCS7EncoderContext *
00620 SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo,
00621                      SEC_PKCS7EncoderOutputCallback outputfn,
00622                      void *outputarg,
00623                      PK11SymKey *bulkkey)
00624 {
00625     SEC_PKCS7EncoderContext *p7ecx;
00626     SECStatus rv;
00627 
00628     p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
00629     if (p7ecx == NULL)
00630        return NULL;
00631 
00632     p7ecx->output.outputfn = outputfn;
00633     p7ecx->output.outputarg = outputarg;
00634 
00635     /*
00636      * Initialize the BER encoder.
00637      */
00638     p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate,
00639                                    sec_pkcs7_encoder_out, &(p7ecx->output));
00640     if (p7ecx->ecx == NULL) {
00641        PORT_Free (p7ecx);
00642        return NULL;
00643     }
00644 
00645     /*
00646      * Indicate that we are streaming.  We will be streaming until we
00647      * get past the contents bytes.
00648      */
00649     SEC_ASN1EncoderSetStreaming (p7ecx->ecx);
00650 
00651     /*
00652      * The notify function will watch for the contents field.
00653      */
00654     SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx);
00655 
00656     /*
00657      * This will encode everything up to the content bytes.  (The notify
00658      * function will then cause the encoding to stop there.)  Then our
00659      * caller can start passing contents bytes to our Update, which we
00660      * will pass along.
00661      */
00662     rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
00663     if (rv != SECSuccess) {
00664        PORT_Free (p7ecx);
00665        return NULL;
00666     }
00667 
00668     return p7ecx;
00669 }
00670 
00671 
00672 /*
00673  * XXX If/when we support nested contents, this needs to be revised.
00674  */
00675 static SECStatus
00676 sec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest,
00677                           const unsigned char *data, unsigned long len,
00678                           PRBool final)
00679 {
00680     unsigned char *buf = NULL;
00681     SECStatus rv;
00682 
00683 
00684     rv = SECSuccess;        /* may as well be optimistic */
00685 
00686     /*
00687      * We should really have data to process, or we should be trying
00688      * to finish/flush the last block.  (This is an overly paranoid
00689      * check since all callers are in this file and simple inspection
00690      * proves they do it right.  But it could find a bug in future
00691      * modifications/development, that is why it is here.)
00692      */
00693     PORT_Assert ((data != NULL && len) || final);
00694 
00695     /*
00696      * Update the running digest.
00697      * XXX This needs modification if/when we handle multiple digests.
00698      */
00699     if (len && p7ecx->digestobj != NULL) {
00700        (* p7ecx->digestobj->update) (p7ecx->digestcx, data, len);
00701     }
00702 
00703     /*
00704      * Encrypt this chunk.
00705      */
00706     if (p7ecx->encryptobj != NULL) {
00707        /* XXX the following lengths should all be longs? */
00708        unsigned int inlen;  /* length of data being encrypted */
00709        unsigned int outlen; /* length of encrypted data */
00710        unsigned int buflen; /* length available for encrypted data */
00711 
00712        inlen = len;
00713        buflen = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final);
00714        if (buflen == 0) {
00715            /*
00716             * No output is expected, but the input data may be buffered
00717             * so we still have to call Encrypt.
00718             */
00719            rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0,
00720                                data, inlen, final);
00721            if (final) {
00722               len = 0;
00723               goto done;
00724            }
00725            return rv;
00726        }
00727 
00728        if (dest != NULL)
00729            buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen);
00730        else
00731            buf = (unsigned char*)PORT_Alloc (buflen);
00732 
00733        if (buf == NULL) {
00734            rv = SECFailure;
00735        } else {
00736            rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen,
00737                                data, inlen, final);
00738            data = buf;
00739            len = outlen;
00740        }
00741        if (rv != SECSuccess) {
00742            if (final)
00743               goto done;
00744            return rv;
00745        }
00746     }
00747 
00748     if (p7ecx->ecx != NULL) {
00749        /*
00750         * Encode the contents bytes.
00751         */
00752        if(len) {
00753            rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len);
00754        }
00755     }
00756 
00757 done:
00758     if (p7ecx->encryptobj != NULL) {
00759        if (final)
00760            sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj);
00761        if (dest != NULL) {
00762            dest->data = buf;
00763            dest->len = len;
00764        } else if (buf != NULL) {
00765            PORT_Free (buf);
00766        }
00767     }
00768 
00769     if (final && p7ecx->digestobj != NULL) {
00770        SECItem *digest, **digests, ***digestsp;
00771        unsigned char *digdata;
00772        SECOidTag kind;
00773 
00774        kind = SEC_PKCS7ContentType (p7ecx->cinfo);
00775        switch (kind) {
00776          default:
00777            PORT_Assert (0);
00778            return SECFailure;
00779          case SEC_OID_PKCS7_DIGESTED_DATA:
00780            digest = &(p7ecx->cinfo->content.digestedData->digest);
00781            digestsp = NULL;
00782            break;
00783          case SEC_OID_PKCS7_SIGNED_DATA:
00784            digest = NULL;
00785            digestsp = &(p7ecx->cinfo->content.signedData->digests);
00786            break;
00787          case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
00788            digest = NULL;
00789            digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests);
00790            break;
00791        }
00792 
00793        digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
00794                                p7ecx->digestobj->length);
00795        if (digdata == NULL)
00796            return SECFailure;
00797 
00798        if (digestsp != NULL) {
00799            PORT_Assert (digest == NULL);
00800 
00801            digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, 
00802                                           sizeof(SECItem));
00803            digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp,
00804                                    2 * sizeof(SECItem *));
00805            if (digests == NULL || digest == NULL)
00806               return SECFailure;
00807 
00808            digests[0] = digest;
00809            digests[1] = NULL;
00810 
00811            *digestsp = digests;
00812        }
00813 
00814        PORT_Assert (digest != NULL);
00815 
00816        digest->data = digdata;
00817        digest->len = p7ecx->digestobj->length;
00818 
00819        (* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data,
00820                                &(digest->len), digest->len);
00821        (* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE);
00822     }
00823 
00824     return rv;
00825 }
00826 
00827 
00828 SECStatus
00829 SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx,
00830                      const char *data, unsigned long len)
00831 {
00832     /* XXX Error handling needs help.  Return what?  Do "Finish" on failure? */
00833     return sec_pkcs7_encoder_work_data (p7ecx, NULL,
00834                                    (const unsigned char *)data, len,
00835                                    PR_FALSE);
00836 }
00837 
00838 
00839 /*
00840  * XXX I would *really* like to not have to do this, but the current
00841  * signing interface gives me little choice.
00842  */
00843 static SECOidTag
00844 sec_pkcs7_pick_sign_alg (SECOidTag hashalg, SECOidTag encalg)
00845 {
00846     switch (encalg) {
00847       case SEC_OID_PKCS1_RSA_ENCRYPTION:
00848        switch (hashalg) {
00849          case SEC_OID_MD2:
00850            return SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
00851          case SEC_OID_MD5:
00852            return SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
00853          case SEC_OID_SHA1:
00854            return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
00855          case SEC_OID_SHA256:
00856            return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
00857          case SEC_OID_SHA384:
00858            return SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
00859          case SEC_OID_SHA512:
00860            return SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
00861          default:
00862            return SEC_OID_UNKNOWN;
00863        }
00864       case SEC_OID_ANSIX9_DSA_SIGNATURE:
00865       case SEC_OID_MISSI_KEA_DSS:
00866       case SEC_OID_MISSI_DSS:
00867        switch (hashalg) {
00868          case SEC_OID_SHA1:
00869            return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
00870          default:
00871            return SEC_OID_UNKNOWN;
00872        }
00873       case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
00874        switch (hashalg) {
00875          case SEC_OID_SHA1:
00876            return SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
00877          default:
00878            return SEC_OID_UNKNOWN;
00879        }
00880       default:
00881        break;
00882     }
00883 
00884     return encalg;          /* maybe it is already the right algid */
00885 }
00886 
00887 
00888 static SECStatus
00889 sec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo,
00890                              SECKEYGetPasswordKey pwfn, void *pwfnarg)
00891 {
00892     SECOidTag kind;
00893     CERTCertificate **certs;
00894     CERTCertificateList **certlists;
00895     SECAlgorithmID **digestalgs;
00896     SECItem **digests;
00897     SEC_PKCS7SignerInfo *signerinfo, **signerinfos;
00898     SECItem **rawcerts, ***rawcertsp;
00899     PRArenaPool *poolp;
00900     int certcount;
00901     int ci, cli, rci, si;
00902 
00903     kind = SEC_PKCS7ContentType (cinfo);
00904     switch (kind) {
00905       default:
00906       case SEC_OID_PKCS7_DATA:
00907       case SEC_OID_PKCS7_DIGESTED_DATA:
00908       case SEC_OID_PKCS7_ENCRYPTED_DATA:
00909       case SEC_OID_PKCS7_ENVELOPED_DATA:
00910        certs = NULL;
00911        certlists = NULL;
00912        digestalgs = NULL;
00913        digests = NULL;
00914        signerinfos = NULL;
00915        rawcertsp = NULL;
00916        break;
00917       case SEC_OID_PKCS7_SIGNED_DATA:
00918        {
00919            SEC_PKCS7SignedData *sdp;
00920 
00921            sdp = cinfo->content.signedData;
00922            certs = sdp->certs;
00923            certlists = sdp->certLists;
00924            digestalgs = sdp->digestAlgorithms;
00925            digests = sdp->digests;
00926            signerinfos = sdp->signerInfos;
00927            rawcertsp = &(sdp->rawCerts);
00928        }
00929        break;
00930       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
00931        {
00932            SEC_PKCS7SignedAndEnvelopedData *saedp;
00933 
00934            saedp = cinfo->content.signedAndEnvelopedData;
00935            certs = saedp->certs;
00936            certlists = saedp->certLists;
00937            digestalgs = saedp->digestAlgorithms;
00938            digests = saedp->digests;
00939            signerinfos = saedp->signerInfos;
00940            rawcertsp = &(saedp->rawCerts);
00941        }
00942        break;
00943     }
00944 
00945     if (certs == NULL && certlists == NULL && signerinfos == NULL)
00946        return SECSuccess;          /* nothing for us to do! */
00947 
00948     poolp = cinfo->poolp;
00949     certcount = 0;
00950 
00951     if (signerinfos != NULL) {
00952        SECOidTag digestalgtag;
00953        int di;
00954        SECStatus rv;
00955        CERTCertificate *cert;
00956        SECKEYPrivateKey *privkey;
00957        SECItem signature;
00958        SECOidTag signalgtag;
00959 
00960        PORT_Assert (digestalgs != NULL && digests != NULL);
00961 
00962        /*
00963         * If one fails, we bail right then.  If we want to continue and
00964         * try to do subsequent signatures, this loop, and the departures
00965         * from it, will need to be reworked.
00966         */
00967        for (si = 0; signerinfos[si] != NULL; si++) {
00968 
00969            signerinfo = signerinfos[si];
00970 
00971            /* find right digest */
00972            digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg));
00973            for (di = 0; digestalgs[di] != NULL; di++) {
00974               /* XXX Should I be comparing more than the tag? */
00975               if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di]))
00976                   break;
00977            }
00978            if (digestalgs[di] == NULL) {
00979               /* XXX oops; do what? set an error? */
00980               return SECFailure;
00981            }
00982            PORT_Assert (digests[di] != NULL);
00983 
00984            cert = signerinfo->cert;
00985            privkey = PK11_FindKeyByAnyCert (cert, pwfnarg);
00986            if (privkey == NULL)
00987               return SECFailure;
00988 
00989            /*
00990             * XXX I think there should be a cert-level interface for this,
00991             * so that I do not have to know about subjectPublicKeyInfo...
00992             */
00993            signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.algorithm));
00994 
00995            /* Fortezza MISSI have weird signature formats.  Map them
00996             * to standard DSA formats */
00997            signalgtag = PK11_FortezzaMapSig(signalgtag);
00998 
00999            if (signerinfo->authAttr != NULL) {
01000               SEC_PKCS7Attribute *attr;
01001               SECItem encoded_attrs;
01002               SECItem *dummy;
01003 
01004               /*
01005                * First, find and fill in the message digest attribute.
01006                */
01007               attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
01008                                           SEC_OID_PKCS9_MESSAGE_DIGEST,
01009                                           PR_TRUE);
01010               PORT_Assert (attr != NULL);
01011               if (attr == NULL) {
01012                   SECKEY_DestroyPrivateKey (privkey);
01013                   return SECFailure;
01014               }
01015 
01016               /*
01017                * XXX The second half of the following assertion prevents
01018                * the encoder from being called twice on the same content.
01019                * Either just remove the second half the assertion, or
01020                * change the code to check if the value already there is
01021                * the same as digests[di], whichever seems more right.
01022                */
01023               PORT_Assert (attr->values != NULL && attr->values[0] == NULL);
01024               attr->values[0] = digests[di];
01025 
01026               /*
01027                * Before encoding, reorder the attributes so that when they
01028                * are encoded, they will be conforming DER, which is required
01029                * to have a specific order and that is what must be used for
01030                * the hash/signature.  We do this here, rather than building
01031                * it into EncodeAttributes, because we do not want to do
01032                * such reordering on incoming messages (which also uses
01033                * EncodeAttributes) or our old signatures (and other "broken"
01034                * implementations) will not verify.  So, we want to guarantee
01035                * that we send out good DER encodings of attributes, but not
01036                * to expect to receive them.
01037                */
01038               rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr);
01039               if (rv != SECSuccess) {
01040                   SECKEY_DestroyPrivateKey (privkey);
01041                   return SECFailure;
01042               }
01043 
01044               encoded_attrs.data = NULL;
01045               encoded_attrs.len = 0;
01046               dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
01047                                              &(signerinfo->authAttr));
01048               if (dummy == NULL) {
01049                   SECKEY_DestroyPrivateKey (privkey);
01050                   return SECFailure;
01051               }
01052 
01053               rv = SEC_SignData (&signature,
01054                                encoded_attrs.data, encoded_attrs.len,
01055                                privkey,
01056                                sec_pkcs7_pick_sign_alg (digestalgtag,
01057                                                      signalgtag));
01058               SECITEM_FreeItem (&encoded_attrs, PR_FALSE);
01059            } else {
01060               rv = SGN_Digest (privkey, digestalgtag, &signature,
01061                              digests[di]);
01062            }
01063 
01064            SECKEY_DestroyPrivateKey (privkey);
01065 
01066            if (rv != SECSuccess)
01067               return rv;
01068 
01069            rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature);
01070            if (rv != SECSuccess)
01071               return rv;
01072 
01073            SECITEM_FreeItem (&signature, PR_FALSE);
01074 
01075            rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg),
01076                                    signalgtag, NULL);
01077            if (rv != SECSuccess)
01078               return SECFailure;
01079 
01080            /*
01081             * Count the cert chain for this signer.
01082             */
01083            if (signerinfo->certList != NULL)
01084               certcount += signerinfo->certList->len;
01085        }
01086     }
01087 
01088     if (certs != NULL) {
01089        for (ci = 0; certs[ci] != NULL; ci++)
01090            certcount++;
01091     }
01092 
01093     if (certlists != NULL) {
01094        for (cli = 0; certlists[cli] != NULL; cli++)
01095            certcount += certlists[cli]->len;
01096     }
01097 
01098     if (certcount == 0)
01099        return SECSuccess;          /* signing done; no certs */
01100 
01101     /*
01102      * Combine all of the certs and cert chains into rawcerts.
01103      * Note: certcount is an upper bound; we may not need that many slots
01104      * but we will allocate anyway to avoid having to do another pass.
01105      * (The temporary space saving is not worth it.)
01106      */
01107     rawcerts = (SECItem**)PORT_ArenaAlloc (poolp, 
01108                                    (certcount + 1) * sizeof(SECItem *));
01109     if (rawcerts == NULL)
01110        return SECFailure;
01111 
01112     /*
01113      * XXX Want to check for duplicates and not add *any* cert that is
01114      * already in the set.  This will be more important when we start
01115      * dealing with larger sets of certs, dual-key certs (signing and
01116      * encryption), etc.  For the time being we can slide by...
01117      */
01118     rci = 0;
01119     if (signerinfos != NULL) {
01120        for (si = 0; signerinfos[si] != NULL; si++) {
01121            signerinfo = signerinfos[si];
01122            for (ci = 0; ci < signerinfo->certList->len; ci++)
01123               rawcerts[rci++] = &(signerinfo->certList->certs[ci]);
01124        }
01125 
01126     }
01127 
01128     if (certs != NULL) {
01129        for (ci = 0; certs[ci] != NULL; ci++)
01130            rawcerts[rci++] = &(certs[ci]->derCert);
01131     }
01132 
01133     if (certlists != NULL) {
01134        for (cli = 0; certlists[cli] != NULL; cli++) {
01135            for (ci = 0; ci < certlists[cli]->len; ci++)
01136               rawcerts[rci++] = &(certlists[cli]->certs[ci]);
01137        }
01138     }
01139 
01140     rawcerts[rci] = NULL;
01141     *rawcertsp = rawcerts;
01142 
01143     return SECSuccess;
01144 }
01145 
01146 
01147 SECStatus
01148 SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,
01149                      SECKEYGetPasswordKey pwfn, void *pwfnarg)
01150 {
01151     SECStatus rv;
01152 
01153     /*
01154      * Flush out any remaining data.
01155      */
01156     rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE);
01157 
01158     /*
01159      * Turn off streaming stuff.
01160      */
01161     SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx);
01162     SEC_ASN1EncoderClearStreaming (p7ecx->ecx);
01163 
01164     if (rv != SECSuccess)
01165        goto loser;
01166 
01167     rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg);
01168     if (rv != SECSuccess)
01169        goto loser;
01170 
01171     rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);
01172 
01173 loser:
01174     SEC_ASN1EncoderFinish (p7ecx->ecx);
01175     PORT_Free (p7ecx);
01176     return rv;
01177 }
01178 
01179 /*
01180  * Abort the ASN.1 stream. Used by pkcs 12
01181  */
01182 void
01183 SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7ecx, int error)
01184 {
01185     PORT_Assert(p7ecx);
01186     SEC_ASN1EncoderAbort(p7ecx->ecx, error);
01187 }
01188 
01189 /*
01190  * After this routine is called, the entire PKCS7 contentInfo is ready
01191  * to be encoded.  This is used internally, but can also be called from
01192  * elsewhere for those who want to be able to just have pointers to
01193  * the ASN1 template for pkcs7 contentInfo built into their own encodings.
01194  */
01195 SECStatus
01196 SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,
01197                         PK11SymKey *bulkkey,
01198                         SECKEYGetPasswordKey pwfn,
01199                         void *pwfnarg)
01200 {
01201     SEC_PKCS7EncoderContext *p7ecx;
01202     SECItem *content, *enc_content;
01203     SECStatus rv;
01204 
01205     p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);
01206     if (p7ecx == NULL)
01207        return SECFailure;
01208 
01209     content = SEC_PKCS7GetContent (cinfo);
01210 
01211     if (p7ecx->encryptobj != NULL) {
01212        SECOidTag kind;
01213        SEC_PKCS7EncryptedContentInfo *enccinfo;
01214 
01215        kind = SEC_PKCS7ContentType (p7ecx->cinfo);
01216        switch (kind) {
01217          default:
01218            PORT_Assert (0);
01219            rv = SECFailure;
01220            goto loser;
01221          case SEC_OID_PKCS7_ENCRYPTED_DATA:
01222            enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);
01223            break;
01224          case SEC_OID_PKCS7_ENVELOPED_DATA:
01225            enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);
01226            break;
01227          case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
01228            enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);
01229            break;
01230        }
01231        enc_content = &(enccinfo->encContent);
01232     } else {
01233        enc_content = NULL;
01234     }
01235 
01236     if (content != NULL && content->data != NULL && content->len) {
01237        rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content,
01238                                      content->data, content->len, PR_TRUE);
01239        if (rv != SECSuccess)
01240            goto loser;
01241     }
01242 
01243     rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg);
01244 
01245 loser:
01246     PORT_Free (p7ecx);
01247     return rv;
01248 }
01249 
01250 
01251 /*
01252  * Encode a PKCS7 object, in one shot.  All necessary components
01253  * of the object must already be specified.  Either the data has
01254  * already been included (via SetContent), or the data is detached,
01255  * or there is no data at all (certs-only).
01256  *
01257  * "cinfo" specifies the object to be encoded.
01258  *
01259  * "outputfn" is where the encoded bytes will be passed.
01260  *
01261  * "outputarg" is an opaque argument to the above callback.
01262  *
01263  * "bulkkey" specifies the bulk encryption key to use.   This argument
01264  * can be NULL if no encryption is being done, or if the bulk key should
01265  * be generated internally (usually the case for EnvelopedData but never
01266  * for EncryptedData, which *must* provide a bulk encryption key).
01267  *
01268  * "pwfn" is a callback for getting the password which protects the
01269  * private key of the signer.  This argument can be NULL if it is known
01270  * that no signing is going to be done.
01271  *
01272  * "pwfnarg" is an opaque argument to the above callback.
01273  */
01274 SECStatus
01275 SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,
01276                SEC_PKCS7EncoderOutputCallback outputfn,
01277                void *outputarg,
01278                PK11SymKey *bulkkey,
01279                SECKEYGetPasswordKey pwfn,
01280                void *pwfnarg)
01281 {
01282     SECStatus rv;
01283 
01284     rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
01285     if (rv == SECSuccess) {
01286        struct sec_pkcs7_encoder_output outputcx;
01287 
01288        outputcx.outputfn = outputfn;
01289        outputcx.outputarg = outputarg;
01290 
01291        rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate,
01292                           sec_pkcs7_encoder_out, &outputcx);
01293     }
01294 
01295     return rv;
01296 }
01297 
01298 
01299 /*
01300  * Encode a PKCS7 object, in one shot.  All necessary components
01301  * of the object must already be specified.  Either the data has
01302  * already been included (via SetContent), or the data is detached,
01303  * or there is no data at all (certs-only).  The output, rather than
01304  * being passed to an output function as is done above, is all put
01305  * into a SECItem.
01306  *
01307  * "pool" specifies a pool from which to allocate the result.
01308  * It can be NULL, in which case memory is allocated generically.
01309  *
01310  * "dest" specifies a SECItem in which to put the result data.
01311  * It can be NULL, in which case the entire item is allocated, too.
01312  *
01313  * "cinfo" specifies the object to be encoded.
01314  *
01315  * "bulkkey" specifies the bulk encryption key to use.   This argument
01316  * can be NULL if no encryption is being done, or if the bulk key should
01317  * be generated internally (usually the case for EnvelopedData but never
01318  * for EncryptedData, which *must* provide a bulk encryption key).
01319  *
01320  * "pwfn" is a callback for getting the password which protects the
01321  * private key of the signer.  This argument can be NULL if it is known
01322  * that no signing is going to be done.
01323  *
01324  * "pwfnarg" is an opaque argument to the above callback.
01325  */
01326 SECItem *
01327 SEC_PKCS7EncodeItem (PRArenaPool *pool,
01328                    SECItem *dest,
01329                    SEC_PKCS7ContentInfo *cinfo,
01330                    PK11SymKey *bulkkey,
01331                    SECKEYGetPasswordKey pwfn,
01332                    void *pwfnarg)
01333 {
01334     SECStatus rv;
01335 
01336     rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);
01337     if (rv != SECSuccess)
01338        return NULL;
01339 
01340     return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);
01341 }
01342