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