Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/pkcs7/p7create.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 creation. | |
7 */ | |
8 | |
9 #include "p7local.h" | |
10 | |
11 #include "cert.h" | |
12 #include "secasn1.h" | |
13 #include "secitem.h" | |
14 #include "secoid.h" | |
15 #include "pk11func.h" | |
16 #include "prtime.h" | |
17 #include "secerr.h" | |
18 #include "secder.h" | |
19 #include "secpkcs5.h" | |
20 | |
21 const int NSS_PBE_DEFAULT_ITERATION_COUNT = 2000; /* used in p12e.c too */ | |
22 | |
23 static SECStatus | |
24 sec_pkcs7_init_content_info (SEC_PKCS7ContentInfo *cinfo, PLArenaPool *poolp, | |
25 SECOidTag kind, PRBool detached) | |
26 { | |
27 void *thing; | |
28 int version; | |
29 SECItem *versionp; | |
30 SECStatus rv; | |
31 | |
32 PORT_Assert (cinfo != NULL && poolp != NULL); | |
33 if (cinfo == NULL || poolp == NULL) | |
34 return SECFailure; | |
35 | |
36 cinfo->contentTypeTag = SECOID_FindOIDByTag (kind); | |
37 PORT_Assert (cinfo->contentTypeTag | |
38 && cinfo->contentTypeTag->offset == kind); | |
39 | |
40 rv = SECITEM_CopyItem (poolp, &(cinfo->contentType), | |
41 &(cinfo->contentTypeTag->oid)); | |
42 if (rv != SECSuccess) | |
43 return rv; | |
44 | |
45 if (detached) | |
46 return SECSuccess; | |
47 | |
48 switch (kind) { | |
49 default: | |
50 case SEC_OID_PKCS7_DATA: | |
51 thing = PORT_ArenaZAlloc (poolp, sizeof(SECItem)); | |
52 cinfo->content.data = (SECItem*)thing; | |
53 versionp = NULL; | |
54 version = -1; | |
55 break; | |
56 case SEC_OID_PKCS7_DIGESTED_DATA: | |
57 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7DigestedData)); | |
58 cinfo->content.digestedData = (SEC_PKCS7DigestedData*)thing; | |
59 versionp = &(cinfo->content.digestedData->version); | |
60 version = SEC_PKCS7_DIGESTED_DATA_VERSION; | |
61 break; | |
62 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
63 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EncryptedData)); | |
64 cinfo->content.encryptedData = (SEC_PKCS7EncryptedData*)thing; | |
65 versionp = &(cinfo->content.encryptedData->version); | |
66 version = SEC_PKCS7_ENCRYPTED_DATA_VERSION; | |
67 break; | |
68 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
69 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7EnvelopedData)); | |
70 cinfo->content.envelopedData = | |
71 (SEC_PKCS7EnvelopedData*)thing; | |
72 versionp = &(cinfo->content.envelopedData->version); | |
73 version = SEC_PKCS7_ENVELOPED_DATA_VERSION; | |
74 break; | |
75 case SEC_OID_PKCS7_SIGNED_DATA: | |
76 thing = PORT_ArenaZAlloc (poolp, sizeof(SEC_PKCS7SignedData)); | |
77 cinfo->content.signedData = | |
78 (SEC_PKCS7SignedData*)thing; | |
79 versionp = &(cinfo->content.signedData->version); | |
80 version = SEC_PKCS7_SIGNED_DATA_VERSION; | |
81 break; | |
82 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
83 thing = PORT_ArenaZAlloc(poolp,sizeof(SEC_PKCS7SignedAndEnvelopedData)); | |
84 cinfo->content.signedAndEnvelopedData = | |
85 (SEC_PKCS7SignedAndEnvelopedData*)thing; | |
86 versionp = &(cinfo->content.signedAndEnvelopedData->version); | |
87 version = SEC_PKCS7_SIGNED_AND_ENVELOPED_DATA_VERSION; | |
88 break; | |
89 } | |
90 | |
91 if (thing == NULL) | |
92 return SECFailure; | |
93 | |
94 if (versionp != NULL) { | |
95 SECItem *dummy; | |
96 | |
97 PORT_Assert (version >= 0); | |
98 dummy = SEC_ASN1EncodeInteger (poolp, versionp, version); | |
99 if (dummy == NULL) | |
100 return SECFailure; | |
101 PORT_Assert (dummy == versionp); | |
102 } | |
103 | |
104 return SECSuccess; | |
105 } | |
106 | |
107 | |
108 static SEC_PKCS7ContentInfo * | |
109 sec_pkcs7_create_content_info (SECOidTag kind, PRBool detached, | |
110 SECKEYGetPasswordKey pwfn, void *pwfn_arg) | |
111 { | |
112 SEC_PKCS7ContentInfo *cinfo; | |
113 PLArenaPool *poolp; | |
114 SECStatus rv; | |
115 | |
116 poolp = PORT_NewArena (1024); /* XXX what is right value? */ | |
117 if (poolp == NULL) | |
118 return NULL; | |
119 | |
120 cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo)); | |
121 if (cinfo == NULL) { | |
122 PORT_FreeArena (poolp, PR_FALSE); | |
123 return NULL; | |
124 } | |
125 | |
126 cinfo->poolp = poolp; | |
127 cinfo->pwfn = pwfn; | |
128 cinfo->pwfn_arg = pwfn_arg; | |
129 cinfo->created = PR_TRUE; | |
130 cinfo->refCount = 1; | |
131 | |
132 rv = sec_pkcs7_init_content_info (cinfo, poolp, kind, detached); | |
133 if (rv != SECSuccess) { | |
134 PORT_FreeArena (poolp, PR_FALSE); | |
135 return NULL; | |
136 } | |
137 | |
138 return cinfo; | |
139 } | |
140 | |
141 | |
142 /* | |
143 * Add a signer to a PKCS7 thing, verifying the signature cert first. | |
144 * Any error returns SECFailure. | |
145 * | |
146 * XXX Right now this only adds the *first* signer. It fails if you try | |
147 * to add a second one -- this needs to be fixed. | |
148 */ | |
149 static SECStatus | |
150 sec_pkcs7_add_signer (SEC_PKCS7ContentInfo *cinfo, | |
151 CERTCertificate * cert, | |
152 SECCertUsage certusage, | |
153 CERTCertDBHandle * certdb, | |
154 SECOidTag digestalgtag, | |
155 SECItem * digestdata) | |
156 { | |
157 SEC_PKCS7SignerInfo *signerinfo, **signerinfos, ***signerinfosp; | |
158 SECAlgorithmID *digestalg, **digestalgs, ***digestalgsp; | |
159 SECItem *digest, **digests, ***digestsp; | |
160 SECItem * dummy; | |
161 void * mark; | |
162 SECStatus rv; | |
163 SECOidTag kind; | |
164 | |
165 kind = SEC_PKCS7ContentType (cinfo); | |
166 switch (kind) { | |
167 case SEC_OID_PKCS7_SIGNED_DATA: | |
168 { | |
169 SEC_PKCS7SignedData *sdp; | |
170 | |
171 sdp = cinfo->content.signedData; | |
172 digestalgsp = &(sdp->digestAlgorithms); | |
173 digestsp = &(sdp->digests); | |
174 signerinfosp = &(sdp->signerInfos); | |
175 } | |
176 break; | |
177 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
178 { | |
179 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
180 | |
181 saedp = cinfo->content.signedAndEnvelopedData; | |
182 digestalgsp = &(saedp->digestAlgorithms); | |
183 digestsp = &(saedp->digests); | |
184 signerinfosp = &(saedp->signerInfos); | |
185 } | |
186 break; | |
187 default: | |
188 return SECFailure; /* XXX set an error? */ | |
189 } | |
190 | |
191 /* | |
192 * XXX I think that CERT_VerifyCert should do this if *it* is passed | |
193 * a NULL database. | |
194 */ | |
195 if (certdb == NULL) { | |
196 certdb = CERT_GetDefaultCertDB(); | |
197 if (certdb == NULL) | |
198 return SECFailure; /* XXX set an error? */ | |
199 } | |
200 | |
201 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(), | |
202 cinfo->pwfn_arg, NULL) != SECSuccess) | |
203 { | |
204 /* XXX Did CERT_VerifyCert set an error? */ | |
205 return SECFailure; | |
206 } | |
207 | |
208 /* | |
209 * XXX This is the check that we do not already have a signer. | |
210 * This is not what we really want -- we want to allow this | |
211 * and *add* the new signer. | |
212 */ | |
213 PORT_Assert (*signerinfosp == NULL | |
214 && *digestalgsp == NULL && *digestsp == NULL); | |
215 if (*signerinfosp != NULL || *digestalgsp != NULL || *digestsp != NULL) | |
216 return SECFailure; | |
217 | |
218 mark = PORT_ArenaMark (cinfo->poolp); | |
219 | |
220 signerinfo = (SEC_PKCS7SignerInfo*)PORT_ArenaZAlloc (cinfo->poolp, | |
221 sizeof(SEC_PKCS7SignerInfo)); | |
222 if (signerinfo == NULL) { | |
223 PORT_ArenaRelease (cinfo->poolp, mark); | |
224 return SECFailure; | |
225 } | |
226 | |
227 dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &signerinfo->version, | |
228 SEC_PKCS7_SIGNER_INFO_VERSION); | |
229 if (dummy == NULL) { | |
230 PORT_ArenaRelease (cinfo->poolp, mark); | |
231 return SECFailure; | |
232 } | |
233 PORT_Assert (dummy == &signerinfo->version); | |
234 | |
235 signerinfo->cert = CERT_DupCertificate (cert); | |
236 if (signerinfo->cert == NULL) { | |
237 PORT_ArenaRelease (cinfo->poolp, mark); | |
238 return SECFailure; | |
239 } | |
240 | |
241 signerinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert); | |
242 if (signerinfo->issuerAndSN == NULL) { | |
243 PORT_ArenaRelease (cinfo->poolp, mark); | |
244 return SECFailure; | |
245 } | |
246 | |
247 rv = SECOID_SetAlgorithmID (cinfo->poolp, &signerinfo->digestAlg, | |
248 digestalgtag, NULL); | |
249 if (rv != SECSuccess) { | |
250 PORT_ArenaRelease (cinfo->poolp, mark); | |
251 return SECFailure; | |
252 } | |
253 | |
254 /* | |
255 * Okay, now signerinfo is all set. We just need to put it and its | |
256 * companions (another copy of the digest algorithm, and the digest | |
257 * itself if given) into the main structure. | |
258 * | |
259 * XXX If we are handling more than one signer, the following code | |
260 * needs to look through the digest algorithms already specified | |
261 * and see if the same one is there already. If it is, it does not | |
262 * need to be added again. Also, if it is there *and* the digest | |
263 * is not null, then the digest given should match the digest already | |
264 * specified -- if not, that is an error. Finally, the new signerinfo | |
265 * should be *added* to the set already found. | |
266 */ | |
267 | |
268 signerinfos = (SEC_PKCS7SignerInfo**)PORT_ArenaAlloc (cinfo->poolp, | |
269 2 * sizeof(SEC_PKCS7SignerInfo *)); | |
270 if (signerinfos == NULL) { | |
271 PORT_ArenaRelease (cinfo->poolp, mark); | |
272 return SECFailure; | |
273 } | |
274 signerinfos[0] = signerinfo; | |
275 signerinfos[1] = NULL; | |
276 | |
277 digestalg = PORT_ArenaZAlloc (cinfo->poolp, sizeof(SECAlgorithmID)); | |
278 digestalgs = PORT_ArenaAlloc (cinfo->poolp, 2 * sizeof(SECAlgorithmID *)); | |
279 if (digestalg == NULL || digestalgs == NULL) { | |
280 PORT_ArenaRelease (cinfo->poolp, mark); | |
281 return SECFailure; | |
282 } | |
283 rv = SECOID_SetAlgorithmID (cinfo->poolp, digestalg, digestalgtag, NULL); | |
284 if (rv != SECSuccess) { | |
285 PORT_ArenaRelease (cinfo->poolp, mark); | |
286 return SECFailure; | |
287 } | |
288 digestalgs[0] = digestalg; | |
289 digestalgs[1] = NULL; | |
290 | |
291 if (digestdata != NULL) { | |
292 digest = (SECItem*)PORT_ArenaAlloc (cinfo->poolp, sizeof(SECItem)); | |
293 digests = (SECItem**)PORT_ArenaAlloc (cinfo->poolp, | |
294 2 * sizeof(SECItem *)); | |
295 if (digest == NULL || digests == NULL) { | |
296 PORT_ArenaRelease (cinfo->poolp, mark); | |
297 return SECFailure; | |
298 } | |
299 rv = SECITEM_CopyItem (cinfo->poolp, digest, digestdata); | |
300 if (rv != SECSuccess) { | |
301 PORT_ArenaRelease (cinfo->poolp, mark); | |
302 return SECFailure; | |
303 } | |
304 digests[0] = digest; | |
305 digests[1] = NULL; | |
306 } else { | |
307 digests = NULL; | |
308 } | |
309 | |
310 *signerinfosp = signerinfos; | |
311 *digestalgsp = digestalgs; | |
312 *digestsp = digests; | |
313 | |
314 PORT_ArenaUnmark(cinfo->poolp, mark); | |
315 return SECSuccess; | |
316 } | |
317 | |
318 | |
319 /* | |
320 * Helper function for creating an empty signedData. | |
321 */ | |
322 static SEC_PKCS7ContentInfo * | |
323 sec_pkcs7_create_signed_data (SECKEYGetPasswordKey pwfn, void *pwfn_arg) | |
324 { | |
325 SEC_PKCS7ContentInfo *cinfo; | |
326 SEC_PKCS7SignedData *sigd; | |
327 SECStatus rv; | |
328 | |
329 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_SIGNED_DATA, PR_FALSE, | |
330 pwfn, pwfn_arg); | |
331 if (cinfo == NULL) | |
332 return NULL; | |
333 | |
334 sigd = cinfo->content.signedData; | |
335 PORT_Assert (sigd != NULL); | |
336 | |
337 /* | |
338 * XXX Might we want to allow content types other than data? | |
339 * If so, via what interface? | |
340 */ | |
341 rv = sec_pkcs7_init_content_info (&(sigd->contentInfo), cinfo->poolp, | |
342 SEC_OID_PKCS7_DATA, PR_TRUE); | |
343 if (rv != SECSuccess) { | |
344 SEC_PKCS7DestroyContentInfo (cinfo); | |
345 return NULL; | |
346 } | |
347 | |
348 return cinfo; | |
349 } | |
350 | |
351 | |
352 /* | |
353 * Start a PKCS7 signing context. | |
354 * | |
355 * "cert" is the cert that will be used to sign the data. It will be | |
356 * checked for validity. | |
357 * | |
358 * "certusage" describes the signing usage (e.g. certUsageEmailSigner) | |
359 * XXX Maybe SECCertUsage should be split so that our caller just says | |
360 * "email" and *we* add the "signing" part -- otherwise our caller | |
361 * could be lying about the usage; we do not want to allow encryption | |
362 * certs for signing or vice versa. | |
363 * | |
364 * "certdb" is the cert database to use for verifying the cert. | |
365 * It can be NULL if a default database is available (like in the client). | |
366 * | |
367 * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1). | |
368 * | |
369 * "digest" is the actual digest of the data. It must be provided in | |
370 * the case of detached data or NULL if the content will be included. | |
371 * | |
372 * The return value can be passed to functions which add things to | |
373 * it like attributes, then eventually to SEC_PKCS7Encode() or to | |
374 * SEC_PKCS7EncoderStart() to create the encoded data, and finally to | |
375 * SEC_PKCS7DestroyContentInfo(). | |
376 * | |
377 * An error results in a return value of NULL and an error set. | |
378 * (Retrieve specific errors via PORT_GetError()/XP_GetError().) | |
379 */ | |
380 SEC_PKCS7ContentInfo * | |
381 SEC_PKCS7CreateSignedData (CERTCertificate *cert, | |
382 SECCertUsage certusage, | |
383 CERTCertDBHandle *certdb, | |
384 SECOidTag digestalg, | |
385 SECItem *digest, | |
386 SECKEYGetPasswordKey pwfn, void *pwfn_arg) | |
387 { | |
388 SEC_PKCS7ContentInfo *cinfo; | |
389 SECStatus rv; | |
390 | |
391 cinfo = sec_pkcs7_create_signed_data (pwfn, pwfn_arg); | |
392 if (cinfo == NULL) | |
393 return NULL; | |
394 | |
395 rv = sec_pkcs7_add_signer (cinfo, cert, certusage, certdb, | |
396 digestalg, digest); | |
397 if (rv != SECSuccess) { | |
398 SEC_PKCS7DestroyContentInfo (cinfo); | |
399 return NULL; | |
400 } | |
401 | |
402 return cinfo; | |
403 } | |
404 | |
405 | |
406 static SEC_PKCS7Attribute * | |
407 sec_pkcs7_create_attribute (PLArenaPool *poolp, SECOidTag oidtag, | |
408 SECItem *value, PRBool encoded) | |
409 { | |
410 SEC_PKCS7Attribute *attr; | |
411 SECItem **values; | |
412 void *mark; | |
413 | |
414 PORT_Assert (poolp != NULL); | |
415 mark = PORT_ArenaMark (poolp); | |
416 | |
417 attr = (SEC_PKCS7Attribute*)PORT_ArenaAlloc (poolp, | |
418 sizeof(SEC_PKCS7Attribute)); | |
419 if (attr == NULL) | |
420 goto loser; | |
421 | |
422 attr->typeTag = SECOID_FindOIDByTag (oidtag); | |
423 if (attr->typeTag == NULL) | |
424 goto loser; | |
425 | |
426 if (SECITEM_CopyItem (poolp, &(attr->type), | |
427 &(attr->typeTag->oid)) != SECSuccess) | |
428 goto loser; | |
429 | |
430 values = (SECItem**)PORT_ArenaAlloc (poolp, 2 * sizeof(SECItem *)); | |
431 if (values == NULL) | |
432 goto loser; | |
433 | |
434 if (value != NULL) { | |
435 SECItem *copy; | |
436 | |
437 copy = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem)); | |
438 if (copy == NULL) | |
439 goto loser; | |
440 | |
441 if (SECITEM_CopyItem (poolp, copy, value) != SECSuccess) | |
442 goto loser; | |
443 | |
444 value = copy; | |
445 } | |
446 | |
447 values[0] = value; | |
448 values[1] = NULL; | |
449 attr->values = values; | |
450 attr->encoded = encoded; | |
451 | |
452 PORT_ArenaUnmark (poolp, mark); | |
453 return attr; | |
454 | |
455 loser: | |
456 PORT_Assert (mark != NULL); | |
457 PORT_ArenaRelease (poolp, mark); | |
458 return NULL; | |
459 } | |
460 | |
461 | |
462 static SECStatus | |
463 sec_pkcs7_add_attribute (SEC_PKCS7ContentInfo *cinfo, | |
464 SEC_PKCS7Attribute ***attrsp, | |
465 SEC_PKCS7Attribute *attr) | |
466 { | |
467 SEC_PKCS7Attribute **attrs; | |
468 SECItem *ct_value; | |
469 void *mark; | |
470 | |
471 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA); | |
472 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA) | |
473 return SECFailure; | |
474 | |
475 attrs = *attrsp; | |
476 if (attrs != NULL) { | |
477 int count; | |
478 | |
479 /* | |
480 * We already have some attributes, and just need to add this | |
481 * new one. | |
482 */ | |
483 | |
484 /* | |
485 * We should already have the *required* attributes, which were | |
486 * created/added at the same time the first attribute was added. | |
487 */ | |
488 PORT_Assert (sec_PKCS7FindAttribute (attrs, | |
489 SEC_OID_PKCS9_CONTENT_TYPE, | |
490 PR_FALSE) != NULL); | |
491 PORT_Assert (sec_PKCS7FindAttribute (attrs, | |
492 SEC_OID_PKCS9_MESSAGE_DIGEST, | |
493 PR_FALSE) != NULL); | |
494 | |
495 for (count = 0; attrs[count] != NULL; count++) | |
496 ; | |
497 attrs = (SEC_PKCS7Attribute**)PORT_ArenaGrow (cinfo->poolp, attrs, | |
498 (count + 1) * sizeof(SEC_PKCS7Attribute *), | |
499 (count + 2) * sizeof(SEC_PKCS7Attribute *)); | |
500 if (attrs == NULL) | |
501 return SECFailure; | |
502 | |
503 attrs[count] = attr; | |
504 attrs[count+1] = NULL; | |
505 *attrsp = attrs; | |
506 | |
507 return SECSuccess; | |
508 } | |
509 | |
510 /* | |
511 * This is the first time an attribute is going in. | |
512 * We need to create and add the required attributes, and then | |
513 * we will also add in the one our caller gave us. | |
514 */ | |
515 | |
516 /* | |
517 * There are 2 required attributes, plus the one our caller wants | |
518 * to add, plus we always end with a NULL one. Thus, four slots. | |
519 */ | |
520 attrs = (SEC_PKCS7Attribute**)PORT_ArenaAlloc (cinfo->poolp, | |
521 4 * sizeof(SEC_PKCS7Attribute *)); | |
522 if (attrs == NULL) | |
523 return SECFailure; | |
524 | |
525 mark = PORT_ArenaMark (cinfo->poolp); | |
526 | |
527 /* | |
528 * First required attribute is the content type of the data | |
529 * being signed. | |
530 */ | |
531 ct_value = &(cinfo->content.signedData->contentInfo.contentType); | |
532 attrs[0] = sec_pkcs7_create_attribute (cinfo->poolp, | |
533 SEC_OID_PKCS9_CONTENT_TYPE, | |
534 ct_value, PR_FALSE); | |
535 /* | |
536 * Second required attribute is the message digest of the data | |
537 * being signed; we leave the value NULL for now (just create | |
538 * the place for it to go), and the encoder will fill it in later. | |
539 */ | |
540 attrs[1] = sec_pkcs7_create_attribute (cinfo->poolp, | |
541 SEC_OID_PKCS9_MESSAGE_DIGEST, | |
542 NULL, PR_FALSE); | |
543 if (attrs[0] == NULL || attrs[1] == NULL) { | |
544 PORT_ArenaRelease (cinfo->poolp, mark); | |
545 return SECFailure; | |
546 } | |
547 | |
548 attrs[2] = attr; | |
549 attrs[3] = NULL; | |
550 *attrsp = attrs; | |
551 | |
552 PORT_ArenaUnmark (cinfo->poolp, mark); | |
553 return SECSuccess; | |
554 } | |
555 | |
556 | |
557 /* | |
558 * Add the signing time to the authenticated (i.e. signed) attributes | |
559 * of "cinfo". This is expected to be included in outgoing signed | |
560 * messages for email (S/MIME) but is likely useful in other situations. | |
561 * | |
562 * This should only be added once; a second call will either do | |
563 * nothing or replace an old signing time with a newer one. | |
564 * | |
565 * XXX This will probably just shove the current time into "cinfo" | |
566 * but it will not actually get signed until the entire item is | |
567 * processed for encoding. Is this (expected to be small) delay okay? | |
568 * | |
569 * "cinfo" should be of type signedData (the only kind of pkcs7 data | |
570 * that is allowed authenticated attributes); SECFailure will be returned | |
571 * if it is not. | |
572 */ | |
573 SECStatus | |
574 SEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo) | |
575 { | |
576 SEC_PKCS7SignerInfo **signerinfos; | |
577 SEC_PKCS7Attribute *attr; | |
578 SECItem stime; | |
579 SECStatus rv; | |
580 int si; | |
581 | |
582 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA); | |
583 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA) | |
584 return SECFailure; | |
585 | |
586 signerinfos = cinfo->content.signedData->signerInfos; | |
587 | |
588 /* There has to be a signer, or it makes no sense. */ | |
589 if (signerinfos == NULL || signerinfos[0] == NULL) | |
590 return SECFailure; | |
591 | |
592 rv = DER_EncodeTimeChoice(NULL, &stime, PR_Now()); | |
593 if (rv != SECSuccess) | |
594 return rv; | |
595 | |
596 attr = sec_pkcs7_create_attribute (cinfo->poolp, | |
597 SEC_OID_PKCS9_SIGNING_TIME, | |
598 &stime, PR_FALSE); | |
599 SECITEM_FreeItem (&stime, PR_FALSE); | |
600 | |
601 if (attr == NULL) | |
602 return SECFailure; | |
603 | |
604 rv = SECSuccess; | |
605 for (si = 0; signerinfos[si] != NULL; si++) { | |
606 SEC_PKCS7Attribute *oattr; | |
607 | |
608 oattr = sec_PKCS7FindAttribute (signerinfos[si]->authAttr, | |
609 SEC_OID_PKCS9_SIGNING_TIME, PR_FALSE); | |
610 PORT_Assert (oattr == NULL); | |
611 if (oattr != NULL) | |
612 continue; /* XXX or would it be better to replace it? */ | |
613 | |
614 rv = sec_pkcs7_add_attribute (cinfo, &(signerinfos[si]->authAttr), | |
615 attr); | |
616 if (rv != SECSuccess) | |
617 break; /* could try to continue, but may as well give up now */ | |
618 } | |
619 | |
620 return rv; | |
621 } | |
622 | |
623 | |
624 /* | |
625 * Add the specified attribute to the authenticated (i.e. signed) attributes | |
626 * of "cinfo" -- "oidtag" describes the attribute and "value" is the | |
627 * value to be associated with it. NOTE! "value" must already be encoded; | |
628 * no interpretation of "oidtag" is done. Also, it is assumed that this | |
629 * signedData has only one signer -- if we ever need to add attributes | |
630 * when there is more than one signature, we need a way to specify *which* | |
631 * signature should get the attribute. | |
632 * | |
633 * XXX Technically, a signed attribute can have multiple values; if/when | |
634 * we ever need to support an attribute which takes multiple values, we | |
635 * either need to change this interface or create an AddSignedAttributeValue | |
636 * which can be called subsequently, and would then append a value. | |
637 * | |
638 * "cinfo" should be of type signedData (the only kind of pkcs7 data | |
639 * that is allowed authenticated attributes); SECFailure will be returned | |
640 * if it is not. | |
641 */ | |
642 SECStatus | |
643 SEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo, | |
644 SECOidTag oidtag, | |
645 SECItem *value) | |
646 { | |
647 SEC_PKCS7SignerInfo **signerinfos; | |
648 SEC_PKCS7Attribute *attr; | |
649 | |
650 PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA); | |
651 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA) | |
652 return SECFailure; | |
653 | |
654 signerinfos = cinfo->content.signedData->signerInfos; | |
655 | |
656 /* | |
657 * No signature or more than one means no deal. | |
658 */ | |
659 if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL) | |
660 return SECFailure; | |
661 | |
662 attr = sec_pkcs7_create_attribute (cinfo->poolp, oidtag, value, PR_TRUE); | |
663 if (attr == NULL) | |
664 return SECFailure; | |
665 | |
666 return sec_pkcs7_add_attribute (cinfo, &(signerinfos[0]->authAttr), attr); | |
667 } | |
668 | |
669 | |
670 /* | |
671 * Mark that the signer certificates and their issuing chain should | |
672 * be included in the encoded data. This is expected to be used | |
673 * in outgoing signed messages for email (S/MIME). | |
674 * | |
675 * "certdb" is the cert database to use for finding the chain. | |
676 * It can be NULL, meaning use the default database. | |
677 * | |
678 * "cinfo" should be of type signedData or signedAndEnvelopedData; | |
679 * SECFailure will be returned if it is not. | |
680 */ | |
681 SECStatus | |
682 SEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo, | |
683 CERTCertDBHandle *certdb) | |
684 { | |
685 SECOidTag kind; | |
686 SEC_PKCS7SignerInfo *signerinfo, **signerinfos; | |
687 | |
688 kind = SEC_PKCS7ContentType (cinfo); | |
689 switch (kind) { | |
690 case SEC_OID_PKCS7_SIGNED_DATA: | |
691 signerinfos = cinfo->content.signedData->signerInfos; | |
692 break; | |
693 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
694 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos; | |
695 break; | |
696 default: | |
697 return SECFailure; /* XXX set an error? */ | |
698 } | |
699 | |
700 if (signerinfos == NULL) /* no signer, no certs? */ | |
701 return SECFailure; /* XXX set an error? */ | |
702 | |
703 if (certdb == NULL) { | |
704 certdb = CERT_GetDefaultCertDB(); | |
705 if (certdb == NULL) { | |
706 PORT_SetError (SEC_ERROR_BAD_DATABASE); | |
707 return SECFailure; | |
708 } | |
709 } | |
710 | |
711 /* XXX Should it be an error if we find no signerinfo or no certs? */ | |
712 while ((signerinfo = *signerinfos++) != NULL) { | |
713 if (signerinfo->cert != NULL) | |
714 /* get the cert chain. don't send the root to avoid contamination | |
715 * of old clients with a new root that they don't trust | |
716 */ | |
717 signerinfo->certList = CERT_CertChainFromCert (signerinfo->cert, | |
718 certUsageEmailSigner, | |
719 PR_FALSE); | |
720 } | |
721 | |
722 return SECSuccess; | |
723 } | |
724 | |
725 | |
726 /* | |
727 * Helper function to add a certificate chain for inclusion in the | |
728 * bag of certificates in a signedData. | |
729 */ | |
730 static SECStatus | |
731 sec_pkcs7_add_cert_chain (SEC_PKCS7ContentInfo *cinfo, | |
732 CERTCertificate *cert, | |
733 CERTCertDBHandle *certdb) | |
734 { | |
735 SECOidTag kind; | |
736 CERTCertificateList *certlist, **certlists, ***certlistsp; | |
737 int count; | |
738 | |
739 kind = SEC_PKCS7ContentType (cinfo); | |
740 switch (kind) { | |
741 case SEC_OID_PKCS7_SIGNED_DATA: | |
742 { | |
743 SEC_PKCS7SignedData *sdp; | |
744 | |
745 sdp = cinfo->content.signedData; | |
746 certlistsp = &(sdp->certLists); | |
747 } | |
748 break; | |
749 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
750 { | |
751 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
752 | |
753 saedp = cinfo->content.signedAndEnvelopedData; | |
754 certlistsp = &(saedp->certLists); | |
755 } | |
756 break; | |
757 default: | |
758 return SECFailure; /* XXX set an error? */ | |
759 } | |
760 | |
761 if (certdb == NULL) { | |
762 certdb = CERT_GetDefaultCertDB(); | |
763 if (certdb == NULL) { | |
764 PORT_SetError (SEC_ERROR_BAD_DATABASE); | |
765 return SECFailure; | |
766 } | |
767 } | |
768 | |
769 certlist = CERT_CertChainFromCert (cert, certUsageEmailSigner, PR_FALSE); | |
770 if (certlist == NULL) | |
771 return SECFailure; | |
772 | |
773 certlists = *certlistsp; | |
774 if (certlists == NULL) { | |
775 count = 0; | |
776 certlists = (CERTCertificateList**)PORT_ArenaAlloc (cinfo->poolp, | |
777 2 * sizeof(CERTCertificateList *)); | |
778 } else { | |
779 for (count = 0; certlists[count] != NULL; count++) | |
780 ; | |
781 PORT_Assert (count); /* should be at least one already */ | |
782 certlists = (CERTCertificateList**)PORT_ArenaGrow (cinfo->poolp, | |
783 certlists, | |
784 (count + 1) * sizeof(CERTCertificateList *), | |
785 (count + 2) * sizeof(CERTCertificateList *)); | |
786 } | |
787 | |
788 if (certlists == NULL) { | |
789 CERT_DestroyCertificateList (certlist); | |
790 return SECFailure; | |
791 } | |
792 | |
793 certlists[count] = certlist; | |
794 certlists[count + 1] = NULL; | |
795 | |
796 *certlistsp = certlists; | |
797 | |
798 return SECSuccess; | |
799 } | |
800 | |
801 | |
802 /* | |
803 * Helper function to add a certificate for inclusion in the bag of | |
804 * certificates in a signedData. | |
805 */ | |
806 static SECStatus | |
807 sec_pkcs7_add_certificate (SEC_PKCS7ContentInfo *cinfo, | |
808 CERTCertificate *cert) | |
809 { | |
810 SECOidTag kind; | |
811 CERTCertificate **certs, ***certsp; | |
812 int count; | |
813 | |
814 kind = SEC_PKCS7ContentType (cinfo); | |
815 switch (kind) { | |
816 case SEC_OID_PKCS7_SIGNED_DATA: | |
817 { | |
818 SEC_PKCS7SignedData *sdp; | |
819 | |
820 sdp = cinfo->content.signedData; | |
821 certsp = &(sdp->certs); | |
822 } | |
823 break; | |
824 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
825 { | |
826 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
827 | |
828 saedp = cinfo->content.signedAndEnvelopedData; | |
829 certsp = &(saedp->certs); | |
830 } | |
831 break; | |
832 default: | |
833 return SECFailure; /* XXX set an error? */ | |
834 } | |
835 | |
836 cert = CERT_DupCertificate (cert); | |
837 if (cert == NULL) | |
838 return SECFailure; | |
839 | |
840 certs = *certsp; | |
841 if (certs == NULL) { | |
842 count = 0; | |
843 certs = (CERTCertificate**)PORT_ArenaAlloc (cinfo->poolp, | |
844 2 * sizeof(CERTCertificate *)); | |
845 } else { | |
846 for (count = 0; certs[count] != NULL; count++) | |
847 ; | |
848 PORT_Assert (count); /* should be at least one already */ | |
849 certs = (CERTCertificate**)PORT_ArenaGrow (cinfo->poolp, certs, | |
850 (count + 1) * sizeof(CERTCertificate *), | |
851 (count + 2) * sizeof(CERTCertificate *)); | |
852 } | |
853 | |
854 if (certs == NULL) { | |
855 CERT_DestroyCertificate (cert); | |
856 return SECFailure; | |
857 } | |
858 | |
859 certs[count] = cert; | |
860 certs[count + 1] = NULL; | |
861 | |
862 *certsp = certs; | |
863 | |
864 return SECSuccess; | |
865 } | |
866 | |
867 | |
868 /* | |
869 * Create a PKCS7 certs-only container. | |
870 * | |
871 * "cert" is the (first) cert that will be included. | |
872 * | |
873 * "include_chain" specifies whether the entire chain for "cert" should | |
874 * be included. | |
875 * | |
876 * "certdb" is the cert database to use for finding the chain. | |
877 * It can be NULL in when "include_chain" is false, or when meaning | |
878 * use the default database. | |
879 * | |
880 * More certs and chains can be added via AddCertificate and AddCertChain. | |
881 * | |
882 * An error results in a return value of NULL and an error set. | |
883 * (Retrieve specific errors via PORT_GetError()/XP_GetError().) | |
884 */ | |
885 SEC_PKCS7ContentInfo * | |
886 SEC_PKCS7CreateCertsOnly (CERTCertificate *cert, | |
887 PRBool include_chain, | |
888 CERTCertDBHandle *certdb) | |
889 { | |
890 SEC_PKCS7ContentInfo *cinfo; | |
891 SECStatus rv; | |
892 | |
893 cinfo = sec_pkcs7_create_signed_data (NULL, NULL); | |
894 if (cinfo == NULL) | |
895 return NULL; | |
896 | |
897 if (include_chain) | |
898 rv = sec_pkcs7_add_cert_chain (cinfo, cert, certdb); | |
899 else | |
900 rv = sec_pkcs7_add_certificate (cinfo, cert); | |
901 | |
902 if (rv != SECSuccess) { | |
903 SEC_PKCS7DestroyContentInfo (cinfo); | |
904 return NULL; | |
905 } | |
906 | |
907 return cinfo; | |
908 } | |
909 | |
910 | |
911 /* | |
912 * Add "cert" and its entire chain to the set of certs included in "cinfo". | |
913 * | |
914 * "certdb" is the cert database to use for finding the chain. | |
915 * It can be NULL, meaning use the default database. | |
916 * | |
917 * "cinfo" should be of type signedData or signedAndEnvelopedData; | |
918 * SECFailure will be returned if it is not. | |
919 */ | |
920 SECStatus | |
921 SEC_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo, | |
922 CERTCertificate *cert, | |
923 CERTCertDBHandle *certdb) | |
924 { | |
925 SECOidTag kind; | |
926 | |
927 kind = SEC_PKCS7ContentType (cinfo); | |
928 if (kind != SEC_OID_PKCS7_SIGNED_DATA | |
929 && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA) | |
930 return SECFailure; /* XXX set an error? */ | |
931 | |
932 return sec_pkcs7_add_cert_chain (cinfo, cert, certdb); | |
933 } | |
934 | |
935 | |
936 /* | |
937 * Add "cert" to the set of certs included in "cinfo". | |
938 * | |
939 * "cinfo" should be of type signedData or signedAndEnvelopedData; | |
940 * SECFailure will be returned if it is not. | |
941 */ | |
942 SECStatus | |
943 SEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert) | |
944 { | |
945 SECOidTag kind; | |
946 | |
947 kind = SEC_PKCS7ContentType (cinfo); | |
948 if (kind != SEC_OID_PKCS7_SIGNED_DATA | |
949 && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA) | |
950 return SECFailure; /* XXX set an error? */ | |
951 | |
952 return sec_pkcs7_add_certificate (cinfo, cert); | |
953 } | |
954 | |
955 | |
956 static SECStatus | |
957 sec_pkcs7_init_encrypted_content_info (SEC_PKCS7EncryptedContentInfo *enccinfo, | |
958 PLArenaPool *poolp, | |
959 SECOidTag kind, PRBool detached, | |
960 SECOidTag encalg, int keysize) | |
961 { | |
962 SECStatus rv; | |
963 | |
964 PORT_Assert (enccinfo != NULL && poolp != NULL); | |
965 if (enccinfo == NULL || poolp == NULL) | |
966 return SECFailure; | |
967 | |
968 /* | |
969 * XXX Some day we may want to allow for other kinds. That needs | |
970 * more work and modifications to the creation interface, etc. | |
971 * For now, allow but notice callers who pass in other kinds. | |
972 * They are responsible for creating the inner type and encoding, | |
973 * if it is other than DATA. | |
974 */ | |
975 PORT_Assert (kind == SEC_OID_PKCS7_DATA); | |
976 | |
977 enccinfo->contentTypeTag = SECOID_FindOIDByTag (kind); | |
978 PORT_Assert (enccinfo->contentTypeTag | |
979 && enccinfo->contentTypeTag->offset == kind); | |
980 | |
981 rv = SECITEM_CopyItem (poolp, &(enccinfo->contentType), | |
982 &(enccinfo->contentTypeTag->oid)); | |
983 if (rv != SECSuccess) | |
984 return rv; | |
985 | |
986 /* Save keysize and algorithm for later. */ | |
987 enccinfo->keysize = keysize; | |
988 enccinfo->encalg = encalg; | |
989 | |
990 return SECSuccess; | |
991 } | |
992 | |
993 | |
994 /* | |
995 * Add a recipient to a PKCS7 thing, verifying their cert first. | |
996 * Any error returns SECFailure. | |
997 */ | |
998 static SECStatus | |
999 sec_pkcs7_add_recipient (SEC_PKCS7ContentInfo *cinfo, | |
1000 CERTCertificate *cert, | |
1001 SECCertUsage certusage, | |
1002 CERTCertDBHandle *certdb) | |
1003 { | |
1004 SECOidTag kind; | |
1005 SEC_PKCS7RecipientInfo *recipientinfo, **recipientinfos, ***recipientinfosp; | |
1006 SECItem *dummy; | |
1007 void *mark; | |
1008 int count; | |
1009 | |
1010 kind = SEC_PKCS7ContentType (cinfo); | |
1011 switch (kind) { | |
1012 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
1013 { | |
1014 SEC_PKCS7EnvelopedData *edp; | |
1015 | |
1016 edp = cinfo->content.envelopedData; | |
1017 recipientinfosp = &(edp->recipientInfos); | |
1018 } | |
1019 break; | |
1020 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
1021 { | |
1022 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
1023 | |
1024 saedp = cinfo->content.signedAndEnvelopedData; | |
1025 recipientinfosp = &(saedp->recipientInfos); | |
1026 } | |
1027 break; | |
1028 default: | |
1029 return SECFailure; /* XXX set an error? */ | |
1030 } | |
1031 | |
1032 /* | |
1033 * XXX I think that CERT_VerifyCert should do this if *it* is passed | |
1034 * a NULL database. | |
1035 */ | |
1036 if (certdb == NULL) { | |
1037 certdb = CERT_GetDefaultCertDB(); | |
1038 if (certdb == NULL) | |
1039 return SECFailure; /* XXX set an error? */ | |
1040 } | |
1041 | |
1042 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(), | |
1043 cinfo->pwfn_arg, NULL) != SECSuccess) | |
1044 { | |
1045 /* XXX Did CERT_VerifyCert set an error? */ | |
1046 return SECFailure; | |
1047 } | |
1048 | |
1049 mark = PORT_ArenaMark (cinfo->poolp); | |
1050 | |
1051 recipientinfo = (SEC_PKCS7RecipientInfo*)PORT_ArenaZAlloc (cinfo->poolp, | |
1052 sizeof(SEC_PKCS7RecipientInfo)); | |
1053 if (recipientinfo == NULL) { | |
1054 PORT_ArenaRelease (cinfo->poolp, mark); | |
1055 return SECFailure; | |
1056 } | |
1057 | |
1058 dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &recipientinfo->version, | |
1059 SEC_PKCS7_RECIPIENT_INFO_VERSION); | |
1060 if (dummy == NULL) { | |
1061 PORT_ArenaRelease (cinfo->poolp, mark); | |
1062 return SECFailure; | |
1063 } | |
1064 PORT_Assert (dummy == &recipientinfo->version); | |
1065 | |
1066 recipientinfo->cert = CERT_DupCertificate (cert); | |
1067 if (recipientinfo->cert == NULL) { | |
1068 PORT_ArenaRelease (cinfo->poolp, mark); | |
1069 return SECFailure; | |
1070 } | |
1071 | |
1072 recipientinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert); | |
1073 if (recipientinfo->issuerAndSN == NULL) { | |
1074 PORT_ArenaRelease (cinfo->poolp, mark); | |
1075 return SECFailure; | |
1076 } | |
1077 | |
1078 /* | |
1079 * Okay, now recipientinfo is all set. We just need to put it into | |
1080 * the main structure. | |
1081 * | |
1082 * If this is the first recipient, allocate a new recipientinfos array; | |
1083 * otherwise, reallocate the array, making room for the new entry. | |
1084 */ | |
1085 recipientinfos = *recipientinfosp; | |
1086 if (recipientinfos == NULL) { | |
1087 count = 0; | |
1088 recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaAlloc ( | |
1089 cinfo->poolp, | |
1090 2 * sizeof(SEC_PKCS7RecipientInfo *)); | |
1091 } else { | |
1092 for (count = 0; recipientinfos[count] != NULL; count++) | |
1093 ; | |
1094 PORT_Assert (count); /* should be at least one already */ | |
1095 recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaGrow ( | |
1096 cinfo->poolp, recipientinfos, | |
1097 (count + 1) * sizeof(SEC_PKCS7RecipientInfo *), | |
1098 (count + 2) * sizeof(SEC_PKCS7RecipientInfo *)); | |
1099 } | |
1100 | |
1101 if (recipientinfos == NULL) { | |
1102 PORT_ArenaRelease (cinfo->poolp, mark); | |
1103 return SECFailure; | |
1104 } | |
1105 | |
1106 recipientinfos[count] = recipientinfo; | |
1107 recipientinfos[count + 1] = NULL; | |
1108 | |
1109 *recipientinfosp = recipientinfos; | |
1110 | |
1111 PORT_ArenaUnmark (cinfo->poolp, mark); | |
1112 return SECSuccess; | |
1113 } | |
1114 | |
1115 | |
1116 /* | |
1117 * Start a PKCS7 enveloping context. | |
1118 * | |
1119 * "cert" is the cert for the recipient. It will be checked for validity. | |
1120 * | |
1121 * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient) | |
1122 * XXX Maybe SECCertUsage should be split so that our caller just says | |
1123 * "email" and *we* add the "recipient" part -- otherwise our caller | |
1124 * could be lying about the usage; we do not want to allow encryption | |
1125 * certs for signing or vice versa. | |
1126 * | |
1127 * "certdb" is the cert database to use for verifying the cert. | |
1128 * It can be NULL if a default database is available (like in the client). | |
1129 * | |
1130 * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2). | |
1131 * | |
1132 * "keysize" specifies the bulk encryption key size, in bits. | |
1133 * | |
1134 * The return value can be passed to functions which add things to | |
1135 * it like more recipients, then eventually to SEC_PKCS7Encode() or to | |
1136 * SEC_PKCS7EncoderStart() to create the encoded data, and finally to | |
1137 * SEC_PKCS7DestroyContentInfo(). | |
1138 * | |
1139 * An error results in a return value of NULL and an error set. | |
1140 * (Retrieve specific errors via PORT_GetError()/XP_GetError().) | |
1141 */ | |
1142 extern SEC_PKCS7ContentInfo * | |
1143 SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert, | |
1144 SECCertUsage certusage, | |
1145 CERTCertDBHandle *certdb, | |
1146 SECOidTag encalg, | |
1147 int keysize, | |
1148 SECKEYGetPasswordKey pwfn, void *pwfn_arg) | |
1149 { | |
1150 SEC_PKCS7ContentInfo *cinfo; | |
1151 SEC_PKCS7EnvelopedData *envd; | |
1152 SECStatus rv; | |
1153 | |
1154 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENVELOPED_DATA, | |
1155 PR_FALSE, pwfn, pwfn_arg); | |
1156 if (cinfo == NULL) | |
1157 return NULL; | |
1158 | |
1159 rv = sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb); | |
1160 if (rv != SECSuccess) { | |
1161 SEC_PKCS7DestroyContentInfo (cinfo); | |
1162 return NULL; | |
1163 } | |
1164 | |
1165 envd = cinfo->content.envelopedData; | |
1166 PORT_Assert (envd != NULL); | |
1167 | |
1168 /* | |
1169 * XXX Might we want to allow content types other than data? | |
1170 * If so, via what interface? | |
1171 */ | |
1172 rv = sec_pkcs7_init_encrypted_content_info (&(envd->encContentInfo), | |
1173 cinfo->poolp, | |
1174 SEC_OID_PKCS7_DATA, PR_FALSE, | |
1175 encalg, keysize); | |
1176 if (rv != SECSuccess) { | |
1177 SEC_PKCS7DestroyContentInfo (cinfo); | |
1178 return NULL; | |
1179 } | |
1180 | |
1181 /* XXX Anything more to do here? */ | |
1182 | |
1183 return cinfo; | |
1184 } | |
1185 | |
1186 | |
1187 /* | |
1188 * Add another recipient to an encrypted message. | |
1189 * | |
1190 * "cinfo" should be of type envelopedData or signedAndEnvelopedData; | |
1191 * SECFailure will be returned if it is not. | |
1192 * | |
1193 * "cert" is the cert for the recipient. It will be checked for validity. | |
1194 * | |
1195 * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient) | |
1196 * XXX Maybe SECCertUsage should be split so that our caller just says | |
1197 * "email" and *we* add the "recipient" part -- otherwise our caller | |
1198 * could be lying about the usage; we do not want to allow encryption | |
1199 * certs for signing or vice versa. | |
1200 * | |
1201 * "certdb" is the cert database to use for verifying the cert. | |
1202 * It can be NULL if a default database is available (like in the client). | |
1203 */ | |
1204 SECStatus | |
1205 SEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo, | |
1206 CERTCertificate *cert, | |
1207 SECCertUsage certusage, | |
1208 CERTCertDBHandle *certdb) | |
1209 { | |
1210 return sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb); | |
1211 } | |
1212 | |
1213 | |
1214 /* | |
1215 * Create an empty PKCS7 data content info. | |
1216 * | |
1217 * An error results in a return value of NULL and an error set. | |
1218 * (Retrieve specific errors via PORT_GetError()/XP_GetError().) | |
1219 */ | |
1220 SEC_PKCS7ContentInfo * | |
1221 SEC_PKCS7CreateData (void) | |
1222 { | |
1223 return sec_pkcs7_create_content_info (SEC_OID_PKCS7_DATA, PR_FALSE, | |
1224 NULL, NULL); | |
1225 } | |
1226 | |
1227 | |
1228 /* | |
1229 * Create an empty PKCS7 encrypted content info. | |
1230 * | |
1231 * "algorithm" specifies the bulk encryption algorithm to use. | |
1232 * | |
1233 * An error results in a return value of NULL and an error set. | |
1234 * (Retrieve specific errors via PORT_GetError()/XP_GetError().) | |
1235 */ | |
1236 SEC_PKCS7ContentInfo * | |
1237 SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize, | |
1238 SECKEYGetPasswordKey pwfn, void *pwfn_arg) | |
1239 { | |
1240 SEC_PKCS7ContentInfo *cinfo; | |
1241 SECAlgorithmID *algid; | |
1242 SEC_PKCS7EncryptedData *enc_data; | |
1243 SECStatus rv; | |
1244 | |
1245 cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENCRYPTED_DATA, | |
1246 PR_FALSE, pwfn, pwfn_arg); | |
1247 if (cinfo == NULL) | |
1248 return NULL; | |
1249 | |
1250 enc_data = cinfo->content.encryptedData; | |
1251 algid = &(enc_data->encContentInfo.contentEncAlg); | |
1252 | |
1253 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) { | |
1254 rv = SECOID_SetAlgorithmID (cinfo->poolp, algid, algorithm, NULL); | |
1255 } else { | |
1256 /* Assume password-based-encryption. | |
1257 * Note: we can't generate pkcs5v2 from this interface. | |
1258 * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting | |
1259 * non-PBE oids and assuming that they are pkcs5v2 oids, but | |
1260 * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular | |
1261 * CMS encrypted data, so we can't tell SEC_PKCS7CreateEncryptedtedData | |
1262 * to create pkcs5v2 PBEs */ | |
1263 SECAlgorithmID *pbe_algid; | |
1264 pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, | |
1265 NSS_PBE_DEFAULT_ITERATION_COUNT, | |
1266 NULL); | |
1267 if (pbe_algid == NULL) { | |
1268 rv = SECFailure; | |
1269 } else { | |
1270 rv = SECOID_CopyAlgorithmID (cinfo->poolp, algid, pbe_algid); | |
1271 SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE); | |
1272 } | |
1273 } | |
1274 | |
1275 if (rv != SECSuccess) { | |
1276 SEC_PKCS7DestroyContentInfo (cinfo); | |
1277 return NULL; | |
1278 } | |
1279 | |
1280 rv = sec_pkcs7_init_encrypted_content_info (&(enc_data->encContentInfo), | |
1281 cinfo->poolp, | |
1282 SEC_OID_PKCS7_DATA, PR_FALSE, | |
1283 algorithm, keysize); | |
1284 if (rv != SECSuccess) { | |
1285 SEC_PKCS7DestroyContentInfo (cinfo); | |
1286 return NULL; | |
1287 } | |
1288 | |
1289 return cinfo; | |
1290 } | |
1291 |