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