Back to index

lightning-sunbird  0.9+nobinonly
p7local.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  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * Support routines for PKCS7 implementation, none of which are exported.
00039  * This file should only contain things that are needed by both the
00040  * encoding/creation side *and* the decoding/decryption side.  Anything
00041  * else should be static routines in the appropriate file.
00042  *
00043  * $Id: p7local.c,v 1.8 2005/10/03 22:01:56 relyea%netscape.com Exp $
00044  */
00045 
00046 #include "p7local.h"
00047 
00048 #include "cryptohi.h" 
00049 #include "secasn1.h"
00050 #include "secoid.h"
00051 #include "secitem.h"
00052 #include "pk11func.h"
00053 #include "secpkcs5.h"
00054 #include "secerr.h"
00055 
00056 /*
00057  * -------------------------------------------------------------------
00058  * Cipher stuff.
00059  */
00060 
00061 typedef SECStatus (*sec_pkcs7_cipher_function) (void *,
00062                                           unsigned char *,
00063                                           unsigned *,
00064                                           unsigned int,
00065                                           const unsigned char *,
00066                                           unsigned int);
00067 typedef SECStatus (*sec_pkcs7_cipher_destroy) (void *, PRBool);
00068 
00069 #define BLOCK_SIZE 4096
00070 
00071 struct sec_pkcs7_cipher_object {
00072     void *cx;
00073     sec_pkcs7_cipher_function doit;
00074     sec_pkcs7_cipher_destroy destroy;
00075     PRBool encrypt;
00076     int block_size;
00077     int pad_size;
00078     int pending_count;
00079     unsigned char pending_buf[BLOCK_SIZE];
00080 };
00081 
00082 SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
00083 SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate)
00084 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
00085 SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
00086 SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
00087 
00088 /*
00089  * Create a cipher object to do decryption,  based on the given bulk
00090  * encryption key and algorithm identifier (which may include an iv).
00091  *
00092  * XXX This interface, or one similar, would be really nice available
00093  * in general...  I tried to keep the pkcs7-specific stuff (mostly
00094  * having to do with padding) out of here.
00095  *
00096  * XXX Once both are working, it might be nice to combine this and the
00097  * function below (for starting up encryption) into one routine, and just
00098  * have two simple cover functions which call it. 
00099  */
00100 sec_PKCS7CipherObject *
00101 sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid)
00102 {
00103     sec_PKCS7CipherObject *result;
00104     SECOidTag algtag;
00105     void *ciphercx;
00106     CK_MECHANISM_TYPE mechanism;
00107     SECItem *param;
00108     PK11SlotInfo *slot;
00109 
00110     result = (struct sec_pkcs7_cipher_object*)
00111       PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
00112     if (result == NULL)
00113        return NULL;
00114 
00115     ciphercx = NULL;
00116     algtag = SECOID_GetAlgorithmTag (algid);
00117 
00118     if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
00119        CK_MECHANISM pbeMech, cryptoMech;
00120        SECItem *pbeParams, *pwitem;
00121 
00122        pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
00123        if (!pwitem) {
00124            PORT_Free(result);
00125            return NULL;
00126        }
00127 
00128        pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
00129        pbeParams = PK11_ParamFromAlgid(algid);
00130        if (!pbeParams) {
00131            PORT_Free(result);
00132            return NULL;
00133        }
00134 
00135        pbeMech.pParameter = pbeParams->data;
00136        pbeMech.ulParameterLen = pbeParams->len;
00137        if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, pwitem,
00138                                             PR_FALSE) != CKR_OK) { 
00139            PORT_Free(result);
00140            SECITEM_ZfreeItem(pbeParams, PR_TRUE);
00141            return NULL;
00142        }
00143        SECITEM_ZfreeItem(pbeParams, PR_TRUE);
00144 
00145        param = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
00146        if(!param) {
00147             PORT_Free(result);
00148             return NULL;
00149        }
00150        param->data = (unsigned char *)cryptoMech.pParameter;
00151        param->len = cryptoMech.ulParameterLen;
00152        mechanism = cryptoMech.mechanism;
00153     } else {
00154        mechanism = PK11_AlgtagToMechanism(algtag);
00155        param = PK11_ParamFromAlgid(algid);
00156        if (param == NULL) {
00157            PORT_Free(result);
00158            return NULL;
00159        }
00160     }
00161 
00162     result->pad_size = PK11_GetBlockSize(mechanism,param);
00163     slot = PK11_GetSlotFromKey(key);
00164     result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
00165     PK11_FreeSlot(slot);
00166     ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param);
00167     SECITEM_FreeItem(param,PR_TRUE);
00168     if (ciphercx == NULL) {
00169        PORT_Free (result);
00170        return NULL;
00171     }
00172 
00173     result->cx = ciphercx;
00174     result->doit =  (sec_pkcs7_cipher_function) PK11_CipherOp;
00175     result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
00176     result->encrypt = PR_FALSE;
00177     result->pending_count = 0;
00178 
00179     return result;
00180 }
00181 
00182 /*
00183  * Create a cipher object to do encryption, based on the given bulk
00184  * encryption key and algorithm tag.  Fill in the algorithm identifier
00185  * (which may include an iv) appropriately.
00186  *
00187  * XXX This interface, or one similar, would be really nice available
00188  * in general...  I tried to keep the pkcs7-specific stuff (mostly
00189  * having to do with padding) out of here.
00190  *
00191  * XXX Once both are working, it might be nice to combine this and the
00192  * function above (for starting up decryption) into one routine, and just
00193  * have two simple cover functions which call it. 
00194  */
00195 sec_PKCS7CipherObject *
00196 sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key,
00197                            SECOidTag algtag, SECAlgorithmID *algid)
00198 {
00199     sec_PKCS7CipherObject *result;
00200     void *ciphercx;
00201     SECItem *param;
00202     SECStatus rv;
00203     CK_MECHANISM_TYPE mechanism;
00204     PRBool needToEncodeAlgid = PR_FALSE;
00205     PK11SlotInfo *slot;
00206 
00207     result = (struct sec_pkcs7_cipher_object*)
00208              PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
00209     if (result == NULL)
00210        return NULL;
00211 
00212     ciphercx = NULL;
00213     if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
00214        CK_MECHANISM pbeMech, cryptoMech;
00215        SECItem *pbeParams, *pwitem;
00216 
00217        PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM));
00218        PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM));
00219 
00220        pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
00221        if (!pwitem) {
00222            PORT_Free(result);
00223            return NULL;
00224        }
00225 
00226        pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
00227        pbeParams = PK11_ParamFromAlgid(algid);
00228        if(!pbeParams) {
00229            PORT_Free(result);
00230            return NULL;
00231        }
00232 
00233        pbeMech.pParameter = pbeParams->data;
00234        pbeMech.ulParameterLen = pbeParams->len;
00235        if(PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, pwitem,
00236                                                   PR_FALSE) != CKR_OK) {
00237            PORT_Free(result);
00238            SECITEM_ZfreeItem(pbeParams, PR_TRUE);
00239            return NULL;
00240        }
00241        SECITEM_ZfreeItem(pbeParams, PR_TRUE);
00242 
00243        param = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
00244        if(!param) {
00245             PORT_Free(result);
00246             return NULL;
00247        }
00248        param->data = (unsigned char *)cryptoMech.pParameter;
00249        param->len = cryptoMech.ulParameterLen;
00250        mechanism = cryptoMech.mechanism;
00251     } else {
00252        mechanism = PK11_AlgtagToMechanism(algtag);
00253        param = PK11_GenerateNewParam(mechanism,key);
00254        if (param == NULL) {
00255            PORT_Free(result);
00256            return NULL;
00257        }
00258        needToEncodeAlgid = PR_TRUE;
00259     }
00260 
00261     result->pad_size = PK11_GetBlockSize(mechanism,param);
00262     slot = PK11_GetSlotFromKey(key);
00263     result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
00264     PK11_FreeSlot(slot);
00265     ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, 
00266                                      key, param);
00267     if (ciphercx == NULL) {
00268        PORT_Free (result);
00269         SECITEM_FreeItem(param,PR_TRUE);
00270        return NULL;
00271     }
00272 
00273     /*
00274      * These are placed after the CreateContextBySymKey() because some
00275      * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
00276      * Don't move it from here.
00277      */
00278     if (needToEncodeAlgid) {
00279        rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
00280        if(rv != SECSuccess) {
00281            return NULL;
00282        }
00283     }
00284     SECITEM_FreeItem(param,PR_TRUE);
00285 
00286     result->cx = ciphercx;
00287     result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
00288     result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
00289     result->encrypt = PR_TRUE;
00290     result->pending_count = 0;
00291 
00292     return result;
00293 }
00294 
00295 
00296 /*
00297  * Destroy the cipher object.
00298  */
00299 static void
00300 sec_pkcs7_destroy_cipher (sec_PKCS7CipherObject *obj)
00301 {
00302     (* obj->destroy) (obj->cx, PR_TRUE);
00303     PORT_Free (obj);
00304 }
00305 
00306 void
00307 sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj)
00308 {
00309     PORT_Assert (obj != NULL);
00310     if (obj == NULL)
00311        return;
00312     PORT_Assert (! obj->encrypt);
00313     sec_pkcs7_destroy_cipher (obj);
00314 }
00315 
00316 void
00317 sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj)
00318 {
00319     PORT_Assert (obj != NULL);
00320     if (obj == NULL)
00321        return;
00322     PORT_Assert (obj->encrypt);
00323     sec_pkcs7_destroy_cipher (obj);
00324 }
00325 
00326 
00327 /*
00328  * XXX I think all of the following lengths should be longs instead
00329  * of ints, but our current crypto interface uses ints, so I did too.
00330  */
00331 
00332 
00333 /*
00334  * What will be the output length of the next call to decrypt?
00335  * Result can be used to perform memory allocations.  Note that the amount
00336  * is exactly accurate only when not doing a block cipher or when final
00337  * is false, otherwise it is an upper bound on the amount because until
00338  * we see the data we do not know how many padding bytes there are
00339  * (always between 1 and bsize).
00340  *
00341  * Note that this can return zero, which does not mean that the decrypt
00342  * operation can be skipped!  (It simply means that there are not enough
00343  * bytes to make up an entire block; the bytes will be reserved until
00344  * there are enough to encrypt/decrypt at least one block.)  However,
00345  * if zero is returned it *does* mean that no output buffer need be
00346  * passed in to the subsequent decrypt operation, as no output bytes
00347  * will be stored.
00348  */
00349 unsigned int
00350 sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
00351                      PRBool final)
00352 {
00353     int blocks, block_size;
00354 
00355     PORT_Assert (! obj->encrypt);
00356 
00357     block_size = obj->block_size;
00358 
00359     /*
00360      * If this is not a block cipher, then we always have the same
00361      * number of output bytes as we had input bytes.
00362      */
00363     if (block_size == 0)
00364        return input_len;
00365 
00366     /*
00367      * On the final call, we will always use up all of the pending
00368      * bytes plus all of the input bytes, *but*, there will be padding
00369      * at the end and we cannot predict how many bytes of padding we
00370      * will end up removing.  The amount given here is actually known
00371      * to be at least 1 byte too long (because we know we will have
00372      * at least 1 byte of padding), but seemed clearer/better to me.
00373      */
00374     if (final)
00375        return obj->pending_count + input_len;
00376 
00377     /*
00378      * Okay, this amount is exactly what we will output on the
00379      * next cipher operation.  We will always hang onto the last
00380      * 1 - block_size bytes for non-final operations.  That is,
00381      * we will do as many complete blocks as we can *except* the
00382      * last block (complete or partial).  (This is because until
00383      * we know we are at the end, we cannot know when to interpret
00384      * and removing the padding byte(s), which are guaranteed to
00385      * be there.)
00386      */
00387     blocks = (obj->pending_count + input_len - 1) / block_size;
00388     return blocks * block_size;
00389 }
00390 
00391 /*
00392  * What will be the output length of the next call to encrypt?
00393  * Result can be used to perform memory allocations.
00394  *
00395  * Note that this can return zero, which does not mean that the encrypt
00396  * operation can be skipped!  (It simply means that there are not enough
00397  * bytes to make up an entire block; the bytes will be reserved until
00398  * there are enough to encrypt/decrypt at least one block.)  However,
00399  * if zero is returned it *does* mean that no output buffer need be
00400  * passed in to the subsequent encrypt operation, as no output bytes
00401  * will be stored.
00402  */
00403 unsigned int
00404 sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
00405                      PRBool final)
00406 {
00407     int blocks, block_size;
00408     int pad_size;
00409 
00410     PORT_Assert (obj->encrypt);
00411 
00412     block_size = obj->block_size;
00413     pad_size = obj->pad_size;
00414 
00415     /*
00416      * If this is not a block cipher, then we always have the same
00417      * number of output bytes as we had input bytes.
00418      */
00419     if (block_size == 0)
00420        return input_len;
00421 
00422     /*
00423      * On the final call, we only send out what we need for
00424      * remaining bytes plus the padding.  (There is always padding,
00425      * so even if we have an exact number of blocks as input, we
00426      * will add another full block that is just padding.)
00427      */
00428     if (final) {
00429        if (pad_size == 0) {
00430            return obj->pending_count + input_len;
00431        } else {
00432            blocks = (obj->pending_count + input_len) / pad_size;
00433            blocks++;
00434            return blocks*pad_size;
00435        }
00436     }
00437 
00438     /*
00439      * Now, count the number of complete blocks of data we have.
00440      */
00441     blocks = (obj->pending_count + input_len) / block_size;
00442 
00443 
00444     return blocks * block_size;
00445 }
00446 
00447 
00448 /*
00449  * Decrypt a given length of input buffer (starting at "input" and
00450  * containing "input_len" bytes), placing the decrypted bytes in
00451  * "output" and storing the output length in "*output_len_p".
00452  * "obj" is the return value from sec_PKCS7CreateDecryptObject.
00453  * When "final" is true, this is the last of the data to be decrypted.
00454  *
00455  * This is much more complicated than it sounds when the cipher is
00456  * a block-type, meaning that the decryption function will only
00457  * operate on whole blocks.  But our caller is operating stream-wise,
00458  * and can pass in any number of bytes.  So we need to keep track
00459  * of block boundaries.  We save excess bytes between calls in "obj".
00460  * We also need to determine which bytes are padding, and remove
00461  * them from the output.  We can only do this step when we know we
00462  * have the final block of data.  PKCS #7 specifies that the padding
00463  * used for a block cipher is a string of bytes, each of whose value is
00464  * the same as the length of the padding, and that all data is padded.
00465  * (Even data that starts out with an exact multiple of blocks gets
00466  * added to it another block, all of which is padding.)
00467  */ 
00468 SECStatus
00469 sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
00470                 unsigned int *output_len_p, unsigned int max_output_len,
00471                 const unsigned char *input, unsigned int input_len,
00472                 PRBool final)
00473 {
00474     int blocks, bsize, pcount, padsize;
00475     unsigned int max_needed, ifraglen, ofraglen, output_len;
00476     unsigned char *pbuf;
00477     SECStatus rv;
00478 
00479     PORT_Assert (! obj->encrypt);
00480 
00481     /*
00482      * Check that we have enough room for the output.  Our caller should
00483      * already handle this; failure is really an internal error (i.e. bug).
00484      */
00485     max_needed = sec_PKCS7DecryptLength (obj, input_len, final);
00486     PORT_Assert (max_output_len >= max_needed);
00487     if (max_output_len < max_needed) {
00488        /* PORT_SetError (XXX); */
00489        return SECFailure;
00490     }
00491 
00492     /*
00493      * hardware encryption does not like small decryption sizes here, so we
00494      * allow both blocking and padding.
00495      */
00496     bsize = obj->block_size;
00497     padsize = obj->pad_size;
00498 
00499     /*
00500      * When no blocking or padding work to do, we can simply call the
00501      * cipher function and we are done.
00502      */
00503     if (bsize == 0) {
00504        return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
00505                            input, input_len);
00506     }
00507 
00508     pcount = obj->pending_count;
00509     pbuf = obj->pending_buf;
00510 
00511     output_len = 0;
00512 
00513     if (pcount) {
00514        /*
00515         * Try to fill in an entire block, starting with the bytes
00516         * we already have saved away.
00517         */
00518        while (input_len && pcount < bsize) {
00519            pbuf[pcount++] = *input++;
00520            input_len--;
00521        }
00522        /*
00523         * If we have at most a whole block and this is not our last call,
00524         * then we are done for now.  (We do not try to decrypt a lone
00525         * single block because we cannot interpret the padding bytes
00526         * until we know we are handling the very last block of all input.)
00527         */
00528        if (input_len == 0 && !final) {
00529            obj->pending_count = pcount;
00530            if (output_len_p)
00531               *output_len_p = 0;
00532            return SECSuccess;
00533        }
00534        /*
00535         * Given the logic above, we expect to have a full block by now.
00536         * If we do not, there is something wrong, either with our own
00537         * logic or with (length of) the data given to us.
00538         */
00539        PORT_Assert ((padsize == 0) || (pcount % padsize) == 0);
00540        if ((padsize != 0) && (pcount % padsize) != 0) {
00541            PORT_Assert (final);    
00542            PORT_SetError (SEC_ERROR_BAD_DATA);
00543            return SECFailure;
00544        }
00545        /*
00546         * Decrypt the block.
00547         */
00548        rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
00549                          pbuf, pcount);
00550        if (rv != SECSuccess)
00551            return rv;
00552 
00553        /*
00554         * For now anyway, all of our ciphers have the same number of
00555         * bytes of output as they do input.  If this ever becomes untrue,
00556         * then sec_PKCS7DecryptLength needs to be made smarter!
00557         */
00558        PORT_Assert (ofraglen == pcount);
00559 
00560        /*
00561         * Account for the bytes now in output.
00562         */
00563        max_output_len -= ofraglen;
00564        output_len += ofraglen;
00565        output += ofraglen;
00566     }
00567 
00568     /*
00569      * If this is our last call, we expect to have an exact number of
00570      * blocks left to be decrypted; we will decrypt them all.
00571      * 
00572      * If not our last call, we always save between 1 and bsize bytes
00573      * until next time.  (We must do this because we cannot be sure
00574      * that none of the decrypted bytes are padding bytes until we
00575      * have at least another whole block of data.  You cannot tell by
00576      * looking -- the data could be anything -- you can only tell by
00577      * context, knowing you are looking at the last block.)  We could
00578      * decrypt a whole block now but it is easier if we just treat it
00579      * the same way we treat partial block bytes.
00580      */
00581     if (final) {
00582        if (padsize) {
00583            blocks = input_len / padsize;
00584            ifraglen = blocks * padsize;
00585        } else ifraglen = input_len;
00586        PORT_Assert (ifraglen == input_len);
00587 
00588        if (ifraglen != input_len) {
00589            PORT_SetError (SEC_ERROR_BAD_DATA);
00590            return SECFailure;
00591        }
00592     } else {
00593        blocks = (input_len - 1) / bsize;
00594        ifraglen = blocks * bsize;
00595        PORT_Assert (ifraglen < input_len);
00596 
00597        pcount = input_len - ifraglen;
00598        PORT_Memcpy (pbuf, input + ifraglen, pcount);
00599        obj->pending_count = pcount;
00600     }
00601 
00602     if (ifraglen) {
00603        rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
00604                          input, ifraglen);
00605        if (rv != SECSuccess)
00606            return rv;
00607 
00608        /*
00609         * For now anyway, all of our ciphers have the same number of
00610         * bytes of output as they do input.  If this ever becomes untrue,
00611         * then sec_PKCS7DecryptLength needs to be made smarter!
00612         */
00613        PORT_Assert (ifraglen == ofraglen);
00614        if (ifraglen != ofraglen) {
00615            PORT_SetError (SEC_ERROR_BAD_DATA);
00616            return SECFailure;
00617        }
00618 
00619        output_len += ofraglen;
00620     } else {
00621        ofraglen = 0;
00622     }
00623 
00624     /*
00625      * If we just did our very last block, "remove" the padding by
00626      * adjusting the output length.
00627      */
00628     if (final && (padsize != 0)) {
00629        unsigned int padlen = *(output + ofraglen - 1);
00630        PORT_Assert (padlen > 0 && padlen <= padsize);
00631        if (padlen == 0 || padlen > padsize) {
00632            PORT_SetError (SEC_ERROR_BAD_DATA);
00633            return SECFailure;
00634        }
00635        output_len -= padlen;
00636     }
00637 
00638     PORT_Assert (output_len_p != NULL || output_len == 0);
00639     if (output_len_p != NULL)
00640        *output_len_p = output_len;
00641 
00642     return SECSuccess;
00643 }
00644 
00645 /*
00646  * Encrypt a given length of input buffer (starting at "input" and
00647  * containing "input_len" bytes), placing the encrypted bytes in
00648  * "output" and storing the output length in "*output_len_p".
00649  * "obj" is the return value from sec_PKCS7CreateEncryptObject.
00650  * When "final" is true, this is the last of the data to be encrypted.
00651  *
00652  * This is much more complicated than it sounds when the cipher is
00653  * a block-type, meaning that the encryption function will only
00654  * operate on whole blocks.  But our caller is operating stream-wise,
00655  * and can pass in any number of bytes.  So we need to keep track
00656  * of block boundaries.  We save excess bytes between calls in "obj".
00657  * We also need to add padding bytes at the end.  PKCS #7 specifies
00658  * that the padding used for a block cipher is a string of bytes,
00659  * each of whose value is the same as the length of the padding,
00660  * and that all data is padded.  (Even data that starts out with
00661  * an exact multiple of blocks gets added to it another block,
00662  * all of which is padding.)
00663  *
00664  * XXX I would kind of like to combine this with the function above
00665  * which does decryption, since they have a lot in common.  But the
00666  * tricky parts about padding and filling blocks would be much
00667  * harder to read that way, so I left them separate.  At least for
00668  * now until it is clear that they are right.
00669  */ 
00670 SECStatus
00671 sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
00672                 unsigned int *output_len_p, unsigned int max_output_len,
00673                 const unsigned char *input, unsigned int input_len,
00674                 PRBool final)
00675 {
00676     int blocks, bsize, padlen, pcount, padsize;
00677     unsigned int max_needed, ifraglen, ofraglen, output_len;
00678     unsigned char *pbuf;
00679     SECStatus rv;
00680 
00681     PORT_Assert (obj->encrypt);
00682 
00683     /*
00684      * Check that we have enough room for the output.  Our caller should
00685      * already handle this; failure is really an internal error (i.e. bug).
00686      */
00687     max_needed = sec_PKCS7EncryptLength (obj, input_len, final);
00688     PORT_Assert (max_output_len >= max_needed);
00689     if (max_output_len < max_needed) {
00690        /* PORT_SetError (XXX); */
00691        return SECFailure;
00692     }
00693 
00694     bsize = obj->block_size;
00695     padsize = obj->pad_size;
00696 
00697     /*
00698      * When no blocking and padding work to do, we can simply call the
00699      * cipher function and we are done.
00700      */
00701     if (bsize == 0) {
00702        return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
00703                            input, input_len);
00704     }
00705 
00706     pcount = obj->pending_count;
00707     pbuf = obj->pending_buf;
00708 
00709     output_len = 0;
00710 
00711     if (pcount) {
00712        /*
00713         * Try to fill in an entire block, starting with the bytes
00714         * we already have saved away.
00715         */
00716        while (input_len && pcount < bsize) {
00717            pbuf[pcount++] = *input++;
00718            input_len--;
00719        }
00720        /*
00721         * If we do not have a full block and we know we will be
00722         * called again, then we are done for now.
00723         */
00724        if (pcount < bsize && !final) {
00725            obj->pending_count = pcount;
00726            if (output_len_p != NULL)
00727               *output_len_p = 0;
00728            return SECSuccess;
00729        }
00730        /*
00731         * If we have a whole block available, encrypt it.
00732         */
00733        if ((padsize == 0) || (pcount % padsize) == 0) {
00734            rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
00735                             pbuf, pcount);
00736            if (rv != SECSuccess)
00737               return rv;
00738 
00739            /*
00740             * For now anyway, all of our ciphers have the same number of
00741             * bytes of output as they do input.  If this ever becomes untrue,
00742             * then sec_PKCS7EncryptLength needs to be made smarter!
00743             */
00744            PORT_Assert (ofraglen == pcount);
00745 
00746            /*
00747             * Account for the bytes now in output.
00748             */
00749            max_output_len -= ofraglen;
00750            output_len += ofraglen;
00751            output += ofraglen;
00752 
00753            pcount = 0;
00754        }
00755     }
00756 
00757     if (input_len) {
00758        PORT_Assert (pcount == 0);
00759 
00760        blocks = input_len / bsize;
00761        ifraglen = blocks * bsize;
00762 
00763        if (ifraglen) {
00764            rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
00765                             input, ifraglen);
00766            if (rv != SECSuccess)
00767               return rv;
00768 
00769            /*
00770             * For now anyway, all of our ciphers have the same number of
00771             * bytes of output as they do input.  If this ever becomes untrue,
00772             * then sec_PKCS7EncryptLength needs to be made smarter!
00773             */
00774            PORT_Assert (ifraglen == ofraglen);
00775 
00776            max_output_len -= ofraglen;
00777            output_len += ofraglen;
00778            output += ofraglen;
00779        }
00780 
00781        pcount = input_len - ifraglen;
00782        PORT_Assert (pcount < bsize);
00783        if (pcount)
00784            PORT_Memcpy (pbuf, input + ifraglen, pcount);
00785     }
00786 
00787     if (final) {
00788        padlen = padsize - (pcount % padsize);
00789        PORT_Memset (pbuf + pcount, padlen, padlen);
00790        rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
00791                          pbuf, pcount+padlen);
00792        if (rv != SECSuccess)
00793            return rv;
00794 
00795        /*
00796         * For now anyway, all of our ciphers have the same number of
00797         * bytes of output as they do input.  If this ever becomes untrue,
00798         * then sec_PKCS7EncryptLength needs to be made smarter!
00799         */
00800        PORT_Assert (ofraglen == (pcount+padlen));
00801        output_len += ofraglen;
00802     } else {
00803        obj->pending_count = pcount;
00804     }
00805 
00806     PORT_Assert (output_len_p != NULL || output_len == 0);
00807     if (output_len_p != NULL)
00808        *output_len_p = output_len;
00809 
00810     return SECSuccess;
00811 }
00812 
00813 /*
00814  * End of cipher stuff.
00815  * -------------------------------------------------------------------
00816  */
00817 
00818 
00819 /*
00820  * -------------------------------------------------------------------
00821  * XXX The following Attribute stuff really belongs elsewhere.
00822  * The Attribute type is *not* part of pkcs7 but rather X.501.
00823  * But for now, since PKCS7 is the only customer of attributes,
00824  * we define them here.  Once there is a use outside of PKCS7,
00825  * then change the attribute types and functions from internal
00826  * to external naming convention, and move them elsewhere!
00827  */
00828 
00829 /*
00830  * Look through a set of attributes and find one that matches the
00831  * specified object ID.  If "only" is true, then make sure that
00832  * there is not more than one attribute of the same type.  Otherwise,
00833  * just return the first one found. (XXX Does anybody really want
00834  * that first-found behavior?  It was like that when I found it...)
00835  */
00836 SEC_PKCS7Attribute *
00837 sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs, SECOidTag oidtag,
00838                      PRBool only)
00839 {
00840     SECOidData *oid;
00841     SEC_PKCS7Attribute *attr1, *attr2;
00842 
00843     if (attrs == NULL)
00844        return NULL;
00845 
00846     oid = SECOID_FindOIDByTag(oidtag);
00847     if (oid == NULL)
00848        return NULL;
00849 
00850     while ((attr1 = *attrs++) != NULL) {
00851        if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
00852                                                      oid->oid.data,
00853                                                      oid->oid.len) == 0)
00854            break;
00855     }
00856 
00857     if (attr1 == NULL)
00858        return NULL;
00859 
00860     if (!only)
00861        return attr1;
00862 
00863     while ((attr2 = *attrs++) != NULL) {
00864        if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
00865                                                      oid->oid.data,
00866                                                      oid->oid.len) == 0)
00867            break;
00868     }
00869 
00870     if (attr2 != NULL)
00871        return NULL;
00872 
00873     return attr1;
00874 }
00875 
00876 
00877 /*
00878  * Return the single attribute value, doing some sanity checking first:
00879  * - Multiple values are *not* expected.
00880  * - Empty values are *not* expected.
00881  */
00882 SECItem *
00883 sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr)
00884 {
00885     SECItem *value;
00886 
00887     if (attr == NULL)
00888        return NULL;
00889 
00890     value = attr->values[0];
00891 
00892     if (value == NULL || value->data == NULL || value->len == 0)
00893        return NULL;
00894 
00895     if (attr->values[1] != NULL)
00896        return NULL;
00897 
00898     return value;
00899 }
00900 
00901 static const SEC_ASN1Template *
00902 sec_attr_choose_attr_value_template(void *src_or_dest, PRBool encoding)
00903 {
00904     const SEC_ASN1Template *theTemplate;
00905 
00906     SEC_PKCS7Attribute *attribute;
00907     SECOidData *oiddata;
00908     PRBool encoded;
00909 
00910     PORT_Assert (src_or_dest != NULL);
00911     if (src_or_dest == NULL)
00912        return NULL;
00913 
00914     attribute = (SEC_PKCS7Attribute*)src_or_dest;
00915 
00916     if (encoding && attribute->encoded)
00917        return SEC_ASN1_GET(SEC_AnyTemplate);
00918 
00919     oiddata = attribute->typeTag;
00920     if (oiddata == NULL) {
00921        oiddata = SECOID_FindOID(&attribute->type);
00922        attribute->typeTag = oiddata;
00923     }
00924 
00925     if (oiddata == NULL) {
00926        encoded = PR_TRUE;
00927        theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
00928     } else {
00929        switch (oiddata->offset) {
00930          default:
00931            encoded = PR_TRUE;
00932            theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
00933            break;
00934          case SEC_OID_PKCS9_EMAIL_ADDRESS:
00935          case SEC_OID_RFC1274_MAIL:
00936          case SEC_OID_PKCS9_UNSTRUCTURED_NAME:
00937            encoded = PR_FALSE;
00938            theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
00939            break;
00940          case SEC_OID_PKCS9_CONTENT_TYPE:
00941            encoded = PR_FALSE;
00942            theTemplate = SEC_ASN1_GET(SEC_ObjectIDTemplate);
00943            break;
00944          case SEC_OID_PKCS9_MESSAGE_DIGEST:
00945            encoded = PR_FALSE;
00946            theTemplate = SEC_ASN1_GET(SEC_OctetStringTemplate);
00947            break;
00948          case SEC_OID_PKCS9_SIGNING_TIME:
00949            encoded = PR_FALSE;
00950             theTemplate = SEC_ASN1_GET(CERT_TimeChoiceTemplate);
00951            break;
00952          /* XXX Want other types here, too */
00953        }
00954     }
00955 
00956     if (encoding) {
00957        /*
00958         * If we are encoding and we think we have an already-encoded value,
00959         * then the code which initialized this attribute should have set
00960         * the "encoded" property to true (and we would have returned early,
00961         * up above).  No devastating error, but that code should be fixed.
00962         * (It could indicate that the resulting encoded bytes are wrong.)
00963         */
00964        PORT_Assert (!encoded);
00965     } else {
00966        /*
00967         * We are decoding; record whether the resulting value is
00968         * still encoded or not.
00969         */
00970        attribute->encoded = encoded;
00971     }
00972     return theTemplate;
00973 }
00974 
00975 static const SEC_ASN1TemplateChooserPtr sec_attr_chooser
00976        = sec_attr_choose_attr_value_template;
00977 
00978 static const SEC_ASN1Template sec_pkcs7_attribute_template[] = {
00979     { SEC_ASN1_SEQUENCE,
00980          0, NULL, sizeof(SEC_PKCS7Attribute) },
00981     { SEC_ASN1_OBJECT_ID,
00982          offsetof(SEC_PKCS7Attribute,type) },
00983     { SEC_ASN1_DYNAMIC | SEC_ASN1_SET_OF,
00984          offsetof(SEC_PKCS7Attribute,values),
00985          &sec_attr_chooser },
00986     { 0 }
00987 };
00988 
00989 static const SEC_ASN1Template sec_pkcs7_set_of_attribute_template[] = {
00990     { SEC_ASN1_SET_OF, 0, sec_pkcs7_attribute_template },
00991 };
00992 
00993 /*
00994  * If you are wondering why this routine does not reorder the attributes
00995  * first, and might be tempted to make it do so, see the comment by the
00996  * call to ReorderAttributes in p7encode.c.  (Or, see who else calls this
00997  * and think long and hard about the implications of making it always
00998  * do the reordering.)
00999  */
01000 SECItem *
01001 sec_PKCS7EncodeAttributes (PRArenaPool *poolp, SECItem *dest, void *src)
01002 {
01003     return SEC_ASN1EncodeItem (poolp, dest, src,
01004                             sec_pkcs7_set_of_attribute_template);
01005 }
01006 
01007 /*
01008  * Make sure that the order of the attributes guarantees valid DER
01009  * (which must be in lexigraphically ascending order for a SET OF);
01010  * if reordering is necessary it will be done in place (in attrs).
01011  */
01012 SECStatus
01013 sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs)
01014 {
01015     PRArenaPool *poolp;
01016     int num_attrs, i, pass, besti;
01017     unsigned int j;
01018     SECItem **enc_attrs;
01019     SEC_PKCS7Attribute **new_attrs;
01020 
01021     /*
01022      * I think we should not be called with NULL.  But if we are,
01023      * call it a success anyway, because the order *is* okay.
01024      */
01025     PORT_Assert (attrs != NULL);
01026     if (attrs == NULL)
01027        return SECSuccess;
01028 
01029     /*
01030      * Count how many attributes we are dealing with here.
01031      */
01032     num_attrs = 0;
01033     while (attrs[num_attrs] != NULL)
01034        num_attrs++;
01035 
01036     /*
01037      * Again, I think we should have some attributes here.
01038      * But if we do not, or if there is only one, then call it
01039      * a success because it also already has a fine order.
01040      */
01041     PORT_Assert (num_attrs);
01042     if (num_attrs == 0 || num_attrs == 1)
01043        return SECSuccess;
01044 
01045     /*
01046      * Allocate an arena for us to work with, so it is easy to
01047      * clean up all of the memory (fairly small pieces, really).
01048      */
01049     poolp = PORT_NewArena (1024);  /* XXX what is right value? */
01050     if (poolp == NULL)
01051        return SECFailure;          /* no memory; nothing we can do... */
01052 
01053     /*
01054      * Allocate arrays to hold the individual encodings which we will use
01055      * for comparisons and the reordered attributes as they are sorted.
01056      */
01057     enc_attrs=(SECItem**)PORT_ArenaZAlloc(poolp, num_attrs*sizeof(SECItem *));
01058     new_attrs = (SEC_PKCS7Attribute**)PORT_ArenaZAlloc (poolp,
01059                               num_attrs * sizeof(SEC_PKCS7Attribute *));
01060     if (enc_attrs == NULL || new_attrs == NULL) {
01061        PORT_FreeArena (poolp, PR_FALSE);
01062        return SECFailure;
01063     }
01064 
01065     /*
01066      * DER encode each individual attribute.
01067      */
01068     for (i = 0; i < num_attrs; i++) {
01069        enc_attrs[i] = SEC_ASN1EncodeItem (poolp, NULL, attrs[i],
01070                                       sec_pkcs7_attribute_template);
01071        if (enc_attrs[i] == NULL) {
01072            PORT_FreeArena (poolp, PR_FALSE);
01073            return SECFailure;
01074        }
01075     }
01076 
01077     /*
01078      * Now compare and sort them; this is not the most efficient sorting
01079      * method, but it is just fine for the problem at hand, because the
01080      * number of attributes is (always) going to be small.
01081      */
01082     for (pass = 0; pass < num_attrs; pass++) {
01083        /*
01084         * Find the first not-yet-accepted attribute.  (Once one is
01085         * sorted into the other array, it is cleared from enc_attrs.)
01086         */
01087        for (i = 0; i < num_attrs; i++) {
01088            if (enc_attrs[i] != NULL)
01089               break;
01090        }
01091        PORT_Assert (i < num_attrs);
01092        besti = i;
01093 
01094        /*
01095         * Find the lowest (lexigraphically) encoding.  One that is
01096         * shorter than all the rest is known to be "less" because each
01097         * attribute is of the same type (a SEQUENCE) and so thus the
01098         * first octet of each is the same, and the second octet is
01099         * the length (or the length of the length with the high bit
01100         * set, followed by the length, which also works out to always
01101         * order the shorter first).  Two (or more) that have the
01102         * same length need to be compared byte by byte until a mismatch
01103         * is found.
01104         */
01105        for (i = besti + 1; i < num_attrs; i++) {
01106            if (enc_attrs[i] == NULL)      /* slot already handled */
01107               continue;
01108 
01109            if (enc_attrs[i]->len != enc_attrs[besti]->len) {
01110               if (enc_attrs[i]->len < enc_attrs[besti]->len)
01111                   besti = i;
01112               continue;
01113            }
01114 
01115            for (j = 0; j < enc_attrs[i]->len; j++) {
01116               if (enc_attrs[i]->data[j] < enc_attrs[besti]->data[j]) {
01117                   besti = i;
01118                   break;
01119               }
01120            }
01121 
01122            /*
01123             * For this not to be true, we would have to have encountered     
01124             * two *identical* attributes, which I think we should not see.
01125             * So assert if it happens, but even if it does, let it go
01126             * through; the ordering of the two does not matter.
01127             */
01128            PORT_Assert (j < enc_attrs[i]->len);
01129        }
01130 
01131        /*
01132         * Now we have found the next-lowest one; copy it over and
01133         * remove it from enc_attrs.
01134         */
01135        new_attrs[pass] = attrs[besti];
01136        enc_attrs[besti] = NULL;
01137     }
01138 
01139     /*
01140      * Now new_attrs has the attributes in the order we want;
01141      * copy them back into the attrs array we started with.
01142      */
01143     for (i = 0; i < num_attrs; i++)
01144        attrs[i] = new_attrs[i];
01145 
01146     PORT_FreeArena (poolp, PR_FALSE);
01147     return SECSuccess;
01148 }
01149 
01150 /*
01151  * End of attribute stuff.
01152  * -------------------------------------------------------------------
01153  */
01154 
01155 
01156 /*
01157  * Templates and stuff.  Keep these at the end of the file.
01158  */
01159 
01160 /* forward declaration */
01161 static const SEC_ASN1Template *
01162 sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding);
01163 
01164 static const SEC_ASN1TemplateChooserPtr sec_pkcs7_chooser
01165        = sec_pkcs7_choose_content_template;
01166 
01167 const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[] = {
01168     { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
01169          0, NULL, sizeof(SEC_PKCS7ContentInfo) },
01170     { SEC_ASN1_OBJECT_ID,
01171          offsetof(SEC_PKCS7ContentInfo,contentType) },
01172     { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
01173      | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01174          offsetof(SEC_PKCS7ContentInfo,content),
01175          &sec_pkcs7_chooser },
01176     { 0 }
01177 };
01178 
01179 /* XXX These names should change from external to internal convention. */
01180 
01181 static const SEC_ASN1Template SEC_PKCS7SignerInfoTemplate[] = {
01182     { SEC_ASN1_SEQUENCE,
01183          0, NULL, sizeof(SEC_PKCS7SignerInfo) },
01184     { SEC_ASN1_INTEGER,
01185          offsetof(SEC_PKCS7SignerInfo,version) },
01186     { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
01187          offsetof(SEC_PKCS7SignerInfo,issuerAndSN),
01188          SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
01189     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
01190          offsetof(SEC_PKCS7SignerInfo,digestAlg),
01191          SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
01192     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
01193          offsetof(SEC_PKCS7SignerInfo,authAttr),
01194          sec_pkcs7_set_of_attribute_template },
01195     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
01196          offsetof(SEC_PKCS7SignerInfo,digestEncAlg),
01197          SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
01198     { SEC_ASN1_OCTET_STRING,
01199          offsetof(SEC_PKCS7SignerInfo,encDigest) },
01200     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
01201          offsetof(SEC_PKCS7SignerInfo,unAuthAttr),
01202          sec_pkcs7_set_of_attribute_template },
01203     { 0 }
01204 };
01205 
01206 static const SEC_ASN1Template SEC_PKCS7SignedDataTemplate[] = {
01207     { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
01208          0, NULL, sizeof(SEC_PKCS7SignedData) },
01209     { SEC_ASN1_INTEGER,
01210          offsetof(SEC_PKCS7SignedData,version) },
01211     { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
01212          offsetof(SEC_PKCS7SignedData,digestAlgorithms),
01213          SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
01214     { SEC_ASN1_INLINE,
01215          offsetof(SEC_PKCS7SignedData,contentInfo),
01216          sec_PKCS7ContentInfoTemplate },
01217     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC  |
01218       SEC_ASN1_XTRN | 0,
01219          offsetof(SEC_PKCS7SignedData,rawCerts),
01220          SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
01221     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC  |
01222       SEC_ASN1_XTRN | 1,
01223          offsetof(SEC_PKCS7SignedData,crls),
01224          SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
01225     { SEC_ASN1_SET_OF,
01226          offsetof(SEC_PKCS7SignedData,signerInfos),
01227          SEC_PKCS7SignerInfoTemplate },
01228     { 0 }
01229 };
01230 
01231 static const SEC_ASN1Template SEC_PointerToPKCS7SignedDataTemplate[] = {
01232     { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedDataTemplate }
01233 };
01234 
01235 static const SEC_ASN1Template SEC_PKCS7RecipientInfoTemplate[] = {
01236     { SEC_ASN1_SEQUENCE,
01237          0, NULL, sizeof(SEC_PKCS7RecipientInfo) },
01238     { SEC_ASN1_INTEGER,
01239          offsetof(SEC_PKCS7RecipientInfo,version) },
01240     { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
01241          offsetof(SEC_PKCS7RecipientInfo,issuerAndSN),
01242          SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
01243     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
01244          offsetof(SEC_PKCS7RecipientInfo,keyEncAlg),
01245          SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
01246     { SEC_ASN1_OCTET_STRING,
01247          offsetof(SEC_PKCS7RecipientInfo,encKey) },
01248     { 0 }
01249 };
01250 
01251 static const SEC_ASN1Template SEC_PKCS7EncryptedContentInfoTemplate[] = {
01252     { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
01253          0, NULL, sizeof(SEC_PKCS7EncryptedContentInfo) },
01254     { SEC_ASN1_OBJECT_ID,
01255          offsetof(SEC_PKCS7EncryptedContentInfo,contentType) },
01256     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
01257          offsetof(SEC_PKCS7EncryptedContentInfo,contentEncAlg),
01258          SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
01259     { SEC_ASN1_OPTIONAL | SEC_ASN1_MAY_STREAM | SEC_ASN1_CONTEXT_SPECIFIC |
01260       SEC_ASN1_XTRN | 0,
01261          offsetof(SEC_PKCS7EncryptedContentInfo,encContent),
01262          SEC_ASN1_SUB(SEC_OctetStringTemplate) },
01263     { 0 }
01264 };
01265 
01266 static const SEC_ASN1Template SEC_PKCS7EnvelopedDataTemplate[] = {
01267     { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
01268          0, NULL, sizeof(SEC_PKCS7EnvelopedData) },
01269     { SEC_ASN1_INTEGER,
01270          offsetof(SEC_PKCS7EnvelopedData,version) },
01271     { SEC_ASN1_SET_OF,
01272          offsetof(SEC_PKCS7EnvelopedData,recipientInfos),
01273          SEC_PKCS7RecipientInfoTemplate },
01274     { SEC_ASN1_INLINE,
01275          offsetof(SEC_PKCS7EnvelopedData,encContentInfo),
01276          SEC_PKCS7EncryptedContentInfoTemplate },
01277     { 0 }
01278 };
01279 
01280 static const SEC_ASN1Template SEC_PointerToPKCS7EnvelopedDataTemplate[] = {
01281     { SEC_ASN1_POINTER, 0, SEC_PKCS7EnvelopedDataTemplate }
01282 };
01283 
01284 static const SEC_ASN1Template SEC_PKCS7SignedAndEnvelopedDataTemplate[] = {
01285     { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
01286          0, NULL, sizeof(SEC_PKCS7SignedAndEnvelopedData) },
01287     { SEC_ASN1_INTEGER,
01288          offsetof(SEC_PKCS7SignedAndEnvelopedData,version) },
01289     { SEC_ASN1_SET_OF,
01290          offsetof(SEC_PKCS7SignedAndEnvelopedData,recipientInfos),
01291          SEC_PKCS7RecipientInfoTemplate },
01292     { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
01293          offsetof(SEC_PKCS7SignedAndEnvelopedData,digestAlgorithms),
01294          SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
01295     { SEC_ASN1_INLINE,
01296          offsetof(SEC_PKCS7SignedAndEnvelopedData,encContentInfo),
01297          SEC_PKCS7EncryptedContentInfoTemplate },
01298     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
01299       SEC_ASN1_XTRN | 0,
01300          offsetof(SEC_PKCS7SignedAndEnvelopedData,rawCerts),
01301          SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
01302     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
01303       SEC_ASN1_XTRN | 1,
01304          offsetof(SEC_PKCS7SignedAndEnvelopedData,crls),
01305          SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
01306     { SEC_ASN1_SET_OF,
01307          offsetof(SEC_PKCS7SignedAndEnvelopedData,signerInfos),
01308          SEC_PKCS7SignerInfoTemplate },
01309     { 0 }
01310 };
01311 
01312 static const SEC_ASN1Template
01313 SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate[] = {
01314     { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedAndEnvelopedDataTemplate }
01315 };
01316 
01317 static const SEC_ASN1Template SEC_PKCS7DigestedDataTemplate[] = {
01318     { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
01319          0, NULL, sizeof(SEC_PKCS7DigestedData) },
01320     { SEC_ASN1_INTEGER,
01321          offsetof(SEC_PKCS7DigestedData,version) },
01322     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
01323          offsetof(SEC_PKCS7DigestedData,digestAlg),
01324          SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
01325     { SEC_ASN1_INLINE,
01326          offsetof(SEC_PKCS7DigestedData,contentInfo),
01327          sec_PKCS7ContentInfoTemplate },
01328     { SEC_ASN1_OCTET_STRING,
01329          offsetof(SEC_PKCS7DigestedData,digest) },
01330     { 0 }
01331 };
01332 
01333 static const SEC_ASN1Template SEC_PointerToPKCS7DigestedDataTemplate[] = {
01334     { SEC_ASN1_POINTER, 0, SEC_PKCS7DigestedDataTemplate }
01335 };
01336 
01337 static const SEC_ASN1Template SEC_PKCS7EncryptedDataTemplate[] = {
01338     { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
01339          0, NULL, sizeof(SEC_PKCS7EncryptedData) },
01340     { SEC_ASN1_INTEGER,
01341          offsetof(SEC_PKCS7EncryptedData,version) },
01342     { SEC_ASN1_INLINE,
01343          offsetof(SEC_PKCS7EncryptedData,encContentInfo),
01344          SEC_PKCS7EncryptedContentInfoTemplate },
01345     { 0 }
01346 };
01347 
01348 static const SEC_ASN1Template SEC_PointerToPKCS7EncryptedDataTemplate[] = {
01349     { SEC_ASN1_POINTER, 0, SEC_PKCS7EncryptedDataTemplate }
01350 };
01351 
01352 const SEC_ASN1Template SEC_SMIMEKEAParamTemplateSkipjack[] = {
01353        { SEC_ASN1_SEQUENCE,
01354          0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
01355        { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
01356          offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
01357        { SEC_ASN1_OCTET_STRING,
01358          offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
01359        { 0 }
01360 };
01361 
01362 const SEC_ASN1Template SEC_SMIMEKEAParamTemplateNoSkipjack[] = {
01363        { SEC_ASN1_SEQUENCE,
01364          0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
01365        { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
01366          offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
01367        { SEC_ASN1_OCTET_STRING,
01368          offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
01369        { SEC_ASN1_OCTET_STRING  | SEC_ASN1_OPTIONAL ,
01370          offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
01371        { 0 }
01372 };
01373 
01374 const SEC_ASN1Template SEC_SMIMEKEAParamTemplateAllParams[] = {
01375        { SEC_ASN1_SEQUENCE,
01376          0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
01377        { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
01378          offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
01379        { SEC_ASN1_OCTET_STRING,
01380          offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
01381        { SEC_ASN1_OCTET_STRING  | SEC_ASN1_OPTIONAL ,
01382          offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
01383        { SEC_ASN1_OCTET_STRING  | SEC_ASN1_OPTIONAL ,
01384          offsetof(SEC_PKCS7SMIMEKEAParameters,bulkKeySize) },
01385        { 0 }
01386 };
01387 
01388 const SEC_ASN1Template*
01389 sec_pkcs7_get_kea_template(SECKEATemplateSelector whichTemplate)
01390 {
01391        const SEC_ASN1Template *returnVal = NULL;
01392 
01393        switch(whichTemplate)
01394        {
01395        case SECKEAUsesNonSkipjack:
01396               returnVal = SEC_SMIMEKEAParamTemplateNoSkipjack;
01397               break;
01398        case SECKEAUsesSkipjack:
01399               returnVal = SEC_SMIMEKEAParamTemplateSkipjack;
01400               break;
01401        case SECKEAUsesNonSkipjackWithPaddedEncKey:
01402        default:
01403               returnVal = SEC_SMIMEKEAParamTemplateAllParams;
01404               break;
01405        }
01406        return returnVal;
01407 }
01408        
01409 static const SEC_ASN1Template *
01410 sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding)
01411 {
01412     const SEC_ASN1Template *theTemplate;
01413     SEC_PKCS7ContentInfo *cinfo;
01414     SECOidTag kind;
01415 
01416     PORT_Assert (src_or_dest != NULL);
01417     if (src_or_dest == NULL)
01418        return NULL;
01419 
01420     cinfo = (SEC_PKCS7ContentInfo*)src_or_dest;
01421     kind = SEC_PKCS7ContentType (cinfo);
01422     switch (kind) {
01423       default:
01424        theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate);
01425        break;
01426       case SEC_OID_PKCS7_DATA:
01427        theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
01428        break;
01429       case SEC_OID_PKCS7_SIGNED_DATA:
01430        theTemplate = SEC_PointerToPKCS7SignedDataTemplate;
01431        break;
01432       case SEC_OID_PKCS7_ENVELOPED_DATA:
01433        theTemplate = SEC_PointerToPKCS7EnvelopedDataTemplate;
01434        break;
01435       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
01436        theTemplate = SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate;
01437        break;
01438       case SEC_OID_PKCS7_DIGESTED_DATA:
01439        theTemplate = SEC_PointerToPKCS7DigestedDataTemplate;
01440        break;
01441       case SEC_OID_PKCS7_ENCRYPTED_DATA:
01442        theTemplate = SEC_PointerToPKCS7EncryptedDataTemplate;
01443        break;
01444     }
01445     return theTemplate;
01446 }
01447 
01448 /*
01449  * End of templates.  Do not add stuff after this; put new code
01450  * up above the start of the template definitions.
01451  */