p7encode.c (34940B)
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; 59 SECKEYPrivateKey *ourPrivKey = NULL; 60 PK11SymKey *bulkkey; 61 void *mark; 62 int i; 63 PLArenaPool *arena = NULL; 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; 72 enccinfo = NULL; 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); 79 if (orig_bulkkey == NULL) { 80 /* XXX error? */ 81 return NULL; 82 } 83 84 encdp = cinfo->content.encryptedData; 85 recipientinfos = NULL; 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) 105 return NULL; 106 107 bulkkey = orig_bulkkey; 108 if (bulkkey == NULL) { 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) { 114 return NULL; 115 } 116 bulkkey = PK11_KeyGen(slot, type, NULL, enccinfo->keysize / 8, 117 cinfo->pwfn_arg); 118 PK11_FreeSlot(slot); 119 if (bulkkey == NULL) { 120 return NULL; 121 } 122 } 123 124 encryptobj = NULL; 125 mark = PORT_ArenaMark(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; i++) { 131 CERTCertificate *cert; 132 SECOidTag certalgtag, encalgtag; 133 SECStatus rv; 134 int data_len; 135 SECItem *params = NULL; 136 137 cert = ri->cert; 138 PORT_Assert(cert != NULL); 139 if (cert == NULL) 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_GetAlgorithmTag(&(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) 160 goto loser; 161 162 data_len = SECKEY_PublicKeyStrength(publickey); 163 ri->encKey.data = 164 (unsigned char *)PORT_ArenaAlloc(cinfo->poolp, data_len); 165 ri->encKey.len = data_len; 166 if (ri->encKey.data == NULL) 167 goto loser; 168 169 rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag), publickey, 170 bulkkey, &ri->encKey); 171 172 SECKEY_DestroyPublicKey(publickey); 173 publickey = NULL; 174 if (rv != SECSuccess) 175 goto loser; 176 params = NULL; /* paranoia */ 177 break; 178 default: 179 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 180 goto loser; 181 } 182 183 rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, 184 params); 185 if (rv != SECSuccess) 186 goto loser; 187 if (arena) 188 PORT_FreeArena(arena, PR_FALSE); 189 arena = NULL; 190 } 191 192 encryptobj = sec_PKCS7CreateEncryptObject(cinfo->poolp, bulkkey, 193 enccinfo->encalg, 194 &(enccinfo->contentEncAlg)); 195 if (encryptobj != NULL) { 196 PORT_ArenaUnmark(cinfo->poolp, mark); 197 mark = NULL; /* good one; do not want to release */ 198 } 199 /* fallthru */ 200 201 loser: 202 if (arena) { 203 PORT_FreeArena(arena, PR_FALSE); 204 } 205 if (publickey) { 206 SECKEY_DestroyPublicKey(publickey); 207 } 208 if (ourPrivKey) { 209 SECKEY_DestroyPrivateKey(ourPrivKey); 210 } 211 if (mark != NULL) { 212 PORT_ArenaRelease(cinfo->poolp, mark); 213 } 214 if (orig_bulkkey == NULL) { 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_FALSE; 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_TRUE; 256 break; 257 258 case SEC_OID_PKCS7_DIGESTED_DATA: { 259 SEC_PKCS7DigestedData *digd; 260 261 digd = cinfo->content.digestedData; 262 if (digd == NULL) 263 break; 264 265 if (dest == &(digd->contentInfo.content)) 266 before_content = PR_TRUE; 267 } break; 268 269 case SEC_OID_PKCS7_ENCRYPTED_DATA: { 270 SEC_PKCS7EncryptedData *encd; 271 272 encd = cinfo->content.encryptedData; 273 if (encd == NULL) 274 break; 275 276 if (dest == &(encd->encContentInfo.encContent)) 277 before_content = PR_TRUE; 278 } break; 279 280 case SEC_OID_PKCS7_ENVELOPED_DATA: { 281 SEC_PKCS7EnvelopedData *envd; 282 283 envd = cinfo->content.envelopedData; 284 if (envd == NULL) 285 break; 286 287 if (dest == &(envd->encContentInfo.encContent)) 288 before_content = PR_TRUE; 289 } break; 290 291 case SEC_OID_PKCS7_SIGNED_DATA: { 292 SEC_PKCS7SignedData *sigd; 293 294 sigd = cinfo->content.signedData; 295 if (sigd == NULL) 296 break; 297 298 if (dest == &(sigd->contentInfo.content)) 299 before_content = PR_TRUE; 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) 307 break; 308 309 if (dest == &(saed->encContentInfo.encContent)) 310 before_content = PR_TRUE; 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_ASN1EncoderSetTakeFromBuf(p7ecx->ecx); 320 /* 321 * And that is all we needed this notify function for. 322 */ 323 SEC_ASN1EncoderClearNotifyProc(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_ZAlloc(sizeof(SEC_PKCS7EncoderContext)); 339 if (p7ecx == NULL) 340 return NULL; 341 342 digests = NULL; 343 digestalg = NULL; 344 digestalgs = NULL; 345 encrypt = PR_FALSE; 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_TRUE; 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_TRUE; 367 break; 368 } 369 370 if (encrypt) { 371 p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt(cinfo, bulkkey); 372 if (p7ecx->encryptobj == NULL) { 373 PORT_Free(p7ecx); 374 return NULL; 375 } 376 } 377 378 if (digestalgs != NULL) { 379 if (digests != NULL) { 380 /* digests already created (probably for detached data) */ 381 digestalg = NULL; 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); 388 digestalg = digestalgs[0]; 389 } 390 } 391 392 if (digestalg != NULL) { 393 SECOidTag oidTag = SECOID_FindOIDTag(&(digestalg->algorithm)); 394 395 p7ecx->digestobj = HASH_GetHashObjectByOidTag(oidTag); 396 if (p7ecx->digestobj != NULL) { 397 p7ecx->digestcx = (*p7ecx->digestobj->create)(); 398 if (p7ecx->digestcx == NULL) 399 p7ecx->digestobj = NULL; 400 else 401 (*p7ecx->digestobj->begin)(p7ecx->digestcx); 402 } 403 if (p7ecx->digestobj == NULL) { 404 if (p7ecx->encryptobj != NULL) 405 sec_PKCS7DestroyEncryptObject(p7ecx->encryptobj); 406 PORT_Free(p7ecx); 407 return NULL; 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) 426 return NULL; 427 428 p7ecx->output.outputfn = outputfn; 429 p7ecx->output.outputarg = outputarg; 430 431 /* 432 * Initialize the BER encoder. 433 */ 434 p7ecx->ecx = SEC_ASN1EncoderStart(cinfo, sec_PKCS7ContentInfoTemplate, 435 sec_pkcs7_encoder_out, &(p7ecx->output)); 436 if (p7ecx->ecx == NULL) { 437 PORT_Free(p7ecx); 438 return NULL; 439 } 440 441 /* 442 * Indicate that we are streaming. We will be streaming until we 443 * get past the contents bytes. 444 */ 445 SEC_ASN1EncoderSetStreaming(p7ecx->ecx); 446 447 /* 448 * The notify function will watch for the contents field. 449 */ 450 SEC_ASN1EncoderSetNotifyProc(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_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0); 459 if (rv != SECSuccess) { 460 PORT_Free(p7ecx); 461 return NULL; 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; 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); 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) { 494 (*p7ecx->digestobj->update)(p7ecx->digestcx, data, len); 495 } 496 497 /* 498 * Encrypt this chunk. 499 */ 500 if (p7ecx->encryptobj != NULL) { 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, &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) 523 buf = (unsigned char *)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen); 524 else 525 buf = (unsigned char *)PORT_Alloc(buflen); 526 527 if (buf == NULL) { 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) { 543 /* 544 * Encode the contents bytes. 545 */ 546 if (len) { 547 rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, (const char *)data, len); 548 } 549 } 550 551 done: 552 if (p7ecx->encryptobj != NULL) { 553 if (final) 554 sec_PKCS7DestroyEncryptObject(p7ecx->encryptobj); 555 if (dest != NULL) { 556 dest->data = buf; 557 dest->len = len; 558 } else if (buf != NULL) { 559 PORT_Free(buf); 560 } 561 } 562 563 if (final && p7ecx->digestobj != NULL) { 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); 572 return SECFailure; 573 case SEC_OID_PKCS7_DIGESTED_DATA: 574 digest = &(p7ecx->cinfo->content.digestedData->digest); 575 digestsp = NULL; 576 break; 577 case SEC_OID_PKCS7_SIGNED_DATA: 578 digest = NULL; 579 digestsp = &(p7ecx->cinfo->content.signedData->digests); 580 break; 581 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: 582 digest = NULL; 583 digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests); 584 break; 585 } 586 587 digdata = (unsigned char *)PORT_ArenaAlloc(p7ecx->cinfo->poolp, 588 p7ecx->digestobj->length); 589 if (digdata == NULL) 590 return SECFailure; 591 592 if (digestsp != NULL) { 593 PORT_Assert(digest == NULL); 594 595 digest = (SECItem *)PORT_ArenaAlloc(p7ecx->cinfo->poolp, 596 sizeof(SECItem)); 597 digests = (SECItem **)PORT_ArenaAlloc(p7ecx->cinfo->poolp, 598 2 * sizeof(SECItem *)); 599 if (digests == NULL || digest == NULL) 600 return SECFailure; 601 602 digests[0] = digest; 603 digests[1] = NULL; 604 605 *digestsp = digests; 606 } 607 608 PORT_Assert(digest != NULL); 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_TRUE); 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, 627 (const unsigned char *)data, len, 628 PR_FALSE); 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; 654 certlists = NULL; 655 digestalgs = NULL; 656 digests = NULL; 657 signerinfos = NULL; 658 rawcertsp = NULL; 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 && certlists == NULL && signerinfos == NULL) 685 return SECSuccess; /* nothing for us to do! */ 686 687 poolp = cinfo->poolp; 688 certcount = 0; 689 690 if (signerinfos != NULL) { 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); 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; si++) { 707 708 signerinfo = signerinfos[si]; 709 710 /* find right digest */ 711 digestalgtag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg)); 712 for (di = 0; digestalgs[di] != NULL; di++) { 713 /* XXX Should I be comparing more than the tag? */ 714 if (digestalgtag == SECOID_GetAlgorithmTag(digestalgs[di])) 715 break; 716 } 717 if (digestalgs[di] == NULL) { 718 /* XXX oops; do what? set an error? */ 719 return SECFailure; 720 } 721 PORT_Assert(digests[di] != NULL); 722 723 cert = signerinfo->cert; 724 privkey = PK11_FindKeyByAnyCert(cert, pwfnarg); 725 if (privkey == NULL) 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_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); 733 734 if (signerinfo->authAttr != NULL) { 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_TRUE); 746 PORT_Assert(attr != NULL); 747 if (attr == NULL) { 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); 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; 781 encoded_attrs.len = 0; 782 dummy = sec_PKCS7EncodeAttributes(NULL, &encoded_attrs, 783 &(signerinfo->authAttr)); 784 if (dummy == NULL) { 785 SECKEY_DestroyPrivateKey(privkey); 786 return SECFailure; 787 } 788 789 algid = SEC_GetSignatureAlgorithmOidTagByKey(privkey, NULL, 790 digestalgtag); 791 if (algid == SEC_OID_UNKNOWN) { 792 PORT_SetError(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_FreeItem(&encoded_attrs, PR_FALSE); 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_CopyItem(poolp, &(signerinfo->encDigest), &signature); 812 if (rv != SECSuccess) 813 return rv; 814 815 SECITEM_FreeItem(&signature, PR_FALSE); 816 817 rv = SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), 818 signalgtag, NULL); 819 if (rv != SECSuccess) 820 return SECFailure; 821 822 /* 823 * Count the cert chain for this signer. 824 */ 825 if (signerinfo->certList != NULL) 826 certcount += signerinfo->certList->len; 827 } 828 } 829 830 if (certs != NULL) { 831 for (ci = 0; certs[ci] != NULL; ci++) 832 certcount++; 833 } 834 835 if (certlists != NULL) { 836 for (cli = 0; certlists[cli] != NULL; cli++) 837 certcount += certlists[cli]->len; 838 } 839 840 if (certcount == 0) 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_ArenaAlloc(poolp, 850 (certcount + 1) * sizeof(SECItem *)); 851 if (rawcerts == NULL) 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 != NULL) { 862 for (si = 0; signerinfos[si] != NULL; si++) { 863 signerinfo = signerinfos[si]; 864 for (ci = 0; signerinfo->certList && ci < signerinfo->certList->len; ci++) 865 rawcerts[rci++] = &(signerinfo->certList->certs[ci]); 866 } 867 } 868 869 if (certs != NULL) { 870 for (ci = 0; certs[ci] != NULL; ci++) 871 rawcerts[rci++] = &(certs[ci]->derCert); 872 } 873 874 if (certlists != NULL) { 875 for (cli = 0; certlists[cli] != NULL; cli++) { 876 for (ci = 0; ci < certlists[cli]->len; ci++) 877 rawcerts[rci++] = &(certlists[cli]->certs[ci]); 878 } 879 } 880 881 rawcerts[rci] = NULL; 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, NULL, 0, PR_TRUE); 897 898 /* 899 * Turn off streaming stuff. 900 */ 901 SEC_ASN1EncoderClearTakeFromBuf(p7ecx->ecx); 902 SEC_ASN1EncoderClearStreaming(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_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0); 912 913 loser: 914 SEC_ASN1EncoderFinish(p7ecx->ecx); 915 PORT_Free(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); 926 SEC_ASN1EncoderAbort(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 == NULL) 947 return SECFailure; 948 949 content = SEC_PKCS7GetContent(cinfo); 950 951 if (p7ecx->encryptobj != NULL) { 952 SECOidTag kind; 953 SEC_PKCS7EncryptedContentInfo *enccinfo; 954 955 kind = SEC_PKCS7ContentType(p7ecx->cinfo); 956 switch (kind) { 957 default: 958 PORT_Assert(0); 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; 974 } 975 976 if (content != NULL && content->data != NULL && content->len) { 977 rv = sec_pkcs7_encoder_work_data(p7ecx, enc_content, 978 content->data, content->len, PR_TRUE); 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_Free(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_ASN1Encode(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; 1077 1078 return SEC_ASN1EncodeItem(pool, dest, cinfo, sec_PKCS7ContentInfoTemplate); 1079 }