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