Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/pkcs7/p7encode.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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 * PKCS7 encoding. | |
7 */ | |
8 | |
9 #include "p7local.h" | |
10 | |
11 #include "cert.h" | |
12 #include "cryptohi.h" | |
13 #include "keyhi.h" | |
14 #include "secasn1.h" | |
15 #include "secoid.h" | |
16 #include "secitem.h" | |
17 #include "pk11func.h" | |
18 #include "secerr.h" | |
19 #include "sechash.h" /* for HASH_GetHashObject() */ | |
20 | |
21 struct sec_pkcs7_encoder_output { | |
22 SEC_PKCS7EncoderOutputCallback outputfn; | |
23 void *outputarg; | |
24 }; | |
25 | |
26 struct SEC_PKCS7EncoderContextStr { | |
27 SEC_ASN1EncoderContext *ecx; | |
28 SEC_PKCS7ContentInfo *cinfo; | |
29 struct sec_pkcs7_encoder_output output; | |
30 sec_PKCS7CipherObject *encryptobj; | |
31 const SECHashObject *digestobj; | |
32 void *digestcx; | |
33 }; | |
34 | |
35 | |
36 /* | |
37 * The little output function that the ASN.1 encoder calls to hand | |
38 * us bytes which we in turn hand back to our caller (via the callback | |
39 * they gave us). | |
40 */ | |
41 static void | |
42 sec_pkcs7_encoder_out(void *arg, const char *buf, unsigned long len, | |
43 int depth, SEC_ASN1EncodingPart data_kind) | |
44 { | |
45 struct sec_pkcs7_encoder_output *output; | |
46 | |
47 output = (struct sec_pkcs7_encoder_output*)arg; | |
48 output->outputfn (output->outputarg, buf, len); | |
49 } | |
50 | |
51 static sec_PKCS7CipherObject * | |
52 sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo, | |
53 PK11SymKey *orig_bulkkey) | |
54 { | |
55 SECOidTag kind; | |
56 sec_PKCS7CipherObject *encryptobj; | |
57 SEC_PKCS7RecipientInfo **recipientinfos, *ri; | |
58 SEC_PKCS7EncryptedContentInfo *enccinfo; | |
59 SECKEYPublicKey *publickey = NULL; | |
60 SECKEYPrivateKey *ourPrivKey = NULL; | |
61 PK11SymKey *bulkkey; | |
62 void *mark, *wincx; | |
63 int i; | |
64 PLArenaPool *arena = NULL; | |
65 | |
66 /* Get the context in case we need it below. */ | |
67 wincx = cinfo->pwfn_arg; | |
68 | |
69 kind = SEC_PKCS7ContentType (cinfo); | |
70 switch (kind) { | |
71 default: | |
72 case SEC_OID_PKCS7_DATA: | |
73 case SEC_OID_PKCS7_DIGESTED_DATA: | |
74 case SEC_OID_PKCS7_SIGNED_DATA: | |
75 recipientinfos = NULL; | |
76 enccinfo = NULL; | |
77 break; | |
78 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
79 { | |
80 SEC_PKCS7EncryptedData *encdp; | |
81 | |
82 /* To do EncryptedData we *must* be given a bulk key. */ | |
83 PORT_Assert (orig_bulkkey != NULL); | |
84 if (orig_bulkkey == NULL) { | |
85 /* XXX error? */ | |
86 return NULL; | |
87 } | |
88 | |
89 encdp = cinfo->content.encryptedData; | |
90 recipientinfos = NULL; | |
91 enccinfo = &(encdp->encContentInfo); | |
92 } | |
93 break; | |
94 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
95 { | |
96 SEC_PKCS7EnvelopedData *envdp; | |
97 | |
98 envdp = cinfo->content.envelopedData; | |
99 recipientinfos = envdp->recipientInfos; | |
100 enccinfo = &(envdp->encContentInfo); | |
101 } | |
102 break; | |
103 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
104 { | |
105 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
106 | |
107 saedp = cinfo->content.signedAndEnvelopedData; | |
108 recipientinfos = saedp->recipientInfos; | |
109 enccinfo = &(saedp->encContentInfo); | |
110 } | |
111 break; | |
112 } | |
113 | |
114 if (enccinfo == NULL) | |
115 return NULL; | |
116 | |
117 bulkkey = orig_bulkkey; | |
118 if (bulkkey == NULL) { | |
119 CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg); | |
120 PK11SlotInfo *slot; | |
121 | |
122 | |
123 slot = PK11_GetBestSlot(type,cinfo->pwfn_arg); | |
124 if (slot == NULL) { | |
125 return NULL; | |
126 } | |
127 bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8, | |
128 cinfo->pwfn_arg); | |
129 PK11_FreeSlot(slot); | |
130 if (bulkkey == NULL) { | |
131 return NULL; | |
132 } | |
133 } | |
134 | |
135 encryptobj = NULL; | |
136 mark = PORT_ArenaMark (cinfo->poolp); | |
137 | |
138 /* | |
139 * Encrypt the bulk key with the public key of each recipient. | |
140 */ | |
141 for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) { | |
142 CERTCertificate *cert; | |
143 SECOidTag certalgtag, encalgtag; | |
144 SECStatus rv; | |
145 int data_len; | |
146 SECItem *params = NULL; | |
147 | |
148 cert = ri->cert; | |
149 PORT_Assert (cert != NULL); | |
150 if (cert == NULL) | |
151 continue; | |
152 | |
153 /* | |
154 * XXX Want an interface that takes a cert and some data and | |
155 * fills in an algorithmID and encrypts the data with the public | |
156 * key from the cert. Or, give me two interfaces -- one which | |
157 * gets the algorithm tag from a cert (I should not have to go | |
158 * down into the subjectPublicKeyInfo myself) and another which | |
159 * takes a public key and algorithm tag and data and encrypts | |
160 * the data. Or something like that. The point is that all | |
161 * of the following hardwired RSA stuff should be done elsewhere. | |
162 */ | |
163 | |
164 certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); | |
165 | |
166 switch (certalgtag) { | |
167 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
168 encalgtag = certalgtag; | |
169 publickey = CERT_ExtractPublicKey (cert); | |
170 if (publickey == NULL) goto loser; | |
171 | |
172 data_len = SECKEY_PublicKeyStrength(publickey); | |
173 ri->encKey.data = | |
174 (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len); | |
175 ri->encKey.len = data_len; | |
176 if (ri->encKey.data == NULL) goto loser; | |
177 | |
178 rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey, | |
179 bulkkey,&ri->encKey); | |
180 | |
181 SECKEY_DestroyPublicKey(publickey); | |
182 publickey = NULL; | |
183 if (rv != SECSuccess) goto loser; | |
184 params = NULL; /* paranoia */ | |
185 break; | |
186 default: | |
187 PORT_SetError (SEC_ERROR_INVALID_ALGORITHM); | |
188 goto loser; | |
189 } | |
190 | |
191 rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, | |
192 params); | |
193 if (rv != SECSuccess) | |
194 goto loser; | |
195 if (arena) PORT_FreeArena(arena,PR_FALSE); | |
196 arena = NULL; | |
197 } | |
198 | |
199 encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey, | |
200 enccinfo->encalg, | |
201 &(enccinfo->contentEncAlg)); | |
202 if (encryptobj != NULL) { | |
203 PORT_ArenaUnmark (cinfo->poolp, mark); | |
204 mark = NULL; /* good one; do not want to release */ | |
205 } | |
206 /* fallthru */ | |
207 | |
208 loser: | |
209 if (arena) { | |
210 PORT_FreeArena(arena, PR_FALSE); | |
211 } | |
212 if (publickey) { | |
213 SECKEY_DestroyPublicKey(publickey); | |
214 } | |
215 if (ourPrivKey) { | |
216 SECKEY_DestroyPrivateKey(ourPrivKey); | |
217 } | |
218 if (mark != NULL) { | |
219 PORT_ArenaRelease (cinfo->poolp, mark); | |
220 } | |
221 if (orig_bulkkey == NULL) { | |
222 if (bulkkey) PK11_FreeSymKey(bulkkey); | |
223 } | |
224 | |
225 return encryptobj; | |
226 } | |
227 | |
228 | |
229 static void | |
230 sec_pkcs7_encoder_notify (void *arg, PRBool before, void *dest, int depth) | |
231 { | |
232 SEC_PKCS7EncoderContext *p7ecx; | |
233 SEC_PKCS7ContentInfo *cinfo; | |
234 SECOidTag kind; | |
235 PRBool before_content; | |
236 | |
237 /* | |
238 * We want to notice just before the content field. After fields are | |
239 * not interesting to us. | |
240 */ | |
241 if (!before) | |
242 return; | |
243 | |
244 p7ecx = (SEC_PKCS7EncoderContext*)arg; | |
245 cinfo = p7ecx->cinfo; | |
246 | |
247 before_content = PR_FALSE; | |
248 | |
249 /* | |
250 * Watch for the content field, at which point we want to instruct | |
251 * the ASN.1 encoder to start taking bytes from the buffer. | |
252 * | |
253 * XXX The following assumes the inner content type is data; | |
254 * if/when we want to handle fully nested types, this will have | |
255 * to recurse until reaching the innermost data content. | |
256 */ | |
257 kind = SEC_PKCS7ContentType (cinfo); | |
258 switch (kind) { | |
259 default: | |
260 case SEC_OID_PKCS7_DATA: | |
261 if (dest == &(cinfo->content.data)) | |
262 before_content = PR_TRUE; | |
263 break; | |
264 | |
265 case SEC_OID_PKCS7_DIGESTED_DATA: | |
266 { | |
267 SEC_PKCS7DigestedData *digd; | |
268 | |
269 digd = cinfo->content.digestedData; | |
270 if (digd == NULL) | |
271 break; | |
272 | |
273 if (dest == &(digd->contentInfo.content)) | |
274 before_content = PR_TRUE; | |
275 } | |
276 break; | |
277 | |
278 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
279 { | |
280 SEC_PKCS7EncryptedData *encd; | |
281 | |
282 encd = cinfo->content.encryptedData; | |
283 if (encd == NULL) | |
284 break; | |
285 | |
286 if (dest == &(encd->encContentInfo.encContent)) | |
287 before_content = PR_TRUE; | |
288 } | |
289 break; | |
290 | |
291 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
292 { | |
293 SEC_PKCS7EnvelopedData *envd; | |
294 | |
295 envd = cinfo->content.envelopedData; | |
296 if (envd == NULL) | |
297 break; | |
298 | |
299 if (dest == &(envd->encContentInfo.encContent)) | |
300 before_content = PR_TRUE; | |
301 } | |
302 break; | |
303 | |
304 case SEC_OID_PKCS7_SIGNED_DATA: | |
305 { | |
306 SEC_PKCS7SignedData *sigd; | |
307 | |
308 sigd = cinfo->content.signedData; | |
309 if (sigd == NULL) | |
310 break; | |
311 | |
312 if (dest == &(sigd->contentInfo.content)) | |
313 before_content = PR_TRUE; | |
314 } | |
315 break; | |
316 | |
317 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
318 { | |
319 SEC_PKCS7SignedAndEnvelopedData *saed; | |
320 | |
321 saed = cinfo->content.signedAndEnvelopedData; | |
322 if (saed == NULL) | |
323 break; | |
324 | |
325 if (dest == &(saed->encContentInfo.encContent)) | |
326 before_content = PR_TRUE; | |
327 } | |
328 break; | |
329 } | |
330 | |
331 if (before_content) { | |
332 /* | |
333 * This will cause the next SEC_ASN1EncoderUpdate to take the | |
334 * contents bytes from the passed-in buffer. | |
335 */ | |
336 SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx); | |
337 /* | |
338 * And that is all we needed this notify function for. | |
339 */ | |
340 SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx); | |
341 } | |
342 } | |
343 | |
344 | |
345 static SEC_PKCS7EncoderContext * | |
346 sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo, | |
347 PK11SymKey *bulkkey) | |
348 { | |
349 SEC_PKCS7EncoderContext *p7ecx; | |
350 SECOidTag kind; | |
351 PRBool encrypt; | |
352 SECItem **digests; | |
353 SECAlgorithmID *digestalg, **digestalgs; | |
354 | |
355 p7ecx = | |
356 (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext)); | |
357 if (p7ecx == NULL) | |
358 return NULL; | |
359 | |
360 digests = NULL; | |
361 digestalg = NULL; | |
362 digestalgs = NULL; | |
363 encrypt = PR_FALSE; | |
364 | |
365 kind = SEC_PKCS7ContentType (cinfo); | |
366 switch (kind) { | |
367 default: | |
368 case SEC_OID_PKCS7_DATA: | |
369 break; | |
370 case SEC_OID_PKCS7_DIGESTED_DATA: | |
371 digestalg = &(cinfo->content.digestedData->digestAlg); | |
372 break; | |
373 case SEC_OID_PKCS7_SIGNED_DATA: | |
374 digests = cinfo->content.signedData->digests; | |
375 digestalgs = cinfo->content.signedData->digestAlgorithms; | |
376 break; | |
377 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
378 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
379 encrypt = PR_TRUE; | |
380 break; | |
381 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
382 digests = cinfo->content.signedAndEnvelopedData->digests; | |
383 digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms; | |
384 encrypt = PR_TRUE; | |
385 break; | |
386 } | |
387 | |
388 if (encrypt) { | |
389 p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey); | |
390 if (p7ecx->encryptobj == NULL) { | |
391 PORT_Free (p7ecx); | |
392 return NULL; | |
393 } | |
394 } | |
395 | |
396 if (digestalgs != NULL) { | |
397 if (digests != NULL) { | |
398 /* digests already created (probably for detached data) */ | |
399 digestalg = NULL; | |
400 } else { | |
401 /* | |
402 * XXX Some day we should handle multiple digests; for now, | |
403 * assume only one will be done. | |
404 */ | |
405 PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL); | |
406 digestalg = digestalgs[0]; | |
407 } | |
408 } | |
409 | |
410 if (digestalg != NULL) { | |
411 SECOidTag oidTag = SECOID_FindOIDTag(&(digestalg->algorithm)); | |
412 | |
413 p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag); | |
414 if (p7ecx->digestobj != NULL) { | |
415 p7ecx->digestcx = (* p7ecx->digestobj->create) (); | |
416 if (p7ecx->digestcx == NULL) | |
417 p7ecx->digestobj = NULL; | |
418 else | |
419 (* p7ecx->digestobj->begin) (p7ecx->digestcx); | |
420 } | |
421 if (p7ecx->digestobj == NULL) { | |
422 if (p7ecx->encryptobj != NULL) | |
423 sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj); | |
424 PORT_Free (p7ecx); | |
425 return NULL; | |
426 } | |
427 } | |
428 | |
429 p7ecx->cinfo = cinfo; | |
430 return p7ecx; | |
431 } | |
432 | |
433 | |
434 SEC_PKCS7EncoderContext * | |
435 SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo, | |
436 SEC_PKCS7EncoderOutputCallback outputfn, | |
437 void *outputarg, | |
438 PK11SymKey *bulkkey) | |
439 { | |
440 SEC_PKCS7EncoderContext *p7ecx; | |
441 SECStatus rv; | |
442 | |
443 p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey); | |
444 if (p7ecx == NULL) | |
445 return NULL; | |
446 | |
447 p7ecx->output.outputfn = outputfn; | |
448 p7ecx->output.outputarg = outputarg; | |
449 | |
450 /* | |
451 * Initialize the BER encoder. | |
452 */ | |
453 p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate, | |
454 sec_pkcs7_encoder_out, &(p7ecx->output)); | |
455 if (p7ecx->ecx == NULL) { | |
456 PORT_Free (p7ecx); | |
457 return NULL; | |
458 } | |
459 | |
460 /* | |
461 * Indicate that we are streaming. We will be streaming until we | |
462 * get past the contents bytes. | |
463 */ | |
464 SEC_ASN1EncoderSetStreaming (p7ecx->ecx); | |
465 | |
466 /* | |
467 * The notify function will watch for the contents field. | |
468 */ | |
469 SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx); | |
470 | |
471 /* | |
472 * This will encode everything up to the content bytes. (The notify | |
473 * function will then cause the encoding to stop there.) Then our | |
474 * caller can start passing contents bytes to our Update, which we | |
475 * will pass along. | |
476 */ | |
477 rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0); | |
478 if (rv != SECSuccess) { | |
479 PORT_Free (p7ecx); | |
480 return NULL; | |
481 } | |
482 | |
483 return p7ecx; | |
484 } | |
485 | |
486 | |
487 /* | |
488 * XXX If/when we support nested contents, this needs to be revised. | |
489 */ | |
490 static SECStatus | |
491 sec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest, | |
492 const unsigned char *data, unsigned long len, | |
493 PRBool final) | |
494 { | |
495 unsigned char *buf = NULL; | |
496 SECStatus rv; | |
497 | |
498 | |
499 rv = SECSuccess; /* may as well be optimistic */ | |
500 | |
501 /* | |
502 * We should really have data to process, or we should be trying | |
503 * to finish/flush the last block. (This is an overly paranoid | |
504 * check since all callers are in this file and simple inspection | |
505 * proves they do it right. But it could find a bug in future | |
506 * modifications/development, that is why it is here.) | |
507 */ | |
508 PORT_Assert ((data != NULL && len) || final); | |
509 | |
510 /* | |
511 * Update the running digest. | |
512 * XXX This needs modification if/when we handle multiple digests. | |
513 */ | |
514 if (len && p7ecx->digestobj != NULL) { | |
515 (* p7ecx->digestobj->update) (p7ecx->digestcx, data, len); | |
516 } | |
517 | |
518 /* | |
519 * Encrypt this chunk. | |
520 */ | |
521 if (p7ecx->encryptobj != NULL) { | |
522 /* XXX the following lengths should all be longs? */ | |
523 unsigned int inlen; /* length of data being encrypted */ | |
524 unsigned int outlen; /* length of encrypted data */ | |
525 unsigned int buflen; /* length available for encrypted data */ | |
526 | |
527 inlen = len; | |
528 buflen = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final); | |
529 if (buflen == 0) { | |
530 /* | |
531 * No output is expected, but the input data may be buffered | |
532 * so we still have to call Encrypt. | |
533 */ | |
534 rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0, | |
535 data, inlen, final); | |
536 if (final) { | |
537 len = 0; | |
538 goto done; | |
539 } | |
540 return rv; | |
541 } | |
542 | |
543 if (dest != NULL) | |
544 buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen); | |
545 else | |
546 buf = (unsigned char*)PORT_Alloc (buflen); | |
547 | |
548 if (buf == NULL) { | |
549 rv = SECFailure; | |
550 } else { | |
551 rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen, | |
552 data, inlen, final); | |
553 data = buf; | |
554 len = outlen; | |
555 } | |
556 if (rv != SECSuccess) { | |
557 if (final) | |
558 goto done; | |
559 return rv; | |
560 } | |
561 } | |
562 | |
563 if (p7ecx->ecx != NULL) { | |
564 /* | |
565 * Encode the contents bytes. | |
566 */ | |
567 if(len) { | |
568 rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len); | |
569 } | |
570 } | |
571 | |
572 done: | |
573 if (p7ecx->encryptobj != NULL) { | |
574 if (final) | |
575 sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj); | |
576 if (dest != NULL) { | |
577 dest->data = buf; | |
578 dest->len = len; | |
579 } else if (buf != NULL) { | |
580 PORT_Free (buf); | |
581 } | |
582 } | |
583 | |
584 if (final && p7ecx->digestobj != NULL) { | |
585 SECItem *digest, **digests, ***digestsp; | |
586 unsigned char *digdata; | |
587 SECOidTag kind; | |
588 | |
589 kind = SEC_PKCS7ContentType (p7ecx->cinfo); | |
590 switch (kind) { | |
591 default: | |
592 PORT_Assert (0); | |
593 return SECFailure; | |
594 case SEC_OID_PKCS7_DIGESTED_DATA: | |
595 digest = &(p7ecx->cinfo->content.digestedData->digest); | |
596 digestsp = NULL; | |
597 break; | |
598 case SEC_OID_PKCS7_SIGNED_DATA: | |
599 digest = NULL; | |
600 digestsp = &(p7ecx->cinfo->content.signedData->digests); | |
601 break; | |
602 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
603 digest = NULL; | |
604 digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests); | |
605 break; | |
606 } | |
607 | |
608 digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, | |
609 p7ecx->digestobj->length); | |
610 if (digdata == NULL) | |
611 return SECFailure; | |
612 | |
613 if (digestsp != NULL) { | |
614 PORT_Assert (digest == NULL); | |
615 | |
616 digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, | |
617 sizeof(SECItem)); | |
618 digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp, | |
619 2 * sizeof(SECItem *)); | |
620 if (digests == NULL || digest == NULL) | |
621 return SECFailure; | |
622 | |
623 digests[0] = digest; | |
624 digests[1] = NULL; | |
625 | |
626 *digestsp = digests; | |
627 } | |
628 | |
629 PORT_Assert (digest != NULL); | |
630 | |
631 digest->data = digdata; | |
632 digest->len = p7ecx->digestobj->length; | |
633 | |
634 (* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data, | |
635 &(digest->len), digest->len); | |
636 (* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE); | |
637 } | |
638 | |
639 return rv; | |
640 } | |
641 | |
642 | |
643 SECStatus | |
644 SEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx, | |
645 const char *data, unsigned long len) | |
646 { | |
647 /* XXX Error handling needs help. Return what? Do "Finish" on failure? */ | |
648 return sec_pkcs7_encoder_work_data (p7ecx, NULL, | |
649 (const unsigned char *)data, len, | |
650 PR_FALSE); | |
651 } | |
652 | |
653 static SECStatus | |
654 sec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo, | |
655 SECKEYGetPasswordKey pwfn, void *pwfnarg) | |
656 { | |
657 SECOidTag kind; | |
658 CERTCertificate **certs; | |
659 CERTCertificateList **certlists; | |
660 SECAlgorithmID **digestalgs; | |
661 SECItem **digests; | |
662 SEC_PKCS7SignerInfo *signerinfo, **signerinfos; | |
663 SECItem **rawcerts, ***rawcertsp; | |
664 PLArenaPool *poolp; | |
665 int certcount; | |
666 int ci, cli, rci, si; | |
667 | |
668 kind = SEC_PKCS7ContentType (cinfo); | |
669 switch (kind) { | |
670 default: | |
671 case SEC_OID_PKCS7_DATA: | |
672 case SEC_OID_PKCS7_DIGESTED_DATA: | |
673 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
674 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
675 certs = NULL; | |
676 certlists = NULL; | |
677 digestalgs = NULL; | |
678 digests = NULL; | |
679 signerinfos = NULL; | |
680 rawcertsp = NULL; | |
681 break; | |
682 case SEC_OID_PKCS7_SIGNED_DATA: | |
683 { | |
684 SEC_PKCS7SignedData *sdp; | |
685 | |
686 sdp = cinfo->content.signedData; | |
687 certs = sdp->certs; | |
688 certlists = sdp->certLists; | |
689 digestalgs = sdp->digestAlgorithms; | |
690 digests = sdp->digests; | |
691 signerinfos = sdp->signerInfos; | |
692 rawcertsp = &(sdp->rawCerts); | |
693 } | |
694 break; | |
695 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
696 { | |
697 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
698 | |
699 saedp = cinfo->content.signedAndEnvelopedData; | |
700 certs = saedp->certs; | |
701 certlists = saedp->certLists; | |
702 digestalgs = saedp->digestAlgorithms; | |
703 digests = saedp->digests; | |
704 signerinfos = saedp->signerInfos; | |
705 rawcertsp = &(saedp->rawCerts); | |
706 } | |
707 break; | |
708 } | |
709 | |
710 if (certs == NULL && certlists == NULL && signerinfos == NULL) | |
711 return SECSuccess; /* nothing for us to do! */ | |
712 | |
713 poolp = cinfo->poolp; | |
714 certcount = 0; | |
715 | |
716 if (signerinfos != NULL) { | |
717 SECOidTag digestalgtag; | |
718 int di; | |
719 SECStatus rv; | |
720 CERTCertificate *cert; | |
721 SECKEYPrivateKey *privkey; | |
722 SECItem signature; | |
723 SECOidTag signalgtag; | |
724 | |
725 PORT_Assert (digestalgs != NULL && digests != NULL); | |
726 | |
727 /* | |
728 * If one fails, we bail right then. If we want to continue and | |
729 * try to do subsequent signatures, this loop, and the departures | |
730 * from it, will need to be reworked. | |
731 */ | |
732 for (si = 0; signerinfos[si] != NULL; si++) { | |
733 | |
734 signerinfo = signerinfos[si]; | |
735 | |
736 /* find right digest */ | |
737 digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg)); | |
738 for (di = 0; digestalgs[di] != NULL; di++) { | |
739 /* XXX Should I be comparing more than the tag? */ | |
740 if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di])) | |
741 break; | |
742 } | |
743 if (digestalgs[di] == NULL) { | |
744 /* XXX oops; do what? set an error? */ | |
745 return SECFailure; | |
746 } | |
747 PORT_Assert (digests[di] != NULL); | |
748 | |
749 cert = signerinfo->cert; | |
750 privkey = PK11_FindKeyByAnyCert (cert, pwfnarg); | |
751 if (privkey == NULL) | |
752 return SECFailure; | |
753 | |
754 /* | |
755 * XXX I think there should be a cert-level interface for this, | |
756 * so that I do not have to know about subjectPublicKeyInfo... | |
757 */ | |
758 signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.algorithm)); | |
759 | |
760 if (signerinfo->authAttr != NULL) { | |
761 SEC_PKCS7Attribute *attr; | |
762 SECItem encoded_attrs; | |
763 SECItem *dummy; | |
764 SECOidTag algid; | |
765 | |
766 /* | |
767 * First, find and fill in the message digest attribute. | |
768 */ | |
769 attr = sec_PKCS7FindAttribute (signerinfo->authAttr, | |
770 SEC_OID_PKCS9_MESSAGE_DIGEST, | |
771 PR_TRUE); | |
772 PORT_Assert (attr != NULL); | |
773 if (attr == NULL) { | |
774 SECKEY_DestroyPrivateKey (privkey); | |
775 return SECFailure; | |
776 } | |
777 | |
778 /* | |
779 * XXX The second half of the following assertion prevents | |
780 * the encoder from being called twice on the same content. | |
781 * Either just remove the second half the assertion, or | |
782 * change the code to check if the value already there is | |
783 * the same as digests[di], whichever seems more right. | |
784 */ | |
785 PORT_Assert (attr->values != NULL && attr->values[0] == NULL); | |
786 attr->values[0] = digests[di]; | |
787 | |
788 /* | |
789 * Before encoding, reorder the attributes so that when they | |
790 * are encoded, they will be conforming DER, which is required | |
791 * to have a specific order and that is what must be used for | |
792 * the hash/signature. We do this here, rather than building | |
793 * it into EncodeAttributes, because we do not want to do | |
794 * such reordering on incoming messages (which also uses | |
795 * EncodeAttributes) or our old signatures (and other "broken" | |
796 * implementations) will not verify. So, we want to guarantee | |
797 * that we send out good DER encodings of attributes, but not | |
798 * to expect to receive them. | |
799 */ | |
800 rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr); | |
801 if (rv != SECSuccess) { | |
802 SECKEY_DestroyPrivateKey (privkey); | |
803 return SECFailure; | |
804 } | |
805 | |
806 encoded_attrs.data = NULL; | |
807 encoded_attrs.len = 0; | |
808 dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs, | |
809 &(signerinfo->authAttr)); | |
810 if (dummy == NULL) { | |
811 SECKEY_DestroyPrivateKey (privkey); | |
812 return SECFailure; | |
813 } | |
814 | |
815 algid = SEC_GetSignatureAlgorithmOidTag(privkey->keyType, | |
816 digestalgtag); | |
817 if (algid == SEC_OID_UNKNOWN) { | |
818 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
819 SECKEY_DestroyPrivateKey (privkey); | |
820 return SECFailure; | |
821 } | |
822 rv = SEC_SignData (&signature, | |
823 encoded_attrs.data, encoded_attrs.len, | |
824 privkey, | |
825 algid); | |
826 SECITEM_FreeItem (&encoded_attrs, PR_FALSE); | |
827 } else { | |
828 rv = SGN_Digest (privkey, digestalgtag, &signature, | |
829 digests[di]); | |
830 } | |
831 | |
832 SECKEY_DestroyPrivateKey (privkey); | |
833 | |
834 if (rv != SECSuccess) | |
835 return rv; | |
836 | |
837 rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature); | |
838 if (rv != SECSuccess) | |
839 return rv; | |
840 | |
841 SECITEM_FreeItem (&signature, PR_FALSE); | |
842 | |
843 rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg), | |
844 signalgtag, NULL); | |
845 if (rv != SECSuccess) | |
846 return SECFailure; | |
847 | |
848 /* | |
849 * Count the cert chain for this signer. | |
850 */ | |
851 if (signerinfo->certList != NULL) | |
852 certcount += signerinfo->certList->len; | |
853 } | |
854 } | |
855 | |
856 if (certs != NULL) { | |
857 for (ci = 0; certs[ci] != NULL; ci++) | |
858 certcount++; | |
859 } | |
860 | |
861 if (certlists != NULL) { | |
862 for (cli = 0; certlists[cli] != NULL; cli++) | |
863 certcount += certlists[cli]->len; | |
864 } | |
865 | |
866 if (certcount == 0) | |
867 return SECSuccess; /* signing done; no certs */ | |
868 | |
869 /* | |
870 * Combine all of the certs and cert chains into rawcerts. | |
871 * Note: certcount is an upper bound; we may not need that many slots | |
872 * but we will allocate anyway to avoid having to do another pass. | |
873 * (The temporary space saving is not worth it.) | |
874 */ | |
875 rawcerts = (SECItem**)PORT_ArenaAlloc (poolp, | |
876 (certcount + 1) * sizeof(SECItem *)); | |
877 if (rawcerts == NULL) | |
878 return SECFailure; | |
879 | |
880 /* | |
881 * XXX Want to check for duplicates and not add *any* cert that is | |
882 * already in the set. This will be more important when we start | |
883 * dealing with larger sets of certs, dual-key certs (signing and | |
884 * encryption), etc. For the time being we can slide by... | |
885 */ | |
886 rci = 0; | |
887 if (signerinfos != NULL) { | |
888 for (si = 0; signerinfos[si] != NULL; si++) { | |
889 signerinfo = signerinfos[si]; | |
890 for (ci = 0; ci < signerinfo->certList->len; ci++) | |
891 rawcerts[rci++] = &(signerinfo->certList->certs[ci]); | |
892 } | |
893 | |
894 } | |
895 | |
896 if (certs != NULL) { | |
897 for (ci = 0; certs[ci] != NULL; ci++) | |
898 rawcerts[rci++] = &(certs[ci]->derCert); | |
899 } | |
900 | |
901 if (certlists != NULL) { | |
902 for (cli = 0; certlists[cli] != NULL; cli++) { | |
903 for (ci = 0; ci < certlists[cli]->len; ci++) | |
904 rawcerts[rci++] = &(certlists[cli]->certs[ci]); | |
905 } | |
906 } | |
907 | |
908 rawcerts[rci] = NULL; | |
909 *rawcertsp = rawcerts; | |
910 | |
911 return SECSuccess; | |
912 } | |
913 | |
914 | |
915 SECStatus | |
916 SEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx, | |
917 SECKEYGetPasswordKey pwfn, void *pwfnarg) | |
918 { | |
919 SECStatus rv; | |
920 | |
921 /* | |
922 * Flush out any remaining data. | |
923 */ | |
924 rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE); | |
925 | |
926 /* | |
927 * Turn off streaming stuff. | |
928 */ | |
929 SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx); | |
930 SEC_ASN1EncoderClearStreaming (p7ecx->ecx); | |
931 | |
932 if (rv != SECSuccess) | |
933 goto loser; | |
934 | |
935 rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg); | |
936 if (rv != SECSuccess) | |
937 goto loser; | |
938 | |
939 rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0); | |
940 | |
941 loser: | |
942 SEC_ASN1EncoderFinish (p7ecx->ecx); | |
943 PORT_Free (p7ecx); | |
944 return rv; | |
945 } | |
946 | |
947 /* | |
948 * Abort the ASN.1 stream. Used by pkcs 12 | |
949 */ | |
950 void | |
951 SEC_PKCS7EncoderAbort(SEC_PKCS7EncoderContext *p7ecx, int error) | |
952 { | |
953 PORT_Assert(p7ecx); | |
954 SEC_ASN1EncoderAbort(p7ecx->ecx, error); | |
955 } | |
956 | |
957 /* | |
958 * After this routine is called, the entire PKCS7 contentInfo is ready | |
959 * to be encoded. This is used internally, but can also be called from | |
960 * elsewhere for those who want to be able to just have pointers to | |
961 * the ASN1 template for pkcs7 contentInfo built into their own encodings. | |
962 */ | |
963 SECStatus | |
964 SEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo, | |
965 PK11SymKey *bulkkey, | |
966 SECKEYGetPasswordKey pwfn, | |
967 void *pwfnarg) | |
968 { | |
969 SEC_PKCS7EncoderContext *p7ecx; | |
970 SECItem *content, *enc_content; | |
971 SECStatus rv; | |
972 | |
973 p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey); | |
974 if (p7ecx == NULL) | |
975 return SECFailure; | |
976 | |
977 content = SEC_PKCS7GetContent (cinfo); | |
978 | |
979 if (p7ecx->encryptobj != NULL) { | |
980 SECOidTag kind; | |
981 SEC_PKCS7EncryptedContentInfo *enccinfo; | |
982 | |
983 kind = SEC_PKCS7ContentType (p7ecx->cinfo); | |
984 switch (kind) { | |
985 default: | |
986 PORT_Assert (0); | |
987 rv = SECFailure; | |
988 goto loser; | |
989 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
990 enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo); | |
991 break; | |
992 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
993 enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo); | |
994 break; | |
995 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
996 enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo); | |
997 break; | |
998 } | |
999 enc_content = &(enccinfo->encContent); | |
1000 } else { | |
1001 enc_content = NULL; | |
1002 } | |
1003 | |
1004 if (content != NULL && content->data != NULL && content->len) { | |
1005 rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content, | |
1006 content->data, content->len, PR_TRUE); | |
1007 if (rv != SECSuccess) | |
1008 goto loser; | |
1009 } | |
1010 | |
1011 rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg); | |
1012 | |
1013 loser: | |
1014 PORT_Free (p7ecx); | |
1015 return rv; | |
1016 } | |
1017 | |
1018 | |
1019 /* | |
1020 * Encode a PKCS7 object, in one shot. All necessary components | |
1021 * of the object must already be specified. Either the data has | |
1022 * already been included (via SetContent), or the data is detached, | |
1023 * or there is no data at all (certs-only). | |
1024 * | |
1025 * "cinfo" specifies the object to be encoded. | |
1026 * | |
1027 * "outputfn" is where the encoded bytes will be passed. | |
1028 * | |
1029 * "outputarg" is an opaque argument to the above callback. | |
1030 * | |
1031 * "bulkkey" specifies the bulk encryption key to use. This argument | |
1032 * can be NULL if no encryption is being done, or if the bulk key should | |
1033 * be generated internally (usually the case for EnvelopedData but never | |
1034 * for EncryptedData, which *must* provide a bulk encryption key). | |
1035 * | |
1036 * "pwfn" is a callback for getting the password which protects the | |
1037 * private key of the signer. This argument can be NULL if it is known | |
1038 * that no signing is going to be done. | |
1039 * | |
1040 * "pwfnarg" is an opaque argument to the above callback. | |
1041 */ | |
1042 SECStatus | |
1043 SEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo, | |
1044 SEC_PKCS7EncoderOutputCallback outputfn, | |
1045 void *outputarg, | |
1046 PK11SymKey *bulkkey, | |
1047 SECKEYGetPasswordKey pwfn, | |
1048 void *pwfnarg) | |
1049 { | |
1050 SECStatus rv; | |
1051 | |
1052 rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg); | |
1053 if (rv == SECSuccess) { | |
1054 struct sec_pkcs7_encoder_output outputcx; | |
1055 | |
1056 outputcx.outputfn = outputfn; | |
1057 outputcx.outputarg = outputarg; | |
1058 | |
1059 rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate, | |
1060 sec_pkcs7_encoder_out, &outputcx); | |
1061 } | |
1062 | |
1063 return rv; | |
1064 } | |
1065 | |
1066 | |
1067 /* | |
1068 * Encode a PKCS7 object, in one shot. All necessary components | |
1069 * of the object must already be specified. Either the data has | |
1070 * already been included (via SetContent), or the data is detached, | |
1071 * or there is no data at all (certs-only). The output, rather than | |
1072 * being passed to an output function as is done above, is all put | |
1073 * into a SECItem. | |
1074 * | |
1075 * "pool" specifies a pool from which to allocate the result. | |
1076 * It can be NULL, in which case memory is allocated generically. | |
1077 * | |
1078 * "dest" specifies a SECItem in which to put the result data. | |
1079 * It can be NULL, in which case the entire item is allocated, too. | |
1080 * | |
1081 * "cinfo" specifies the object to be encoded. | |
1082 * | |
1083 * "bulkkey" specifies the bulk encryption key to use. This argument | |
1084 * can be NULL if no encryption is being done, or if the bulk key should | |
1085 * be generated internally (usually the case for EnvelopedData but never | |
1086 * for EncryptedData, which *must* provide a bulk encryption key). | |
1087 * | |
1088 * "pwfn" is a callback for getting the password which protects the | |
1089 * private key of the signer. This argument can be NULL if it is known | |
1090 * that no signing is going to be done. | |
1091 * | |
1092 * "pwfnarg" is an opaque argument to the above callback. | |
1093 */ | |
1094 SECItem * | |
1095 SEC_PKCS7EncodeItem (PLArenaPool *pool, | |
1096 SECItem *dest, | |
1097 SEC_PKCS7ContentInfo *cinfo, | |
1098 PK11SymKey *bulkkey, | |
1099 SECKEYGetPasswordKey pwfn, | |
1100 void *pwfnarg) | |
1101 { | |
1102 SECStatus rv; | |
1103 | |
1104 rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg); | |
1105 if (rv != SECSuccess) | |
1106 return NULL; | |
1107 | |
1108 return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate); | |
1109 } | |
1110 |