security/nss/lib/pkcs7/p7common.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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 implementation -- the exported parts that are used whether
michael@0 7 * creating or decoding.
michael@0 8 */
michael@0 9
michael@0 10 #include "p7local.h"
michael@0 11
michael@0 12 #include "cert.h"
michael@0 13 #include "secitem.h"
michael@0 14 #include "secoid.h"
michael@0 15 #include "pk11func.h"
michael@0 16
michael@0 17 /*
michael@0 18 * Find out (saving pointer to lookup result for future reference)
michael@0 19 * and return the inner content type.
michael@0 20 */
michael@0 21 SECOidTag
michael@0 22 SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo)
michael@0 23 {
michael@0 24 if (cinfo->contentTypeTag == NULL)
michael@0 25 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
michael@0 26
michael@0 27 if (cinfo->contentTypeTag == NULL)
michael@0 28 return SEC_OID_UNKNOWN;
michael@0 29
michael@0 30 return cinfo->contentTypeTag->offset;
michael@0 31 }
michael@0 32
michael@0 33
michael@0 34 /*
michael@0 35 * Destroy a PKCS7 contentInfo and all of its sub-pieces.
michael@0 36 */
michael@0 37 void
michael@0 38 SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
michael@0 39 {
michael@0 40 SECOidTag kind;
michael@0 41 CERTCertificate **certs;
michael@0 42 CERTCertificateList **certlists;
michael@0 43 SEC_PKCS7SignerInfo **signerinfos;
michael@0 44 SEC_PKCS7RecipientInfo **recipientinfos;
michael@0 45
michael@0 46 PORT_Assert (cinfo->refCount > 0);
michael@0 47 if (cinfo->refCount <= 0)
michael@0 48 return;
michael@0 49
michael@0 50 cinfo->refCount--;
michael@0 51 if (cinfo->refCount > 0)
michael@0 52 return;
michael@0 53
michael@0 54 certs = NULL;
michael@0 55 certlists = NULL;
michael@0 56 recipientinfos = NULL;
michael@0 57 signerinfos = NULL;
michael@0 58
michael@0 59 kind = SEC_PKCS7ContentType (cinfo);
michael@0 60 switch (kind) {
michael@0 61 case SEC_OID_PKCS7_ENVELOPED_DATA:
michael@0 62 {
michael@0 63 SEC_PKCS7EnvelopedData *edp;
michael@0 64
michael@0 65 edp = cinfo->content.envelopedData;
michael@0 66 if (edp != NULL) {
michael@0 67 recipientinfos = edp->recipientInfos;
michael@0 68 }
michael@0 69 }
michael@0 70 break;
michael@0 71 case SEC_OID_PKCS7_SIGNED_DATA:
michael@0 72 {
michael@0 73 SEC_PKCS7SignedData *sdp;
michael@0 74
michael@0 75 sdp = cinfo->content.signedData;
michael@0 76 if (sdp != NULL) {
michael@0 77 certs = sdp->certs;
michael@0 78 certlists = sdp->certLists;
michael@0 79 signerinfos = sdp->signerInfos;
michael@0 80 }
michael@0 81 }
michael@0 82 break;
michael@0 83 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
michael@0 84 {
michael@0 85 SEC_PKCS7SignedAndEnvelopedData *saedp;
michael@0 86
michael@0 87 saedp = cinfo->content.signedAndEnvelopedData;
michael@0 88 if (saedp != NULL) {
michael@0 89 certs = saedp->certs;
michael@0 90 certlists = saedp->certLists;
michael@0 91 recipientinfos = saedp->recipientInfos;
michael@0 92 signerinfos = saedp->signerInfos;
michael@0 93 if (saedp->sigKey != NULL)
michael@0 94 PK11_FreeSymKey (saedp->sigKey);
michael@0 95 }
michael@0 96 }
michael@0 97 break;
michael@0 98 default:
michael@0 99 /* XXX Anything else that needs to be "manually" freed/destroyed? */
michael@0 100 break;
michael@0 101 }
michael@0 102
michael@0 103 if (certs != NULL) {
michael@0 104 CERTCertificate *cert;
michael@0 105
michael@0 106 while ((cert = *certs++) != NULL) {
michael@0 107 CERT_DestroyCertificate (cert);
michael@0 108 }
michael@0 109 }
michael@0 110
michael@0 111 if (certlists != NULL) {
michael@0 112 CERTCertificateList *certlist;
michael@0 113
michael@0 114 while ((certlist = *certlists++) != NULL) {
michael@0 115 CERT_DestroyCertificateList (certlist);
michael@0 116 }
michael@0 117 }
michael@0 118
michael@0 119 if (recipientinfos != NULL) {
michael@0 120 SEC_PKCS7RecipientInfo *ri;
michael@0 121
michael@0 122 while ((ri = *recipientinfos++) != NULL) {
michael@0 123 if (ri->cert != NULL)
michael@0 124 CERT_DestroyCertificate (ri->cert);
michael@0 125 }
michael@0 126 }
michael@0 127
michael@0 128 if (signerinfos != NULL) {
michael@0 129 SEC_PKCS7SignerInfo *si;
michael@0 130
michael@0 131 while ((si = *signerinfos++) != NULL) {
michael@0 132 if (si->cert != NULL)
michael@0 133 CERT_DestroyCertificate (si->cert);
michael@0 134 if (si->certList != NULL)
michael@0 135 CERT_DestroyCertificateList (si->certList);
michael@0 136 }
michael@0 137 }
michael@0 138
michael@0 139 if (cinfo->poolp != NULL) {
michael@0 140 PORT_FreeArena (cinfo->poolp, PR_FALSE); /* XXX clear it? */
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144
michael@0 145 /*
michael@0 146 * Return a copy of the given contentInfo. The copy may be virtual
michael@0 147 * or may be real -- either way, the result needs to be passed to
michael@0 148 * SEC_PKCS7DestroyContentInfo later (as does the original).
michael@0 149 */
michael@0 150 SEC_PKCS7ContentInfo *
michael@0 151 SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo)
michael@0 152 {
michael@0 153 if (cinfo == NULL)
michael@0 154 return NULL;
michael@0 155
michael@0 156 PORT_Assert (cinfo->refCount > 0);
michael@0 157
michael@0 158 if (cinfo->created) {
michael@0 159 /*
michael@0 160 * Want to do a real copy of these; otherwise subsequent
michael@0 161 * changes made to either copy are likely to be a surprise.
michael@0 162 * XXX I suspect that this will not actually be called for yet,
michael@0 163 * which is why the assert, so to notice if it is...
michael@0 164 */
michael@0 165 PORT_Assert (0);
michael@0 166 /*
michael@0 167 * XXX Create a new pool here, and copy everything from
michael@0 168 * within. For cert stuff, need to call the appropriate
michael@0 169 * copy functions, etc.
michael@0 170 */
michael@0 171 }
michael@0 172
michael@0 173 cinfo->refCount++;
michael@0 174 return cinfo;
michael@0 175 }
michael@0 176
michael@0 177
michael@0 178 /*
michael@0 179 * Return a pointer to the actual content. In the case of those types
michael@0 180 * which are encrypted, this returns the *plain* content.
michael@0 181 * XXX Needs revisiting if/when we handle nested encrypted types.
michael@0 182 */
michael@0 183 SECItem *
michael@0 184 SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
michael@0 185 {
michael@0 186 SECOidTag kind;
michael@0 187
michael@0 188 kind = SEC_PKCS7ContentType (cinfo);
michael@0 189 switch (kind) {
michael@0 190 case SEC_OID_PKCS7_DATA:
michael@0 191 return cinfo->content.data;
michael@0 192 case SEC_OID_PKCS7_DIGESTED_DATA:
michael@0 193 {
michael@0 194 SEC_PKCS7DigestedData *digd;
michael@0 195
michael@0 196 digd = cinfo->content.digestedData;
michael@0 197 if (digd == NULL)
michael@0 198 break;
michael@0 199 return SEC_PKCS7GetContent (&(digd->contentInfo));
michael@0 200 }
michael@0 201 case SEC_OID_PKCS7_ENCRYPTED_DATA:
michael@0 202 {
michael@0 203 SEC_PKCS7EncryptedData *encd;
michael@0 204
michael@0 205 encd = cinfo->content.encryptedData;
michael@0 206 if (encd == NULL)
michael@0 207 break;
michael@0 208 return &(encd->encContentInfo.plainContent);
michael@0 209 }
michael@0 210 case SEC_OID_PKCS7_ENVELOPED_DATA:
michael@0 211 {
michael@0 212 SEC_PKCS7EnvelopedData *envd;
michael@0 213
michael@0 214 envd = cinfo->content.envelopedData;
michael@0 215 if (envd == NULL)
michael@0 216 break;
michael@0 217 return &(envd->encContentInfo.plainContent);
michael@0 218 }
michael@0 219 case SEC_OID_PKCS7_SIGNED_DATA:
michael@0 220 {
michael@0 221 SEC_PKCS7SignedData *sigd;
michael@0 222
michael@0 223 sigd = cinfo->content.signedData;
michael@0 224 if (sigd == NULL)
michael@0 225 break;
michael@0 226 return SEC_PKCS7GetContent (&(sigd->contentInfo));
michael@0 227 }
michael@0 228 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
michael@0 229 {
michael@0 230 SEC_PKCS7SignedAndEnvelopedData *saed;
michael@0 231
michael@0 232 saed = cinfo->content.signedAndEnvelopedData;
michael@0 233 if (saed == NULL)
michael@0 234 break;
michael@0 235 return &(saed->encContentInfo.plainContent);
michael@0 236 }
michael@0 237 default:
michael@0 238 PORT_Assert(0);
michael@0 239 break;
michael@0 240 }
michael@0 241
michael@0 242 return NULL;
michael@0 243 }
michael@0 244
michael@0 245
michael@0 246 /*
michael@0 247 * XXX Fix the placement and formatting of the
michael@0 248 * following routines (i.e. make them consistent with the rest of
michael@0 249 * the pkcs7 code -- I think some/many belong in other files and
michael@0 250 * they all need a formatting/style rehaul)
michael@0 251 */
michael@0 252
michael@0 253 /* retrieve the algorithm identifier for encrypted data.
michael@0 254 * the identifier returned is a copy of the algorithm identifier
michael@0 255 * in the content info and needs to be freed after being used.
michael@0 256 *
michael@0 257 * cinfo is the content info for which to retrieve the
michael@0 258 * encryption algorithm.
michael@0 259 *
michael@0 260 * if the content info is not encrypted data or an error
michael@0 261 * occurs NULL is returned.
michael@0 262 */
michael@0 263 SECAlgorithmID *
michael@0 264 SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo)
michael@0 265 {
michael@0 266 SECAlgorithmID *alg = 0;
michael@0 267 switch (SEC_PKCS7ContentType(cinfo))
michael@0 268 {
michael@0 269 case SEC_OID_PKCS7_ENCRYPTED_DATA:
michael@0 270 alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg;
michael@0 271 break;
michael@0 272 case SEC_OID_PKCS7_ENVELOPED_DATA:
michael@0 273 alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
michael@0 274 break;
michael@0 275 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
michael@0 276 alg = &cinfo->content.signedAndEnvelopedData
michael@0 277 ->encContentInfo.contentEncAlg;
michael@0 278 break;
michael@0 279 default:
michael@0 280 alg = 0;
michael@0 281 break;
michael@0 282 }
michael@0 283
michael@0 284 return alg;
michael@0 285 }
michael@0 286
michael@0 287 /* set the content of the content info. For data content infos,
michael@0 288 * the data is set. For encrytped content infos, the plainContent
michael@0 289 * is set, and is expected to be encrypted later.
michael@0 290 *
michael@0 291 * cinfo is the content info where the data will be set
michael@0 292 *
michael@0 293 * buf is a buffer of the data to set
michael@0 294 *
michael@0 295 * len is the length of the data being set.
michael@0 296 *
michael@0 297 * in the event of an error, SECFailure is returned. SECSuccess
michael@0 298 * indicates the content was successfully set.
michael@0 299 */
michael@0 300 SECStatus
michael@0 301 SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
michael@0 302 const char *buf,
michael@0 303 unsigned long len)
michael@0 304 {
michael@0 305 SECOidTag cinfo_type;
michael@0 306 SECStatus rv;
michael@0 307 SECItem content;
michael@0 308 SECOidData *contentTypeTag = NULL;
michael@0 309
michael@0 310 content.type = siBuffer;
michael@0 311 content.data = (unsigned char *)buf;
michael@0 312 content.len = len;
michael@0 313
michael@0 314 cinfo_type = SEC_PKCS7ContentType(cinfo);
michael@0 315
michael@0 316 /* set inner content */
michael@0 317 switch(cinfo_type)
michael@0 318 {
michael@0 319 case SEC_OID_PKCS7_SIGNED_DATA:
michael@0 320 if(content.len > 0) {
michael@0 321 /* we "leak" the old content here, but as it's all in the pool */
michael@0 322 /* it does not really matter */
michael@0 323
michael@0 324 /* create content item if necessary */
michael@0 325 if (cinfo->content.signedData->contentInfo.content.data == NULL)
michael@0 326 cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
michael@0 327 rv = SECITEM_CopyItem(cinfo->poolp,
michael@0 328 cinfo->content.signedData->contentInfo.content.data,
michael@0 329 &content);
michael@0 330 } else {
michael@0 331 cinfo->content.signedData->contentInfo.content.data->data = NULL;
michael@0 332 cinfo->content.signedData->contentInfo.content.data->len = 0;
michael@0 333 rv = SECSuccess;
michael@0 334 }
michael@0 335 if(rv == SECFailure)
michael@0 336 goto loser;
michael@0 337
michael@0 338 break;
michael@0 339 case SEC_OID_PKCS7_ENCRYPTED_DATA:
michael@0 340 /* XXX this forces the inner content type to be "data" */
michael@0 341 /* do we really want to override without asking or reason? */
michael@0 342 contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
michael@0 343 if(contentTypeTag == NULL)
michael@0 344 goto loser;
michael@0 345 rv = SECITEM_CopyItem(cinfo->poolp,
michael@0 346 &(cinfo->content.encryptedData->encContentInfo.contentType),
michael@0 347 &(contentTypeTag->oid));
michael@0 348 if(rv == SECFailure)
michael@0 349 goto loser;
michael@0 350 if(content.len > 0) {
michael@0 351 rv = SECITEM_CopyItem(cinfo->poolp,
michael@0 352 &(cinfo->content.encryptedData->encContentInfo.plainContent),
michael@0 353 &content);
michael@0 354 } else {
michael@0 355 cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
michael@0 356 cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
michael@0 357 cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
michael@0 358 cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
michael@0 359 rv = SECSuccess;
michael@0 360 }
michael@0 361 if(rv == SECFailure)
michael@0 362 goto loser;
michael@0 363 break;
michael@0 364 case SEC_OID_PKCS7_DATA:
michael@0 365 cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
michael@0 366 sizeof(SECItem));
michael@0 367 if(cinfo->content.data == NULL)
michael@0 368 goto loser;
michael@0 369 if(content.len > 0) {
michael@0 370 rv = SECITEM_CopyItem(cinfo->poolp,
michael@0 371 cinfo->content.data, &content);
michael@0 372 } else {
michael@0 373 /* handle case with NULL content */
michael@0 374 rv = SECSuccess;
michael@0 375 }
michael@0 376 if(rv == SECFailure)
michael@0 377 goto loser;
michael@0 378 break;
michael@0 379 default:
michael@0 380 goto loser;
michael@0 381 }
michael@0 382
michael@0 383 return SECSuccess;
michael@0 384
michael@0 385 loser:
michael@0 386
michael@0 387 return SECFailure;
michael@0 388 }
michael@0 389
michael@0 390 /* the content of an encrypted data content info is encrypted.
michael@0 391 * it is assumed that for encrypted data, that the data has already
michael@0 392 * been set and is in the "plainContent" field of the content info.
michael@0 393 *
michael@0 394 * cinfo is the content info to encrypt
michael@0 395 *
michael@0 396 * key is the key with which to perform the encryption. if the
michael@0 397 * algorithm is a password based encryption algorithm, the
michael@0 398 * key is actually a password which will be processed per
michael@0 399 * PKCS #5.
michael@0 400 *
michael@0 401 * in the event of an error, SECFailure is returned. SECSuccess
michael@0 402 * indicates a success.
michael@0 403 */
michael@0 404 SECStatus
michael@0 405 SEC_PKCS7EncryptContents(PLArenaPool *poolp,
michael@0 406 SEC_PKCS7ContentInfo *cinfo,
michael@0 407 SECItem *key,
michael@0 408 void *wincx)
michael@0 409 {
michael@0 410 SECAlgorithmID *algid = NULL;
michael@0 411 SECItem * result = NULL;
michael@0 412 SECItem * src;
michael@0 413 SECItem * dest;
michael@0 414 SECItem * blocked_data = NULL;
michael@0 415 void * mark;
michael@0 416 void * cx;
michael@0 417 PK11SymKey * eKey = NULL;
michael@0 418 PK11SlotInfo * slot = NULL;
michael@0 419
michael@0 420 CK_MECHANISM_TYPE cryptoMechType;
michael@0 421 int bs;
michael@0 422 SECStatus rv = SECFailure;
michael@0 423 SECItem *c_param = NULL;
michael@0 424
michael@0 425 if((cinfo == NULL) || (key == NULL))
michael@0 426 return SECFailure;
michael@0 427
michael@0 428 if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
michael@0 429 return SECFailure;
michael@0 430
michael@0 431 algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
michael@0 432 if(algid == NULL)
michael@0 433 return SECFailure;
michael@0 434
michael@0 435 if(poolp == NULL)
michael@0 436 poolp = cinfo->poolp;
michael@0 437
michael@0 438 mark = PORT_ArenaMark(poolp);
michael@0 439
michael@0 440 src = &cinfo->content.encryptedData->encContentInfo.plainContent;
michael@0 441 dest = &cinfo->content.encryptedData->encContentInfo.encContent;
michael@0 442 dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
michael@0 443 dest->len = (src->len + 64);
michael@0 444 if(dest->data == NULL) {
michael@0 445 rv = SECFailure;
michael@0 446 goto loser;
michael@0 447 }
michael@0 448
michael@0 449 slot = PK11_GetInternalKeySlot();
michael@0 450 if(slot == NULL) {
michael@0 451 rv = SECFailure;
michael@0 452 goto loser;
michael@0 453 }
michael@0 454
michael@0 455 eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
michael@0 456 if(eKey == NULL) {
michael@0 457 rv = SECFailure;
michael@0 458 goto loser;
michael@0 459 }
michael@0 460
michael@0 461 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
michael@0 462 if (cryptoMechType == CKM_INVALID_MECHANISM) {
michael@0 463 rv = SECFailure;
michael@0 464 goto loser;
michael@0 465 }
michael@0 466
michael@0 467 /* block according to PKCS 8 */
michael@0 468 bs = PK11_GetBlockSize(cryptoMechType, c_param);
michael@0 469 rv = SECSuccess;
michael@0 470 if(bs) {
michael@0 471 char pad_char;
michael@0 472 pad_char = (char)(bs - (src->len % bs));
michael@0 473 if(src->len % bs) {
michael@0 474 rv = SECSuccess;
michael@0 475 blocked_data = PK11_BlockData(src, bs);
michael@0 476 if(blocked_data) {
michael@0 477 PORT_Memset((blocked_data->data + blocked_data->len
michael@0 478 - (int)pad_char),
michael@0 479 pad_char, (int)pad_char);
michael@0 480 } else {
michael@0 481 rv = SECFailure;
michael@0 482 goto loser;
michael@0 483 }
michael@0 484 } else {
michael@0 485 blocked_data = SECITEM_DupItem(src);
michael@0 486 if(blocked_data) {
michael@0 487 blocked_data->data = (unsigned char*)PORT_Realloc(
michael@0 488 blocked_data->data,
michael@0 489 blocked_data->len + bs);
michael@0 490 if(blocked_data->data) {
michael@0 491 blocked_data->len += bs;
michael@0 492 PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
michael@0 493 } else {
michael@0 494 rv = SECFailure;
michael@0 495 goto loser;
michael@0 496 }
michael@0 497 } else {
michael@0 498 rv = SECFailure;
michael@0 499 goto loser;
michael@0 500 }
michael@0 501 }
michael@0 502 } else {
michael@0 503 blocked_data = SECITEM_DupItem(src);
michael@0 504 if(!blocked_data) {
michael@0 505 rv = SECFailure;
michael@0 506 goto loser;
michael@0 507 }
michael@0 508 }
michael@0 509
michael@0 510 cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
michael@0 511 eKey, c_param);
michael@0 512 if(cx == NULL) {
michael@0 513 rv = SECFailure;
michael@0 514 goto loser;
michael@0 515 }
michael@0 516
michael@0 517 rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
michael@0 518 (int)(src->len + 64), blocked_data->data,
michael@0 519 (int)blocked_data->len);
michael@0 520 PK11_DestroyContext((PK11Context*)cx, PR_TRUE);
michael@0 521
michael@0 522 loser:
michael@0 523 /* let success fall through */
michael@0 524 if(blocked_data != NULL)
michael@0 525 SECITEM_ZfreeItem(blocked_data, PR_TRUE);
michael@0 526
michael@0 527 if(result != NULL)
michael@0 528 SECITEM_ZfreeItem(result, PR_TRUE);
michael@0 529
michael@0 530 if(rv == SECFailure)
michael@0 531 PORT_ArenaRelease(poolp, mark);
michael@0 532 else
michael@0 533 PORT_ArenaUnmark(poolp, mark);
michael@0 534
michael@0 535 if(eKey != NULL)
michael@0 536 PK11_FreeSymKey(eKey);
michael@0 537
michael@0 538 if(slot != NULL)
michael@0 539 PK11_FreeSlot(slot);
michael@0 540
michael@0 541 if(c_param != NULL)
michael@0 542 SECITEM_ZfreeItem(c_param, PR_TRUE);
michael@0 543
michael@0 544 return rv;
michael@0 545 }
michael@0 546
michael@0 547 /* the content of an encrypted data content info is decrypted.
michael@0 548 * it is assumed that for encrypted data, that the data has already
michael@0 549 * been set and is in the "encContent" field of the content info.
michael@0 550 *
michael@0 551 * cinfo is the content info to decrypt
michael@0 552 *
michael@0 553 * key is the key with which to perform the decryption. if the
michael@0 554 * algorithm is a password based encryption algorithm, the
michael@0 555 * key is actually a password which will be processed per
michael@0 556 * PKCS #5.
michael@0 557 *
michael@0 558 * in the event of an error, SECFailure is returned. SECSuccess
michael@0 559 * indicates a success.
michael@0 560 */
michael@0 561 SECStatus
michael@0 562 SEC_PKCS7DecryptContents(PLArenaPool *poolp,
michael@0 563 SEC_PKCS7ContentInfo *cinfo,
michael@0 564 SECItem *key,
michael@0 565 void *wincx)
michael@0 566 {
michael@0 567 SECAlgorithmID *algid = NULL;
michael@0 568 SECStatus rv = SECFailure;
michael@0 569 SECItem *result = NULL, *dest, *src;
michael@0 570 void *mark;
michael@0 571
michael@0 572 PK11SymKey *eKey = NULL;
michael@0 573 PK11SlotInfo *slot = NULL;
michael@0 574 CK_MECHANISM_TYPE cryptoMechType;
michael@0 575 void *cx;
michael@0 576 SECItem *c_param = NULL;
michael@0 577 int bs;
michael@0 578
michael@0 579 if((cinfo == NULL) || (key == NULL))
michael@0 580 return SECFailure;
michael@0 581
michael@0 582 if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
michael@0 583 return SECFailure;
michael@0 584
michael@0 585 algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);
michael@0 586 if(algid == NULL)
michael@0 587 return SECFailure;
michael@0 588
michael@0 589 if(poolp == NULL)
michael@0 590 poolp = cinfo->poolp;
michael@0 591
michael@0 592 mark = PORT_ArenaMark(poolp);
michael@0 593
michael@0 594 src = &cinfo->content.encryptedData->encContentInfo.encContent;
michael@0 595 dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
michael@0 596 dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
michael@0 597 dest->len = (src->len + 64);
michael@0 598 if(dest->data == NULL) {
michael@0 599 rv = SECFailure;
michael@0 600 goto loser;
michael@0 601 }
michael@0 602
michael@0 603 slot = PK11_GetInternalKeySlot();
michael@0 604 if(slot == NULL) {
michael@0 605 rv = SECFailure;
michael@0 606 goto loser;
michael@0 607 }
michael@0 608
michael@0 609 eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
michael@0 610 if(eKey == NULL) {
michael@0 611 rv = SECFailure;
michael@0 612 goto loser;
michael@0 613 }
michael@0 614
michael@0 615 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
michael@0 616 if (cryptoMechType == CKM_INVALID_MECHANISM) {
michael@0 617 rv = SECFailure;
michael@0 618 goto loser;
michael@0 619 }
michael@0 620
michael@0 621 cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
michael@0 622 eKey, c_param);
michael@0 623 if(cx == NULL) {
michael@0 624 rv = SECFailure;
michael@0 625 goto loser;
michael@0 626 }
michael@0 627
michael@0 628 rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len),
michael@0 629 (int)(src->len + 64), src->data, (int)src->len);
michael@0 630 PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
michael@0 631
michael@0 632 bs = PK11_GetBlockSize(cryptoMechType, c_param);
michael@0 633 if(bs) {
michael@0 634 /* check for proper badding in block algorithms. this assumes
michael@0 635 * RC2 cbc or a DES cbc variant. and the padding is thus defined
michael@0 636 */
michael@0 637 if(((int)dest->data[dest->len-1] <= bs) &&
michael@0 638 ((int)dest->data[dest->len-1] > 0)) {
michael@0 639 dest->len -= (int)dest->data[dest->len-1];
michael@0 640 } else {
michael@0 641 rv = SECFailure;
michael@0 642 /* set an error ? */
michael@0 643 }
michael@0 644 }
michael@0 645
michael@0 646 loser:
michael@0 647 /* let success fall through */
michael@0 648 if(result != NULL)
michael@0 649 SECITEM_ZfreeItem(result, PR_TRUE);
michael@0 650
michael@0 651 if(rv == SECFailure)
michael@0 652 PORT_ArenaRelease(poolp, mark);
michael@0 653 else
michael@0 654 PORT_ArenaUnmark(poolp, mark);
michael@0 655
michael@0 656 if(eKey != NULL)
michael@0 657 PK11_FreeSymKey(eKey);
michael@0 658
michael@0 659 if(slot != NULL)
michael@0 660 PK11_FreeSlot(slot);
michael@0 661
michael@0 662 if(c_param != NULL)
michael@0 663 SECITEM_ZfreeItem(c_param, PR_TRUE);
michael@0 664
michael@0 665 return rv;
michael@0 666 }
michael@0 667
michael@0 668 SECItem **
michael@0 669 SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
michael@0 670 {
michael@0 671 switch(SEC_PKCS7ContentType(cinfo))
michael@0 672 {
michael@0 673 case SEC_OID_PKCS7_SIGNED_DATA:
michael@0 674 return cinfo->content.signedData->rawCerts;
michael@0 675 break;
michael@0 676 default:
michael@0 677 return NULL;
michael@0 678 break;
michael@0 679 }
michael@0 680 }
michael@0 681
michael@0 682
michael@0 683 int
michael@0 684 SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
michael@0 685 {
michael@0 686 if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
michael@0 687 return cinfo->content.envelopedData->encContentInfo.keysize;
michael@0 688 else
michael@0 689 return 0;
michael@0 690 }
michael@0 691

mercurial