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