security/nss/lib/pkcs7/p7local.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * Support routines for PKCS7 implementation, none of which are exported.
michael@0 7 * This file should only contain things that are needed by both the
michael@0 8 * encoding/creation side *and* the decoding/decryption side. Anything
michael@0 9 * else should be static routines in the appropriate file.
michael@0 10 */
michael@0 11
michael@0 12 #include "p7local.h"
michael@0 13
michael@0 14 #include "cryptohi.h"
michael@0 15 #include "secasn1.h"
michael@0 16 #include "secoid.h"
michael@0 17 #include "secitem.h"
michael@0 18 #include "pk11func.h"
michael@0 19 #include "secpkcs5.h"
michael@0 20 #include "secerr.h"
michael@0 21
michael@0 22 /*
michael@0 23 * -------------------------------------------------------------------
michael@0 24 * Cipher stuff.
michael@0 25 */
michael@0 26
michael@0 27 typedef SECStatus (*sec_pkcs7_cipher_function) (void *,
michael@0 28 unsigned char *,
michael@0 29 unsigned *,
michael@0 30 unsigned int,
michael@0 31 const unsigned char *,
michael@0 32 unsigned int);
michael@0 33 typedef SECStatus (*sec_pkcs7_cipher_destroy) (void *, PRBool);
michael@0 34
michael@0 35 #define BLOCK_SIZE 4096
michael@0 36
michael@0 37 struct sec_pkcs7_cipher_object {
michael@0 38 void *cx;
michael@0 39 sec_pkcs7_cipher_function doit;
michael@0 40 sec_pkcs7_cipher_destroy destroy;
michael@0 41 PRBool encrypt;
michael@0 42 int block_size;
michael@0 43 int pad_size;
michael@0 44 int pending_count;
michael@0 45 unsigned char pending_buf[BLOCK_SIZE];
michael@0 46 };
michael@0 47
michael@0 48 SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
michael@0 49 SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate)
michael@0 50 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
michael@0 51 SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
michael@0 52 SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
michael@0 53
michael@0 54 /*
michael@0 55 * Create a cipher object to do decryption, based on the given bulk
michael@0 56 * encryption key and algorithm identifier (which may include an iv).
michael@0 57 *
michael@0 58 * XXX This interface, or one similar, would be really nice available
michael@0 59 * in general... I tried to keep the pkcs7-specific stuff (mostly
michael@0 60 * having to do with padding) out of here.
michael@0 61 *
michael@0 62 * XXX Once both are working, it might be nice to combine this and the
michael@0 63 * function below (for starting up encryption) into one routine, and just
michael@0 64 * have two simple cover functions which call it.
michael@0 65 */
michael@0 66 sec_PKCS7CipherObject *
michael@0 67 sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid)
michael@0 68 {
michael@0 69 sec_PKCS7CipherObject *result;
michael@0 70 SECOidTag algtag;
michael@0 71 void *ciphercx;
michael@0 72 CK_MECHANISM_TYPE cryptoMechType;
michael@0 73 PK11SlotInfo *slot;
michael@0 74 SECItem *param = NULL;
michael@0 75
michael@0 76 result = (struct sec_pkcs7_cipher_object*)
michael@0 77 PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
michael@0 78 if (result == NULL)
michael@0 79 return NULL;
michael@0 80
michael@0 81 ciphercx = NULL;
michael@0 82 algtag = SECOID_GetAlgorithmTag (algid);
michael@0 83
michael@0 84 if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
michael@0 85 SECItem *pwitem;
michael@0 86
michael@0 87 pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
michael@0 88 if (!pwitem) {
michael@0 89 PORT_Free(result);
michael@0 90 return NULL;
michael@0 91 }
michael@0 92
michael@0 93 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
michael@0 94 if (cryptoMechType == CKM_INVALID_MECHANISM) {
michael@0 95 PORT_Free(result);
michael@0 96 SECITEM_FreeItem(param,PR_TRUE);
michael@0 97 return NULL;
michael@0 98 }
michael@0 99 } else {
michael@0 100 cryptoMechType = PK11_AlgtagToMechanism(algtag);
michael@0 101 param = PK11_ParamFromAlgid(algid);
michael@0 102 if (param == NULL) {
michael@0 103 PORT_Free(result);
michael@0 104 return NULL;
michael@0 105 }
michael@0 106 }
michael@0 107
michael@0 108 result->pad_size = PK11_GetBlockSize(cryptoMechType, param);
michael@0 109 slot = PK11_GetSlotFromKey(key);
michael@0 110 result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
michael@0 111 PK11_FreeSlot(slot);
michael@0 112 ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
michael@0 113 key, param);
michael@0 114 SECITEM_FreeItem(param,PR_TRUE);
michael@0 115 if (ciphercx == NULL) {
michael@0 116 PORT_Free (result);
michael@0 117 return NULL;
michael@0 118 }
michael@0 119
michael@0 120 result->cx = ciphercx;
michael@0 121 result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
michael@0 122 result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
michael@0 123 result->encrypt = PR_FALSE;
michael@0 124 result->pending_count = 0;
michael@0 125
michael@0 126 return result;
michael@0 127 }
michael@0 128
michael@0 129 /*
michael@0 130 * Create a cipher object to do encryption, based on the given bulk
michael@0 131 * encryption key and algorithm tag. Fill in the algorithm identifier
michael@0 132 * (which may include an iv) appropriately.
michael@0 133 *
michael@0 134 * XXX This interface, or one similar, would be really nice available
michael@0 135 * in general... I tried to keep the pkcs7-specific stuff (mostly
michael@0 136 * having to do with padding) out of here.
michael@0 137 *
michael@0 138 * XXX Once both are working, it might be nice to combine this and the
michael@0 139 * function above (for starting up decryption) into one routine, and just
michael@0 140 * have two simple cover functions which call it.
michael@0 141 */
michael@0 142 sec_PKCS7CipherObject *
michael@0 143 sec_PKCS7CreateEncryptObject (PLArenaPool *poolp, PK11SymKey *key,
michael@0 144 SECOidTag algtag, SECAlgorithmID *algid)
michael@0 145 {
michael@0 146 sec_PKCS7CipherObject *result;
michael@0 147 void *ciphercx;
michael@0 148 SECStatus rv;
michael@0 149 CK_MECHANISM_TYPE cryptoMechType;
michael@0 150 PK11SlotInfo *slot;
michael@0 151 SECItem *param = NULL;
michael@0 152 PRBool needToEncodeAlgid = PR_FALSE;
michael@0 153
michael@0 154 result = (struct sec_pkcs7_cipher_object*)
michael@0 155 PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
michael@0 156 if (result == NULL)
michael@0 157 return NULL;
michael@0 158
michael@0 159 ciphercx = NULL;
michael@0 160 if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
michael@0 161 SECItem *pwitem;
michael@0 162
michael@0 163 pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
michael@0 164 if (!pwitem) {
michael@0 165 PORT_Free(result);
michael@0 166 return NULL;
michael@0 167 }
michael@0 168
michael@0 169 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
michael@0 170 if (cryptoMechType == CKM_INVALID_MECHANISM) {
michael@0 171 PORT_Free(result);
michael@0 172 SECITEM_FreeItem(param,PR_TRUE);
michael@0 173 return NULL;
michael@0 174 }
michael@0 175 } else {
michael@0 176 cryptoMechType = PK11_AlgtagToMechanism(algtag);
michael@0 177 param = PK11_GenerateNewParam(cryptoMechType, key);
michael@0 178 if (param == NULL) {
michael@0 179 PORT_Free(result);
michael@0 180 return NULL;
michael@0 181 }
michael@0 182 needToEncodeAlgid = PR_TRUE;
michael@0 183 }
michael@0 184
michael@0 185 result->pad_size = PK11_GetBlockSize(cryptoMechType,param);
michael@0 186 slot = PK11_GetSlotFromKey(key);
michael@0 187 result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
michael@0 188 PK11_FreeSlot(slot);
michael@0 189 ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
michael@0 190 key, param);
michael@0 191 if (ciphercx == NULL) {
michael@0 192 PORT_Free (result);
michael@0 193 SECITEM_FreeItem(param,PR_TRUE);
michael@0 194 return NULL;
michael@0 195 }
michael@0 196
michael@0 197 /*
michael@0 198 * These are placed after the CreateContextBySymKey() because some
michael@0 199 * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
michael@0 200 * Don't move it from here.
michael@0 201 */
michael@0 202 if (needToEncodeAlgid) {
michael@0 203 rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
michael@0 204 if(rv != SECSuccess) {
michael@0 205 PORT_Free (result);
michael@0 206 SECITEM_FreeItem(param,PR_TRUE);
michael@0 207 return NULL;
michael@0 208 }
michael@0 209 }
michael@0 210 SECITEM_FreeItem(param,PR_TRUE);
michael@0 211
michael@0 212 result->cx = ciphercx;
michael@0 213 result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
michael@0 214 result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
michael@0 215 result->encrypt = PR_TRUE;
michael@0 216 result->pending_count = 0;
michael@0 217
michael@0 218 return result;
michael@0 219 }
michael@0 220
michael@0 221
michael@0 222 /*
michael@0 223 * Destroy the cipher object.
michael@0 224 */
michael@0 225 static void
michael@0 226 sec_pkcs7_destroy_cipher (sec_PKCS7CipherObject *obj)
michael@0 227 {
michael@0 228 (* obj->destroy) (obj->cx, PR_TRUE);
michael@0 229 PORT_Free (obj);
michael@0 230 }
michael@0 231
michael@0 232 void
michael@0 233 sec_PKCS7DestroyDecryptObject (sec_PKCS7CipherObject *obj)
michael@0 234 {
michael@0 235 PORT_Assert (obj != NULL);
michael@0 236 if (obj == NULL)
michael@0 237 return;
michael@0 238 PORT_Assert (! obj->encrypt);
michael@0 239 sec_pkcs7_destroy_cipher (obj);
michael@0 240 }
michael@0 241
michael@0 242 void
michael@0 243 sec_PKCS7DestroyEncryptObject (sec_PKCS7CipherObject *obj)
michael@0 244 {
michael@0 245 PORT_Assert (obj != NULL);
michael@0 246 if (obj == NULL)
michael@0 247 return;
michael@0 248 PORT_Assert (obj->encrypt);
michael@0 249 sec_pkcs7_destroy_cipher (obj);
michael@0 250 }
michael@0 251
michael@0 252
michael@0 253 /*
michael@0 254 * XXX I think all of the following lengths should be longs instead
michael@0 255 * of ints, but our current crypto interface uses ints, so I did too.
michael@0 256 */
michael@0 257
michael@0 258
michael@0 259 /*
michael@0 260 * What will be the output length of the next call to decrypt?
michael@0 261 * Result can be used to perform memory allocations. Note that the amount
michael@0 262 * is exactly accurate only when not doing a block cipher or when final
michael@0 263 * is false, otherwise it is an upper bound on the amount because until
michael@0 264 * we see the data we do not know how many padding bytes there are
michael@0 265 * (always between 1 and bsize).
michael@0 266 *
michael@0 267 * Note that this can return zero, which does not mean that the decrypt
michael@0 268 * operation can be skipped! (It simply means that there are not enough
michael@0 269 * bytes to make up an entire block; the bytes will be reserved until
michael@0 270 * there are enough to encrypt/decrypt at least one block.) However,
michael@0 271 * if zero is returned it *does* mean that no output buffer need be
michael@0 272 * passed in to the subsequent decrypt operation, as no output bytes
michael@0 273 * will be stored.
michael@0 274 */
michael@0 275 unsigned int
michael@0 276 sec_PKCS7DecryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
michael@0 277 PRBool final)
michael@0 278 {
michael@0 279 int blocks, block_size;
michael@0 280
michael@0 281 PORT_Assert (! obj->encrypt);
michael@0 282
michael@0 283 block_size = obj->block_size;
michael@0 284
michael@0 285 /*
michael@0 286 * If this is not a block cipher, then we always have the same
michael@0 287 * number of output bytes as we had input bytes.
michael@0 288 */
michael@0 289 if (block_size == 0)
michael@0 290 return input_len;
michael@0 291
michael@0 292 /*
michael@0 293 * On the final call, we will always use up all of the pending
michael@0 294 * bytes plus all of the input bytes, *but*, there will be padding
michael@0 295 * at the end and we cannot predict how many bytes of padding we
michael@0 296 * will end up removing. The amount given here is actually known
michael@0 297 * to be at least 1 byte too long (because we know we will have
michael@0 298 * at least 1 byte of padding), but seemed clearer/better to me.
michael@0 299 */
michael@0 300 if (final)
michael@0 301 return obj->pending_count + input_len;
michael@0 302
michael@0 303 /*
michael@0 304 * Okay, this amount is exactly what we will output on the
michael@0 305 * next cipher operation. We will always hang onto the last
michael@0 306 * 1 - block_size bytes for non-final operations. That is,
michael@0 307 * we will do as many complete blocks as we can *except* the
michael@0 308 * last block (complete or partial). (This is because until
michael@0 309 * we know we are at the end, we cannot know when to interpret
michael@0 310 * and removing the padding byte(s), which are guaranteed to
michael@0 311 * be there.)
michael@0 312 */
michael@0 313 blocks = (obj->pending_count + input_len - 1) / block_size;
michael@0 314 return blocks * block_size;
michael@0 315 }
michael@0 316
michael@0 317 /*
michael@0 318 * What will be the output length of the next call to encrypt?
michael@0 319 * Result can be used to perform memory allocations.
michael@0 320 *
michael@0 321 * Note that this can return zero, which does not mean that the encrypt
michael@0 322 * operation can be skipped! (It simply means that there are not enough
michael@0 323 * bytes to make up an entire block; the bytes will be reserved until
michael@0 324 * there are enough to encrypt/decrypt at least one block.) However,
michael@0 325 * if zero is returned it *does* mean that no output buffer need be
michael@0 326 * passed in to the subsequent encrypt operation, as no output bytes
michael@0 327 * will be stored.
michael@0 328 */
michael@0 329 unsigned int
michael@0 330 sec_PKCS7EncryptLength (sec_PKCS7CipherObject *obj, unsigned int input_len,
michael@0 331 PRBool final)
michael@0 332 {
michael@0 333 int blocks, block_size;
michael@0 334 int pad_size;
michael@0 335
michael@0 336 PORT_Assert (obj->encrypt);
michael@0 337
michael@0 338 block_size = obj->block_size;
michael@0 339 pad_size = obj->pad_size;
michael@0 340
michael@0 341 /*
michael@0 342 * If this is not a block cipher, then we always have the same
michael@0 343 * number of output bytes as we had input bytes.
michael@0 344 */
michael@0 345 if (block_size == 0)
michael@0 346 return input_len;
michael@0 347
michael@0 348 /*
michael@0 349 * On the final call, we only send out what we need for
michael@0 350 * remaining bytes plus the padding. (There is always padding,
michael@0 351 * so even if we have an exact number of blocks as input, we
michael@0 352 * will add another full block that is just padding.)
michael@0 353 */
michael@0 354 if (final) {
michael@0 355 if (pad_size == 0) {
michael@0 356 return obj->pending_count + input_len;
michael@0 357 } else {
michael@0 358 blocks = (obj->pending_count + input_len) / pad_size;
michael@0 359 blocks++;
michael@0 360 return blocks*pad_size;
michael@0 361 }
michael@0 362 }
michael@0 363
michael@0 364 /*
michael@0 365 * Now, count the number of complete blocks of data we have.
michael@0 366 */
michael@0 367 blocks = (obj->pending_count + input_len) / block_size;
michael@0 368
michael@0 369
michael@0 370 return blocks * block_size;
michael@0 371 }
michael@0 372
michael@0 373
michael@0 374 /*
michael@0 375 * Decrypt a given length of input buffer (starting at "input" and
michael@0 376 * containing "input_len" bytes), placing the decrypted bytes in
michael@0 377 * "output" and storing the output length in "*output_len_p".
michael@0 378 * "obj" is the return value from sec_PKCS7CreateDecryptObject.
michael@0 379 * When "final" is true, this is the last of the data to be decrypted.
michael@0 380 *
michael@0 381 * This is much more complicated than it sounds when the cipher is
michael@0 382 * a block-type, meaning that the decryption function will only
michael@0 383 * operate on whole blocks. But our caller is operating stream-wise,
michael@0 384 * and can pass in any number of bytes. So we need to keep track
michael@0 385 * of block boundaries. We save excess bytes between calls in "obj".
michael@0 386 * We also need to determine which bytes are padding, and remove
michael@0 387 * them from the output. We can only do this step when we know we
michael@0 388 * have the final block of data. PKCS #7 specifies that the padding
michael@0 389 * used for a block cipher is a string of bytes, each of whose value is
michael@0 390 * the same as the length of the padding, and that all data is padded.
michael@0 391 * (Even data that starts out with an exact multiple of blocks gets
michael@0 392 * added to it another block, all of which is padding.)
michael@0 393 */
michael@0 394 SECStatus
michael@0 395 sec_PKCS7Decrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
michael@0 396 unsigned int *output_len_p, unsigned int max_output_len,
michael@0 397 const unsigned char *input, unsigned int input_len,
michael@0 398 PRBool final)
michael@0 399 {
michael@0 400 int blocks, bsize, pcount, padsize;
michael@0 401 unsigned int max_needed, ifraglen, ofraglen, output_len;
michael@0 402 unsigned char *pbuf;
michael@0 403 SECStatus rv;
michael@0 404
michael@0 405 PORT_Assert (! obj->encrypt);
michael@0 406
michael@0 407 /*
michael@0 408 * Check that we have enough room for the output. Our caller should
michael@0 409 * already handle this; failure is really an internal error (i.e. bug).
michael@0 410 */
michael@0 411 max_needed = sec_PKCS7DecryptLength (obj, input_len, final);
michael@0 412 PORT_Assert (max_output_len >= max_needed);
michael@0 413 if (max_output_len < max_needed) {
michael@0 414 /* PORT_SetError (XXX); */
michael@0 415 return SECFailure;
michael@0 416 }
michael@0 417
michael@0 418 /*
michael@0 419 * hardware encryption does not like small decryption sizes here, so we
michael@0 420 * allow both blocking and padding.
michael@0 421 */
michael@0 422 bsize = obj->block_size;
michael@0 423 padsize = obj->pad_size;
michael@0 424
michael@0 425 /*
michael@0 426 * When no blocking or padding work to do, we can simply call the
michael@0 427 * cipher function and we are done.
michael@0 428 */
michael@0 429 if (bsize == 0) {
michael@0 430 return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
michael@0 431 input, input_len);
michael@0 432 }
michael@0 433
michael@0 434 pcount = obj->pending_count;
michael@0 435 pbuf = obj->pending_buf;
michael@0 436
michael@0 437 output_len = 0;
michael@0 438
michael@0 439 if (pcount) {
michael@0 440 /*
michael@0 441 * Try to fill in an entire block, starting with the bytes
michael@0 442 * we already have saved away.
michael@0 443 */
michael@0 444 while (input_len && pcount < bsize) {
michael@0 445 pbuf[pcount++] = *input++;
michael@0 446 input_len--;
michael@0 447 }
michael@0 448 /*
michael@0 449 * If we have at most a whole block and this is not our last call,
michael@0 450 * then we are done for now. (We do not try to decrypt a lone
michael@0 451 * single block because we cannot interpret the padding bytes
michael@0 452 * until we know we are handling the very last block of all input.)
michael@0 453 */
michael@0 454 if (input_len == 0 && !final) {
michael@0 455 obj->pending_count = pcount;
michael@0 456 if (output_len_p)
michael@0 457 *output_len_p = 0;
michael@0 458 return SECSuccess;
michael@0 459 }
michael@0 460 /*
michael@0 461 * Given the logic above, we expect to have a full block by now.
michael@0 462 * If we do not, there is something wrong, either with our own
michael@0 463 * logic or with (length of) the data given to us.
michael@0 464 */
michael@0 465 PORT_Assert ((padsize == 0) || (pcount % padsize) == 0);
michael@0 466 if ((padsize != 0) && (pcount % padsize) != 0) {
michael@0 467 PORT_Assert (final);
michael@0 468 PORT_SetError (SEC_ERROR_BAD_DATA);
michael@0 469 return SECFailure;
michael@0 470 }
michael@0 471 /*
michael@0 472 * Decrypt the block.
michael@0 473 */
michael@0 474 rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
michael@0 475 pbuf, pcount);
michael@0 476 if (rv != SECSuccess)
michael@0 477 return rv;
michael@0 478
michael@0 479 /*
michael@0 480 * For now anyway, all of our ciphers have the same number of
michael@0 481 * bytes of output as they do input. If this ever becomes untrue,
michael@0 482 * then sec_PKCS7DecryptLength needs to be made smarter!
michael@0 483 */
michael@0 484 PORT_Assert (ofraglen == pcount);
michael@0 485
michael@0 486 /*
michael@0 487 * Account for the bytes now in output.
michael@0 488 */
michael@0 489 max_output_len -= ofraglen;
michael@0 490 output_len += ofraglen;
michael@0 491 output += ofraglen;
michael@0 492 }
michael@0 493
michael@0 494 /*
michael@0 495 * If this is our last call, we expect to have an exact number of
michael@0 496 * blocks left to be decrypted; we will decrypt them all.
michael@0 497 *
michael@0 498 * If not our last call, we always save between 1 and bsize bytes
michael@0 499 * until next time. (We must do this because we cannot be sure
michael@0 500 * that none of the decrypted bytes are padding bytes until we
michael@0 501 * have at least another whole block of data. You cannot tell by
michael@0 502 * looking -- the data could be anything -- you can only tell by
michael@0 503 * context, knowing you are looking at the last block.) We could
michael@0 504 * decrypt a whole block now but it is easier if we just treat it
michael@0 505 * the same way we treat partial block bytes.
michael@0 506 */
michael@0 507 if (final) {
michael@0 508 if (padsize) {
michael@0 509 blocks = input_len / padsize;
michael@0 510 ifraglen = blocks * padsize;
michael@0 511 } else ifraglen = input_len;
michael@0 512 PORT_Assert (ifraglen == input_len);
michael@0 513
michael@0 514 if (ifraglen != input_len) {
michael@0 515 PORT_SetError (SEC_ERROR_BAD_DATA);
michael@0 516 return SECFailure;
michael@0 517 }
michael@0 518 } else {
michael@0 519 blocks = (input_len - 1) / bsize;
michael@0 520 ifraglen = blocks * bsize;
michael@0 521 PORT_Assert (ifraglen < input_len);
michael@0 522
michael@0 523 pcount = input_len - ifraglen;
michael@0 524 PORT_Memcpy (pbuf, input + ifraglen, pcount);
michael@0 525 obj->pending_count = pcount;
michael@0 526 }
michael@0 527
michael@0 528 if (ifraglen) {
michael@0 529 rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
michael@0 530 input, ifraglen);
michael@0 531 if (rv != SECSuccess)
michael@0 532 return rv;
michael@0 533
michael@0 534 /*
michael@0 535 * For now anyway, all of our ciphers have the same number of
michael@0 536 * bytes of output as they do input. If this ever becomes untrue,
michael@0 537 * then sec_PKCS7DecryptLength needs to be made smarter!
michael@0 538 */
michael@0 539 PORT_Assert (ifraglen == ofraglen);
michael@0 540 if (ifraglen != ofraglen) {
michael@0 541 PORT_SetError (SEC_ERROR_BAD_DATA);
michael@0 542 return SECFailure;
michael@0 543 }
michael@0 544
michael@0 545 output_len += ofraglen;
michael@0 546 } else {
michael@0 547 ofraglen = 0;
michael@0 548 }
michael@0 549
michael@0 550 /*
michael@0 551 * If we just did our very last block, "remove" the padding by
michael@0 552 * adjusting the output length.
michael@0 553 */
michael@0 554 if (final && (padsize != 0)) {
michael@0 555 unsigned int padlen = *(output + ofraglen - 1);
michael@0 556 if (padlen == 0 || padlen > padsize) {
michael@0 557 PORT_SetError (SEC_ERROR_BAD_DATA);
michael@0 558 return SECFailure;
michael@0 559 }
michael@0 560 output_len -= padlen;
michael@0 561 }
michael@0 562
michael@0 563 PORT_Assert (output_len_p != NULL || output_len == 0);
michael@0 564 if (output_len_p != NULL)
michael@0 565 *output_len_p = output_len;
michael@0 566
michael@0 567 return SECSuccess;
michael@0 568 }
michael@0 569
michael@0 570 /*
michael@0 571 * Encrypt a given length of input buffer (starting at "input" and
michael@0 572 * containing "input_len" bytes), placing the encrypted bytes in
michael@0 573 * "output" and storing the output length in "*output_len_p".
michael@0 574 * "obj" is the return value from sec_PKCS7CreateEncryptObject.
michael@0 575 * When "final" is true, this is the last of the data to be encrypted.
michael@0 576 *
michael@0 577 * This is much more complicated than it sounds when the cipher is
michael@0 578 * a block-type, meaning that the encryption function will only
michael@0 579 * operate on whole blocks. But our caller is operating stream-wise,
michael@0 580 * and can pass in any number of bytes. So we need to keep track
michael@0 581 * of block boundaries. We save excess bytes between calls in "obj".
michael@0 582 * We also need to add padding bytes at the end. PKCS #7 specifies
michael@0 583 * that the padding used for a block cipher is a string of bytes,
michael@0 584 * each of whose value is the same as the length of the padding,
michael@0 585 * and that all data is padded. (Even data that starts out with
michael@0 586 * an exact multiple of blocks gets added to it another block,
michael@0 587 * all of which is padding.)
michael@0 588 *
michael@0 589 * XXX I would kind of like to combine this with the function above
michael@0 590 * which does decryption, since they have a lot in common. But the
michael@0 591 * tricky parts about padding and filling blocks would be much
michael@0 592 * harder to read that way, so I left them separate. At least for
michael@0 593 * now until it is clear that they are right.
michael@0 594 */
michael@0 595 SECStatus
michael@0 596 sec_PKCS7Encrypt (sec_PKCS7CipherObject *obj, unsigned char *output,
michael@0 597 unsigned int *output_len_p, unsigned int max_output_len,
michael@0 598 const unsigned char *input, unsigned int input_len,
michael@0 599 PRBool final)
michael@0 600 {
michael@0 601 int blocks, bsize, padlen, pcount, padsize;
michael@0 602 unsigned int max_needed, ifraglen, ofraglen, output_len;
michael@0 603 unsigned char *pbuf;
michael@0 604 SECStatus rv;
michael@0 605
michael@0 606 PORT_Assert (obj->encrypt);
michael@0 607
michael@0 608 /*
michael@0 609 * Check that we have enough room for the output. Our caller should
michael@0 610 * already handle this; failure is really an internal error (i.e. bug).
michael@0 611 */
michael@0 612 max_needed = sec_PKCS7EncryptLength (obj, input_len, final);
michael@0 613 PORT_Assert (max_output_len >= max_needed);
michael@0 614 if (max_output_len < max_needed) {
michael@0 615 /* PORT_SetError (XXX); */
michael@0 616 return SECFailure;
michael@0 617 }
michael@0 618
michael@0 619 bsize = obj->block_size;
michael@0 620 padsize = obj->pad_size;
michael@0 621
michael@0 622 /*
michael@0 623 * When no blocking and padding work to do, we can simply call the
michael@0 624 * cipher function and we are done.
michael@0 625 */
michael@0 626 if (bsize == 0) {
michael@0 627 return (* obj->doit) (obj->cx, output, output_len_p, max_output_len,
michael@0 628 input, input_len);
michael@0 629 }
michael@0 630
michael@0 631 pcount = obj->pending_count;
michael@0 632 pbuf = obj->pending_buf;
michael@0 633
michael@0 634 output_len = 0;
michael@0 635
michael@0 636 if (pcount) {
michael@0 637 /*
michael@0 638 * Try to fill in an entire block, starting with the bytes
michael@0 639 * we already have saved away.
michael@0 640 */
michael@0 641 while (input_len && pcount < bsize) {
michael@0 642 pbuf[pcount++] = *input++;
michael@0 643 input_len--;
michael@0 644 }
michael@0 645 /*
michael@0 646 * If we do not have a full block and we know we will be
michael@0 647 * called again, then we are done for now.
michael@0 648 */
michael@0 649 if (pcount < bsize && !final) {
michael@0 650 obj->pending_count = pcount;
michael@0 651 if (output_len_p != NULL)
michael@0 652 *output_len_p = 0;
michael@0 653 return SECSuccess;
michael@0 654 }
michael@0 655 /*
michael@0 656 * If we have a whole block available, encrypt it.
michael@0 657 */
michael@0 658 if ((padsize == 0) || (pcount % padsize) == 0) {
michael@0 659 rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
michael@0 660 pbuf, pcount);
michael@0 661 if (rv != SECSuccess)
michael@0 662 return rv;
michael@0 663
michael@0 664 /*
michael@0 665 * For now anyway, all of our ciphers have the same number of
michael@0 666 * bytes of output as they do input. If this ever becomes untrue,
michael@0 667 * then sec_PKCS7EncryptLength needs to be made smarter!
michael@0 668 */
michael@0 669 PORT_Assert (ofraglen == pcount);
michael@0 670
michael@0 671 /*
michael@0 672 * Account for the bytes now in output.
michael@0 673 */
michael@0 674 max_output_len -= ofraglen;
michael@0 675 output_len += ofraglen;
michael@0 676 output += ofraglen;
michael@0 677
michael@0 678 pcount = 0;
michael@0 679 }
michael@0 680 }
michael@0 681
michael@0 682 if (input_len) {
michael@0 683 PORT_Assert (pcount == 0);
michael@0 684
michael@0 685 blocks = input_len / bsize;
michael@0 686 ifraglen = blocks * bsize;
michael@0 687
michael@0 688 if (ifraglen) {
michael@0 689 rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
michael@0 690 input, ifraglen);
michael@0 691 if (rv != SECSuccess)
michael@0 692 return rv;
michael@0 693
michael@0 694 /*
michael@0 695 * For now anyway, all of our ciphers have the same number of
michael@0 696 * bytes of output as they do input. If this ever becomes untrue,
michael@0 697 * then sec_PKCS7EncryptLength needs to be made smarter!
michael@0 698 */
michael@0 699 PORT_Assert (ifraglen == ofraglen);
michael@0 700
michael@0 701 max_output_len -= ofraglen;
michael@0 702 output_len += ofraglen;
michael@0 703 output += ofraglen;
michael@0 704 }
michael@0 705
michael@0 706 pcount = input_len - ifraglen;
michael@0 707 PORT_Assert (pcount < bsize);
michael@0 708 if (pcount)
michael@0 709 PORT_Memcpy (pbuf, input + ifraglen, pcount);
michael@0 710 }
michael@0 711
michael@0 712 if (final) {
michael@0 713 padlen = padsize - (pcount % padsize);
michael@0 714 PORT_Memset (pbuf + pcount, padlen, padlen);
michael@0 715 rv = (* obj->doit) (obj->cx, output, &ofraglen, max_output_len,
michael@0 716 pbuf, pcount+padlen);
michael@0 717 if (rv != SECSuccess)
michael@0 718 return rv;
michael@0 719
michael@0 720 /*
michael@0 721 * For now anyway, all of our ciphers have the same number of
michael@0 722 * bytes of output as they do input. If this ever becomes untrue,
michael@0 723 * then sec_PKCS7EncryptLength needs to be made smarter!
michael@0 724 */
michael@0 725 PORT_Assert (ofraglen == (pcount+padlen));
michael@0 726 output_len += ofraglen;
michael@0 727 } else {
michael@0 728 obj->pending_count = pcount;
michael@0 729 }
michael@0 730
michael@0 731 PORT_Assert (output_len_p != NULL || output_len == 0);
michael@0 732 if (output_len_p != NULL)
michael@0 733 *output_len_p = output_len;
michael@0 734
michael@0 735 return SECSuccess;
michael@0 736 }
michael@0 737
michael@0 738 /*
michael@0 739 * End of cipher stuff.
michael@0 740 * -------------------------------------------------------------------
michael@0 741 */
michael@0 742
michael@0 743
michael@0 744 /*
michael@0 745 * -------------------------------------------------------------------
michael@0 746 * XXX The following Attribute stuff really belongs elsewhere.
michael@0 747 * The Attribute type is *not* part of pkcs7 but rather X.501.
michael@0 748 * But for now, since PKCS7 is the only customer of attributes,
michael@0 749 * we define them here. Once there is a use outside of PKCS7,
michael@0 750 * then change the attribute types and functions from internal
michael@0 751 * to external naming convention, and move them elsewhere!
michael@0 752 */
michael@0 753
michael@0 754 /*
michael@0 755 * Look through a set of attributes and find one that matches the
michael@0 756 * specified object ID. If "only" is true, then make sure that
michael@0 757 * there is not more than one attribute of the same type. Otherwise,
michael@0 758 * just return the first one found. (XXX Does anybody really want
michael@0 759 * that first-found behavior? It was like that when I found it...)
michael@0 760 */
michael@0 761 SEC_PKCS7Attribute *
michael@0 762 sec_PKCS7FindAttribute (SEC_PKCS7Attribute **attrs, SECOidTag oidtag,
michael@0 763 PRBool only)
michael@0 764 {
michael@0 765 SECOidData *oid;
michael@0 766 SEC_PKCS7Attribute *attr1, *attr2;
michael@0 767
michael@0 768 if (attrs == NULL)
michael@0 769 return NULL;
michael@0 770
michael@0 771 oid = SECOID_FindOIDByTag(oidtag);
michael@0 772 if (oid == NULL)
michael@0 773 return NULL;
michael@0 774
michael@0 775 while ((attr1 = *attrs++) != NULL) {
michael@0 776 if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
michael@0 777 oid->oid.data,
michael@0 778 oid->oid.len) == 0)
michael@0 779 break;
michael@0 780 }
michael@0 781
michael@0 782 if (attr1 == NULL)
michael@0 783 return NULL;
michael@0 784
michael@0 785 if (!only)
michael@0 786 return attr1;
michael@0 787
michael@0 788 while ((attr2 = *attrs++) != NULL) {
michael@0 789 if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
michael@0 790 oid->oid.data,
michael@0 791 oid->oid.len) == 0)
michael@0 792 break;
michael@0 793 }
michael@0 794
michael@0 795 if (attr2 != NULL)
michael@0 796 return NULL;
michael@0 797
michael@0 798 return attr1;
michael@0 799 }
michael@0 800
michael@0 801
michael@0 802 /*
michael@0 803 * Return the single attribute value, doing some sanity checking first:
michael@0 804 * - Multiple values are *not* expected.
michael@0 805 * - Empty values are *not* expected.
michael@0 806 */
michael@0 807 SECItem *
michael@0 808 sec_PKCS7AttributeValue(SEC_PKCS7Attribute *attr)
michael@0 809 {
michael@0 810 SECItem *value;
michael@0 811
michael@0 812 if (attr == NULL)
michael@0 813 return NULL;
michael@0 814
michael@0 815 value = attr->values[0];
michael@0 816
michael@0 817 if (value == NULL || value->data == NULL || value->len == 0)
michael@0 818 return NULL;
michael@0 819
michael@0 820 if (attr->values[1] != NULL)
michael@0 821 return NULL;
michael@0 822
michael@0 823 return value;
michael@0 824 }
michael@0 825
michael@0 826 static const SEC_ASN1Template *
michael@0 827 sec_attr_choose_attr_value_template(void *src_or_dest, PRBool encoding)
michael@0 828 {
michael@0 829 const SEC_ASN1Template *theTemplate;
michael@0 830
michael@0 831 SEC_PKCS7Attribute *attribute;
michael@0 832 SECOidData *oiddata;
michael@0 833 PRBool encoded;
michael@0 834
michael@0 835 PORT_Assert (src_or_dest != NULL);
michael@0 836 if (src_or_dest == NULL)
michael@0 837 return NULL;
michael@0 838
michael@0 839 attribute = (SEC_PKCS7Attribute*)src_or_dest;
michael@0 840
michael@0 841 if (encoding && attribute->encoded)
michael@0 842 return SEC_ASN1_GET(SEC_AnyTemplate);
michael@0 843
michael@0 844 oiddata = attribute->typeTag;
michael@0 845 if (oiddata == NULL) {
michael@0 846 oiddata = SECOID_FindOID(&attribute->type);
michael@0 847 attribute->typeTag = oiddata;
michael@0 848 }
michael@0 849
michael@0 850 if (oiddata == NULL) {
michael@0 851 encoded = PR_TRUE;
michael@0 852 theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
michael@0 853 } else {
michael@0 854 switch (oiddata->offset) {
michael@0 855 default:
michael@0 856 encoded = PR_TRUE;
michael@0 857 theTemplate = SEC_ASN1_GET(SEC_AnyTemplate);
michael@0 858 break;
michael@0 859 case SEC_OID_PKCS9_EMAIL_ADDRESS:
michael@0 860 case SEC_OID_RFC1274_MAIL:
michael@0 861 case SEC_OID_PKCS9_UNSTRUCTURED_NAME:
michael@0 862 encoded = PR_FALSE;
michael@0 863 theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
michael@0 864 break;
michael@0 865 case SEC_OID_PKCS9_CONTENT_TYPE:
michael@0 866 encoded = PR_FALSE;
michael@0 867 theTemplate = SEC_ASN1_GET(SEC_ObjectIDTemplate);
michael@0 868 break;
michael@0 869 case SEC_OID_PKCS9_MESSAGE_DIGEST:
michael@0 870 encoded = PR_FALSE;
michael@0 871 theTemplate = SEC_ASN1_GET(SEC_OctetStringTemplate);
michael@0 872 break;
michael@0 873 case SEC_OID_PKCS9_SIGNING_TIME:
michael@0 874 encoded = PR_FALSE;
michael@0 875 theTemplate = SEC_ASN1_GET(CERT_TimeChoiceTemplate);
michael@0 876 break;
michael@0 877 /* XXX Want other types here, too */
michael@0 878 }
michael@0 879 }
michael@0 880
michael@0 881 if (encoding) {
michael@0 882 /*
michael@0 883 * If we are encoding and we think we have an already-encoded value,
michael@0 884 * then the code which initialized this attribute should have set
michael@0 885 * the "encoded" property to true (and we would have returned early,
michael@0 886 * up above). No devastating error, but that code should be fixed.
michael@0 887 * (It could indicate that the resulting encoded bytes are wrong.)
michael@0 888 */
michael@0 889 PORT_Assert (!encoded);
michael@0 890 } else {
michael@0 891 /*
michael@0 892 * We are decoding; record whether the resulting value is
michael@0 893 * still encoded or not.
michael@0 894 */
michael@0 895 attribute->encoded = encoded;
michael@0 896 }
michael@0 897 return theTemplate;
michael@0 898 }
michael@0 899
michael@0 900 static const SEC_ASN1TemplateChooserPtr sec_attr_chooser
michael@0 901 = sec_attr_choose_attr_value_template;
michael@0 902
michael@0 903 static const SEC_ASN1Template sec_pkcs7_attribute_template[] = {
michael@0 904 { SEC_ASN1_SEQUENCE,
michael@0 905 0, NULL, sizeof(SEC_PKCS7Attribute) },
michael@0 906 { SEC_ASN1_OBJECT_ID,
michael@0 907 offsetof(SEC_PKCS7Attribute,type) },
michael@0 908 { SEC_ASN1_DYNAMIC | SEC_ASN1_SET_OF,
michael@0 909 offsetof(SEC_PKCS7Attribute,values),
michael@0 910 &sec_attr_chooser },
michael@0 911 { 0 }
michael@0 912 };
michael@0 913
michael@0 914 static const SEC_ASN1Template sec_pkcs7_set_of_attribute_template[] = {
michael@0 915 { SEC_ASN1_SET_OF, 0, sec_pkcs7_attribute_template },
michael@0 916 };
michael@0 917
michael@0 918 /*
michael@0 919 * If you are wondering why this routine does not reorder the attributes
michael@0 920 * first, and might be tempted to make it do so, see the comment by the
michael@0 921 * call to ReorderAttributes in p7encode.c. (Or, see who else calls this
michael@0 922 * and think long and hard about the implications of making it always
michael@0 923 * do the reordering.)
michael@0 924 */
michael@0 925 SECItem *
michael@0 926 sec_PKCS7EncodeAttributes (PLArenaPool *poolp, SECItem *dest, void *src)
michael@0 927 {
michael@0 928 return SEC_ASN1EncodeItem (poolp, dest, src,
michael@0 929 sec_pkcs7_set_of_attribute_template);
michael@0 930 }
michael@0 931
michael@0 932 /*
michael@0 933 * Make sure that the order of the attributes guarantees valid DER
michael@0 934 * (which must be in lexigraphically ascending order for a SET OF);
michael@0 935 * if reordering is necessary it will be done in place (in attrs).
michael@0 936 */
michael@0 937 SECStatus
michael@0 938 sec_PKCS7ReorderAttributes (SEC_PKCS7Attribute **attrs)
michael@0 939 {
michael@0 940 PLArenaPool *poolp;
michael@0 941 int num_attrs, i, pass, besti;
michael@0 942 unsigned int j;
michael@0 943 SECItem **enc_attrs;
michael@0 944 SEC_PKCS7Attribute **new_attrs;
michael@0 945
michael@0 946 /*
michael@0 947 * I think we should not be called with NULL. But if we are,
michael@0 948 * call it a success anyway, because the order *is* okay.
michael@0 949 */
michael@0 950 PORT_Assert (attrs != NULL);
michael@0 951 if (attrs == NULL)
michael@0 952 return SECSuccess;
michael@0 953
michael@0 954 /*
michael@0 955 * Count how many attributes we are dealing with here.
michael@0 956 */
michael@0 957 num_attrs = 0;
michael@0 958 while (attrs[num_attrs] != NULL)
michael@0 959 num_attrs++;
michael@0 960
michael@0 961 /*
michael@0 962 * Again, I think we should have some attributes here.
michael@0 963 * But if we do not, or if there is only one, then call it
michael@0 964 * a success because it also already has a fine order.
michael@0 965 */
michael@0 966 PORT_Assert (num_attrs);
michael@0 967 if (num_attrs == 0 || num_attrs == 1)
michael@0 968 return SECSuccess;
michael@0 969
michael@0 970 /*
michael@0 971 * Allocate an arena for us to work with, so it is easy to
michael@0 972 * clean up all of the memory (fairly small pieces, really).
michael@0 973 */
michael@0 974 poolp = PORT_NewArena (1024); /* XXX what is right value? */
michael@0 975 if (poolp == NULL)
michael@0 976 return SECFailure; /* no memory; nothing we can do... */
michael@0 977
michael@0 978 /*
michael@0 979 * Allocate arrays to hold the individual encodings which we will use
michael@0 980 * for comparisons and the reordered attributes as they are sorted.
michael@0 981 */
michael@0 982 enc_attrs=(SECItem**)PORT_ArenaZAlloc(poolp, num_attrs*sizeof(SECItem *));
michael@0 983 new_attrs = (SEC_PKCS7Attribute**)PORT_ArenaZAlloc (poolp,
michael@0 984 num_attrs * sizeof(SEC_PKCS7Attribute *));
michael@0 985 if (enc_attrs == NULL || new_attrs == NULL) {
michael@0 986 PORT_FreeArena (poolp, PR_FALSE);
michael@0 987 return SECFailure;
michael@0 988 }
michael@0 989
michael@0 990 /*
michael@0 991 * DER encode each individual attribute.
michael@0 992 */
michael@0 993 for (i = 0; i < num_attrs; i++) {
michael@0 994 enc_attrs[i] = SEC_ASN1EncodeItem (poolp, NULL, attrs[i],
michael@0 995 sec_pkcs7_attribute_template);
michael@0 996 if (enc_attrs[i] == NULL) {
michael@0 997 PORT_FreeArena (poolp, PR_FALSE);
michael@0 998 return SECFailure;
michael@0 999 }
michael@0 1000 }
michael@0 1001
michael@0 1002 /*
michael@0 1003 * Now compare and sort them; this is not the most efficient sorting
michael@0 1004 * method, but it is just fine for the problem at hand, because the
michael@0 1005 * number of attributes is (always) going to be small.
michael@0 1006 */
michael@0 1007 for (pass = 0; pass < num_attrs; pass++) {
michael@0 1008 /*
michael@0 1009 * Find the first not-yet-accepted attribute. (Once one is
michael@0 1010 * sorted into the other array, it is cleared from enc_attrs.)
michael@0 1011 */
michael@0 1012 for (i = 0; i < num_attrs; i++) {
michael@0 1013 if (enc_attrs[i] != NULL)
michael@0 1014 break;
michael@0 1015 }
michael@0 1016 PORT_Assert (i < num_attrs);
michael@0 1017 besti = i;
michael@0 1018
michael@0 1019 /*
michael@0 1020 * Find the lowest (lexigraphically) encoding. One that is
michael@0 1021 * shorter than all the rest is known to be "less" because each
michael@0 1022 * attribute is of the same type (a SEQUENCE) and so thus the
michael@0 1023 * first octet of each is the same, and the second octet is
michael@0 1024 * the length (or the length of the length with the high bit
michael@0 1025 * set, followed by the length, which also works out to always
michael@0 1026 * order the shorter first). Two (or more) that have the
michael@0 1027 * same length need to be compared byte by byte until a mismatch
michael@0 1028 * is found.
michael@0 1029 */
michael@0 1030 for (i = besti + 1; i < num_attrs; i++) {
michael@0 1031 if (enc_attrs[i] == NULL) /* slot already handled */
michael@0 1032 continue;
michael@0 1033
michael@0 1034 if (enc_attrs[i]->len != enc_attrs[besti]->len) {
michael@0 1035 if (enc_attrs[i]->len < enc_attrs[besti]->len)
michael@0 1036 besti = i;
michael@0 1037 continue;
michael@0 1038 }
michael@0 1039
michael@0 1040 for (j = 0; j < enc_attrs[i]->len; j++) {
michael@0 1041 if (enc_attrs[i]->data[j] < enc_attrs[besti]->data[j]) {
michael@0 1042 besti = i;
michael@0 1043 break;
michael@0 1044 }
michael@0 1045 }
michael@0 1046
michael@0 1047 /*
michael@0 1048 * For this not to be true, we would have to have encountered
michael@0 1049 * two *identical* attributes, which I think we should not see.
michael@0 1050 * So assert if it happens, but even if it does, let it go
michael@0 1051 * through; the ordering of the two does not matter.
michael@0 1052 */
michael@0 1053 PORT_Assert (j < enc_attrs[i]->len);
michael@0 1054 }
michael@0 1055
michael@0 1056 /*
michael@0 1057 * Now we have found the next-lowest one; copy it over and
michael@0 1058 * remove it from enc_attrs.
michael@0 1059 */
michael@0 1060 new_attrs[pass] = attrs[besti];
michael@0 1061 enc_attrs[besti] = NULL;
michael@0 1062 }
michael@0 1063
michael@0 1064 /*
michael@0 1065 * Now new_attrs has the attributes in the order we want;
michael@0 1066 * copy them back into the attrs array we started with.
michael@0 1067 */
michael@0 1068 for (i = 0; i < num_attrs; i++)
michael@0 1069 attrs[i] = new_attrs[i];
michael@0 1070
michael@0 1071 PORT_FreeArena (poolp, PR_FALSE);
michael@0 1072 return SECSuccess;
michael@0 1073 }
michael@0 1074
michael@0 1075 /*
michael@0 1076 * End of attribute stuff.
michael@0 1077 * -------------------------------------------------------------------
michael@0 1078 */
michael@0 1079
michael@0 1080
michael@0 1081 /*
michael@0 1082 * Templates and stuff. Keep these at the end of the file.
michael@0 1083 */
michael@0 1084
michael@0 1085 /* forward declaration */
michael@0 1086 static const SEC_ASN1Template *
michael@0 1087 sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding);
michael@0 1088
michael@0 1089 static const SEC_ASN1TemplateChooserPtr sec_pkcs7_chooser
michael@0 1090 = sec_pkcs7_choose_content_template;
michael@0 1091
michael@0 1092 const SEC_ASN1Template sec_PKCS7ContentInfoTemplate[] = {
michael@0 1093 { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
michael@0 1094 0, NULL, sizeof(SEC_PKCS7ContentInfo) },
michael@0 1095 { SEC_ASN1_OBJECT_ID,
michael@0 1096 offsetof(SEC_PKCS7ContentInfo,contentType) },
michael@0 1097 { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
michael@0 1098 | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
michael@0 1099 offsetof(SEC_PKCS7ContentInfo,content),
michael@0 1100 &sec_pkcs7_chooser },
michael@0 1101 { 0 }
michael@0 1102 };
michael@0 1103
michael@0 1104 /* XXX These names should change from external to internal convention. */
michael@0 1105
michael@0 1106 static const SEC_ASN1Template SEC_PKCS7SignerInfoTemplate[] = {
michael@0 1107 { SEC_ASN1_SEQUENCE,
michael@0 1108 0, NULL, sizeof(SEC_PKCS7SignerInfo) },
michael@0 1109 { SEC_ASN1_INTEGER,
michael@0 1110 offsetof(SEC_PKCS7SignerInfo,version) },
michael@0 1111 { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
michael@0 1112 offsetof(SEC_PKCS7SignerInfo,issuerAndSN),
michael@0 1113 SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
michael@0 1114 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 1115 offsetof(SEC_PKCS7SignerInfo,digestAlg),
michael@0 1116 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1117 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
michael@0 1118 offsetof(SEC_PKCS7SignerInfo,authAttr),
michael@0 1119 sec_pkcs7_set_of_attribute_template },
michael@0 1120 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 1121 offsetof(SEC_PKCS7SignerInfo,digestEncAlg),
michael@0 1122 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1123 { SEC_ASN1_OCTET_STRING,
michael@0 1124 offsetof(SEC_PKCS7SignerInfo,encDigest) },
michael@0 1125 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
michael@0 1126 offsetof(SEC_PKCS7SignerInfo,unAuthAttr),
michael@0 1127 sec_pkcs7_set_of_attribute_template },
michael@0 1128 { 0 }
michael@0 1129 };
michael@0 1130
michael@0 1131 static const SEC_ASN1Template SEC_PKCS7SignedDataTemplate[] = {
michael@0 1132 { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
michael@0 1133 0, NULL, sizeof(SEC_PKCS7SignedData) },
michael@0 1134 { SEC_ASN1_INTEGER,
michael@0 1135 offsetof(SEC_PKCS7SignedData,version) },
michael@0 1136 { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
michael@0 1137 offsetof(SEC_PKCS7SignedData,digestAlgorithms),
michael@0 1138 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1139 { SEC_ASN1_INLINE,
michael@0 1140 offsetof(SEC_PKCS7SignedData,contentInfo),
michael@0 1141 sec_PKCS7ContentInfoTemplate },
michael@0 1142 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
michael@0 1143 SEC_ASN1_XTRN | 0,
michael@0 1144 offsetof(SEC_PKCS7SignedData,rawCerts),
michael@0 1145 SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
michael@0 1146 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
michael@0 1147 SEC_ASN1_XTRN | 1,
michael@0 1148 offsetof(SEC_PKCS7SignedData,crls),
michael@0 1149 SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
michael@0 1150 { SEC_ASN1_SET_OF,
michael@0 1151 offsetof(SEC_PKCS7SignedData,signerInfos),
michael@0 1152 SEC_PKCS7SignerInfoTemplate },
michael@0 1153 { 0 }
michael@0 1154 };
michael@0 1155
michael@0 1156 static const SEC_ASN1Template SEC_PointerToPKCS7SignedDataTemplate[] = {
michael@0 1157 { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedDataTemplate }
michael@0 1158 };
michael@0 1159
michael@0 1160 static const SEC_ASN1Template SEC_PKCS7RecipientInfoTemplate[] = {
michael@0 1161 { SEC_ASN1_SEQUENCE,
michael@0 1162 0, NULL, sizeof(SEC_PKCS7RecipientInfo) },
michael@0 1163 { SEC_ASN1_INTEGER,
michael@0 1164 offsetof(SEC_PKCS7RecipientInfo,version) },
michael@0 1165 { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
michael@0 1166 offsetof(SEC_PKCS7RecipientInfo,issuerAndSN),
michael@0 1167 SEC_ASN1_SUB(CERT_IssuerAndSNTemplate) },
michael@0 1168 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 1169 offsetof(SEC_PKCS7RecipientInfo,keyEncAlg),
michael@0 1170 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1171 { SEC_ASN1_OCTET_STRING,
michael@0 1172 offsetof(SEC_PKCS7RecipientInfo,encKey) },
michael@0 1173 { 0 }
michael@0 1174 };
michael@0 1175
michael@0 1176 static const SEC_ASN1Template SEC_PKCS7EncryptedContentInfoTemplate[] = {
michael@0 1177 { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
michael@0 1178 0, NULL, sizeof(SEC_PKCS7EncryptedContentInfo) },
michael@0 1179 { SEC_ASN1_OBJECT_ID,
michael@0 1180 offsetof(SEC_PKCS7EncryptedContentInfo,contentType) },
michael@0 1181 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 1182 offsetof(SEC_PKCS7EncryptedContentInfo,contentEncAlg),
michael@0 1183 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1184 { SEC_ASN1_OPTIONAL | SEC_ASN1_MAY_STREAM | SEC_ASN1_CONTEXT_SPECIFIC |
michael@0 1185 SEC_ASN1_XTRN | 0,
michael@0 1186 offsetof(SEC_PKCS7EncryptedContentInfo,encContent),
michael@0 1187 SEC_ASN1_SUB(SEC_OctetStringTemplate) },
michael@0 1188 { 0 }
michael@0 1189 };
michael@0 1190
michael@0 1191 static const SEC_ASN1Template SEC_PKCS7EnvelopedDataTemplate[] = {
michael@0 1192 { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
michael@0 1193 0, NULL, sizeof(SEC_PKCS7EnvelopedData) },
michael@0 1194 { SEC_ASN1_INTEGER,
michael@0 1195 offsetof(SEC_PKCS7EnvelopedData,version) },
michael@0 1196 { SEC_ASN1_SET_OF,
michael@0 1197 offsetof(SEC_PKCS7EnvelopedData,recipientInfos),
michael@0 1198 SEC_PKCS7RecipientInfoTemplate },
michael@0 1199 { SEC_ASN1_INLINE,
michael@0 1200 offsetof(SEC_PKCS7EnvelopedData,encContentInfo),
michael@0 1201 SEC_PKCS7EncryptedContentInfoTemplate },
michael@0 1202 { 0 }
michael@0 1203 };
michael@0 1204
michael@0 1205 static const SEC_ASN1Template SEC_PointerToPKCS7EnvelopedDataTemplate[] = {
michael@0 1206 { SEC_ASN1_POINTER, 0, SEC_PKCS7EnvelopedDataTemplate }
michael@0 1207 };
michael@0 1208
michael@0 1209 static const SEC_ASN1Template SEC_PKCS7SignedAndEnvelopedDataTemplate[] = {
michael@0 1210 { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
michael@0 1211 0, NULL, sizeof(SEC_PKCS7SignedAndEnvelopedData) },
michael@0 1212 { SEC_ASN1_INTEGER,
michael@0 1213 offsetof(SEC_PKCS7SignedAndEnvelopedData,version) },
michael@0 1214 { SEC_ASN1_SET_OF,
michael@0 1215 offsetof(SEC_PKCS7SignedAndEnvelopedData,recipientInfos),
michael@0 1216 SEC_PKCS7RecipientInfoTemplate },
michael@0 1217 { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
michael@0 1218 offsetof(SEC_PKCS7SignedAndEnvelopedData,digestAlgorithms),
michael@0 1219 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1220 { SEC_ASN1_INLINE,
michael@0 1221 offsetof(SEC_PKCS7SignedAndEnvelopedData,encContentInfo),
michael@0 1222 SEC_PKCS7EncryptedContentInfoTemplate },
michael@0 1223 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
michael@0 1224 SEC_ASN1_XTRN | 0,
michael@0 1225 offsetof(SEC_PKCS7SignedAndEnvelopedData,rawCerts),
michael@0 1226 SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
michael@0 1227 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
michael@0 1228 SEC_ASN1_XTRN | 1,
michael@0 1229 offsetof(SEC_PKCS7SignedAndEnvelopedData,crls),
michael@0 1230 SEC_ASN1_SUB(CERT_SetOfSignedCrlTemplate) },
michael@0 1231 { SEC_ASN1_SET_OF,
michael@0 1232 offsetof(SEC_PKCS7SignedAndEnvelopedData,signerInfos),
michael@0 1233 SEC_PKCS7SignerInfoTemplate },
michael@0 1234 { 0 }
michael@0 1235 };
michael@0 1236
michael@0 1237 static const SEC_ASN1Template
michael@0 1238 SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate[] = {
michael@0 1239 { SEC_ASN1_POINTER, 0, SEC_PKCS7SignedAndEnvelopedDataTemplate }
michael@0 1240 };
michael@0 1241
michael@0 1242 static const SEC_ASN1Template SEC_PKCS7DigestedDataTemplate[] = {
michael@0 1243 { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
michael@0 1244 0, NULL, sizeof(SEC_PKCS7DigestedData) },
michael@0 1245 { SEC_ASN1_INTEGER,
michael@0 1246 offsetof(SEC_PKCS7DigestedData,version) },
michael@0 1247 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 1248 offsetof(SEC_PKCS7DigestedData,digestAlg),
michael@0 1249 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1250 { SEC_ASN1_INLINE,
michael@0 1251 offsetof(SEC_PKCS7DigestedData,contentInfo),
michael@0 1252 sec_PKCS7ContentInfoTemplate },
michael@0 1253 { SEC_ASN1_OCTET_STRING,
michael@0 1254 offsetof(SEC_PKCS7DigestedData,digest) },
michael@0 1255 { 0 }
michael@0 1256 };
michael@0 1257
michael@0 1258 static const SEC_ASN1Template SEC_PointerToPKCS7DigestedDataTemplate[] = {
michael@0 1259 { SEC_ASN1_POINTER, 0, SEC_PKCS7DigestedDataTemplate }
michael@0 1260 };
michael@0 1261
michael@0 1262 static const SEC_ASN1Template SEC_PKCS7EncryptedDataTemplate[] = {
michael@0 1263 { SEC_ASN1_SEQUENCE | SEC_ASN1_MAY_STREAM,
michael@0 1264 0, NULL, sizeof(SEC_PKCS7EncryptedData) },
michael@0 1265 { SEC_ASN1_INTEGER,
michael@0 1266 offsetof(SEC_PKCS7EncryptedData,version) },
michael@0 1267 { SEC_ASN1_INLINE,
michael@0 1268 offsetof(SEC_PKCS7EncryptedData,encContentInfo),
michael@0 1269 SEC_PKCS7EncryptedContentInfoTemplate },
michael@0 1270 { 0 }
michael@0 1271 };
michael@0 1272
michael@0 1273 static const SEC_ASN1Template SEC_PointerToPKCS7EncryptedDataTemplate[] = {
michael@0 1274 { SEC_ASN1_POINTER, 0, SEC_PKCS7EncryptedDataTemplate }
michael@0 1275 };
michael@0 1276
michael@0 1277 static const SEC_ASN1Template *
michael@0 1278 sec_pkcs7_choose_content_template(void *src_or_dest, PRBool encoding)
michael@0 1279 {
michael@0 1280 const SEC_ASN1Template *theTemplate;
michael@0 1281 SEC_PKCS7ContentInfo *cinfo;
michael@0 1282 SECOidTag kind;
michael@0 1283
michael@0 1284 PORT_Assert (src_or_dest != NULL);
michael@0 1285 if (src_or_dest == NULL)
michael@0 1286 return NULL;
michael@0 1287
michael@0 1288 cinfo = (SEC_PKCS7ContentInfo*)src_or_dest;
michael@0 1289 kind = SEC_PKCS7ContentType (cinfo);
michael@0 1290 switch (kind) {
michael@0 1291 default:
michael@0 1292 theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate);
michael@0 1293 break;
michael@0 1294 case SEC_OID_PKCS7_DATA:
michael@0 1295 theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
michael@0 1296 break;
michael@0 1297 case SEC_OID_PKCS7_SIGNED_DATA:
michael@0 1298 theTemplate = SEC_PointerToPKCS7SignedDataTemplate;
michael@0 1299 break;
michael@0 1300 case SEC_OID_PKCS7_ENVELOPED_DATA:
michael@0 1301 theTemplate = SEC_PointerToPKCS7EnvelopedDataTemplate;
michael@0 1302 break;
michael@0 1303 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
michael@0 1304 theTemplate = SEC_PointerToPKCS7SignedAndEnvelopedDataTemplate;
michael@0 1305 break;
michael@0 1306 case SEC_OID_PKCS7_DIGESTED_DATA:
michael@0 1307 theTemplate = SEC_PointerToPKCS7DigestedDataTemplate;
michael@0 1308 break;
michael@0 1309 case SEC_OID_PKCS7_ENCRYPTED_DATA:
michael@0 1310 theTemplate = SEC_PointerToPKCS7EncryptedDataTemplate;
michael@0 1311 break;
michael@0 1312 }
michael@0 1313 return theTemplate;
michael@0 1314 }
michael@0 1315
michael@0 1316 /*
michael@0 1317 * End of templates. Do not add stuff after this; put new code
michael@0 1318 * up above the start of the template definitions.
michael@0 1319 */

mercurial