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, ¶m, 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, ¶m, 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 + */