p7local.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:43k
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- /*
- * Support routines for PKCS7 implementation, none of which are exported.
- * This file should only contain things that are needed by both the
- * encoding/creation side *and* the decoding/decryption side. Anything
- * else should be static routines in the appropriate file.
- *
- * $Id: p7local.c,v 1.1 2000/03/31 19:16:06 relyea%netscape.com Exp $
- */
- #include "p7local.h"
- #include "cryptohi.h"
- #include "secasn1.h"
- #include "secoid.h"
- #include "secitem.h"
- #include "pk11func.h"
- #include "secpkcs5.h"
- #include "secerr.h"
- /*
- * -------------------------------------------------------------------
- * Cipher stuff.
- */
- typedef SECStatus (*sec_pkcs7_cipher_function) (void *,
- unsigned char *,
- unsigned *,
- unsigned int,
- const unsigned char *,
- unsigned int);
- typedef SECStatus (*sec_pkcs7_cipher_destroy) (void *, PRBool);
- #define BLOCK_SIZE 4096
- struct sec_pkcs7_cipher_object {
- void *cx;
- sec_pkcs7_cipher_function doit;
- sec_pkcs7_cipher_destroy destroy;
- PRBool encrypt;
- int block_size;
- int pad_size;
- int pending_count;
- unsigned char pending_buf[BLOCK_SIZE];
- };
- /*
- * Create a cipher object to do decryption, based on the given bulk
- * encryption key and algorithm identifier (which may include an iv).
- *
- * XXX This interface, or one similar, would be really nice available
- * in general... I tried to keep the pkcs7-specific stuff (mostly
- * having to do with padding) out of here.
- *
- * XXX Once both are working, it might be nice to combine this and the
- * function below (for starting up encryption) into one routine, and just
- * have two simple cover functions which call it.
- */
- sec_PKCS7CipherObject *
- sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid)
- {
- sec_PKCS7CipherObject *result;
- SECOidTag algtag;
- void *ciphercx;
- CK_MECHANISM_TYPE mechanism;
- SECItem *param;
- PK11SlotInfo *slot;
- result = (struct sec_pkcs7_cipher_object*)
- PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
- if (result == NULL)
- return NULL;
- ciphercx = NULL;
- algtag = SECOID_GetAlgorithmTag (algid);
- if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
- CK_MECHANISM pbeMech, cryptoMech;
- SECItem *pbeParams, *pwitem;
- SEC_PKCS5KeyAndPassword *keyPwd;
- keyPwd = (SEC_PKCS5KeyAndPassword *)key;
- key = keyPwd->key;
- pwitem = keyPwd->pwitem;
- pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
- pbeParams = PK11_ParamFromAlgid(algid);
- if (!pbeParams) {
- PORT_Free(result);
- return NULL;
- }
- pbeMech.pParameter = pbeParams->data;
- pbeMech.ulParameterLen = pbeParams->len;
- if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, pwitem,
- PR_FALSE) != CKR_OK) {
- PORT_Free(result);
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
- return NULL;
- }
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
- param = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
- if(!param) {
- PORT_Free(result);
- return NULL;
- }
- param->data = (unsigned char *)cryptoMech.pParameter;
- param->len = cryptoMech.ulParameterLen;
- mechanism = cryptoMech.mechanism;
- } else {
- mechanism = PK11_AlgtagToMechanism(algtag);
- param = PK11_ParamFromAlgid(algid);
- if (param == NULL) {
- PORT_Free(result);
- return NULL;
- }
- }
- result->pad_size = PK11_GetBlockSize(mechanism,param);
- slot = PK11_GetSlotFromKey(key);
- result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
- PK11_FreeSlot(slot);
- ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param);
- SECITEM_FreeItem(param,PR_TRUE);
- if (ciphercx == NULL) {
- PORT_Free (result);
- return NULL;
- }
- result->cx = ciphercx;
- result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
- result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
- result->encrypt = PR_FALSE;
- result->pending_count = 0;
- return result;
- }
- /*
- * Create a cipher object to do encryption, based on the given bulk
- * encryption key and algorithm tag. Fill in the algorithm identifier
- * (which may include an iv) appropriately.
- *
- * XXX This interface, or one similar, would be really nice available
- * in general... I tried to keep the pkcs7-specific stuff (mostly
- * having to do with padding) out of here.
- *
- * XXX Once both are working, it might be nice to combine this and the
- * function above (for starting up decryption) into one routine, and just
- * have two simple cover functions which call it.
- */
- sec_PKCS7CipherObject *
- sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key,
- SECOidTag algtag, SECAlgorithmID *algid)
- {
- sec_PKCS7CipherObject *result;
- void *ciphercx;
- SECItem *param;
- SECStatus rv;
- CK_MECHANISM_TYPE mechanism;
- PRBool needToEncodeAlgid = PR_FALSE;
- PK11SlotInfo *slot;
- result = (struct sec_pkcs7_cipher_object*)
- PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
- if (result == NULL)
- return NULL;
- ciphercx = NULL;
- if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
- CK_MECHANISM pbeMech, cryptoMech;
- SECItem *pbeParams;
- SEC_PKCS5KeyAndPassword *keyPwd;
- PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM));
- PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM));
- pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
- pbeParams = PK11_ParamFromAlgid(algid);
- if(!pbeParams) {
- PORT_Free(result);
- return NULL;
- }
- keyPwd = (SEC_PKCS5KeyAndPassword *)key;
- key = keyPwd->key;
- pbeMech.pParameter = pbeParams->data;
- pbeMech.ulParameterLen = pbeParams->len;
- if(PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech,
- keyPwd->pwitem, PR_FALSE) != CKR_OK) {
- PORT_Free(result);
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
- return NULL;
- }
- SECITEM_ZfreeItem(pbeParams, PR_TRUE);
- param = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
- if(!param) {
- PORT_Free(result);
- return NULL;
- }
- param->data = (unsigned char *)cryptoMech.pParameter;
- param->len = cryptoMech.ulParameterLen;
- mechanism = cryptoMech.mechanism;
- } else {
- mechanism = PK11_AlgtagToMechanism(algtag);
- param = PK11_GenerateNewParam(mechanism,key);
- if (param == NULL) {
- PORT_Free(result);
- return NULL;
- }
- needToEncodeAlgid = PR_TRUE;
- }
- result->pad_size = PK11_GetBlockSize(mechanism,param);
- slot = PK11_GetSlotFromKey(key);
- result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
- PK11_FreeSlot(slot);
- ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT,
- key, param);
- if (ciphercx == NULL) {
- PORT_Free (result);
- SECITEM_FreeItem(param,PR_TRUE);
- return NULL;
- }
- /*
- * These are placed after the CreateContextBySymKey() because some
- * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
- * Don't move it from here.
- */
- if (needToEncodeAlgid) {
- rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
- if(rv != SECSuccess) {
- return NULL;
- }
- }
- SECITEM_FreeItem(param,PR_TRUE);
- result->cx = ciphercx;
- result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
- result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
- result->encrypt = PR_TRUE;
- result->pending_count = 0;
- return result;
- }
- /*
- * Destroy the cipher object.
- */
- static void
- sec_pkcs7_destroy_cipher (sec_PKCS7CipherObject *obj)
- {
- (* obj->destroy) (obj->cx, PR_TRUE);
- PORT_Free (obj);
- }
- void
- sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj)
- {
- PORT_Assert (obj != NULL);
- if (obj == NULL)
- return;
- PORT_Assert (! obj->encrypt);
- sec_pkcs7_destroy_cipher (obj);
- }
- void
- sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj)
- {
- PORT_Assert (obj != NULL);
- if (obj == NULL)
- return;
- PORT_Assert (obj->encrypt);
- sec_pkcs7_destroy_cipher (obj);
- }
- /*
- * XXX I think all of the following lengths should be longs instead
- * of ints, but our current crypto interface uses ints, so I did too.
- */
- /*
- * What will be the output length of the next call to decrypt?
- * Result can be used to perform memory allocations. Note that the amount
- * is exactly accurate only when not doing a block cipher or when final
- * is false, otherwise it is an upper bound on the amount because until
- * we see the data we do not know how many padding bytes there are
- * (always between 1 and bsize).
- *
- * Note that this can return zero, which does not mean that the decrypt
- * operation can be skipped! (It simply means that there are not enough
- * bytes to make up an entire block; the bytes will be reserved until
- * there are enough to encrypt/decrypt at least one block.) However,
- * if zero is returned it *does* mean that no output buffer need be
- * passed in to the subsequent decrypt operation, as no output bytes
- * will be stored.
- */
- unsigned int
- sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
- PRBool final)
- {
- int blocks, block_size;
- PORT_Assert (! obj->encrypt);
- block_size = obj->block_size;
- /*
- * If this is not a block cipher, then we always have the same
- * number of output bytes as we had input bytes.
- */
- if (block_size == 0)
- return input_len;
- /*
- * On the final call, we will always use up all of the pending
- * bytes plus all of the input bytes, *but*, there will be padding
- * at the end and we cannot predict how many bytes of padding we
- * will end up removing. The amount given here is actually known
- * to be at least 1 byte too long (because we know we will have
- * at least 1 byte of padding), but seemed clearer/better to me.
- */
- if (final)
- return obj->pending_count + input_len;
- /*
- * Okay, this amount is exactly what we will output on the
- * next cipher operation. We will always hang onto the last
- * 1 - block_size bytes for non-final operations. That is,
- * we will do as many complete blocks as we can *except* the
- * last block (complete or partial). (This is because until
- * we know we are at the end, we cannot know when to interpret
- * and removing the padding byte(s), which are guaranteed to
- * be there.)
- */
- blocks = (obj->pending_count + input_len - 1) / block_size;
- return blocks * block_size;
- }
- /*
- * What will be the output length of the next call to encrypt?
- * Result can be used to perform memory allocations.
- *
- * Note that this can return zero, which does not mean that the encrypt
- * operation can be skipped! (It simply means that there are not enough
- * bytes to make up an entire block; the bytes will be reserved until
- * there are enough to encrypt/decrypt at least one block.) However,
- * if zero is returned it *does* mean that no output buffer need be
- * passed in to the subsequent encrypt operation, as no output bytes
- * will be stored.
- */
- unsigned int
- sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
- PRBool final)
- {
- int blocks, block_size;
- int pad_size;
- PORT_Assert (obj->encrypt);
- block_size = obj->block_size;
- pad_size = obj->pad_size;
- /*
- * If this is not a block cipher, then we always have the same
- * number of output bytes as we had input bytes.
- */
- if (block_size == 0)
- return input_len;
- /*
- * On the final call, we only send out what we need for
- * remaining bytes plus the padding. (There is always padding,
- * so even if we have an exact number of blocks as input, we
- * will add another full block that is just padding.)
- */
- if (final) {
- if (pad_size == 0) {
- return obj->pending_count + input_len;
- } else {
- blocks = (obj->pending_count + input_len) / pad_size;
- blocks++;
- return blocks*pad_size;
- }
- }
- /*
- * Now, count the number of complete blocks of data we have.
- */
- blocks = (obj->pending_count + input_len) / block_size;
- return blocks * block_size;
- }
- /*
- * Decrypt a given length of input buffer (starting at "input" and
- * containing "input_len" bytes), placing the decrypted bytes in
- * "output" and storing the output length in "*output_len_p".
- * "obj" is the return value from sec_PKCS7CreateDecryptObject.
- * When "final" is true, this is the last of the data to be decrypted.
- *
- * This is much more complicated than it sounds when the cipher is
- * a block-type, meaning that the decryption function will only
- * operate on whole blocks. But our caller is operating stream-wise,
- * and can pass in any number of bytes. So we need to keep track
- * of block boundaries. We save excess bytes between calls in "obj".
- * We also need to determine which bytes are padding, and remove
- * them from the output. We can only do this step when we know we
- * have the final block of data. PKCS #7 specifies that the padding
- * used for a block cipher is a string of bytes, each of whose value is
- * the same as the length of the padding, and that all data is padded.
- * (Even data that starts out with an exact multiple of blocks gets
- * added to it another block, all of which is padding.)
- */
- SECStatus
- sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
- unsigned int *output_len_p, unsigned int max_output_len,
- const unsigned char *input, unsigned int input_len,
- PRBool final)
- {
- int blocks, bsize, pcount, padsize;
- unsigned int max_needed, ifraglen, ofraglen, output_len;
- unsigned char *pbuf;
- SECStatus rv;
- PORT_Assert (! obj->encrypt);
- /*
- * Check that we have enough room for the output. Our caller should
- * already handle this; failure is really an internal error (i.e. bug).
- */
- max_needed = sec_PKCS7DecryptLength (obj, input_len, final);
- PORT_Assert (max_output_len >= max_needed);
- if (max_output_len < max_needed) {
- /* PORT_SetError (XXX); */
- return SECFailure;
- }
- /*
- * hardware encryption does not like small decryption sizes here, so we
- * allow both blocking and padding.
- */
- bsize = obj->block_size;
- padsize = obj->pad_size;
- /*
- * When no blocking or padding work to do, we can simply call the
- * cipher function and we are done.
- */
- if (bsize == 0) {
- return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
- input, input_len);
- }
- pcount = obj->pending_count;
- pbuf = obj->pending_buf;
- output_len = 0;
- if (pcount) {
- /*
- * Try to fill in an entire block, starting with the bytes
- * we already have saved away.
- */
- while (input_len && pcount < bsize) {
- pbuf[pcount++] = *input++;
- input_len--;
- }
- /*
- * If we have at most a whole block and this is not our last call,
- * then we are done for now. (We do not try to decrypt a lone
- * single block because we cannot interpret the padding bytes
- * until we know we are handling the very last block of all input.)
- */
- if (input_len == 0 && !final) {
- obj->pending_count = pcount;
- if (output_len_p)
- *output_len_p = 0;
- return SECSuccess;
- }
- /*
- * Given the logic above, we expect to have a full block by now.
- * If we do not, there is something wrong, either with our own
- * logic or with (length of) the data given to us.
- */
- PORT_Assert ((padsize == 0) || (pcount % padsize) == 0);
- if ((padsize != 0) && (pcount % padsize) != 0) {
- PORT_Assert (final);
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
- /*
- * Decrypt the block.
- */
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- pbuf, pcount);
- if (rv != SECSuccess)
- return rv;
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7DecryptLength needs to be made smarter!
- */
- PORT_Assert (ofraglen == pcount);
- /*
- * Account for the bytes now in output.
- */
- max_output_len -= ofraglen;
- output_len += ofraglen;
- output += ofraglen;
- }
- /*
- * If this is our last call, we expect to have an exact number of
- * blocks left to be decrypted; we will decrypt them all.
- *
- * If not our last call, we always save between 1 and bsize bytes
- * until next time. (We must do this because we cannot be sure
- * that none of the decrypted bytes are padding bytes until we
- * have at least another whole block of data. You cannot tell by
- * looking -- the data could be anything -- you can only tell by
- * context, knowing you are looking at the last block.) We could
- * decrypt a whole block now but it is easier if we just treat it
- * the same way we treat partial block bytes.
- */
- if (final) {
- if (padsize) {
- blocks = input_len / padsize;
- ifraglen = blocks * padsize;
- } else ifraglen = input_len;
- PORT_Assert (ifraglen == input_len);
- if (ifraglen != input_len) {
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
- } else {
- blocks = (input_len - 1) / bsize;
- ifraglen = blocks * bsize;
- PORT_Assert (ifraglen < input_len);
- pcount = input_len - ifraglen;
- PORT_Memcpy (pbuf, input + ifraglen, pcount);
- obj->pending_count = pcount;
- }
- if (ifraglen) {
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- input, ifraglen);
- if (rv != SECSuccess)
- return rv;
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7DecryptLength needs to be made smarter!
- */
- PORT_Assert (ifraglen == ofraglen);
- if (ifraglen != ofraglen) {
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
- output_len += ofraglen;
- } else {
- ofraglen = 0;
- }
- /*
- * If we just did our very last block, "remove" the padding by
- * adjusting the output length.
- */
- if (final && (padsize != 0)) {
- unsigned int padlen = *(output + ofraglen - 1);
- PORT_Assert (padlen > 0 && padlen <= padsize);
- if (padlen == 0 || padlen > padsize) {
- PORT_SetError (SEC_ERROR_BAD_DATA);
- return SECFailure;
- }
- output_len -= padlen;
- }
- PORT_Assert (output_len_p != NULL || output_len == 0);
- if (output_len_p != NULL)
- *output_len_p = output_len;
- return SECSuccess;
- }
- /*
- * Encrypt a given length of input buffer (starting at "input" and
- * containing "input_len" bytes), placing the encrypted bytes in
- * "output" and storing the output length in "*output_len_p".
- * "obj" is the return value from sec_PKCS7CreateEncryptObject.
- * When "final" is true, this is the last of the data to be encrypted.
- *
- * This is much more complicated than it sounds when the cipher is
- * a block-type, meaning that the encryption function will only
- * operate on whole blocks. But our caller is operating stream-wise,
- * and can pass in any number of bytes. So we need to keep track
- * of block boundaries. We save excess bytes between calls in "obj".
- * We also need to add padding bytes at the end. PKCS #7 specifies
- * that the padding used for a block cipher is a string of bytes,
- * each of whose value is the same as the length of the padding,
- * and that all data is padded. (Even data that starts out with
- * an exact multiple of blocks gets added to it another block,
- * all of which is padding.)
- *
- * XXX I would kind of like to combine this with the function above
- * which does decryption, since they have a lot in common. But the
- * tricky parts about padding and filling blocks would be much
- * harder to read that way, so I left them separate. At least for
- * now until it is clear that they are right.
- */
- SECStatus
- sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
- unsigned int *output_len_p, unsigned int max_output_len,
- const unsigned char *input, unsigned int input_len,
- PRBool final)
- {
- int blocks, bsize, padlen, pcount, padsize;
- unsigned int max_needed, ifraglen, ofraglen, output_len;
- unsigned char *pbuf;
- SECStatus rv;
- PORT_Assert (obj->encrypt);
- /*
- * Check that we have enough room for the output. Our caller should
- * already handle this; failure is really an internal error (i.e. bug).
- */
- max_needed = sec_PKCS7EncryptLength (obj, input_len, final);
- PORT_Assert (max_output_len >= max_needed);
- if (max_output_len < max_needed) {
- /* PORT_SetError (XXX); */
- return SECFailure;
- }
- bsize = obj->block_size;
- padsize = obj->pad_size;
- /*
- * When no blocking and padding work to do, we can simply call the
- * cipher function and we are done.
- */
- if (bsize == 0) {
- return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
- input, input_len);
- }
- pcount = obj->pending_count;
- pbuf = obj->pending_buf;
- output_len = 0;
- if (pcount) {
- /*
- * Try to fill in an entire block, starting with the bytes
- * we already have saved away.
- */
- while (input_len && pcount < bsize) {
- pbuf[pcount++] = *input++;
- input_len--;
- }
- /*
- * If we do not have a full block and we know we will be
- * called again, then we are done for now.
- */
- if (pcount < bsize && !final) {
- obj->pending_count = pcount;
- if (output_len_p != NULL)
- *output_len_p = 0;
- return SECSuccess;
- }
- /*
- * If we have a whole block available, encrypt it.
- */
- if ((padsize == 0) || (pcount % padsize) == 0) {
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- pbuf, pcount);
- if (rv != SECSuccess)
- return rv;
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7EncryptLength needs to be made smarter!
- */
- PORT_Assert (ofraglen == pcount);
- /*
- * Account for the bytes now in output.
- */
- max_output_len -= ofraglen;
- output_len += ofraglen;
- output += ofraglen;
- pcount = 0;
- }
- }
- if (input_len) {
- PORT_Assert (pcount == 0);
- blocks = input_len / bsize;
- ifraglen = blocks * bsize;
- if (ifraglen) {
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- input, ifraglen);
- if (rv != SECSuccess)
- return rv;
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7EncryptLength needs to be made smarter!
- */
- PORT_Assert (ifraglen == ofraglen);
- max_output_len -= ofraglen;
- output_len += ofraglen;
- output += ofraglen;
- }
- pcount = input_len - ifraglen;
- PORT_Assert (pcount < bsize);
- if (pcount)
- PORT_Memcpy (pbuf, input + ifraglen, pcount);
- }
- if (final) {
- padlen = padsize - (pcount % padsize);
- PORT_Memset (pbuf + pcount, padlen, padlen);
- rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
- pbuf, pcount+padlen);
- if (rv != SECSuccess)
- return rv;
- /*
- * For now anyway, all of our ciphers have the same number of
- * bytes of output as they do input. If this ever becomes untrue,
- * then sec_PKCS7EncryptLength needs to be made smarter!
- */
- PORT_Assert (ofraglen == (pcount+padlen));
- output_len += ofraglen;
- } else {
- obj->pending_count = pcount;
- }
- PORT_Assert (output_len_p != NULL || output_len == 0);
- if (output_len_p != NULL)
- *output_len_p = output_len;
- return SECSuccess;
- }
- /*
- * End of cipher stuff.
- * -------------------------------------------------------------------
- */
- /*
- * -------------------------------------------------------------------
- * XXX The following Attribute stuff really belongs elsewhere.
- * The Attribute type is *not* part of pkcs7 but rather X.501.
- * But for now, since PKCS7 is the only customer of attributes,
- * we define them here. Once there is a use outside of PKCS7,
- * then change the attribute types and functions from internal
- * to external naming convention, and move them elsewhere!
- */
- /*
- * Look through a set of attributes and find one that matches the
- * specified object ID. If "only" is true, then make sure that
- * there is not more than one attribute of the same type. Otherwise,
- * just return the first one found. (XXX Does anybody really want
- * that first-found behavior? It was like that when I found it...)
- */
- SEC_PKCS7Attribute *
- sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs, SECOidTag oidtag,
- PRBool only)
- {
- SECOidData *oid;
- SEC_PKCS7Attribute *attr1, *attr2;
- if (attrs == NULL)
- return NULL;
- oid = SECOID_FindOIDByTag(oidtag);
- if (oid == NULL)
- return NULL;
- while ((attr1 = *attrs++) != NULL) {
- if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
- oid->oid.data,
- oid->oid.len) == 0)
- break;
- }
- if (attr1 == NULL)
- return NULL;
- if (!only)
- return attr1;
- while ((attr2 = *attrs++) != NULL) {
- if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
- oid->oid.data,
- oid->oid.len) == 0)
- break;
- }
- if (attr2 != NULL)
- return NULL;
- return attr1;
- }
- /*
- * Return the single attribute value, doing some sanity checking first:
- * - Multiple values are *not* expected.
- * - Empty values are *not* expected.
- */
- SECItem *
- sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr)
- {
- SECItem *value;
- if (attr == NULL)
- return NULL;
- value = attr->values[0];
- if (value == NULL || value->data == NULL || value->len == 0)
- return NULL;
- if (attr->values[1] != NULL)
- return NULL;
- return value;
- }
- static const SEC_ASN1Template *
- sec_attr_choose_attr_value_template(void *src_or_dest, PRBool encoding)
- {
- const SEC_ASN1Template *theTemplate;
- SEC_PKCS7Attribute *attribute;
- SECOidData *oiddata;
- PRBool encoded;
- PORT_Assert (src_or_dest != NULL);
- if (src_or_dest == NULL)
- return NULL;
- attribute = (SEC_PKCS7Attribute*)src_or_dest;
- if (encoding && attribute->encoded)
- return SEC_AnyTemplate;
- oiddata = attribute->typeTag;
- if (oiddata == NULL) {
- oiddata = SECOID_FindOID(&attribute->type);
- attribute->typeTag = oiddata;
- }
- if (oiddata == NULL) {
- encoded = PR_TRUE;
- theTemplate = SEC_AnyTemplate;
- } else {
- switch (oiddata->offset) {
- default:
- encoded = PR_TRUE;
- theTemplate = SEC_AnyTemplate;
- break;
- case SEC_OID_PKCS9_EMAIL_ADDRESS:
- case SEC_OID_RFC1274_MAIL:
- case SEC_OID_PKCS9_UNSTRUCTURED_NAME:
- encoded = PR_FALSE;
- theTemplate = SEC_IA5StringTemplate;
- break;
- case SEC_OID_PKCS9_CONTENT_TYPE:
- encoded = PR_FALSE;
- theTemplate = SEC_ObjectIDTemplate;
- break;
- case SEC_OID_PKCS9_MESSAGE_DIGEST:
- encoded = PR_FALSE;
- theTemplate = SEC_OctetStringTemplate;
- break;
- case SEC_OID_PKCS9_SIGNING_TIME:
- encoded = PR_FALSE;
- theTemplate = SEC_UTCTimeTemplate;
- break;
- /* XXX Want other types here, too */
- }
- }
- if (encoding) {
- /*
- * If we are encoding and we think we have an already-encoded value,
- * then the code which initialized this attribute should have set
- * the "encoded" property to true (and we would have returned early,
- * up above). No devastating error, but that code should be fixed.
- * (It could indicate that the resulting encoded bytes are wrong.)
- */
- PORT_Assert (!encoded);
- } else {
- /*
- * We are decoding; record whether the resulting value is
- * still encoded or not.
- */
- attribute->encoded = encoded;
- }
- return theTemplate;
- }
- static SEC_ChooseASN1TemplateFunc sec_attr_chooser
- = sec_attr_choose_attr_value_template;
- static const SEC_ASN1Template sec_pkcs7_attribute_template[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7Attribute) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(SEC_PKCS7Attribute,type) },
- { SEC_ASN1_DYNAMIC | SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7Attribute,values),
- &sec_attr_chooser },
- { 0 }
- };
- static const SEC_ASN1Template sec_pkcs7_set_of_attribute_template[] = {
- { SEC_ASN1_SET_OF, 0, sec_pkcs7_attribute_template },
- };
- /*
- * If you are wondering why this routine does not reorder the attributes
- * first, and might be tempted to make it do so, see the comment by the
- * call to ReorderAttributes in p7encode.c. (Or, see who else calls this
- * and think long and hard about the implications of making it always
- * do the reordering.)
- */
- SECItem *
- sec_PKCS7EncodeAttributes (PRArenaPool *poolp, SECItem *dest, void *src)
- {
- return SEC_ASN1EncodeItem (poolp, dest, src,
- sec_pkcs7_set_of_attribute_template);
- }
- /*
- * Make sure that the order of the attributes guarantees valid DER
- * (which must be in lexigraphically ascending order for a SET OF);
- * if reordering is necessary it will be done in place (in attrs).
- */
- SECStatus
- sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs)
- {
- PRArenaPool *poolp;
- int num_attrs, i, j, pass, besti;
- SECItem **enc_attrs;
- SEC_PKCS7Attribute **new_attrs;
- /*
- * I think we should not be called with NULL. But if we are,
- * call it a success anyway, because the order *is* okay.
- */
- PORT_Assert (attrs != NULL);
- if (attrs == NULL)
- return SECSuccess;
- /*
- * Count how many attributes we are dealing with here.
- */
- num_attrs = 0;
- while (attrs[num_attrs] != NULL)
- num_attrs++;
- /*
- * Again, I think we should have some attributes here.
- * But if we do not, or if there is only one, then call it
- * a success because it also already has a fine order.
- */
- PORT_Assert (num_attrs);
- if (num_attrs == 0 || num_attrs == 1)
- return SECSuccess;
- /*
- * Allocate an arena for us to work with, so it is easy to
- * clean up all of the memory (fairly small pieces, really).
- */
- poolp = PORT_NewArena (1024); /* XXX what is right value? */
- if (poolp == NULL)
- return SECFailure; /* no memory; nothing we can do... */
- /*
- * Allocate arrays to hold the individual encodings which we will use
- * for comparisons and the reordered attributes as they are sorted.
- */
- enc_attrs=(SECItem**)PORT_ArenaZAlloc(poolp, num_attrs*sizeof(SECItem *));
- new_attrs = (SEC_PKCS7Attribute**)PORT_ArenaZAlloc (poolp,
- num_attrs * sizeof(SEC_PKCS7Attribute *));
- if (enc_attrs == NULL || new_attrs == NULL) {
- PORT_FreeArena (poolp, PR_FALSE);
- return SECFailure;
- }
- /*
- * DER encode each individual attribute.
- */
- for (i = 0; i < num_attrs; i++) {
- enc_attrs[i] = SEC_ASN1EncodeItem (poolp, NULL, attrs[i],
- sec_pkcs7_attribute_template);
- if (enc_attrs[i] == NULL) {
- PORT_FreeArena (poolp, PR_FALSE);
- return SECFailure;
- }
- }
- /*
- * Now compare and sort them; this is not the most efficient sorting
- * method, but it is just fine for the problem at hand, because the
- * number of attributes is (always) going to be small.
- */
- for (pass = 0; pass < num_attrs; pass++) {
- /*
- * Find the first not-yet-accepted attribute. (Once one is
- * sorted into the other array, it is cleared from enc_attrs.)
- */
- for (i = 0; i < num_attrs; i++) {
- if (enc_attrs[i] != NULL)
- break;
- }
- PORT_Assert (i < num_attrs);
- besti = i;
- /*
- * Find the lowest (lexigraphically) encoding. One that is
- * shorter than all the rest is known to be "less" because each
- * attribute is of the same type (a SEQUENCE) and so thus the
- * first octet of each is the same, and the second octet is
- * the length (or the length of the length with the high bit
- * set, followed by the length, which also works out to always
- * order the shorter first). Two (or more) that have the
- * same length need to be compared byte by byte until a mismatch
- * is found.
- */
- for (i = besti + 1; i < num_attrs; i++) {
- if (enc_attrs[i] == NULL) /* slot already handled */
- continue;
- if (enc_attrs[i]->len != enc_attrs[besti]->len) {
- if (enc_attrs[i]->len < enc_attrs[besti]->len)
- besti = i;
- continue;
- }
- for (j = 0; j < enc_attrs[i]->len; j++) {
- if (enc_attrs[i]->data[j] < enc_attrs[besti]->data[j]) {
- besti = i;
- break;
- }
- }
- /*
- * For this not to be true, we would have to have encountered
- * two *identical* attributes, which I think we should not see.
- * So assert if it happens, but even if it does, let it go
- * through; the ordering of the two does not matter.
- */
- PORT_Assert (j < enc_attrs[i]->len);
- }
- /*
- * Now we have found the next-lowest one; copy it over and
- * remove it from enc_attrs.
- */
- new_attrs[pass] = attrs[besti];
- enc_attrs[besti] = NULL;
- }
- /*
- * Now new_attrs has the attributes in the order we want;
- * copy them back into the attrs array we started with.
- */
- for (i = 0; i < num_attrs; i++)
- attrs[i] = new_attrs[i];
- PORT_FreeArena (poolp, PR_FALSE);
- return SECSuccess;
- }
- /*
- * End of attribute stuff.
- * -------------------------------------------------------------------
- */
- /*
- * Templates and stuff. Keep these at the end of the file.
- */
- /* forward declaration */
- static const SEC_ASN1Template *
- sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding);
- static SEC_ChooseASN1TemplateFunc sec_pkcs7_chooser
- = sec_pkcs7_choose_content_template;
- const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7ContentInfo) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(SEC_PKCS7ContentInfo,contentType) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
- | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7ContentInfo,content),
- &sec_pkcs7_chooser },
- { 0 }
- };
- /* XXX These names should change from external to internal convention. */
- static const SEC_ASN1Template SEC_PKCS7SignerInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SignerInfo) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7SignerInfo,version) },
- { SEC_ASN1_POINTER,
- offsetof(SEC_PKCS7SignerInfo,issuerAndSN),
- CERT_IssuerAndSNTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignerInfo,digestAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7SignerInfo,authAttr),
- sec_pkcs7_set_of_attribute_template },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignerInfo,digestEncAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SignerInfo,encDigest) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(SEC_PKCS7SignerInfo,unAuthAttr),
- sec_pkcs7_set_of_attribute_template },
- { 0 }
- };
- static const SEC_ASN1Template SEC_PKCS7SignedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7SignedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7SignedData,version) },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedData,digestAlgorithms),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignedData,contentInfo),
- sec_PKCS7ContentInfoTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7SignedData,rawCerts),
- SEC_SetOfAnyTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(SEC_PKCS7SignedData,crls),
- CERT_SetOfSignedCrlTemplate },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedData,signerInfos),
- SEC_PKCS7SignerInfoTemplate },
- { 0 }
- };
- static const SEC_ASN1Template SEC_PointerToPKCS7SignedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedDataTemplate }
- };
- static const SEC_ASN1Template SEC_PKCS7RecipientInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7RecipientInfo) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7RecipientInfo,version) },
- { SEC_ASN1_POINTER,
- offsetof(SEC_PKCS7RecipientInfo,issuerAndSN),
- CERT_IssuerAndSNTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7RecipientInfo,keyEncAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7RecipientInfo,encKey) },
- { 0 }
- };
- static const SEC_ASN1Template SEC_PKCS7EncryptedContentInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7EncryptedContentInfo) },
- { SEC_ASN1_OBJECT_ID,
- offsetof(SEC_PKCS7EncryptedContentInfo,contentType) },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7EncryptedContentInfo,contentEncAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_MAY_STREAM | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7EncryptedContentInfo,encContent),
- SEC_OctetStringTemplate },
- { 0 }
- };
- static const SEC_ASN1Template SEC_PKCS7EnvelopedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7EnvelopedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7EnvelopedData,version) },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7EnvelopedData,recipientInfos),
- SEC_PKCS7RecipientInfoTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7EnvelopedData,encContentInfo),
- SEC_PKCS7EncryptedContentInfoTemplate },
- { 0 }
- };
- static const SEC_ASN1Template SEC_PointerToPKCS7EnvelopedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7EnvelopedDataTemplate }
- };
- static const SEC_ASN1Template SEC_PKCS7SignedAndEnvelopedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7SignedAndEnvelopedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,version) },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,recipientInfos),
- SEC_PKCS7RecipientInfoTemplate },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,digestAlgorithms),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,encContentInfo),
- SEC_PKCS7EncryptedContentInfoTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,rawCerts),
- SEC_SetOfAnyTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,crls),
- CERT_SetOfSignedCrlTemplate },
- { SEC_ASN1_SET_OF,
- offsetof(SEC_PKCS7SignedAndEnvelopedData,signerInfos),
- SEC_PKCS7SignerInfoTemplate },
- { 0 }
- };
- static const SEC_ASN1Template
- SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedAndEnvelopedDataTemplate }
- };
- static const SEC_ASN1Template SEC_PKCS7DigestedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7DigestedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7DigestedData,version) },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7DigestedData,digestAlg),
- SECOID_AlgorithmIDTemplate },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7DigestedData,contentInfo),
- sec_PKCS7ContentInfoTemplate },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7DigestedData,digest) },
- { 0 }
- };
- static const SEC_ASN1Template SEC_PointerToPKCS7DigestedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7DigestedDataTemplate }
- };
- static const SEC_ASN1Template SEC_PKCS7EncryptedDataTemplate[] = {
- { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
- 0, NULL, sizeof(SEC_PKCS7EncryptedData) },
- { SEC_ASN1_INTEGER,
- offsetof(SEC_PKCS7EncryptedData,version) },
- { SEC_ASN1_INLINE,
- offsetof(SEC_PKCS7EncryptedData,encContentInfo),
- SEC_PKCS7EncryptedContentInfoTemplate },
- { 0 }
- };
- static const SEC_ASN1Template SEC_PointerToPKCS7EncryptedDataTemplate[] = {
- { SEC_ASN1_POINTER, 0, SEC_PKCS7EncryptedDataTemplate }
- };
- const SEC_ASN1Template SEC_SMIMEKEAParamTemplateSkipjack[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
- { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
- { 0 }
- };
- const SEC_ASN1Template SEC_SMIMEKEAParamTemplateNoSkipjack[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
- { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
- { SEC_ASN1_OCTET_STRING | SEC_ASN1_OPTIONAL ,
- offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
- { 0 }
- };
- const SEC_ASN1Template SEC_SMIMEKEAParamTemplateAllParams[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(SEC_PKCS7SMIMEKEAParameters) },
- { SEC_ASN1_OCTET_STRING /* | SEC_ASN1_OPTIONAL */,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorKEAKey) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SEC_PKCS7SMIMEKEAParameters,originatorRA) },
- { SEC_ASN1_OCTET_STRING | SEC_ASN1_OPTIONAL ,
- offsetof(SEC_PKCS7SMIMEKEAParameters,nonSkipjackIV) },
- { SEC_ASN1_OCTET_STRING | SEC_ASN1_OPTIONAL ,
- offsetof(SEC_PKCS7SMIMEKEAParameters,bulkKeySize) },
- { 0 }
- };
- const SEC_ASN1Template*
- sec_pkcs7_get_kea_template(SECKEATemplateSelector whichTemplate)
- {
- const SEC_ASN1Template *returnVal = NULL;
- switch(whichTemplate)
- {
- case SECKEAUsesNonSkipjack:
- returnVal = SEC_SMIMEKEAParamTemplateNoSkipjack;
- break;
- case SECKEAUsesSkipjack:
- returnVal = SEC_SMIMEKEAParamTemplateSkipjack;
- break;
- case SECKEAUsesNonSkipjackWithPaddedEncKey:
- default:
- returnVal = SEC_SMIMEKEAParamTemplateAllParams;
- break;
- }
- return returnVal;
- }
-
- static const SEC_ASN1Template *
- sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding)
- {
- const SEC_ASN1Template *theTemplate;
- SEC_PKCS7ContentInfo *cinfo;
- SECOidTag kind;
- PORT_Assert (src_or_dest != NULL);
- if (src_or_dest == NULL)
- return NULL;
- cinfo = (SEC_PKCS7ContentInfo*)src_or_dest;
- kind = SEC_PKCS7ContentType (cinfo);
- switch (kind) {
- default:
- theTemplate = SEC_PointerToAnyTemplate;
- break;
- case SEC_OID_PKCS7_DATA:
- theTemplate = SEC_PointerToOctetStringTemplate;
- break;
- case SEC_OID_PKCS7_SIGNED_DATA:
- theTemplate = SEC_PointerToPKCS7SignedDataTemplate;
- break;
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- theTemplate = SEC_PointerToPKCS7EnvelopedDataTemplate;
- break;
- case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
- theTemplate = SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate;
- break;
- case SEC_OID_PKCS7_DIGESTED_DATA:
- theTemplate = SEC_PointerToPKCS7DigestedDataTemplate;
- break;
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- theTemplate = SEC_PointerToPKCS7EncryptedDataTemplate;
- break;
- }
- return theTemplate;
- }
- /*
- * End of templates. Do not add stuff after this; put new code
- * up above the start of the template definitions.
- */