| 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 |