| OLD | NEW |
| (Empty) | |
| 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 #include "plarena.h" |
| 6 #include "secitem.h" |
| 7 #include "secoid.h" |
| 8 #include "seccomon.h" |
| 9 #include "secport.h" |
| 10 #include "cert.h" |
| 11 #include "pkcs12.h" |
| 12 #include "p12local.h" |
| 13 #include "secpkcs7.h" |
| 14 #include "secasn1.h" |
| 15 #include "secerr.h" |
| 16 #include "p12plcy.h" |
| 17 |
| 18 /* release the memory taken up by the list of nicknames */ |
| 19 static void |
| 20 sec_pkcs12_destroy_nickname_list(SECItem **nicknames) |
| 21 { |
| 22 int i = 0; |
| 23 |
| 24 if(nicknames == NULL) { |
| 25 return; |
| 26 } |
| 27 |
| 28 while(nicknames[i] != NULL) { |
| 29 SECITEM_FreeItem(nicknames[i], PR_FALSE); |
| 30 i++; |
| 31 } |
| 32 |
| 33 PORT_Free(nicknames); |
| 34 } |
| 35 |
| 36 /* release the memory taken up by the list of certificates */ |
| 37 static void |
| 38 sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs) |
| 39 { |
| 40 int i = 0; |
| 41 |
| 42 if(ref_certs == NULL) { |
| 43 return; |
| 44 } |
| 45 |
| 46 while(ref_certs[i] != NULL) { |
| 47 CERT_DestroyCertificate(ref_certs[i]); |
| 48 i++; |
| 49 } |
| 50 } |
| 51 |
| 52 static void |
| 53 sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag) |
| 54 { |
| 55 int j = 0; |
| 56 j = 0; |
| 57 while(certBag->certAndCRLs[j] != NULL) { |
| 58 SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID); |
| 59 if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) { |
| 60 SEC_PKCS12X509CertCRL *x509; |
| 61 x509 = certBag->certAndCRLs[j]->value.x509; |
| 62 SEC_PKCS7DestroyContentInfo(&x509->certOrCRL); |
| 63 } |
| 64 j++; |
| 65 } |
| 66 } |
| 67 |
| 68 /* destroy all content infos since they were not allocated in common |
| 69 * pool |
| 70 */ |
| 71 static void |
| 72 sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe, |
| 73 SEC_PKCS12Baggage *baggage) |
| 74 { |
| 75 int i, j; |
| 76 |
| 77 if((safe != NULL) && (safe->contents != NULL)) { |
| 78 i = 0; |
| 79 while(safe->contents[i] != NULL) { |
| 80 SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagTyp
e); |
| 81 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) { |
| 82 SEC_PKCS12CertAndCRLBag *certBag; |
| 83 certBag = safe->contents[i]->safeContent.certAndCRLBag; |
| 84 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag); |
| 85 } |
| 86 i++; |
| 87 } |
| 88 } |
| 89 |
| 90 if((baggage != NULL) && (baggage->bags != NULL)) { |
| 91 i = 0; |
| 92 while(baggage->bags[i] != NULL) { |
| 93 if(baggage->bags[i]->unencSecrets != NULL) { |
| 94 j = 0; |
| 95 while(baggage->bags[i]->unencSecrets[j] != NULL) { |
| 96 SECOidTag bagType; |
| 97 bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[
j]->safeBagType); |
| 98 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) { |
| 99 SEC_PKCS12CertAndCRLBag *certBag; |
| 100 certBag = baggage->bags[i]->unencSecrets[j]->safeContent
.certAndCRLBag; |
| 101 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag); |
| 102 } |
| 103 j++; |
| 104 } |
| 105 } |
| 106 i++; |
| 107 } |
| 108 } |
| 109 } |
| 110 |
| 111 /* convert the nickname list from a NULL termincated Char list |
| 112 * to a NULL terminated SECItem list |
| 113 */ |
| 114 static SECItem ** |
| 115 sec_pkcs12_convert_nickname_list(char **nicknames) |
| 116 { |
| 117 SECItem **nicks; |
| 118 int i, j; |
| 119 PRBool error = PR_FALSE; |
| 120 |
| 121 if(nicknames == NULL) { |
| 122 return NULL; |
| 123 } |
| 124 |
| 125 i = j = 0; |
| 126 while(nicknames[i] != NULL) { |
| 127 i++; |
| 128 } |
| 129 |
| 130 /* allocate the space and copy the data */ |
| 131 nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1)); |
| 132 if(nicks != NULL) { |
| 133 for(j = 0; ((j < i) && (error == PR_FALSE)); j++) { |
| 134 nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
| 135 if(nicks[j] != NULL) { |
| 136 nicks[j]->data = |
| 137 (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1); |
| 138 if(nicks[j]->data != NULL) { |
| 139 nicks[j]->len = PORT_Strlen(nicknames[j]); |
| 140 PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len); |
| 141 nicks[j]->data[nicks[j]->len] = 0; |
| 142 } else { |
| 143 error = PR_TRUE; |
| 144 } |
| 145 } else { |
| 146 error = PR_TRUE; |
| 147 } |
| 148 } |
| 149 } |
| 150 |
| 151 if(error == PR_TRUE) { |
| 152 for(i = 0; i < j; i++) { |
| 153 SECITEM_FreeItem(nicks[i], PR_TRUE); |
| 154 } |
| 155 PORT_Free(nicks); |
| 156 nicks = NULL; |
| 157 } |
| 158 |
| 159 return nicks; |
| 160 } |
| 161 |
| 162 /* package the certificate add_cert into PKCS12 structures, |
| 163 * retrieve the certificate chain for the cert and return |
| 164 * the packaged contents. |
| 165 * poolp -- common memory pool; |
| 166 * add_cert -- certificate to package up |
| 167 * nickname for the certificate |
| 168 * a return of NULL indicates an error |
| 169 */ |
| 170 static SEC_PKCS12CertAndCRL * |
| 171 sec_pkcs12_get_cert(PLArenaPool *poolp, |
| 172 CERTCertificate *add_cert, |
| 173 SECItem *nickname) |
| 174 { |
| 175 SEC_PKCS12CertAndCRL *cert; |
| 176 SEC_PKCS7ContentInfo *cinfo; |
| 177 SGNDigestInfo *t_di; |
| 178 void *mark; |
| 179 SECStatus rv; |
| 180 |
| 181 if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) { |
| 182 return NULL; |
| 183 } |
| 184 mark = PORT_ArenaMark(poolp); |
| 185 |
| 186 cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG); |
| 187 if(cert != NULL) { |
| 188 |
| 189 /* copy the nickname */ |
| 190 rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname); |
| 191 if(rv != SECSuccess) { |
| 192 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 193 cert = NULL; |
| 194 } else { |
| 195 |
| 196 /* package the certificate and cert chain into a NULL signer |
| 197 * PKCS 7 SignedData content Info and prepare it for encoding |
| 198 * since we cannot use DER_ANY_TEMPLATE |
| 199 */ |
| 200 cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL); |
| 201 rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL); |
| 202 |
| 203 /* thumbprint the certificate */ |
| 204 if((cinfo != NULL) && (rv == SECSuccess)) |
| 205 { |
| 206 PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo))
; |
| 207 t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert); |
| 208 if(t_di != NULL) |
| 209 { |
| 210 /* test */ |
| 211 rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint
, |
| 212 t_di); |
| 213 if(rv != SECSuccess) { |
| 214 cert = NULL; |
| 215 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 216 } |
| 217 SGN_DestroyDigestInfo(t_di); |
| 218 } |
| 219 else |
| 220 cert = NULL; |
| 221 } |
| 222 } |
| 223 } |
| 224 |
| 225 if (cert == NULL) { |
| 226 PORT_ArenaRelease(poolp, mark); |
| 227 } else { |
| 228 PORT_ArenaUnmark(poolp, mark); |
| 229 } |
| 230 |
| 231 return cert; |
| 232 } |
| 233 |
| 234 /* package the private key associated with the certificate and |
| 235 * return the appropriate PKCS 12 structure |
| 236 * poolp common memory pool |
| 237 * nickname key nickname |
| 238 * cert -- cert to look up |
| 239 * wincx -- window handle |
| 240 * an error is indicated by a return of NULL |
| 241 */ |
| 242 static SEC_PKCS12PrivateKey * |
| 243 sec_pkcs12_get_private_key(PLArenaPool *poolp, |
| 244 SECItem *nickname, |
| 245 CERTCertificate *cert, |
| 246 void *wincx) |
| 247 { |
| 248 SECKEYPrivateKeyInfo *pki; |
| 249 SEC_PKCS12PrivateKey *pk; |
| 250 SECStatus rv; |
| 251 void *mark; |
| 252 |
| 253 if((poolp == NULL) || (nickname == NULL)) { |
| 254 return NULL; |
| 255 } |
| 256 |
| 257 mark = PORT_ArenaMark(poolp); |
| 258 |
| 259 /* retrieve key from the data base */ |
| 260 pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx); |
| 261 if(pki == NULL) { |
| 262 PORT_ArenaRelease(poolp, mark); |
| 263 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); |
| 264 return NULL; |
| 265 } |
| 266 |
| 267 pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp, |
| 268 sizeof(SEC_PKCS12PrivateKey)); |
| 269 if(pk != NULL) { |
| 270 rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData); |
| 271 |
| 272 if(rv == SECSuccess) { |
| 273 /* copy the key into poolp memory space */ |
| 274 rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki); |
| 275 if(rv == SECSuccess) { |
| 276 rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname); |
| 277 } |
| 278 } |
| 279 |
| 280 if(rv != SECSuccess) { |
| 281 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 282 pk = NULL; |
| 283 } |
| 284 } else { |
| 285 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 286 } |
| 287 |
| 288 /* destroy private key, zeroing out data */ |
| 289 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); |
| 290 if (pk == NULL) { |
| 291 PORT_ArenaRelease(poolp, mark); |
| 292 } else { |
| 293 PORT_ArenaUnmark(poolp, mark); |
| 294 } |
| 295 |
| 296 return pk; |
| 297 } |
| 298 |
| 299 /* get a shrouded key item associated with a certificate |
| 300 * return the appropriate PKCS 12 structure |
| 301 * poolp common memory pool |
| 302 * nickname key nickname |
| 303 * cert -- cert to look up |
| 304 * wincx -- window handle |
| 305 * an error is indicated by a return of NULL |
| 306 */ |
| 307 static SEC_PKCS12ESPVKItem * |
| 308 sec_pkcs12_get_shrouded_key(PLArenaPool *poolp, |
| 309 SECItem *nickname, |
| 310 CERTCertificate *cert, |
| 311 SECOidTag algorithm, |
| 312 SECItem *pwitem, |
| 313 PKCS12UnicodeConvertFunction unicodeFn, |
| 314 void *wincx) |
| 315 { |
| 316 SECKEYEncryptedPrivateKeyInfo *epki; |
| 317 SEC_PKCS12ESPVKItem *pk; |
| 318 void *mark; |
| 319 SECStatus rv; |
| 320 PK11SlotInfo *slot = NULL; |
| 321 PRBool swapUnicodeBytes = PR_FALSE; |
| 322 |
| 323 #ifdef IS_LITTLE_ENDIAN |
| 324 swapUnicodeBytes = PR_TRUE; |
| 325 #endif |
| 326 |
| 327 if((poolp == NULL) || (nickname == NULL)) |
| 328 return NULL; |
| 329 |
| 330 mark = PORT_ArenaMark(poolp); |
| 331 |
| 332 /* use internal key slot */ |
| 333 slot = PK11_GetInternalKeySlot(); |
| 334 |
| 335 /* retrieve encrypted prviate key */ |
| 336 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem, |
| 337 nickname, cert, 1, 0, NULL); |
| 338 PK11_FreeSlot(slot); |
| 339 if(epki == NULL) { |
| 340 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); |
| 341 PORT_ArenaRelease(poolp, mark); |
| 342 return NULL; |
| 343 } |
| 344 |
| 345 /* create a private key and store the data into the poolp memory space */ |
| 346 pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING); |
| 347 if(pk != NULL) { |
| 348 rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData); |
| 349 rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname); |
| 350 pk->espvkCipherText.pkcs8KeyShroud = |
| 351 (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp, |
| 352 sizeof(SECKEYEncryptedPrivateKeyInfo)); |
| 353 if((pk->espvkCipherText.pkcs8KeyShroud != NULL) && (rv == SECSuccess))
{ |
| 354 rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp, |
| 355 pk->espvkCipherText.pkcs8KeyShroud, epki
); |
| 356 if(rv == SECSuccess) { |
| 357 rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname, |
| 358 PR_TRUE, swapUnicodeBytes); |
| 359 } |
| 360 } |
| 361 |
| 362 if(rv != SECSuccess) { |
| 363 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 364 pk = NULL; |
| 365 } |
| 366 } |
| 367 |
| 368 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); |
| 369 if(pk == NULL) { |
| 370 PORT_ArenaRelease(poolp, mark); |
| 371 } else { |
| 372 PORT_ArenaUnmark(poolp, mark); |
| 373 } |
| 374 |
| 375 return pk; |
| 376 } |
| 377 |
| 378 /* add a thumbprint to a private key associated certs list |
| 379 * pvk is the area where the list is stored |
| 380 * thumb is the thumbprint to copy |
| 381 * a return of SECFailure indicates an error |
| 382 */ |
| 383 static SECStatus |
| 384 sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk, |
| 385 SGNDigestInfo *thumb) |
| 386 { |
| 387 SGNDigestInfo **thumb_list = NULL; |
| 388 int nthumbs, size; |
| 389 void *mark, *dummy; |
| 390 SECStatus rv = SECFailure; |
| 391 |
| 392 if((pvk == NULL) || (thumb == NULL)) { |
| 393 return SECFailure; |
| 394 } |
| 395 |
| 396 mark = PORT_ArenaMark(pvk->poolp); |
| 397 |
| 398 thumb_list = pvk->assocCerts; |
| 399 nthumbs = pvk->nThumbs; |
| 400 |
| 401 /* allocate list space needed -- either growing or allocating |
| 402 * list must be NULL terminated |
| 403 */ |
| 404 size = sizeof(SGNDigestInfo *); |
| 405 dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)), |
| 406 (size * (nthumbs + 2))); |
| 407 thumb_list = dummy; |
| 408 if(dummy != NULL) { |
| 409 thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp, |
| 410 sizeof(SGNDigestInfo)); |
| 411 if(thumb_list[nthumbs] != NULL) { |
| 412 SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb); |
| 413 nthumbs += 1; |
| 414 thumb_list[nthumbs] = 0; |
| 415 } else { |
| 416 dummy = NULL; |
| 417 } |
| 418 } |
| 419 |
| 420 if(dummy == NULL) { |
| 421 PORT_ArenaRelease(pvk->poolp, mark); |
| 422 return SECFailure; |
| 423 } |
| 424 |
| 425 pvk->assocCerts = thumb_list; |
| 426 pvk->nThumbs = nthumbs; |
| 427 |
| 428 PORT_ArenaUnmark(pvk->poolp, mark); |
| 429 return SECSuccess; |
| 430 } |
| 431 |
| 432 /* search the list of shrouded keys in the baggage for the desired |
| 433 * name. return a pointer to the item. a return of NULL indicates |
| 434 * that no match was present or that an error occurred. |
| 435 */ |
| 436 static SEC_PKCS12ESPVKItem * |
| 437 sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage, |
| 438 SECItem *name) |
| 439 { |
| 440 PRBool found = PR_FALSE; |
| 441 SEC_PKCS12ESPVKItem *espvk = NULL; |
| 442 int i, j; |
| 443 SECComparison rv = SECEqual; |
| 444 SECItem *t_name; |
| 445 SEC_PKCS12BaggageItem *bag; |
| 446 |
| 447 if((luggage == NULL) || (name == NULL)) { |
| 448 return NULL; |
| 449 } |
| 450 |
| 451 i = 0; |
| 452 while((found == PR_FALSE) && (i < luggage->luggage_size)) { |
| 453 j = 0; |
| 454 bag = luggage->bags[i]; |
| 455 while((found == PR_FALSE) && (j < bag->nEspvks)) { |
| 456 espvk = bag->espvks[j]; |
| 457 if(espvk->poolp == NULL) { |
| 458 espvk->poolp = luggage->poolp; |
| 459 } |
| 460 t_name = SECITEM_DupItem(&espvk->espvkData.nickname); |
| 461 if(t_name != NULL) { |
| 462 rv = SECITEM_CompareItem(name, t_name); |
| 463 if(rv == SECEqual) { |
| 464 found = PR_TRUE; |
| 465 } |
| 466 SECITEM_FreeItem(t_name, PR_TRUE); |
| 467 } else { |
| 468 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 469 return NULL; |
| 470 } |
| 471 j++; |
| 472 } |
| 473 i++; |
| 474 } |
| 475 |
| 476 if(found != PR_TRUE) { |
| 477 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME); |
| 478 return NULL; |
| 479 } |
| 480 |
| 481 return espvk; |
| 482 } |
| 483 |
| 484 /* locates a certificate and copies the thumbprint to the |
| 485 * appropriate private key |
| 486 */ |
| 487 static SECStatus |
| 488 sec_pkcs12_propagate_thumbprints(SECItem **nicknames, |
| 489 CERTCertificate **ref_certs, |
| 490 SEC_PKCS12SafeContents *safe, |
| 491 SEC_PKCS12Baggage *baggage) |
| 492 { |
| 493 SEC_PKCS12CertAndCRL *cert; |
| 494 SEC_PKCS12PrivateKey *key; |
| 495 SEC_PKCS12ESPVKItem *espvk; |
| 496 int i; |
| 497 PRBool error = PR_FALSE; |
| 498 SECStatus rv = SECFailure; |
| 499 |
| 500 if((nicknames == NULL) || (safe == NULL)) { |
| 501 return SECFailure; |
| 502 } |
| 503 |
| 504 i = 0; |
| 505 while((nicknames[i] != NULL) && (error == PR_FALSE)) { |
| 506 /* process all certs */ |
| 507 cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage, |
| 508 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, |
| 509 nicknames[i], NULL); |
| 510 if(cert != NULL) { |
| 511 /* locate key and copy thumbprint */ |
| 512 key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage, |
| 513 SEC_OID_PKCS12_KEY_BAG_ID, |
| 514 nicknames[i], NULL); |
| 515 if(key != NULL) { |
| 516 key->pvkData.poolp = key->poolp; |
| 517 rv = sec_pkcs12_add_thumbprint(&key->pvkData, |
| 518 &cert->value.x509->thumbprint); |
| 519 if(rv == SECFailure) |
| 520 error = PR_TRUE; /* XXX Set error? */ |
| 521 } |
| 522 |
| 523 /* look in the baggage as well...*/ |
| 524 if((baggage != NULL) && (error == PR_FALSE)) { |
| 525 espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]); |
| 526 if(espvk != NULL) { |
| 527 espvk->espvkData.poolp = espvk->poolp; |
| 528 rv = sec_pkcs12_add_thumbprint(&espvk->espvkData, |
| 529 &cert->value.x509->thumbprint); |
| 530 if(rv == SECFailure) |
| 531 error = PR_TRUE; /* XXX Set error? */ |
| 532 } |
| 533 } |
| 534 } |
| 535 i++; |
| 536 } |
| 537 |
| 538 if(error == PR_TRUE) { |
| 539 return SECFailure; |
| 540 } |
| 541 |
| 542 return SECSuccess; |
| 543 } |
| 544 |
| 545 /* append a safe bag to the end of the safe contents list */ |
| 546 SECStatus |
| 547 sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe, |
| 548 SEC_PKCS12SafeBag *bag) |
| 549 { |
| 550 int size; |
| 551 void *mark = NULL, *dummy = NULL; |
| 552 |
| 553 if((bag == NULL) || (safe == NULL)) |
| 554 return SECFailure; |
| 555 |
| 556 mark = PORT_ArenaMark(safe->poolp); |
| 557 |
| 558 size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *)); |
| 559 |
| 560 if(safe->safe_size > 0) { |
| 561 dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp, |
| 562 safe->contents, |
| 563 size, |
| 564 (size + sizeof(SEC_PKCS12SafeBag *))); |
| 565 safe->contents = dummy; |
| 566 } else { |
| 567 safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp, |
| 568 (2 * sizeof(SEC_PKCS12SafeBag *))); |
| 569 dummy = safe->contents; |
| 570 } |
| 571 |
| 572 if(dummy == NULL) { |
| 573 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 574 goto loser; |
| 575 } |
| 576 |
| 577 safe->contents[safe->safe_size] = bag; |
| 578 safe->safe_size++; |
| 579 safe->contents[safe->safe_size] = NULL; |
| 580 |
| 581 PORT_ArenaUnmark(safe->poolp, mark); |
| 582 return SECSuccess; |
| 583 |
| 584 loser: |
| 585 PORT_ArenaRelease(safe->poolp, mark); |
| 586 return SECFailure; |
| 587 } |
| 588 |
| 589 /* append a certificate onto the end of a cert bag */ |
| 590 static SECStatus |
| 591 sec_pkcs12_append_cert_to_bag(PLArenaPool *arena, |
| 592 SEC_PKCS12SafeBag *safebag, |
| 593 CERTCertificate *cert, |
| 594 SECItem *nickname) |
| 595 { |
| 596 int size; |
| 597 void *dummy = NULL, *mark = NULL; |
| 598 SEC_PKCS12CertAndCRL *p12cert; |
| 599 SEC_PKCS12CertAndCRLBag *bag; |
| 600 |
| 601 if((arena == NULL) || (safebag == NULL) || |
| 602 (cert == NULL) || (nickname == NULL)) { |
| 603 return SECFailure; |
| 604 } |
| 605 |
| 606 bag = safebag->safeContent.certAndCRLBag; |
| 607 if(bag == NULL) { |
| 608 return SECFailure; |
| 609 } |
| 610 |
| 611 mark = PORT_ArenaMark(arena); |
| 612 |
| 613 p12cert = sec_pkcs12_get_cert(arena, cert, nickname); |
| 614 if(p12cert == NULL) { |
| 615 PORT_ArenaRelease(bag->poolp, mark); |
| 616 return SECFailure; |
| 617 } |
| 618 |
| 619 size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *); |
| 620 if(bag->bag_size > 0) { |
| 621 dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp, |
| 622 bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *)); |
| 623 bag->certAndCRLs = dummy; |
| 624 } else { |
| 625 bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp, |
| 626 (2 * sizeof(SEC_PKCS12CertAndCRL *))); |
| 627 dummy = bag->certAndCRLs; |
| 628 } |
| 629 |
| 630 if(dummy == NULL) { |
| 631 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 632 goto loser; |
| 633 } |
| 634 |
| 635 bag->certAndCRLs[bag->bag_size] = p12cert; |
| 636 bag->bag_size++; |
| 637 bag->certAndCRLs[bag->bag_size] = NULL; |
| 638 |
| 639 PORT_ArenaUnmark(bag->poolp, mark); |
| 640 return SECSuccess; |
| 641 |
| 642 loser: |
| 643 PORT_ArenaRelease(bag->poolp, mark); |
| 644 return SECFailure; |
| 645 } |
| 646 |
| 647 /* append a key onto the end of a list of keys in a key bag */ |
| 648 SECStatus |
| 649 sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag, |
| 650 SEC_PKCS12PrivateKey *pk) |
| 651 { |
| 652 void *mark, *dummy; |
| 653 SEC_PKCS12PrivateKeyBag *bag; |
| 654 int size; |
| 655 |
| 656 if((safebag == NULL) || (pk == NULL)) |
| 657 return SECFailure; |
| 658 |
| 659 bag = safebag->safeContent.keyBag; |
| 660 if(bag == NULL) { |
| 661 return SECFailure; |
| 662 } |
| 663 |
| 664 mark = PORT_ArenaMark(bag->poolp); |
| 665 |
| 666 size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *)); |
| 667 |
| 668 if(bag->bag_size > 0) { |
| 669 dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp, |
| 670 bag->privateKeys, |
| 671 size, |
| 672 size + sizeof(SEC_PKCS12PrivateKey *)); |
| 673 bag->privateKeys = dummy; |
| 674 } else { |
| 675 bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp, |
| 676 (2 * sizeof(SEC_PKCS12PrivateKey *))); |
| 677 dummy = bag->privateKeys; |
| 678 } |
| 679 |
| 680 if(dummy == NULL) { |
| 681 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 682 goto loser; |
| 683 } |
| 684 |
| 685 bag->privateKeys[bag->bag_size] = pk; |
| 686 bag->bag_size++; |
| 687 bag->privateKeys[bag->bag_size] = NULL; |
| 688 |
| 689 PORT_ArenaUnmark(bag->poolp, mark); |
| 690 return SECSuccess; |
| 691 |
| 692 loser: |
| 693 /* XXX Free memory? */ |
| 694 PORT_ArenaRelease(bag->poolp, mark); |
| 695 return SECFailure; |
| 696 } |
| 697 |
| 698 /* append a safe bag to the baggage area */ |
| 699 static SECStatus |
| 700 sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag, |
| 701 SEC_PKCS12SafeBag *u_bag) |
| 702 { |
| 703 int size; |
| 704 void *mark = NULL, *dummy = NULL; |
| 705 |
| 706 if((bag == NULL) || (u_bag == NULL)) |
| 707 return SECFailure; |
| 708 |
| 709 mark = PORT_ArenaMark(bag->poolp); |
| 710 |
| 711 /* dump things into the first bag */ |
| 712 size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *); |
| 713 dummy = PORT_ArenaGrow(bag->poolp, |
| 714 bag->unencSecrets, size, |
| 715 size + sizeof(SEC_PKCS12SafeBag *)); |
| 716 bag->unencSecrets = dummy; |
| 717 if(dummy == NULL) { |
| 718 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 719 goto loser; |
| 720 } |
| 721 |
| 722 bag->unencSecrets[bag->nSecrets] = u_bag; |
| 723 bag->nSecrets++; |
| 724 bag->unencSecrets[bag->nSecrets] = NULL; |
| 725 |
| 726 PORT_ArenaUnmark(bag->poolp, mark); |
| 727 return SECSuccess; |
| 728 |
| 729 loser: |
| 730 PORT_ArenaRelease(bag->poolp, mark); |
| 731 return SECFailure; |
| 732 } |
| 733 |
| 734 /* gather up all certificates and keys and package them up |
| 735 * in the safe, baggage, or both. |
| 736 * nicknames is the list of nicknames and corresponding certs in ref_certs |
| 737 * ref_certs a null terminated list of certificates |
| 738 * rSafe, rBaggage -- return areas for safe and baggage |
| 739 * shroud_keys -- store keys externally |
| 740 * pwitem -- password for computing integrity mac and encrypting contents |
| 741 * wincx -- window handle |
| 742 * |
| 743 * if a failure occurs, an error is set and SECFailure returned. |
| 744 */ |
| 745 static SECStatus |
| 746 sec_pkcs12_package_certs_and_keys(SECItem **nicknames, |
| 747 CERTCertificate **ref_certs, |
| 748 PRBool unencryptedCerts, |
| 749 SEC_PKCS12SafeContents **rSafe, |
| 750 SEC_PKCS12Baggage **rBaggage, |
| 751 PRBool shroud_keys, |
| 752 SECOidTag shroud_alg, |
| 753 SECItem *pwitem, |
| 754 PKCS12UnicodeConvertFunction unicodeFn, |
| 755 void *wincx) |
| 756 { |
| 757 PLArenaPool *permArena; |
| 758 SEC_PKCS12SafeContents *safe = NULL; |
| 759 SEC_PKCS12Baggage *baggage = NULL; |
| 760 |
| 761 SECStatus rv = SECFailure; |
| 762 PRBool problem = PR_FALSE; |
| 763 |
| 764 SEC_PKCS12ESPVKItem *espvk = NULL; |
| 765 SEC_PKCS12PrivateKey *pk = NULL; |
| 766 CERTCertificate *add_cert = NULL; |
| 767 SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL; |
| 768 SEC_PKCS12BaggageItem *external_bag = NULL; |
| 769 int ncerts = 0, nkeys = 0; |
| 770 int i; |
| 771 |
| 772 if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) { |
| 773 return SECFailure; |
| 774 } |
| 775 |
| 776 *rBaggage = baggage; |
| 777 *rSafe = safe; |
| 778 |
| 779 permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
| 780 if(permArena == NULL) { |
| 781 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 782 return SECFailure; |
| 783 } |
| 784 |
| 785 /* allocate structures */ |
| 786 safe = sec_pkcs12_create_safe_contents(permArena); |
| 787 if(safe == NULL) { |
| 788 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 789 rv = SECFailure; |
| 790 goto loser; |
| 791 } |
| 792 |
| 793 certbag = sec_pkcs12_create_safe_bag(permArena, |
| 794 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID); |
| 795 if(certbag == NULL) { |
| 796 rv = SECFailure; |
| 797 goto loser; |
| 798 } |
| 799 |
| 800 if(shroud_keys != PR_TRUE) { |
| 801 keybag = sec_pkcs12_create_safe_bag(permArena, |
| 802 SEC_OID_PKCS12_KEY_BAG_ID); |
| 803 if(keybag == NULL) { |
| 804 rv = SECFailure; |
| 805 goto loser; |
| 806 } |
| 807 } |
| 808 |
| 809 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) { |
| 810 baggage = sec_pkcs12_create_baggage(permArena); |
| 811 if(baggage == NULL) { |
| 812 rv = SECFailure; |
| 813 goto loser; |
| 814 } |
| 815 external_bag = sec_pkcs12_create_external_bag(baggage); |
| 816 } |
| 817 |
| 818 /* package keys and certs */ |
| 819 i = 0; |
| 820 while((nicknames[i] != NULL) && (problem == PR_FALSE)) { |
| 821 if(ref_certs[i] != NULL) { |
| 822 /* append cert to bag o certs */ |
| 823 rv = sec_pkcs12_append_cert_to_bag(permArena, certbag, |
| 824 ref_certs[i], |
| 825 nicknames[i]); |
| 826 if(rv == SECFailure) { |
| 827 problem = PR_FALSE; |
| 828 } else { |
| 829 ncerts++; |
| 830 } |
| 831 |
| 832 if(rv == SECSuccess) { |
| 833 /* package up them keys */ |
| 834 if(shroud_keys == PR_TRUE) { |
| 835 espvk = sec_pkcs12_get_shrouded_key(permArena, |
| 836 nicknames[i], |
| 837 ref_certs[i], |
| 838 shroud_alg, |
| 839 pwitem, unicodeFn, |
| 840 wincx); |
| 841 if(espvk != NULL) { |
| 842 rv = sec_pkcs12_append_shrouded_key(external_bag, espvk)
; |
| 843 SECITEM_CopyItem(permArena, &espvk->derCert, |
| 844 &ref_certs[i]->derCert); |
| 845 } else { |
| 846 rv = SECFailure; |
| 847 } |
| 848 } else { |
| 849 pk = sec_pkcs12_get_private_key(permArena, nicknames[i], |
| 850 ref_certs[i], wincx); |
| 851 if(pk != NULL) { |
| 852 rv = sec_pkcs12_append_key_to_bag(keybag, pk); |
| 853 SECITEM_CopyItem(permArena, &espvk->derCert, |
| 854 &ref_certs[i]->derCert); |
| 855 } else { |
| 856 rv = SECFailure; |
| 857 } |
| 858 } |
| 859 |
| 860 if(rv == SECFailure) { |
| 861 problem = PR_TRUE; |
| 862 } else { |
| 863 nkeys++; |
| 864 } |
| 865 } |
| 866 } else { |
| 867 /* handle only keys here ? */ |
| 868 problem = PR_TRUE; |
| 869 } |
| 870 i++; |
| 871 } |
| 872 |
| 873 /* let success fall through */ |
| 874 loser: |
| 875 if(problem == PR_FALSE) { |
| 876 /* if we have certs, we want to append the cert bag to the |
| 877 * appropriate area |
| 878 */ |
| 879 if(ncerts > 0) { |
| 880 if(unencryptedCerts != PR_TRUE) { |
| 881 rv = sec_pkcs12_append_safe_bag(safe, certbag); |
| 882 } else { |
| 883 rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag); |
| 884 } |
| 885 } else { |
| 886 rv = SECSuccess; |
| 887 } |
| 888 |
| 889 /* append key bag, if they are stored in safe contents */ |
| 890 if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) { |
| 891 rv = sec_pkcs12_append_safe_bag(safe, keybag); |
| 892 } |
| 893 } else { |
| 894 rv = SECFailure; |
| 895 } |
| 896 |
| 897 /* if baggage not used, NULLify it */ |
| 898 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) { |
| 899 if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) && |
| 900 ((shroud_keys == PR_TRUE) && (nkeys == 0))) |
| 901 baggage = NULL; |
| 902 } else { |
| 903 baggage = NULL; |
| 904 } |
| 905 |
| 906 if((problem == PR_TRUE) || (rv == SECFailure)) { |
| 907 PORT_FreeArena(permArena, PR_TRUE); |
| 908 rv = SECFailure; |
| 909 baggage = NULL; |
| 910 safe = NULL; |
| 911 } |
| 912 |
| 913 *rBaggage = baggage; |
| 914 *rSafe = safe; |
| 915 |
| 916 return rv; |
| 917 } |
| 918 |
| 919 /* DER encode the safe contents and return a SECItem. if an error |
| 920 * occurs, NULL is returned. |
| 921 */ |
| 922 static SECItem * |
| 923 sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe) |
| 924 { |
| 925 SECItem *dsafe = NULL, *tsafe; |
| 926 void *dummy = NULL; |
| 927 PLArenaPool *arena; |
| 928 |
| 929 if(safe == NULL) { |
| 930 return NULL; |
| 931 } |
| 932 |
| 933 /* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE); |
| 934 if(rv != SECSuccess) { |
| 935 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 936 return NULL; |
| 937 }*/ |
| 938 |
| 939 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
| 940 if(arena == NULL) { |
| 941 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 942 return NULL; |
| 943 } |
| 944 |
| 945 tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem)); |
| 946 if(tsafe != NULL) { |
| 947 dummy = SEC_ASN1EncodeItem(arena, tsafe, safe, |
| 948 SEC_PKCS12SafeContentsTemplate); |
| 949 if(dummy != NULL) { |
| 950 dsafe = SECITEM_DupItem(tsafe); |
| 951 } else { |
| 952 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 953 } |
| 954 } else { |
| 955 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 956 } |
| 957 |
| 958 PORT_FreeArena(arena, PR_TRUE); |
| 959 |
| 960 return dsafe; |
| 961 } |
| 962 |
| 963 /* prepare the authenicated safe for encoding and encode it. |
| 964 * baggage is copied to the appropriate area, safe is encoded and |
| 965 * encrypted. the version and transport mode are set on the asafe. |
| 966 * the whole ball of wax is then der encoded and packaged up into |
| 967 * data content info |
| 968 * safe -- container of certs and keys, is encrypted. |
| 969 * baggage -- container of certs and keys, keys assumed to be encrypted by |
| 970 * another method, certs are in the clear |
| 971 * algorithm -- algorithm by which to encrypt safe |
| 972 * pwitem -- password for encryption |
| 973 * wincx - window handle |
| 974 * |
| 975 * return of NULL is an error condition. |
| 976 */ |
| 977 static SEC_PKCS7ContentInfo * |
| 978 sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe, |
| 979 SEC_PKCS12Baggage *baggage, |
| 980 SECOidTag algorithm, |
| 981 SECItem *pwitem, |
| 982 PKCS12UnicodeConvertFunction unicodeFn, |
| 983 void *wincx) |
| 984 { |
| 985 SECItem *src = NULL, *dest = NULL, *psalt = NULL; |
| 986 PLArenaPool *poolp; |
| 987 SEC_PKCS12AuthenticatedSafe *asafe; |
| 988 SEC_PKCS7ContentInfo *safe_cinfo = NULL; |
| 989 SEC_PKCS7ContentInfo *asafe_cinfo = NULL; |
| 990 void *dummy; |
| 991 SECStatus rv = SECSuccess; |
| 992 PRBool swapUnicodeBytes = PR_FALSE; |
| 993 |
| 994 #ifdef IS_LITTLE_ENDIAN |
| 995 swapUnicodeBytes = PR_TRUE; |
| 996 #endif |
| 997 |
| 998 if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL)) |
| 999 return NULL; |
| 1000 |
| 1001 poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
| 1002 if(poolp == NULL) { |
| 1003 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1004 return NULL; |
| 1005 } |
| 1006 |
| 1007 /* prepare authenticated safe for encode */ |
| 1008 asafe = sec_pkcs12_new_asafe(poolp); |
| 1009 if(asafe != NULL) { |
| 1010 |
| 1011 /* set version */ |
| 1012 dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version, |
| 1013 SEC_PKCS12_PFX_VERSION); |
| 1014 if(dummy == NULL) { |
| 1015 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1016 rv = SECFailure; |
| 1017 goto loser; |
| 1018 } |
| 1019 |
| 1020 /* generate the privacy salt used to create virtual pwd */ |
| 1021 psalt = sec_pkcs12_generate_salt(); |
| 1022 if(psalt != NULL) { |
| 1023 rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt, |
| 1024 psalt); |
| 1025 if(rv == SECSuccess) { |
| 1026 asafe->privacySalt.len *= 8; |
| 1027 } |
| 1028 else { |
| 1029 SECITEM_ZfreeItem(psalt, PR_TRUE); |
| 1030 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1031 goto loser; |
| 1032 } |
| 1033 } |
| 1034 |
| 1035 if((psalt == NULL) || (rv == SECFailure)) { |
| 1036 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1037 rv = SECFailure; |
| 1038 goto loser; |
| 1039 } |
| 1040 |
| 1041 /* package up safe contents */ |
| 1042 if(safe != NULL) |
| 1043 { |
| 1044 safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx); |
| 1045 if((safe_cinfo != NULL) && (safe->safe_size > 0)) { |
| 1046 /* encode the safe and encrypt the contents of the |
| 1047 * content info |
| 1048 */ |
| 1049 src = sec_pkcs12_encode_safe_contents(safe); |
| 1050 |
| 1051 if(src != NULL) { |
| 1052 rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src-
>len); |
| 1053 SECITEM_ZfreeItem(src, PR_TRUE); |
| 1054 if(rv == SECSuccess) { |
| 1055 SECItem *vpwd; |
| 1056 vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt, |
| 1057 unicodeFn, swapUnicodeBytes); |
| 1058 if(vpwd != NULL) { |
| 1059 rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo, |
| 1060 vpwd, wincx); |
| 1061 SECITEM_ZfreeItem(vpwd, PR_TRUE); |
| 1062 } else { |
| 1063 rv = SECFailure; |
| 1064 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1065 } |
| 1066 } else { |
| 1067 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1068 } |
| 1069 } else { |
| 1070 rv = SECFailure; |
| 1071 } |
| 1072 } else if(safe->safe_size > 0) { |
| 1073 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1074 goto loser; |
| 1075 } else { |
| 1076 /* case where there is NULL content in the safe contents */ |
| 1077 rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0); |
| 1078 if(rv != SECFailure) { |
| 1079 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1080 } |
| 1081 } |
| 1082 |
| 1083 if(rv != SECSuccess) { |
| 1084 SEC_PKCS7DestroyContentInfo(safe_cinfo); |
| 1085 safe_cinfo = NULL; |
| 1086 goto loser; |
| 1087 } |
| 1088 |
| 1089 asafe->safe = safe_cinfo; |
| 1090 /* |
| 1091 PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo)); |
| 1092 */ |
| 1093 } |
| 1094 |
| 1095 /* copy the baggage to the authenticated safe baggage if present */ |
| 1096 if(baggage != NULL) { |
| 1097 PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage)); |
| 1098 } |
| 1099 |
| 1100 /* encode authenticated safe and store it in a Data content info */ |
| 1101 dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem)); |
| 1102 if(dest != NULL) { |
| 1103 dummy = SEC_ASN1EncodeItem(poolp, dest, asafe, |
| 1104 SEC_PKCS12AuthenticatedSafeTemplate); |
| 1105 if(dummy != NULL) { |
| 1106 asafe_cinfo = SEC_PKCS7CreateData(); |
| 1107 if(asafe_cinfo != NULL) { |
| 1108 rv = SEC_PKCS7SetContent(asafe_cinfo, |
| 1109 (char *)dest->data, |
| 1110 dest->len); |
| 1111 if(rv != SECSuccess) { |
| 1112 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1113 SEC_PKCS7DestroyContentInfo(asafe_cinfo); |
| 1114 asafe_cinfo = NULL; |
| 1115 } |
| 1116 } |
| 1117 } else { |
| 1118 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1119 rv = SECFailure; |
| 1120 } |
| 1121 } |
| 1122 } |
| 1123 |
| 1124 loser: |
| 1125 PORT_FreeArena(poolp, PR_TRUE); |
| 1126 if(safe_cinfo != NULL) { |
| 1127 SEC_PKCS7DestroyContentInfo(safe_cinfo); |
| 1128 } |
| 1129 if(psalt != NULL) { |
| 1130 SECITEM_ZfreeItem(psalt, PR_TRUE); |
| 1131 } |
| 1132 |
| 1133 if(rv == SECFailure) { |
| 1134 return NULL; |
| 1135 } |
| 1136 |
| 1137 return asafe_cinfo; |
| 1138 } |
| 1139 |
| 1140 /* generates the PFX and computes the mac on the authenticated safe |
| 1141 * NULL implies an error |
| 1142 */ |
| 1143 static SEC_PKCS12PFXItem * |
| 1144 sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo, |
| 1145 PRBool do_mac, |
| 1146 SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn) |
| 1147 { |
| 1148 SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL; |
| 1149 SEC_PKCS12PFXItem *pfx; |
| 1150 SECStatus rv = SECFailure; |
| 1151 SGNDigestInfo *di; |
| 1152 SECItem *vpwd; |
| 1153 PRBool swapUnicodeBytes = PR_FALSE; |
| 1154 |
| 1155 #ifdef IS_LITTLE_ENDIAN |
| 1156 swapUnicodeBytes = PR_TRUE; |
| 1157 #endif |
| 1158 |
| 1159 if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) { |
| 1160 return NULL; |
| 1161 } |
| 1162 |
| 1163 /* allocate new pfx structure */ |
| 1164 pfx = sec_pkcs12_new_pfx(); |
| 1165 if(pfx == NULL) { |
| 1166 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1167 return NULL; |
| 1168 } |
| 1169 |
| 1170 PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo)); |
| 1171 if(do_mac == PR_TRUE) { |
| 1172 |
| 1173 /* salt for computing mac */ |
| 1174 salt = sec_pkcs12_generate_salt(); |
| 1175 if(salt != NULL) { |
| 1176 rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt); |
| 1177 pfx->macData.macSalt.len *= 8; |
| 1178 |
| 1179 vpwd = sec_pkcs12_create_virtual_password(pwitem, salt, |
| 1180 unicodeFn, swapUnicodeBytes); |
| 1181 if(vpwd == NULL) { |
| 1182 rv = SECFailure; |
| 1183 key = NULL; |
| 1184 } else { |
| 1185 key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1, |
| 1186 salt, vpwd); |
| 1187 SECITEM_ZfreeItem(vpwd, PR_TRUE); |
| 1188 } |
| 1189 |
| 1190 if((key != NULL) && (rv == SECSuccess)) { |
| 1191 dest = SEC_PKCS7GetContent(cinfo); |
| 1192 if(dest != NULL) { |
| 1193 |
| 1194 /* compute mac on data -- for password integrity mode */ |
| 1195 mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE); |
| 1196 if(mac != NULL) { |
| 1197 di = SGN_CreateDigestInfo(SEC_OID_SHA1, |
| 1198 mac->data, mac->len); |
| 1199 if(di != NULL) { |
| 1200 rv = SGN_CopyDigestInfo(pfx->poolp, |
| 1201 &pfx->macData.safeMac, di); |
| 1202 SGN_DestroyDigestInfo(di); |
| 1203 } else { |
| 1204 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1205 } |
| 1206 SECITEM_ZfreeItem(mac, PR_TRUE); |
| 1207 } |
| 1208 } else { |
| 1209 rv = SECFailure; |
| 1210 } |
| 1211 } else { |
| 1212 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1213 rv = SECFailure; |
| 1214 } |
| 1215 |
| 1216 if(key != NULL) { |
| 1217 SECITEM_ZfreeItem(key, PR_TRUE); |
| 1218 } |
| 1219 SECITEM_ZfreeItem(salt, PR_TRUE); |
| 1220 } |
| 1221 } |
| 1222 |
| 1223 if(rv == SECFailure) { |
| 1224 SEC_PKCS12DestroyPFX(pfx); |
| 1225 pfx = NULL; |
| 1226 } |
| 1227 |
| 1228 return pfx; |
| 1229 } |
| 1230 |
| 1231 /* der encode the pfx */ |
| 1232 static SECItem * |
| 1233 sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx) |
| 1234 { |
| 1235 SECItem *dest; |
| 1236 void *dummy; |
| 1237 |
| 1238 if(pfx == NULL) { |
| 1239 return NULL; |
| 1240 } |
| 1241 |
| 1242 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
| 1243 if(dest == NULL) { |
| 1244 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1245 return NULL; |
| 1246 } |
| 1247 |
| 1248 dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate); |
| 1249 if(dummy == NULL) { |
| 1250 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1251 SECITEM_ZfreeItem(dest, PR_TRUE); |
| 1252 dest = NULL; |
| 1253 } |
| 1254 |
| 1255 return dest; |
| 1256 } |
| 1257 |
| 1258 SECItem * |
| 1259 SEC_PKCS12GetPFX(char **nicknames, |
| 1260 CERTCertificate **ref_certs, |
| 1261 PRBool shroud_keys, |
| 1262 SEC_PKCS5GetPBEPassword pbef, |
| 1263 void *pbearg, |
| 1264 PKCS12UnicodeConvertFunction unicodeFn, |
| 1265 void *wincx) |
| 1266 { |
| 1267 SECItem **nicks = NULL; |
| 1268 SEC_PKCS12PFXItem *pfx = NULL; |
| 1269 SEC_PKCS12Baggage *baggage = NULL; |
| 1270 SEC_PKCS12SafeContents *safe = NULL; |
| 1271 SEC_PKCS7ContentInfo *cinfo = NULL; |
| 1272 SECStatus rv = SECFailure; |
| 1273 SECItem *dest = NULL, *pwitem = NULL; |
| 1274 PRBool problem = PR_FALSE; |
| 1275 PRBool unencryptedCerts; |
| 1276 SECOidTag shroud_alg, safe_alg; |
| 1277 |
| 1278 /* how should we encrypt certs ? */ |
| 1279 unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed(); |
| 1280 if(!unencryptedCerts) { |
| 1281 safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm(); |
| 1282 if(safe_alg == SEC_OID_UNKNOWN) { |
| 1283 safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm(); |
| 1284 } |
| 1285 if(safe_alg == SEC_OID_UNKNOWN) { |
| 1286 unencryptedCerts = PR_TRUE; |
| 1287 /* for export where no encryption is allowed, we still need |
| 1288 * to encrypt the NULL contents per the spec. encrypted info |
| 1289 * is known plaintext, so it shouldn't be a problem. |
| 1290 */ |
| 1291 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC; |
| 1292 } |
| 1293 } else { |
| 1294 /* for export where no encryption is allowed, we still need |
| 1295 * to encrypt the NULL contents per the spec. encrypted info |
| 1296 * is known plaintext, so it shouldn't be a problem. |
| 1297 */ |
| 1298 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC; |
| 1299 } |
| 1300 |
| 1301 /* keys are always stored with triple DES */ |
| 1302 shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC; |
| 1303 |
| 1304 /* check for FIPS, if so, do not encrypt certs */ |
| 1305 if(PK11_IsFIPS() && !unencryptedCerts) { |
| 1306 unencryptedCerts = PR_TRUE; |
| 1307 } |
| 1308 |
| 1309 if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) { |
| 1310 problem = PR_TRUE; |
| 1311 goto loser; |
| 1312 } |
| 1313 |
| 1314 |
| 1315 /* get password */ |
| 1316 pwitem = (*pbef)(pbearg); |
| 1317 if(pwitem == NULL) { |
| 1318 problem = PR_TRUE; |
| 1319 goto loser; |
| 1320 } |
| 1321 nicks = sec_pkcs12_convert_nickname_list(nicknames); |
| 1322 |
| 1323 /* get safe and baggage */ |
| 1324 rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts, |
| 1325 &safe, &baggage, shroud_keys, |
| 1326 shroud_alg, pwitem, unicodeFn, wincx)
; |
| 1327 if(rv == SECFailure) { |
| 1328 problem = PR_TRUE; |
| 1329 } |
| 1330 |
| 1331 if((safe != NULL) && (problem == PR_FALSE)) { |
| 1332 /* copy thumbprints */ |
| 1333 rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage); |
| 1334 |
| 1335 /* package everything up into AuthenticatedSafe */ |
| 1336 cinfo = sec_pkcs12_get_auth_safe(safe, baggage, |
| 1337 safe_alg, pwitem, unicodeFn, wincx); |
| 1338 |
| 1339 sec_pkcs12_destroy_cert_content_infos(safe, baggage); |
| 1340 |
| 1341 /* get the pfx and mac it */ |
| 1342 if(cinfo != NULL) { |
| 1343 pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn); |
| 1344 if(pfx != NULL) { |
| 1345 dest = sec_pkcs12_encode_pfx(pfx); |
| 1346 SEC_PKCS12DestroyPFX(pfx); |
| 1347 } |
| 1348 SEC_PKCS7DestroyContentInfo(cinfo); |
| 1349 } |
| 1350 |
| 1351 if(safe != NULL) { |
| 1352 PORT_FreeArena(safe->poolp, PR_TRUE); |
| 1353 } |
| 1354 } else { |
| 1355 if(safe != NULL) { |
| 1356 PORT_FreeArena(safe->poolp, PR_TRUE); |
| 1357 } |
| 1358 } |
| 1359 |
| 1360 loser: |
| 1361 if(nicks != NULL) { |
| 1362 sec_pkcs12_destroy_nickname_list(nicks); |
| 1363 } |
| 1364 |
| 1365 if(ref_certs != NULL) { |
| 1366 sec_pkcs12_destroy_certificate_list(ref_certs); |
| 1367 } |
| 1368 |
| 1369 if(pwitem != NULL) { |
| 1370 SECITEM_ZfreeItem(pwitem, PR_TRUE); |
| 1371 } |
| 1372 |
| 1373 if(problem == PR_TRUE) { |
| 1374 dest = NULL; |
| 1375 } |
| 1376 |
| 1377 return dest; |
| 1378 } |
| OLD | NEW |