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