security/nss/lib/pkcs7/p7local.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/pkcs7/p7local.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1319 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * Support routines for PKCS7 implementation, none of which are exported.
    1.10 + * This file should only contain things that are needed by both the
    1.11 + * encoding/creation side *and* the decoding/decryption side.  Anything
    1.12 + * else should be static routines in the appropriate file.
    1.13 + */
    1.14 +
    1.15 +#include "p7local.h"
    1.16 +
    1.17 +#include "cryptohi.h" 
    1.18 +#include "secasn1.h"
    1.19 +#include "secoid.h"
    1.20 +#include "secitem.h"
    1.21 +#include "pk11func.h"
    1.22 +#include "secpkcs5.h"
    1.23 +#include "secerr.h"
    1.24 +
    1.25 +/*
    1.26 + * -------------------------------------------------------------------
    1.27 + * Cipher stuff.
    1.28 + */
    1.29 +
    1.30 +typedef SECStatus (*sec_pkcs7_cipher_function) (void *,
    1.31 +						unsigned char *,
    1.32 +						unsigned *,
    1.33 +						unsigned int,
    1.34 +						const unsigned char *,
    1.35 +						unsigned int);
    1.36 +typedef SECStatus (*sec_pkcs7_cipher_destroy) (void *, PRBool);
    1.37 +
    1.38 +#define BLOCK_SIZE 4096
    1.39 +
    1.40 +struct sec_pkcs7_cipher_object {
    1.41 +    void *cx;
    1.42 +    sec_pkcs7_cipher_function doit;
    1.43 +    sec_pkcs7_cipher_destroy destroy;
    1.44 +    PRBool encrypt;
    1.45 +    int block_size;
    1.46 +    int pad_size;
    1.47 +    int pending_count;
    1.48 +    unsigned char pending_buf[BLOCK_SIZE];
    1.49 +};
    1.50 +
    1.51 +SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
    1.52 +SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate)
    1.53 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    1.54 +SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
    1.55 +SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
    1.56 +
    1.57 +/*
    1.58 + * Create a cipher object to do decryption,  based on the given bulk
    1.59 + * encryption key and algorithm identifier (which may include an iv).
    1.60 + *
    1.61 + * XXX This interface, or one similar, would be really nice available
    1.62 + * in general...  I tried to keep the pkcs7-specific stuff (mostly
    1.63 + * having to do with padding) out of here.
    1.64 + *
    1.65 + * XXX Once both are working, it might be nice to combine this and the
    1.66 + * function below (for starting up encryption) into one routine, and just
    1.67 + * have two simple cover functions which call it. 
    1.68 + */
    1.69 +sec_PKCS7CipherObject *
    1.70 +sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid)
    1.71 +{
    1.72 +    sec_PKCS7CipherObject *result;
    1.73 +    SECOidTag algtag;
    1.74 +    void *ciphercx;
    1.75 +    CK_MECHANISM_TYPE cryptoMechType;
    1.76 +    PK11SlotInfo *slot;
    1.77 +    SECItem *param = NULL;
    1.78 +
    1.79 +    result = (struct sec_pkcs7_cipher_object*)
    1.80 +      PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
    1.81 +    if (result == NULL)
    1.82 +	return NULL;
    1.83 +
    1.84 +    ciphercx = NULL;
    1.85 +    algtag = SECOID_GetAlgorithmTag (algid);
    1.86 +
    1.87 +    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
    1.88 +	SECItem *pwitem;
    1.89 +
    1.90 +	pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
    1.91 +	if (!pwitem) {
    1.92 +	    PORT_Free(result);
    1.93 +	    return NULL;
    1.94 +	}
    1.95 +
    1.96 +	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
    1.97 +	if (cryptoMechType == CKM_INVALID_MECHANISM) {
    1.98 +	    PORT_Free(result);
    1.99 +	    SECITEM_FreeItem(param,PR_TRUE);
   1.100 +	    return NULL;
   1.101 +	}
   1.102 +    } else {
   1.103 +	cryptoMechType = PK11_AlgtagToMechanism(algtag);
   1.104 +	param = PK11_ParamFromAlgid(algid);
   1.105 +	if (param == NULL) {
   1.106 +	    PORT_Free(result);
   1.107 +	    return NULL;
   1.108 +	}
   1.109 +    }
   1.110 +
   1.111 +    result->pad_size = PK11_GetBlockSize(cryptoMechType, param);
   1.112 +    slot = PK11_GetSlotFromKey(key);
   1.113 +    result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
   1.114 +    PK11_FreeSlot(slot);
   1.115 +    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, 
   1.116 +					  key, param);
   1.117 +    SECITEM_FreeItem(param,PR_TRUE);
   1.118 +    if (ciphercx == NULL) {
   1.119 +	PORT_Free (result);
   1.120 +	return NULL;
   1.121 +    }
   1.122 +
   1.123 +    result->cx = ciphercx;
   1.124 +    result->doit =  (sec_pkcs7_cipher_function) PK11_CipherOp;
   1.125 +    result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
   1.126 +    result->encrypt = PR_FALSE;
   1.127 +    result->pending_count = 0;
   1.128 +
   1.129 +    return result;
   1.130 +}
   1.131 +
   1.132 +/*
   1.133 + * Create a cipher object to do encryption, based on the given bulk
   1.134 + * encryption key and algorithm tag.  Fill in the algorithm identifier
   1.135 + * (which may include an iv) appropriately.
   1.136 + *
   1.137 + * XXX This interface, or one similar, would be really nice available
   1.138 + * in general...  I tried to keep the pkcs7-specific stuff (mostly
   1.139 + * having to do with padding) out of here.
   1.140 + *
   1.141 + * XXX Once both are working, it might be nice to combine this and the
   1.142 + * function above (for starting up decryption) into one routine, and just
   1.143 + * have two simple cover functions which call it. 
   1.144 + */
   1.145 +sec_PKCS7CipherObject *
   1.146 +sec_PKCS7CreateEncryptObject (PLArenaPool *poolp, PK11SymKey *key,
   1.147 +			      SECOidTag algtag, SECAlgorithmID *algid)
   1.148 +{
   1.149 +    sec_PKCS7CipherObject *result;
   1.150 +    void *ciphercx;
   1.151 +    SECStatus rv;
   1.152 +    CK_MECHANISM_TYPE cryptoMechType;
   1.153 +    PK11SlotInfo *slot;
   1.154 +    SECItem *param = NULL;
   1.155 +    PRBool needToEncodeAlgid = PR_FALSE;
   1.156 +
   1.157 +    result = (struct sec_pkcs7_cipher_object*)
   1.158 +	      PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
   1.159 +    if (result == NULL)
   1.160 +	return NULL;
   1.161 +
   1.162 +    ciphercx = NULL;
   1.163 +    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
   1.164 +	SECItem *pwitem;
   1.165 +
   1.166 +	pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
   1.167 +	if (!pwitem) {
   1.168 +	    PORT_Free(result);
   1.169 +	    return NULL;
   1.170 +	}
   1.171 +
   1.172 +	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
   1.173 +	if (cryptoMechType == CKM_INVALID_MECHANISM) {
   1.174 +	    PORT_Free(result);
   1.175 +	    SECITEM_FreeItem(param,PR_TRUE);
   1.176 +	    return NULL;
   1.177 +	}
   1.178 +    } else {
   1.179 +	cryptoMechType = PK11_AlgtagToMechanism(algtag);
   1.180 +	param = PK11_GenerateNewParam(cryptoMechType, key);
   1.181 +	if (param == NULL) {
   1.182 +	    PORT_Free(result);
   1.183 +	    return NULL;
   1.184 +	}
   1.185 +	needToEncodeAlgid = PR_TRUE;
   1.186 +    }
   1.187 +
   1.188 +    result->pad_size = PK11_GetBlockSize(cryptoMechType,param);
   1.189 +    slot = PK11_GetSlotFromKey(key);
   1.190 +    result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
   1.191 +    PK11_FreeSlot(slot);
   1.192 +    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, 
   1.193 +    					  key, param);
   1.194 +    if (ciphercx == NULL) {
   1.195 +	PORT_Free (result);
   1.196 +        SECITEM_FreeItem(param,PR_TRUE);
   1.197 +	return NULL;
   1.198 +    }
   1.199 +
   1.200 +    /*
   1.201 +     * These are placed after the CreateContextBySymKey() because some
   1.202 +     * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
   1.203 +     * Don't move it from here.
   1.204 +     */
   1.205 +    if (needToEncodeAlgid) {
   1.206 +	rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
   1.207 +	if(rv != SECSuccess) {
   1.208 +	    PORT_Free (result);
   1.209 +            SECITEM_FreeItem(param,PR_TRUE);
   1.210 +	    return NULL;
   1.211 +	}
   1.212 +    }
   1.213 +    SECITEM_FreeItem(param,PR_TRUE);
   1.214 +
   1.215 +    result->cx = ciphercx;
   1.216 +    result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
   1.217 +    result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
   1.218 +    result->encrypt = PR_TRUE;
   1.219 +    result->pending_count = 0;
   1.220 +
   1.221 +    return result;
   1.222 +}
   1.223 +
   1.224 +
   1.225 +/*
   1.226 + * Destroy the cipher object.
   1.227 + */
   1.228 +static void
   1.229 +sec_pkcs7_destroy_cipher (sec_PKCS7CipherObject *obj)
   1.230 +{
   1.231 +    (* obj->destroy) (obj->cx, PR_TRUE);
   1.232 +    PORT_Free (obj);
   1.233 +}
   1.234 +
   1.235 +void
   1.236 +sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj)
   1.237 +{
   1.238 +    PORT_Assert (obj != NULL);
   1.239 +    if (obj == NULL)
   1.240 +	return;
   1.241 +    PORT_Assert (! obj->encrypt);
   1.242 +    sec_pkcs7_destroy_cipher (obj);
   1.243 +}
   1.244 +
   1.245 +void
   1.246 +sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj)
   1.247 +{
   1.248 +    PORT_Assert (obj != NULL);
   1.249 +    if (obj == NULL)
   1.250 +	return;
   1.251 +    PORT_Assert (obj->encrypt);
   1.252 +    sec_pkcs7_destroy_cipher (obj);
   1.253 +}
   1.254 +
   1.255 +
   1.256 +/*
   1.257 + * XXX I think all of the following lengths should be longs instead
   1.258 + * of ints, but our current crypto interface uses ints, so I did too.
   1.259 + */
   1.260 +
   1.261 +
   1.262 +/*
   1.263 + * What will be the output length of the next call to decrypt?
   1.264 + * Result can be used to perform memory allocations.  Note that the amount
   1.265 + * is exactly accurate only when not doing a block cipher or when final
   1.266 + * is false, otherwise it is an upper bound on the amount because until
   1.267 + * we see the data we do not know how many padding bytes there are
   1.268 + * (always between 1 and bsize).
   1.269 + *
   1.270 + * Note that this can return zero, which does not mean that the decrypt
   1.271 + * operation can be skipped!  (It simply means that there are not enough
   1.272 + * bytes to make up an entire block; the bytes will be reserved until
   1.273 + * there are enough to encrypt/decrypt at least one block.)  However,
   1.274 + * if zero is returned it *does* mean that no output buffer need be
   1.275 + * passed in to the subsequent decrypt operation, as no output bytes
   1.276 + * will be stored.
   1.277 + */
   1.278 +unsigned int
   1.279 +sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
   1.280 +			PRBool final)
   1.281 +{
   1.282 +    int blocks, block_size;
   1.283 +
   1.284 +    PORT_Assert (! obj->encrypt);
   1.285 +
   1.286 +    block_size = obj->block_size;
   1.287 +
   1.288 +    /*
   1.289 +     * If this is not a block cipher, then we always have the same
   1.290 +     * number of output bytes as we had input bytes.
   1.291 +     */
   1.292 +    if (block_size == 0)
   1.293 +	return input_len;
   1.294 +
   1.295 +    /*
   1.296 +     * On the final call, we will always use up all of the pending
   1.297 +     * bytes plus all of the input bytes, *but*, there will be padding
   1.298 +     * at the end and we cannot predict how many bytes of padding we
   1.299 +     * will end up removing.  The amount given here is actually known
   1.300 +     * to be at least 1 byte too long (because we know we will have
   1.301 +     * at least 1 byte of padding), but seemed clearer/better to me.
   1.302 +     */
   1.303 +    if (final)
   1.304 +	return obj->pending_count + input_len;
   1.305 +
   1.306 +    /*
   1.307 +     * Okay, this amount is exactly what we will output on the
   1.308 +     * next cipher operation.  We will always hang onto the last
   1.309 +     * 1 - block_size bytes for non-final operations.  That is,
   1.310 +     * we will do as many complete blocks as we can *except* the
   1.311 +     * last block (complete or partial).  (This is because until
   1.312 +     * we know we are at the end, we cannot know when to interpret
   1.313 +     * and removing the padding byte(s), which are guaranteed to
   1.314 +     * be there.)
   1.315 +     */
   1.316 +    blocks = (obj->pending_count + input_len - 1) / block_size;
   1.317 +    return blocks * block_size;
   1.318 +}
   1.319 +
   1.320 +/*
   1.321 + * What will be the output length of the next call to encrypt?
   1.322 + * Result can be used to perform memory allocations.
   1.323 + *
   1.324 + * Note that this can return zero, which does not mean that the encrypt
   1.325 + * operation can be skipped!  (It simply means that there are not enough
   1.326 + * bytes to make up an entire block; the bytes will be reserved until
   1.327 + * there are enough to encrypt/decrypt at least one block.)  However,
   1.328 + * if zero is returned it *does* mean that no output buffer need be
   1.329 + * passed in to the subsequent encrypt operation, as no output bytes
   1.330 + * will be stored.
   1.331 + */
   1.332 +unsigned int
   1.333 +sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
   1.334 +			PRBool final)
   1.335 +{
   1.336 +    int blocks, block_size;
   1.337 +    int pad_size;
   1.338 +
   1.339 +    PORT_Assert (obj->encrypt);
   1.340 +
   1.341 +    block_size = obj->block_size;
   1.342 +    pad_size = obj->pad_size;
   1.343 +
   1.344 +    /*
   1.345 +     * If this is not a block cipher, then we always have the same
   1.346 +     * number of output bytes as we had input bytes.
   1.347 +     */
   1.348 +    if (block_size == 0)
   1.349 +	return input_len;
   1.350 +
   1.351 +    /*
   1.352 +     * On the final call, we only send out what we need for
   1.353 +     * remaining bytes plus the padding.  (There is always padding,
   1.354 +     * so even if we have an exact number of blocks as input, we
   1.355 +     * will add another full block that is just padding.)
   1.356 +     */
   1.357 +    if (final) {
   1.358 +	if (pad_size == 0) {
   1.359 +    	    return obj->pending_count + input_len;
   1.360 +	} else {
   1.361 +    	    blocks = (obj->pending_count + input_len) / pad_size;
   1.362 +	    blocks++;
   1.363 +	    return blocks*pad_size;
   1.364 +	}
   1.365 +    }
   1.366 +
   1.367 +    /*
   1.368 +     * Now, count the number of complete blocks of data we have.
   1.369 +     */
   1.370 +    blocks = (obj->pending_count + input_len) / block_size;
   1.371 +
   1.372 +
   1.373 +    return blocks * block_size;
   1.374 +}
   1.375 +
   1.376 +
   1.377 +/*
   1.378 + * Decrypt a given length of input buffer (starting at "input" and
   1.379 + * containing "input_len" bytes), placing the decrypted bytes in
   1.380 + * "output" and storing the output length in "*output_len_p".
   1.381 + * "obj" is the return value from sec_PKCS7CreateDecryptObject.
   1.382 + * When "final" is true, this is the last of the data to be decrypted.
   1.383 + *
   1.384 + * This is much more complicated than it sounds when the cipher is
   1.385 + * a block-type, meaning that the decryption function will only
   1.386 + * operate on whole blocks.  But our caller is operating stream-wise,
   1.387 + * and can pass in any number of bytes.  So we need to keep track
   1.388 + * of block boundaries.  We save excess bytes between calls in "obj".
   1.389 + * We also need to determine which bytes are padding, and remove
   1.390 + * them from the output.  We can only do this step when we know we
   1.391 + * have the final block of data.  PKCS #7 specifies that the padding
   1.392 + * used for a block cipher is a string of bytes, each of whose value is
   1.393 + * the same as the length of the padding, and that all data is padded.
   1.394 + * (Even data that starts out with an exact multiple of blocks gets
   1.395 + * added to it another block, all of which is padding.)
   1.396 + */ 
   1.397 +SECStatus
   1.398 +sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
   1.399 +		  unsigned int *output_len_p, unsigned int max_output_len,
   1.400 +		  const unsigned char *input, unsigned int input_len,
   1.401 +		  PRBool final)
   1.402 +{
   1.403 +    int blocks, bsize, pcount, padsize;
   1.404 +    unsigned int max_needed, ifraglen, ofraglen, output_len;
   1.405 +    unsigned char *pbuf;
   1.406 +    SECStatus rv;
   1.407 +
   1.408 +    PORT_Assert (! obj->encrypt);
   1.409 +
   1.410 +    /*
   1.411 +     * Check that we have enough room for the output.  Our caller should
   1.412 +     * already handle this; failure is really an internal error (i.e. bug).
   1.413 +     */
   1.414 +    max_needed = sec_PKCS7DecryptLength (obj, input_len, final);
   1.415 +    PORT_Assert (max_output_len >= max_needed);
   1.416 +    if (max_output_len < max_needed) {
   1.417 +	/* PORT_SetError (XXX); */
   1.418 +	return SECFailure;
   1.419 +    }
   1.420 +
   1.421 +    /*
   1.422 +     * hardware encryption does not like small decryption sizes here, so we
   1.423 +     * allow both blocking and padding.
   1.424 +     */
   1.425 +    bsize = obj->block_size;
   1.426 +    padsize = obj->pad_size;
   1.427 +
   1.428 +    /*
   1.429 +     * When no blocking or padding work to do, we can simply call the
   1.430 +     * cipher function and we are done.
   1.431 +     */
   1.432 +    if (bsize == 0) {
   1.433 +	return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
   1.434 +			      input, input_len);
   1.435 +    }
   1.436 +
   1.437 +    pcount = obj->pending_count;
   1.438 +    pbuf = obj->pending_buf;
   1.439 +
   1.440 +    output_len = 0;
   1.441 +
   1.442 +    if (pcount) {
   1.443 +	/*
   1.444 +	 * Try to fill in an entire block, starting with the bytes
   1.445 +	 * we already have saved away.
   1.446 +	 */
   1.447 +	while (input_len && pcount < bsize) {
   1.448 +	    pbuf[pcount++] = *input++;
   1.449 +	    input_len--;
   1.450 +	}
   1.451 +	/*
   1.452 +	 * If we have at most a whole block and this is not our last call,
   1.453 +	 * then we are done for now.  (We do not try to decrypt a lone
   1.454 +	 * single block because we cannot interpret the padding bytes
   1.455 +	 * until we know we are handling the very last block of all input.)
   1.456 +	 */
   1.457 +	if (input_len == 0 && !final) {
   1.458 +	    obj->pending_count = pcount;
   1.459 +	    if (output_len_p)
   1.460 +		*output_len_p = 0;
   1.461 +	    return SECSuccess;
   1.462 +	}
   1.463 +	/*
   1.464 +	 * Given the logic above, we expect to have a full block by now.
   1.465 +	 * If we do not, there is something wrong, either with our own
   1.466 +	 * logic or with (length of) the data given to us.
   1.467 +	 */
   1.468 +	PORT_Assert ((padsize == 0) || (pcount % padsize) == 0);
   1.469 +	if ((padsize != 0) && (pcount % padsize) != 0) {
   1.470 +	    PORT_Assert (final);	
   1.471 +	    PORT_SetError (SEC_ERROR_BAD_DATA);
   1.472 +	    return SECFailure;
   1.473 +	}
   1.474 +	/*
   1.475 +	 * Decrypt the block.
   1.476 +	 */
   1.477 +	rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
   1.478 +			    pbuf, pcount);
   1.479 +	if (rv != SECSuccess)
   1.480 +	    return rv;
   1.481 +
   1.482 +	/*
   1.483 +	 * For now anyway, all of our ciphers have the same number of
   1.484 +	 * bytes of output as they do input.  If this ever becomes untrue,
   1.485 +	 * then sec_PKCS7DecryptLength needs to be made smarter!
   1.486 +	 */
   1.487 +	PORT_Assert (ofraglen == pcount);
   1.488 +
   1.489 +	/*
   1.490 +	 * Account for the bytes now in output.
   1.491 +	 */
   1.492 +	max_output_len -= ofraglen;
   1.493 +	output_len += ofraglen;
   1.494 +	output += ofraglen;
   1.495 +    }
   1.496 +
   1.497 +    /*
   1.498 +     * If this is our last call, we expect to have an exact number of
   1.499 +     * blocks left to be decrypted; we will decrypt them all.
   1.500 +     * 
   1.501 +     * If not our last call, we always save between 1 and bsize bytes
   1.502 +     * until next time.  (We must do this because we cannot be sure
   1.503 +     * that none of the decrypted bytes are padding bytes until we
   1.504 +     * have at least another whole block of data.  You cannot tell by
   1.505 +     * looking -- the data could be anything -- you can only tell by
   1.506 +     * context, knowing you are looking at the last block.)  We could
   1.507 +     * decrypt a whole block now but it is easier if we just treat it
   1.508 +     * the same way we treat partial block bytes.
   1.509 +     */
   1.510 +    if (final) {
   1.511 +	if (padsize) {
   1.512 +	    blocks = input_len / padsize;
   1.513 +	    ifraglen = blocks * padsize;
   1.514 +	} else ifraglen = input_len;
   1.515 +	PORT_Assert (ifraglen == input_len);
   1.516 +
   1.517 +	if (ifraglen != input_len) {
   1.518 +	    PORT_SetError (SEC_ERROR_BAD_DATA);
   1.519 +	    return SECFailure;
   1.520 +	}
   1.521 +    } else {
   1.522 +	blocks = (input_len - 1) / bsize;
   1.523 +	ifraglen = blocks * bsize;
   1.524 +	PORT_Assert (ifraglen < input_len);
   1.525 +
   1.526 +	pcount = input_len - ifraglen;
   1.527 +	PORT_Memcpy (pbuf, input + ifraglen, pcount);
   1.528 +	obj->pending_count = pcount;
   1.529 +    }
   1.530 +
   1.531 +    if (ifraglen) {
   1.532 +	rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
   1.533 +			    input, ifraglen);
   1.534 +	if (rv != SECSuccess)
   1.535 +	    return rv;
   1.536 +
   1.537 +	/*
   1.538 +	 * For now anyway, all of our ciphers have the same number of
   1.539 +	 * bytes of output as they do input.  If this ever becomes untrue,
   1.540 +	 * then sec_PKCS7DecryptLength needs to be made smarter!
   1.541 +	 */
   1.542 +	PORT_Assert (ifraglen == ofraglen);
   1.543 +	if (ifraglen != ofraglen) {
   1.544 +	    PORT_SetError (SEC_ERROR_BAD_DATA);
   1.545 +	    return SECFailure;
   1.546 +	}
   1.547 +
   1.548 +	output_len += ofraglen;
   1.549 +    } else {
   1.550 +	ofraglen = 0;
   1.551 +    }
   1.552 +
   1.553 +    /*
   1.554 +     * If we just did our very last block, "remove" the padding by
   1.555 +     * adjusting the output length.
   1.556 +     */
   1.557 +    if (final && (padsize != 0)) {
   1.558 +	unsigned int padlen = *(output + ofraglen - 1);
   1.559 +	if (padlen == 0 || padlen > padsize) {
   1.560 +	    PORT_SetError (SEC_ERROR_BAD_DATA);
   1.561 +	    return SECFailure;
   1.562 +	}
   1.563 +	output_len -= padlen;
   1.564 +    }
   1.565 +
   1.566 +    PORT_Assert (output_len_p != NULL || output_len == 0);
   1.567 +    if (output_len_p != NULL)
   1.568 +	*output_len_p = output_len;
   1.569 +
   1.570 +    return SECSuccess;
   1.571 +}
   1.572 +
   1.573 +/*
   1.574 + * Encrypt a given length of input buffer (starting at "input" and
   1.575 + * containing "input_len" bytes), placing the encrypted bytes in
   1.576 + * "output" and storing the output length in "*output_len_p".
   1.577 + * "obj" is the return value from sec_PKCS7CreateEncryptObject.
   1.578 + * When "final" is true, this is the last of the data to be encrypted.
   1.579 + *
   1.580 + * This is much more complicated than it sounds when the cipher is
   1.581 + * a block-type, meaning that the encryption function will only
   1.582 + * operate on whole blocks.  But our caller is operating stream-wise,
   1.583 + * and can pass in any number of bytes.  So we need to keep track
   1.584 + * of block boundaries.  We save excess bytes between calls in "obj".
   1.585 + * We also need to add padding bytes at the end.  PKCS #7 specifies
   1.586 + * that the padding used for a block cipher is a string of bytes,
   1.587 + * each of whose value is the same as the length of the padding,
   1.588 + * and that all data is padded.  (Even data that starts out with
   1.589 + * an exact multiple of blocks gets added to it another block,
   1.590 + * all of which is padding.)
   1.591 + *
   1.592 + * XXX I would kind of like to combine this with the function above
   1.593 + * which does decryption, since they have a lot in common.  But the
   1.594 + * tricky parts about padding and filling blocks would be much
   1.595 + * harder to read that way, so I left them separate.  At least for
   1.596 + * now until it is clear that they are right.
   1.597 + */ 
   1.598 +SECStatus
   1.599 +sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
   1.600 +		  unsigned int *output_len_p, unsigned int max_output_len,
   1.601 +		  const unsigned char *input, unsigned int input_len,
   1.602 +		  PRBool final)
   1.603 +{
   1.604 +    int blocks, bsize, padlen, pcount, padsize;
   1.605 +    unsigned int max_needed, ifraglen, ofraglen, output_len;
   1.606 +    unsigned char *pbuf;
   1.607 +    SECStatus rv;
   1.608 +
   1.609 +    PORT_Assert (obj->encrypt);
   1.610 +
   1.611 +    /*
   1.612 +     * Check that we have enough room for the output.  Our caller should
   1.613 +     * already handle this; failure is really an internal error (i.e. bug).
   1.614 +     */
   1.615 +    max_needed = sec_PKCS7EncryptLength (obj, input_len, final);
   1.616 +    PORT_Assert (max_output_len >= max_needed);
   1.617 +    if (max_output_len < max_needed) {
   1.618 +	/* PORT_SetError (XXX); */
   1.619 +	return SECFailure;
   1.620 +    }
   1.621 +
   1.622 +    bsize = obj->block_size;
   1.623 +    padsize = obj->pad_size;
   1.624 +
   1.625 +    /*
   1.626 +     * When no blocking and padding work to do, we can simply call the
   1.627 +     * cipher function and we are done.
   1.628 +     */
   1.629 +    if (bsize == 0) {
   1.630 +	return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
   1.631 +			      input, input_len);
   1.632 +    }
   1.633 +
   1.634 +    pcount = obj->pending_count;
   1.635 +    pbuf = obj->pending_buf;
   1.636 +
   1.637 +    output_len = 0;
   1.638 +
   1.639 +    if (pcount) {
   1.640 +	/*
   1.641 +	 * Try to fill in an entire block, starting with the bytes
   1.642 +	 * we already have saved away.
   1.643 +	 */
   1.644 +	while (input_len && pcount < bsize) {
   1.645 +	    pbuf[pcount++] = *input++;
   1.646 +	    input_len--;
   1.647 +	}
   1.648 +	/*
   1.649 +	 * If we do not have a full block and we know we will be
   1.650 +	 * called again, then we are done for now.
   1.651 +	 */
   1.652 +	if (pcount < bsize && !final) {
   1.653 +	    obj->pending_count = pcount;
   1.654 +	    if (output_len_p != NULL)
   1.655 +		*output_len_p = 0;
   1.656 +	    return SECSuccess;
   1.657 +	}
   1.658 +	/*
   1.659 +	 * If we have a whole block available, encrypt it.
   1.660 +	 */
   1.661 +	if ((padsize == 0) || (pcount % padsize) == 0) {
   1.662 +	    rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
   1.663 +				pbuf, pcount);
   1.664 +	    if (rv != SECSuccess)
   1.665 +		return rv;
   1.666 +
   1.667 +	    /*
   1.668 +	     * For now anyway, all of our ciphers have the same number of
   1.669 +	     * bytes of output as they do input.  If this ever becomes untrue,
   1.670 +	     * then sec_PKCS7EncryptLength needs to be made smarter!
   1.671 +	     */
   1.672 +	    PORT_Assert (ofraglen == pcount);
   1.673 +
   1.674 +	    /*
   1.675 +	     * Account for the bytes now in output.
   1.676 +	     */
   1.677 +	    max_output_len -= ofraglen;
   1.678 +	    output_len += ofraglen;
   1.679 +	    output += ofraglen;
   1.680 +
   1.681 +	    pcount = 0;
   1.682 +	}
   1.683 +    }
   1.684 +
   1.685 +    if (input_len) {
   1.686 +	PORT_Assert (pcount == 0);
   1.687 +
   1.688 +	blocks = input_len / bsize;
   1.689 +	ifraglen = blocks * bsize;
   1.690 +
   1.691 +	if (ifraglen) {
   1.692 +	    rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
   1.693 +				input, ifraglen);
   1.694 +	    if (rv != SECSuccess)
   1.695 +		return rv;
   1.696 +
   1.697 +	    /*
   1.698 +	     * For now anyway, all of our ciphers have the same number of
   1.699 +	     * bytes of output as they do input.  If this ever becomes untrue,
   1.700 +	     * then sec_PKCS7EncryptLength needs to be made smarter!
   1.701 +	     */
   1.702 +	    PORT_Assert (ifraglen == ofraglen);
   1.703 +
   1.704 +	    max_output_len -= ofraglen;
   1.705 +	    output_len += ofraglen;
   1.706 +	    output += ofraglen;
   1.707 +	}
   1.708 +
   1.709 +	pcount = input_len - ifraglen;
   1.710 +	PORT_Assert (pcount < bsize);
   1.711 +	if (pcount)
   1.712 +	    PORT_Memcpy (pbuf, input + ifraglen, pcount);
   1.713 +    }
   1.714 +
   1.715 +    if (final) {
   1.716 +	padlen = padsize - (pcount % padsize);
   1.717 +	PORT_Memset (pbuf + pcount, padlen, padlen);
   1.718 +	rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
   1.719 +			    pbuf, pcount+padlen);
   1.720 +	if (rv != SECSuccess)
   1.721 +	    return rv;
   1.722 +
   1.723 +	/*
   1.724 +	 * For now anyway, all of our ciphers have the same number of
   1.725 +	 * bytes of output as they do input.  If this ever becomes untrue,
   1.726 +	 * then sec_PKCS7EncryptLength needs to be made smarter!
   1.727 +	 */
   1.728 +	PORT_Assert (ofraglen == (pcount+padlen));
   1.729 +	output_len += ofraglen;
   1.730 +    } else {
   1.731 +	obj->pending_count = pcount;
   1.732 +    }
   1.733 +
   1.734 +    PORT_Assert (output_len_p != NULL || output_len == 0);
   1.735 +    if (output_len_p != NULL)
   1.736 +	*output_len_p = output_len;
   1.737 +
   1.738 +    return SECSuccess;
   1.739 +}
   1.740 +
   1.741 +/*
   1.742 + * End of cipher stuff.
   1.743 + * -------------------------------------------------------------------
   1.744 + */
   1.745 +
   1.746 +
   1.747 +/*
   1.748 + * -------------------------------------------------------------------
   1.749 + * XXX The following Attribute stuff really belongs elsewhere.
   1.750 + * The Attribute type is *not* part of pkcs7 but rather X.501.
   1.751 + * But for now, since PKCS7 is the only customer of attributes,
   1.752 + * we define them here.  Once there is a use outside of PKCS7,
   1.753 + * then change the attribute types and functions from internal
   1.754 + * to external naming convention, and move them elsewhere!
   1.755 + */
   1.756 +
   1.757 +/*
   1.758 + * Look through a set of attributes and find one that matches the
   1.759 + * specified object ID.  If "only" is true, then make sure that
   1.760 + * there is not more than one attribute of the same type.  Otherwise,
   1.761 + * just return the first one found. (XXX Does anybody really want
   1.762 + * that first-found behavior?  It was like that when I found it...)
   1.763 + */
   1.764 +SEC_PKCS7Attribute *
   1.765 +sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs, SECOidTag oidtag,
   1.766 +			PRBool only)
   1.767 +{
   1.768 +    SECOidData *oid;
   1.769 +    SEC_PKCS7Attribute *attr1, *attr2;
   1.770 +
   1.771 +    if (attrs == NULL)
   1.772 +	return NULL;
   1.773 +
   1.774 +    oid = SECOID_FindOIDByTag(oidtag);
   1.775 +    if (oid == NULL)
   1.776 +	return NULL;
   1.777 +
   1.778 +    while ((attr1 = *attrs++) != NULL) {
   1.779 +	if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
   1.780 +							    oid->oid.data,
   1.781 +							    oid->oid.len) == 0)
   1.782 +	    break;
   1.783 +    }
   1.784 +
   1.785 +    if (attr1 == NULL)
   1.786 +	return NULL;
   1.787 +
   1.788 +    if (!only)
   1.789 +	return attr1;
   1.790 +
   1.791 +    while ((attr2 = *attrs++) != NULL) {
   1.792 +	if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
   1.793 +							    oid->oid.data,
   1.794 +							    oid->oid.len) == 0)
   1.795 +	    break;
   1.796 +    }
   1.797 +
   1.798 +    if (attr2 != NULL)
   1.799 +	return NULL;
   1.800 +
   1.801 +    return attr1;
   1.802 +}
   1.803 +
   1.804 +
   1.805 +/*
   1.806 + * Return the single attribute value, doing some sanity checking first:
   1.807 + * - Multiple values are *not* expected.
   1.808 + * - Empty values are *not* expected.
   1.809 + */
   1.810 +SECItem *
   1.811 +sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr)
   1.812 +{
   1.813 +    SECItem *value;
   1.814 +
   1.815 +    if (attr == NULL)
   1.816 +	return NULL;
   1.817 +
   1.818 +    value = attr->values[0];
   1.819 +
   1.820 +    if (value == NULL || value->data == NULL || value->len == 0)
   1.821 +	return NULL;
   1.822 +
   1.823 +    if (attr->values[1] != NULL)
   1.824 +	return NULL;
   1.825 +
   1.826 +    return value;
   1.827 +}
   1.828 +
   1.829 +static const SEC_ASN1Template *
   1.830 +sec_attr_choose_attr_value_template(void *src_or_dest, PRBool encoding)
   1.831 +{
   1.832 +    const SEC_ASN1Template *theTemplate;
   1.833 +
   1.834 +    SEC_PKCS7Attribute *attribute;
   1.835 +    SECOidData *oiddata;
   1.836 +    PRBool encoded;
   1.837 +
   1.838 +    PORT_Assert (src_or_dest != NULL);
   1.839 +    if (src_or_dest == NULL)
   1.840 +	return NULL;
   1.841 +
   1.842 +    attribute = (SEC_PKCS7Attribute*)src_or_dest;
   1.843 +
   1.844 +    if (encoding && attribute->encoded)
   1.845 +	return SEC_ASN1_GET(SEC_AnyTemplate);
   1.846 +
   1.847 +    oiddata = attribute->typeTag;
   1.848 +    if (oiddata == NULL) {
   1.849 +	oiddata = SECOID_FindOID(&attribute->type);
   1.850 +	attribute->typeTag = oiddata;
   1.851 +    }
   1.852 +
   1.853 +    if (oiddata == NULL) {
   1.854 +	encoded = PR_TRUE;
   1.855 +	theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
   1.856 +    } else {
   1.857 +	switch (oiddata->offset) {
   1.858 +	  default:
   1.859 +	    encoded = PR_TRUE;
   1.860 +	    theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
   1.861 +	    break;
   1.862 +	  case SEC_OID_PKCS9_EMAIL_ADDRESS:
   1.863 +	  case SEC_OID_RFC1274_MAIL:
   1.864 +	  case SEC_OID_PKCS9_UNSTRUCTURED_NAME:
   1.865 +	    encoded = PR_FALSE;
   1.866 +	    theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
   1.867 +	    break;
   1.868 +	  case SEC_OID_PKCS9_CONTENT_TYPE:
   1.869 +	    encoded = PR_FALSE;
   1.870 +	    theTemplate = SEC_ASN1_GET(SEC_ObjectIDTemplate);
   1.871 +	    break;
   1.872 +	  case SEC_OID_PKCS9_MESSAGE_DIGEST:
   1.873 +	    encoded = PR_FALSE;
   1.874 +	    theTemplate = SEC_ASN1_GET(SEC_OctetStringTemplate);
   1.875 +	    break;
   1.876 +	  case SEC_OID_PKCS9_SIGNING_TIME:
   1.877 +	    encoded = PR_FALSE;
   1.878 +            theTemplate = SEC_ASN1_GET(CERT_TimeChoiceTemplate);
   1.879 +	    break;
   1.880 +	  /* XXX Want other types here, too */
   1.881 +	}
   1.882 +    }
   1.883 +
   1.884 +    if (encoding) {
   1.885 +	/*
   1.886 +	 * If we are encoding and we think we have an already-encoded value,
   1.887 +	 * then the code which initialized this attribute should have set
   1.888 +	 * the "encoded" property to true (and we would have returned early,
   1.889 +	 * up above).  No devastating error, but that code should be fixed.
   1.890 +	 * (It could indicate that the resulting encoded bytes are wrong.)
   1.891 +	 */
   1.892 +	PORT_Assert (!encoded);
   1.893 +    } else {
   1.894 +	/*
   1.895 +	 * We are decoding; record whether the resulting value is
   1.896 +	 * still encoded or not.
   1.897 +	 */
   1.898 +	attribute->encoded = encoded;
   1.899 +    }
   1.900 +    return theTemplate;
   1.901 +}
   1.902 +
   1.903 +static const SEC_ASN1TemplateChooserPtr sec_attr_chooser
   1.904 +	= sec_attr_choose_attr_value_template;
   1.905 +
   1.906 +static const SEC_ASN1Template sec_pkcs7_attribute_template[] = {
   1.907 +    { SEC_ASN1_SEQUENCE,
   1.908 +	  0, NULL, sizeof(SEC_PKCS7Attribute) },
   1.909 +    { SEC_ASN1_OBJECT_ID,
   1.910 +	  offsetof(SEC_PKCS7Attribute,type) },
   1.911 +    { SEC_ASN1_DYNAMIC | SEC_ASN1_SET_OF,
   1.912 +	  offsetof(SEC_PKCS7Attribute,values),
   1.913 +	  &sec_attr_chooser },
   1.914 +    { 0 }
   1.915 +};
   1.916 +
   1.917 +static const SEC_ASN1Template sec_pkcs7_set_of_attribute_template[] = {
   1.918 +    { SEC_ASN1_SET_OF, 0, sec_pkcs7_attribute_template },
   1.919 +};
   1.920 +
   1.921 +/*
   1.922 + * If you are wondering why this routine does not reorder the attributes
   1.923 + * first, and might be tempted to make it do so, see the comment by the
   1.924 + * call to ReorderAttributes in p7encode.c.  (Or, see who else calls this
   1.925 + * and think long and hard about the implications of making it always
   1.926 + * do the reordering.)
   1.927 + */
   1.928 +SECItem *
   1.929 +sec_PKCS7EncodeAttributes (PLArenaPool *poolp, SECItem *dest, void *src)
   1.930 +{
   1.931 +    return SEC_ASN1EncodeItem (poolp, dest, src,
   1.932 +			       sec_pkcs7_set_of_attribute_template);
   1.933 +}
   1.934 +
   1.935 +/*
   1.936 + * Make sure that the order of the attributes guarantees valid DER
   1.937 + * (which must be in lexigraphically ascending order for a SET OF);
   1.938 + * if reordering is necessary it will be done in place (in attrs).
   1.939 + */
   1.940 +SECStatus
   1.941 +sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs)
   1.942 +{
   1.943 +    PLArenaPool *poolp;
   1.944 +    int num_attrs, i, pass, besti;
   1.945 +    unsigned int j;
   1.946 +    SECItem **enc_attrs;
   1.947 +    SEC_PKCS7Attribute **new_attrs;
   1.948 +
   1.949 +    /*
   1.950 +     * I think we should not be called with NULL.  But if we are,
   1.951 +     * call it a success anyway, because the order *is* okay.
   1.952 +     */
   1.953 +    PORT_Assert (attrs != NULL);
   1.954 +    if (attrs == NULL)
   1.955 +	return SECSuccess;
   1.956 +
   1.957 +    /*
   1.958 +     * Count how many attributes we are dealing with here.
   1.959 +     */
   1.960 +    num_attrs = 0;
   1.961 +    while (attrs[num_attrs] != NULL)
   1.962 +	num_attrs++;
   1.963 +
   1.964 +    /*
   1.965 +     * Again, I think we should have some attributes here.
   1.966 +     * But if we do not, or if there is only one, then call it
   1.967 +     * a success because it also already has a fine order.
   1.968 +     */
   1.969 +    PORT_Assert (num_attrs);
   1.970 +    if (num_attrs == 0 || num_attrs == 1)
   1.971 +	return SECSuccess;
   1.972 +
   1.973 +    /*
   1.974 +     * Allocate an arena for us to work with, so it is easy to
   1.975 +     * clean up all of the memory (fairly small pieces, really).
   1.976 +     */
   1.977 +    poolp = PORT_NewArena (1024);	/* XXX what is right value? */
   1.978 +    if (poolp == NULL)
   1.979 +	return SECFailure;		/* no memory; nothing we can do... */
   1.980 +
   1.981 +    /*
   1.982 +     * Allocate arrays to hold the individual encodings which we will use
   1.983 +     * for comparisons and the reordered attributes as they are sorted.
   1.984 +     */
   1.985 +    enc_attrs=(SECItem**)PORT_ArenaZAlloc(poolp, num_attrs*sizeof(SECItem *));
   1.986 +    new_attrs = (SEC_PKCS7Attribute**)PORT_ArenaZAlloc (poolp,
   1.987 +				  num_attrs * sizeof(SEC_PKCS7Attribute *));
   1.988 +    if (enc_attrs == NULL || new_attrs == NULL) {
   1.989 +	PORT_FreeArena (poolp, PR_FALSE);
   1.990 +	return SECFailure;
   1.991 +    }
   1.992 +
   1.993 +    /*
   1.994 +     * DER encode each individual attribute.
   1.995 +     */
   1.996 +    for (i = 0; i < num_attrs; i++) {
   1.997 +	enc_attrs[i] = SEC_ASN1EncodeItem (poolp, NULL, attrs[i],
   1.998 +					   sec_pkcs7_attribute_template);
   1.999 +	if (enc_attrs[i] == NULL) {
  1.1000 +	    PORT_FreeArena (poolp, PR_FALSE);
  1.1001 +	    return SECFailure;
  1.1002 +	}
  1.1003 +    }
  1.1004 +
  1.1005 +    /*
  1.1006 +     * Now compare and sort them; this is not the most efficient sorting
  1.1007 +     * method, but it is just fine for the problem at hand, because the
  1.1008 +     * number of attributes is (always) going to be small.
  1.1009 +     */
  1.1010 +    for (pass = 0; pass < num_attrs; pass++) {
  1.1011 +	/*
  1.1012 +	 * Find the first not-yet-accepted attribute.  (Once one is
  1.1013 +	 * sorted into the other array, it is cleared from enc_attrs.)
  1.1014 +	 */
  1.1015 +	for (i = 0; i < num_attrs; i++) {
  1.1016 +	    if (enc_attrs[i] != NULL)
  1.1017 +		break;
  1.1018 +	}
  1.1019 +	PORT_Assert (i < num_attrs);
  1.1020 +	besti = i;
  1.1021 +
  1.1022 +	/*
  1.1023 +	 * Find the lowest (lexigraphically) encoding.  One that is
  1.1024 +	 * shorter than all the rest is known to be "less" because each
  1.1025 +	 * attribute is of the same type (a SEQUENCE) and so thus the
  1.1026 +	 * first octet of each is the same, and the second octet is
  1.1027 +	 * the length (or the length of the length with the high bit
  1.1028 +	 * set, followed by the length, which also works out to always
  1.1029 +	 * order the shorter first).  Two (or more) that have the
  1.1030 +	 * same length need to be compared byte by byte until a mismatch
  1.1031 +	 * is found.
  1.1032 +	 */
  1.1033 +	for (i = besti + 1; i < num_attrs; i++) {
  1.1034 +	    if (enc_attrs[i] == NULL)	/* slot already handled */
  1.1035 +		continue;
  1.1036 +
  1.1037 +	    if (enc_attrs[i]->len != enc_attrs[besti]->len) {
  1.1038 +		if (enc_attrs[i]->len < enc_attrs[besti]->len)
  1.1039 +		    besti = i;
  1.1040 +		continue;
  1.1041 +	    }
  1.1042 +
  1.1043 +	    for (j = 0; j < enc_attrs[i]->len; j++) {
  1.1044 +		if (enc_attrs[i]->data[j] < enc_attrs[besti]->data[j]) {
  1.1045 +		    besti = i;
  1.1046 +		    break;
  1.1047 +		}
  1.1048 +	    }
  1.1049 +
  1.1050 +	    /*
  1.1051 +	     * For this not to be true, we would have to have encountered	
  1.1052 +	     * two *identical* attributes, which I think we should not see.
  1.1053 +	     * So assert if it happens, but even if it does, let it go
  1.1054 +	     * through; the ordering of the two does not matter.
  1.1055 +	     */
  1.1056 +	    PORT_Assert (j < enc_attrs[i]->len);
  1.1057 +	}
  1.1058 +
  1.1059 +	/*
  1.1060 +	 * Now we have found the next-lowest one; copy it over and
  1.1061 +	 * remove it from enc_attrs.
  1.1062 +	 */
  1.1063 +	new_attrs[pass] = attrs[besti];
  1.1064 +	enc_attrs[besti] = NULL;
  1.1065 +    }
  1.1066 +
  1.1067 +    /*
  1.1068 +     * Now new_attrs has the attributes in the order we want;
  1.1069 +     * copy them back into the attrs array we started with.
  1.1070 +     */
  1.1071 +    for (i = 0; i < num_attrs; i++)
  1.1072 +	attrs[i] = new_attrs[i];
  1.1073 +
  1.1074 +    PORT_FreeArena (poolp, PR_FALSE);
  1.1075 +    return SECSuccess;
  1.1076 +}
  1.1077 +
  1.1078 +/*
  1.1079 + * End of attribute stuff.
  1.1080 + * -------------------------------------------------------------------
  1.1081 + */
  1.1082 +
  1.1083 +
  1.1084 +/*
  1.1085 + * Templates and stuff.  Keep these at the end of the file.
  1.1086 + */
  1.1087 +
  1.1088 +/* forward declaration */
  1.1089 +static const SEC_ASN1Template *
  1.1090 +sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding);
  1.1091 +
  1.1092 +static const SEC_ASN1TemplateChooserPtr sec_pkcs7_chooser
  1.1093 +	= sec_pkcs7_choose_content_template;
  1.1094 +
  1.1095 +const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[] = {
  1.1096 +    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
  1.1097 +	  0, NULL, sizeof(SEC_PKCS7ContentInfo) },
  1.1098 +    { SEC_ASN1_OBJECT_ID,
  1.1099 +	  offsetof(SEC_PKCS7ContentInfo,contentType) },
  1.1100 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
  1.1101 +     | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
  1.1102 +	  offsetof(SEC_PKCS7ContentInfo,content),
  1.1103 +	  &sec_pkcs7_chooser },
  1.1104 +    { 0 }
  1.1105 +};
  1.1106 +
  1.1107 +/* XXX These names should change from external to internal convention. */
  1.1108 +
  1.1109 +static const SEC_ASN1Template SEC_PKCS7SignerInfoTemplate[] = {
  1.1110 +    { SEC_ASN1_SEQUENCE,
  1.1111 +	  0, NULL, sizeof(SEC_PKCS7SignerInfo) },
  1.1112 +    { SEC_ASN1_INTEGER,
  1.1113 +	  offsetof(SEC_PKCS7SignerInfo,version) },
  1.1114 +    { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
  1.1115 +	  offsetof(SEC_PKCS7SignerInfo,issuerAndSN),
  1.1116 +	  SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
  1.1117 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
  1.1118 +	  offsetof(SEC_PKCS7SignerInfo,digestAlg),
  1.1119 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1120 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
  1.1121 +	  offsetof(SEC_PKCS7SignerInfo,authAttr),
  1.1122 +	  sec_pkcs7_set_of_attribute_template },
  1.1123 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
  1.1124 +	  offsetof(SEC_PKCS7SignerInfo,digestEncAlg),
  1.1125 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1126 +    { SEC_ASN1_OCTET_STRING,
  1.1127 +	  offsetof(SEC_PKCS7SignerInfo,encDigest) },
  1.1128 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
  1.1129 +	  offsetof(SEC_PKCS7SignerInfo,unAuthAttr),
  1.1130 +	  sec_pkcs7_set_of_attribute_template },
  1.1131 +    { 0 }
  1.1132 +};
  1.1133 +
  1.1134 +static const SEC_ASN1Template SEC_PKCS7SignedDataTemplate[] = {
  1.1135 +    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
  1.1136 +	  0, NULL, sizeof(SEC_PKCS7SignedData) },
  1.1137 +    { SEC_ASN1_INTEGER,
  1.1138 +	  offsetof(SEC_PKCS7SignedData,version) },
  1.1139 +    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
  1.1140 +	  offsetof(SEC_PKCS7SignedData,digestAlgorithms),
  1.1141 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1142 +    { SEC_ASN1_INLINE,
  1.1143 +	  offsetof(SEC_PKCS7SignedData,contentInfo),
  1.1144 +	  sec_PKCS7ContentInfoTemplate },
  1.1145 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC  |
  1.1146 +      SEC_ASN1_XTRN | 0,
  1.1147 +	  offsetof(SEC_PKCS7SignedData,rawCerts),
  1.1148 +	  SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
  1.1149 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC  |
  1.1150 +      SEC_ASN1_XTRN | 1,
  1.1151 +	  offsetof(SEC_PKCS7SignedData,crls),
  1.1152 +	  SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
  1.1153 +    { SEC_ASN1_SET_OF,
  1.1154 +	  offsetof(SEC_PKCS7SignedData,signerInfos),
  1.1155 +	  SEC_PKCS7SignerInfoTemplate },
  1.1156 +    { 0 }
  1.1157 +};
  1.1158 +
  1.1159 +static const SEC_ASN1Template SEC_PointerToPKCS7SignedDataTemplate[] = {
  1.1160 +    { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedDataTemplate }
  1.1161 +};
  1.1162 +
  1.1163 +static const SEC_ASN1Template SEC_PKCS7RecipientInfoTemplate[] = {
  1.1164 +    { SEC_ASN1_SEQUENCE,
  1.1165 +	  0, NULL, sizeof(SEC_PKCS7RecipientInfo) },
  1.1166 +    { SEC_ASN1_INTEGER,
  1.1167 +	  offsetof(SEC_PKCS7RecipientInfo,version) },
  1.1168 +    { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
  1.1169 +	  offsetof(SEC_PKCS7RecipientInfo,issuerAndSN),
  1.1170 +	  SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
  1.1171 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
  1.1172 +	  offsetof(SEC_PKCS7RecipientInfo,keyEncAlg),
  1.1173 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1174 +    { SEC_ASN1_OCTET_STRING,
  1.1175 +	  offsetof(SEC_PKCS7RecipientInfo,encKey) },
  1.1176 +    { 0 }
  1.1177 +};
  1.1178 +
  1.1179 +static const SEC_ASN1Template SEC_PKCS7EncryptedContentInfoTemplate[] = {
  1.1180 +    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
  1.1181 +	  0, NULL, sizeof(SEC_PKCS7EncryptedContentInfo) },
  1.1182 +    { SEC_ASN1_OBJECT_ID,
  1.1183 +	  offsetof(SEC_PKCS7EncryptedContentInfo,contentType) },
  1.1184 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
  1.1185 +	  offsetof(SEC_PKCS7EncryptedContentInfo,contentEncAlg),
  1.1186 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1187 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_MAY_STREAM | SEC_ASN1_CONTEXT_SPECIFIC |
  1.1188 +      SEC_ASN1_XTRN | 0,
  1.1189 +	  offsetof(SEC_PKCS7EncryptedContentInfo,encContent),
  1.1190 +	  SEC_ASN1_SUB(SEC_OctetStringTemplate) },
  1.1191 +    { 0 }
  1.1192 +};
  1.1193 +
  1.1194 +static const SEC_ASN1Template SEC_PKCS7EnvelopedDataTemplate[] = {
  1.1195 +    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
  1.1196 +	  0, NULL, sizeof(SEC_PKCS7EnvelopedData) },
  1.1197 +    { SEC_ASN1_INTEGER,
  1.1198 +	  offsetof(SEC_PKCS7EnvelopedData,version) },
  1.1199 +    { SEC_ASN1_SET_OF,
  1.1200 +	  offsetof(SEC_PKCS7EnvelopedData,recipientInfos),
  1.1201 +	  SEC_PKCS7RecipientInfoTemplate },
  1.1202 +    { SEC_ASN1_INLINE,
  1.1203 +	  offsetof(SEC_PKCS7EnvelopedData,encContentInfo),
  1.1204 +	  SEC_PKCS7EncryptedContentInfoTemplate },
  1.1205 +    { 0 }
  1.1206 +};
  1.1207 +
  1.1208 +static const SEC_ASN1Template SEC_PointerToPKCS7EnvelopedDataTemplate[] = {
  1.1209 +    { SEC_ASN1_POINTER, 0, SEC_PKCS7EnvelopedDataTemplate }
  1.1210 +};
  1.1211 +
  1.1212 +static const SEC_ASN1Template SEC_PKCS7SignedAndEnvelopedDataTemplate[] = {
  1.1213 +    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
  1.1214 +	  0, NULL, sizeof(SEC_PKCS7SignedAndEnvelopedData) },
  1.1215 +    { SEC_ASN1_INTEGER,
  1.1216 +	  offsetof(SEC_PKCS7SignedAndEnvelopedData,version) },
  1.1217 +    { SEC_ASN1_SET_OF,
  1.1218 +	  offsetof(SEC_PKCS7SignedAndEnvelopedData,recipientInfos),
  1.1219 +	  SEC_PKCS7RecipientInfoTemplate },
  1.1220 +    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
  1.1221 +	  offsetof(SEC_PKCS7SignedAndEnvelopedData,digestAlgorithms),
  1.1222 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1223 +    { SEC_ASN1_INLINE,
  1.1224 +	  offsetof(SEC_PKCS7SignedAndEnvelopedData,encContentInfo),
  1.1225 +	  SEC_PKCS7EncryptedContentInfoTemplate },
  1.1226 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
  1.1227 +      SEC_ASN1_XTRN | 0,
  1.1228 +	  offsetof(SEC_PKCS7SignedAndEnvelopedData,rawCerts),
  1.1229 +	  SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
  1.1230 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
  1.1231 +      SEC_ASN1_XTRN | 1,
  1.1232 +	  offsetof(SEC_PKCS7SignedAndEnvelopedData,crls),
  1.1233 +	  SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
  1.1234 +    { SEC_ASN1_SET_OF,
  1.1235 +	  offsetof(SEC_PKCS7SignedAndEnvelopedData,signerInfos),
  1.1236 +	  SEC_PKCS7SignerInfoTemplate },
  1.1237 +    { 0 }
  1.1238 +};
  1.1239 +
  1.1240 +static const SEC_ASN1Template
  1.1241 +SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate[] = {
  1.1242 +    { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedAndEnvelopedDataTemplate }
  1.1243 +};
  1.1244 +
  1.1245 +static const SEC_ASN1Template SEC_PKCS7DigestedDataTemplate[] = {
  1.1246 +    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
  1.1247 +	  0, NULL, sizeof(SEC_PKCS7DigestedData) },
  1.1248 +    { SEC_ASN1_INTEGER,
  1.1249 +	  offsetof(SEC_PKCS7DigestedData,version) },
  1.1250 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
  1.1251 +	  offsetof(SEC_PKCS7DigestedData,digestAlg),
  1.1252 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1.1253 +    { SEC_ASN1_INLINE,
  1.1254 +	  offsetof(SEC_PKCS7DigestedData,contentInfo),
  1.1255 +	  sec_PKCS7ContentInfoTemplate },
  1.1256 +    { SEC_ASN1_OCTET_STRING,
  1.1257 +	  offsetof(SEC_PKCS7DigestedData,digest) },
  1.1258 +    { 0 }
  1.1259 +};
  1.1260 +
  1.1261 +static const SEC_ASN1Template SEC_PointerToPKCS7DigestedDataTemplate[] = {
  1.1262 +    { SEC_ASN1_POINTER, 0, SEC_PKCS7DigestedDataTemplate }
  1.1263 +};
  1.1264 +
  1.1265 +static const SEC_ASN1Template SEC_PKCS7EncryptedDataTemplate[] = {
  1.1266 +    { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
  1.1267 +	  0, NULL, sizeof(SEC_PKCS7EncryptedData) },
  1.1268 +    { SEC_ASN1_INTEGER,
  1.1269 +	  offsetof(SEC_PKCS7EncryptedData,version) },
  1.1270 +    { SEC_ASN1_INLINE,
  1.1271 +	  offsetof(SEC_PKCS7EncryptedData,encContentInfo),
  1.1272 +	  SEC_PKCS7EncryptedContentInfoTemplate },
  1.1273 +    { 0 }
  1.1274 +};
  1.1275 +
  1.1276 +static const SEC_ASN1Template SEC_PointerToPKCS7EncryptedDataTemplate[] = {
  1.1277 +    { SEC_ASN1_POINTER, 0, SEC_PKCS7EncryptedDataTemplate }
  1.1278 +};
  1.1279 +
  1.1280 +static const SEC_ASN1Template *
  1.1281 +sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding)
  1.1282 +{
  1.1283 +    const SEC_ASN1Template *theTemplate;
  1.1284 +    SEC_PKCS7ContentInfo *cinfo;
  1.1285 +    SECOidTag kind;
  1.1286 +
  1.1287 +    PORT_Assert (src_or_dest != NULL);
  1.1288 +    if (src_or_dest == NULL)
  1.1289 +	return NULL;
  1.1290 +
  1.1291 +    cinfo = (SEC_PKCS7ContentInfo*)src_or_dest;
  1.1292 +    kind = SEC_PKCS7ContentType (cinfo);
  1.1293 +    switch (kind) {
  1.1294 +      default:
  1.1295 +	theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate);
  1.1296 +	break;
  1.1297 +      case SEC_OID_PKCS7_DATA:
  1.1298 +	theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
  1.1299 +	break;
  1.1300 +      case SEC_OID_PKCS7_SIGNED_DATA:
  1.1301 +	theTemplate = SEC_PointerToPKCS7SignedDataTemplate;
  1.1302 +	break;
  1.1303 +      case SEC_OID_PKCS7_ENVELOPED_DATA:
  1.1304 +	theTemplate = SEC_PointerToPKCS7EnvelopedDataTemplate;
  1.1305 +	break;
  1.1306 +      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  1.1307 +	theTemplate = SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate;
  1.1308 +	break;
  1.1309 +      case SEC_OID_PKCS7_DIGESTED_DATA:
  1.1310 +	theTemplate = SEC_PointerToPKCS7DigestedDataTemplate;
  1.1311 +	break;
  1.1312 +      case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1.1313 +	theTemplate = SEC_PointerToPKCS7EncryptedDataTemplate;
  1.1314 +	break;
  1.1315 +    }
  1.1316 +    return theTemplate;
  1.1317 +}
  1.1318 +
  1.1319 +/*
  1.1320 + * End of templates.  Do not add stuff after this; put new code
  1.1321 + * up above the start of the template definitions.
  1.1322 + */

mercurial