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