security/nss/lib/pkcs7/p7encode.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial