1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/pkcs12/p12exp.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1378 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "plarena.h" 1.9 +#include "secitem.h" 1.10 +#include "secoid.h" 1.11 +#include "seccomon.h" 1.12 +#include "secport.h" 1.13 +#include "cert.h" 1.14 +#include "pkcs12.h" 1.15 +#include "p12local.h" 1.16 +#include "secpkcs7.h" 1.17 +#include "secasn1.h" 1.18 +#include "secerr.h" 1.19 +#include "p12plcy.h" 1.20 + 1.21 +/* release the memory taken up by the list of nicknames */ 1.22 +static void 1.23 +sec_pkcs12_destroy_nickname_list(SECItem **nicknames) 1.24 +{ 1.25 + int i = 0; 1.26 + 1.27 + if(nicknames == NULL) { 1.28 + return; 1.29 + } 1.30 + 1.31 + while(nicknames[i] != NULL) { 1.32 + SECITEM_FreeItem(nicknames[i], PR_FALSE); 1.33 + i++; 1.34 + } 1.35 + 1.36 + PORT_Free(nicknames); 1.37 +} 1.38 + 1.39 +/* release the memory taken up by the list of certificates */ 1.40 +static void 1.41 +sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs) 1.42 +{ 1.43 + int i = 0; 1.44 + 1.45 + if(ref_certs == NULL) { 1.46 + return; 1.47 + } 1.48 + 1.49 + while(ref_certs[i] != NULL) { 1.50 + CERT_DestroyCertificate(ref_certs[i]); 1.51 + i++; 1.52 + } 1.53 +} 1.54 + 1.55 +static void 1.56 +sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag) 1.57 +{ 1.58 + int j = 0; 1.59 + j = 0; 1.60 + while(certBag->certAndCRLs[j] != NULL) { 1.61 + SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID); 1.62 + if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) { 1.63 + SEC_PKCS12X509CertCRL *x509; 1.64 + x509 = certBag->certAndCRLs[j]->value.x509; 1.65 + SEC_PKCS7DestroyContentInfo(&x509->certOrCRL); 1.66 + } 1.67 + j++; 1.68 + } 1.69 +} 1.70 + 1.71 +/* destroy all content infos since they were not allocated in common 1.72 + * pool 1.73 + */ 1.74 +static void 1.75 +sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe, 1.76 + SEC_PKCS12Baggage *baggage) 1.77 +{ 1.78 + int i, j; 1.79 + 1.80 + if((safe != NULL) && (safe->contents != NULL)) { 1.81 + i = 0; 1.82 + while(safe->contents[i] != NULL) { 1.83 + SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType); 1.84 + if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) { 1.85 + SEC_PKCS12CertAndCRLBag *certBag; 1.86 + certBag = safe->contents[i]->safeContent.certAndCRLBag; 1.87 + sec_pkcs12_destroy_cinfos_for_cert_bags(certBag); 1.88 + } 1.89 + i++; 1.90 + } 1.91 + } 1.92 + 1.93 + if((baggage != NULL) && (baggage->bags != NULL)) { 1.94 + i = 0; 1.95 + while(baggage->bags[i] != NULL) { 1.96 + if(baggage->bags[i]->unencSecrets != NULL) { 1.97 + j = 0; 1.98 + while(baggage->bags[i]->unencSecrets[j] != NULL) { 1.99 + SECOidTag bagType; 1.100 + bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[j]->safeBagType); 1.101 + if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) { 1.102 + SEC_PKCS12CertAndCRLBag *certBag; 1.103 + certBag = baggage->bags[i]->unencSecrets[j]->safeContent.certAndCRLBag; 1.104 + sec_pkcs12_destroy_cinfos_for_cert_bags(certBag); 1.105 + } 1.106 + j++; 1.107 + } 1.108 + } 1.109 + i++; 1.110 + } 1.111 + } 1.112 +} 1.113 + 1.114 +/* convert the nickname list from a NULL termincated Char list 1.115 + * to a NULL terminated SECItem list 1.116 + */ 1.117 +static SECItem ** 1.118 +sec_pkcs12_convert_nickname_list(char **nicknames) 1.119 +{ 1.120 + SECItem **nicks; 1.121 + int i, j; 1.122 + PRBool error = PR_FALSE; 1.123 + 1.124 + if(nicknames == NULL) { 1.125 + return NULL; 1.126 + } 1.127 + 1.128 + i = j = 0; 1.129 + while(nicknames[i] != NULL) { 1.130 + i++; 1.131 + } 1.132 + 1.133 + /* allocate the space and copy the data */ 1.134 + nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1)); 1.135 + if(nicks != NULL) { 1.136 + for(j = 0; ((j < i) && (error == PR_FALSE)); j++) { 1.137 + nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); 1.138 + if(nicks[j] != NULL) { 1.139 + nicks[j]->data = 1.140 + (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1); 1.141 + if(nicks[j]->data != NULL) { 1.142 + nicks[j]->len = PORT_Strlen(nicknames[j]); 1.143 + PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len); 1.144 + nicks[j]->data[nicks[j]->len] = 0; 1.145 + } else { 1.146 + error = PR_TRUE; 1.147 + } 1.148 + } else { 1.149 + error = PR_TRUE; 1.150 + } 1.151 + } 1.152 + } 1.153 + 1.154 + if(error == PR_TRUE) { 1.155 + for(i = 0; i < j; i++) { 1.156 + SECITEM_FreeItem(nicks[i], PR_TRUE); 1.157 + } 1.158 + PORT_Free(nicks); 1.159 + nicks = NULL; 1.160 + } 1.161 + 1.162 + return nicks; 1.163 +} 1.164 + 1.165 +/* package the certificate add_cert into PKCS12 structures, 1.166 + * retrieve the certificate chain for the cert and return 1.167 + * the packaged contents. 1.168 + * poolp -- common memory pool; 1.169 + * add_cert -- certificate to package up 1.170 + * nickname for the certificate 1.171 + * a return of NULL indicates an error 1.172 + */ 1.173 +static SEC_PKCS12CertAndCRL * 1.174 +sec_pkcs12_get_cert(PLArenaPool *poolp, 1.175 + CERTCertificate *add_cert, 1.176 + SECItem *nickname) 1.177 +{ 1.178 + SEC_PKCS12CertAndCRL *cert; 1.179 + SEC_PKCS7ContentInfo *cinfo; 1.180 + SGNDigestInfo *t_di; 1.181 + void *mark; 1.182 + SECStatus rv; 1.183 + 1.184 + if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) { 1.185 + return NULL; 1.186 + } 1.187 + mark = PORT_ArenaMark(poolp); 1.188 + 1.189 + cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG); 1.190 + if(cert != NULL) { 1.191 + 1.192 + /* copy the nickname */ 1.193 + rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname); 1.194 + if(rv != SECSuccess) { 1.195 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.196 + cert = NULL; 1.197 + } else { 1.198 + 1.199 + /* package the certificate and cert chain into a NULL signer 1.200 + * PKCS 7 SignedData content Info and prepare it for encoding 1.201 + * since we cannot use DER_ANY_TEMPLATE 1.202 + */ 1.203 + cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL); 1.204 + rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL); 1.205 + 1.206 + /* thumbprint the certificate */ 1.207 + if((cinfo != NULL) && (rv == SECSuccess)) 1.208 + { 1.209 + PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo)); 1.210 + t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert); 1.211 + if(t_di != NULL) 1.212 + { 1.213 + /* test */ 1.214 + rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint, 1.215 + t_di); 1.216 + if(rv != SECSuccess) { 1.217 + cert = NULL; 1.218 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.219 + } 1.220 + SGN_DestroyDigestInfo(t_di); 1.221 + } 1.222 + else 1.223 + cert = NULL; 1.224 + } 1.225 + } 1.226 + } 1.227 + 1.228 + if (cert == NULL) { 1.229 + PORT_ArenaRelease(poolp, mark); 1.230 + } else { 1.231 + PORT_ArenaUnmark(poolp, mark); 1.232 + } 1.233 + 1.234 + return cert; 1.235 +} 1.236 + 1.237 +/* package the private key associated with the certificate and 1.238 + * return the appropriate PKCS 12 structure 1.239 + * poolp common memory pool 1.240 + * nickname key nickname 1.241 + * cert -- cert to look up 1.242 + * wincx -- window handle 1.243 + * an error is indicated by a return of NULL 1.244 + */ 1.245 +static SEC_PKCS12PrivateKey * 1.246 +sec_pkcs12_get_private_key(PLArenaPool *poolp, 1.247 + SECItem *nickname, 1.248 + CERTCertificate *cert, 1.249 + void *wincx) 1.250 +{ 1.251 + SECKEYPrivateKeyInfo *pki; 1.252 + SEC_PKCS12PrivateKey *pk; 1.253 + SECStatus rv; 1.254 + void *mark; 1.255 + 1.256 + if((poolp == NULL) || (nickname == NULL)) { 1.257 + return NULL; 1.258 + } 1.259 + 1.260 + mark = PORT_ArenaMark(poolp); 1.261 + 1.262 + /* retrieve key from the data base */ 1.263 + pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx); 1.264 + if(pki == NULL) { 1.265 + PORT_ArenaRelease(poolp, mark); 1.266 + PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); 1.267 + return NULL; 1.268 + } 1.269 + 1.270 + pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp, 1.271 + sizeof(SEC_PKCS12PrivateKey)); 1.272 + if(pk != NULL) { 1.273 + rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData); 1.274 + 1.275 + if(rv == SECSuccess) { 1.276 + /* copy the key into poolp memory space */ 1.277 + rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki); 1.278 + if(rv == SECSuccess) { 1.279 + rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname); 1.280 + } 1.281 + } 1.282 + 1.283 + if(rv != SECSuccess) { 1.284 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.285 + pk = NULL; 1.286 + } 1.287 + } else { 1.288 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.289 + } 1.290 + 1.291 + /* destroy private key, zeroing out data */ 1.292 + SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); 1.293 + if (pk == NULL) { 1.294 + PORT_ArenaRelease(poolp, mark); 1.295 + } else { 1.296 + PORT_ArenaUnmark(poolp, mark); 1.297 + } 1.298 + 1.299 + return pk; 1.300 +} 1.301 + 1.302 +/* get a shrouded key item associated with a certificate 1.303 + * return the appropriate PKCS 12 structure 1.304 + * poolp common memory pool 1.305 + * nickname key nickname 1.306 + * cert -- cert to look up 1.307 + * wincx -- window handle 1.308 + * an error is indicated by a return of NULL 1.309 + */ 1.310 +static SEC_PKCS12ESPVKItem * 1.311 +sec_pkcs12_get_shrouded_key(PLArenaPool *poolp, 1.312 + SECItem *nickname, 1.313 + CERTCertificate *cert, 1.314 + SECOidTag algorithm, 1.315 + SECItem *pwitem, 1.316 + PKCS12UnicodeConvertFunction unicodeFn, 1.317 + void *wincx) 1.318 +{ 1.319 + SECKEYEncryptedPrivateKeyInfo *epki; 1.320 + SEC_PKCS12ESPVKItem *pk; 1.321 + void *mark; 1.322 + SECStatus rv; 1.323 + PK11SlotInfo *slot = NULL; 1.324 + PRBool swapUnicodeBytes = PR_FALSE; 1.325 + 1.326 +#ifdef IS_LITTLE_ENDIAN 1.327 + swapUnicodeBytes = PR_TRUE; 1.328 +#endif 1.329 + 1.330 + if((poolp == NULL) || (nickname == NULL)) 1.331 + return NULL; 1.332 + 1.333 + mark = PORT_ArenaMark(poolp); 1.334 + 1.335 + /* use internal key slot */ 1.336 + slot = PK11_GetInternalKeySlot(); 1.337 + 1.338 + /* retrieve encrypted prviate key */ 1.339 + epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem, 1.340 + nickname, cert, 1, 0, NULL); 1.341 + PK11_FreeSlot(slot); 1.342 + if(epki == NULL) { 1.343 + PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); 1.344 + PORT_ArenaRelease(poolp, mark); 1.345 + return NULL; 1.346 + } 1.347 + 1.348 + /* create a private key and store the data into the poolp memory space */ 1.349 + pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING); 1.350 + if(pk != NULL) { 1.351 + rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData); 1.352 + rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname); 1.353 + pk->espvkCipherText.pkcs8KeyShroud = 1.354 + (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp, 1.355 + sizeof(SECKEYEncryptedPrivateKeyInfo)); 1.356 + if((pk->espvkCipherText.pkcs8KeyShroud != NULL) && (rv == SECSuccess)) { 1.357 + rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp, 1.358 + pk->espvkCipherText.pkcs8KeyShroud, epki); 1.359 + if(rv == SECSuccess) { 1.360 + rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname, 1.361 + PR_TRUE, swapUnicodeBytes); 1.362 + } 1.363 + } 1.364 + 1.365 + if(rv != SECSuccess) { 1.366 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.367 + pk = NULL; 1.368 + } 1.369 + } 1.370 + 1.371 + SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); 1.372 + if(pk == NULL) { 1.373 + PORT_ArenaRelease(poolp, mark); 1.374 + } else { 1.375 + PORT_ArenaUnmark(poolp, mark); 1.376 + } 1.377 + 1.378 + return pk; 1.379 +} 1.380 + 1.381 +/* add a thumbprint to a private key associated certs list 1.382 + * pvk is the area where the list is stored 1.383 + * thumb is the thumbprint to copy 1.384 + * a return of SECFailure indicates an error 1.385 + */ 1.386 +static SECStatus 1.387 +sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk, 1.388 + SGNDigestInfo *thumb) 1.389 +{ 1.390 + SGNDigestInfo **thumb_list = NULL; 1.391 + int nthumbs, size; 1.392 + void *mark, *dummy; 1.393 + SECStatus rv = SECFailure; 1.394 + 1.395 + if((pvk == NULL) || (thumb == NULL)) { 1.396 + return SECFailure; 1.397 + } 1.398 + 1.399 + mark = PORT_ArenaMark(pvk->poolp); 1.400 + 1.401 + thumb_list = pvk->assocCerts; 1.402 + nthumbs = pvk->nThumbs; 1.403 + 1.404 + /* allocate list space needed -- either growing or allocating 1.405 + * list must be NULL terminated 1.406 + */ 1.407 + size = sizeof(SGNDigestInfo *); 1.408 + dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)), 1.409 + (size * (nthumbs + 2))); 1.410 + thumb_list = dummy; 1.411 + if(dummy != NULL) { 1.412 + thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp, 1.413 + sizeof(SGNDigestInfo)); 1.414 + if(thumb_list[nthumbs] != NULL) { 1.415 + SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb); 1.416 + nthumbs += 1; 1.417 + thumb_list[nthumbs] = 0; 1.418 + } else { 1.419 + dummy = NULL; 1.420 + } 1.421 + } 1.422 + 1.423 + if(dummy == NULL) { 1.424 + PORT_ArenaRelease(pvk->poolp, mark); 1.425 + return SECFailure; 1.426 + } 1.427 + 1.428 + pvk->assocCerts = thumb_list; 1.429 + pvk->nThumbs = nthumbs; 1.430 + 1.431 + PORT_ArenaUnmark(pvk->poolp, mark); 1.432 + return SECSuccess; 1.433 +} 1.434 + 1.435 +/* search the list of shrouded keys in the baggage for the desired 1.436 + * name. return a pointer to the item. a return of NULL indicates 1.437 + * that no match was present or that an error occurred. 1.438 + */ 1.439 +static SEC_PKCS12ESPVKItem * 1.440 +sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage, 1.441 + SECItem *name) 1.442 +{ 1.443 + PRBool found = PR_FALSE; 1.444 + SEC_PKCS12ESPVKItem *espvk = NULL; 1.445 + int i, j; 1.446 + SECComparison rv = SECEqual; 1.447 + SECItem *t_name; 1.448 + SEC_PKCS12BaggageItem *bag; 1.449 + 1.450 + if((luggage == NULL) || (name == NULL)) { 1.451 + return NULL; 1.452 + } 1.453 + 1.454 + i = 0; 1.455 + while((found == PR_FALSE) && (i < luggage->luggage_size)) { 1.456 + j = 0; 1.457 + bag = luggage->bags[i]; 1.458 + while((found == PR_FALSE) && (j < bag->nEspvks)) { 1.459 + espvk = bag->espvks[j]; 1.460 + if(espvk->poolp == NULL) { 1.461 + espvk->poolp = luggage->poolp; 1.462 + } 1.463 + t_name = SECITEM_DupItem(&espvk->espvkData.nickname); 1.464 + if(t_name != NULL) { 1.465 + rv = SECITEM_CompareItem(name, t_name); 1.466 + if(rv == SECEqual) { 1.467 + found = PR_TRUE; 1.468 + } 1.469 + SECITEM_FreeItem(t_name, PR_TRUE); 1.470 + } else { 1.471 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.472 + return NULL; 1.473 + } 1.474 + j++; 1.475 + } 1.476 + i++; 1.477 + } 1.478 + 1.479 + if(found != PR_TRUE) { 1.480 + PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME); 1.481 + return NULL; 1.482 + } 1.483 + 1.484 + return espvk; 1.485 +} 1.486 + 1.487 +/* locates a certificate and copies the thumbprint to the 1.488 + * appropriate private key 1.489 + */ 1.490 +static SECStatus 1.491 +sec_pkcs12_propagate_thumbprints(SECItem **nicknames, 1.492 + CERTCertificate **ref_certs, 1.493 + SEC_PKCS12SafeContents *safe, 1.494 + SEC_PKCS12Baggage *baggage) 1.495 +{ 1.496 + SEC_PKCS12CertAndCRL *cert; 1.497 + SEC_PKCS12PrivateKey *key; 1.498 + SEC_PKCS12ESPVKItem *espvk; 1.499 + int i; 1.500 + PRBool error = PR_FALSE; 1.501 + SECStatus rv = SECFailure; 1.502 + 1.503 + if((nicknames == NULL) || (safe == NULL)) { 1.504 + return SECFailure; 1.505 + } 1.506 + 1.507 + i = 0; 1.508 + while((nicknames[i] != NULL) && (error == PR_FALSE)) { 1.509 + /* process all certs */ 1.510 + cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage, 1.511 + SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, 1.512 + nicknames[i], NULL); 1.513 + if(cert != NULL) { 1.514 + /* locate key and copy thumbprint */ 1.515 + key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage, 1.516 + SEC_OID_PKCS12_KEY_BAG_ID, 1.517 + nicknames[i], NULL); 1.518 + if(key != NULL) { 1.519 + key->pvkData.poolp = key->poolp; 1.520 + rv = sec_pkcs12_add_thumbprint(&key->pvkData, 1.521 + &cert->value.x509->thumbprint); 1.522 + if(rv == SECFailure) 1.523 + error = PR_TRUE; /* XXX Set error? */ 1.524 + } 1.525 + 1.526 + /* look in the baggage as well...*/ 1.527 + if((baggage != NULL) && (error == PR_FALSE)) { 1.528 + espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]); 1.529 + if(espvk != NULL) { 1.530 + espvk->espvkData.poolp = espvk->poolp; 1.531 + rv = sec_pkcs12_add_thumbprint(&espvk->espvkData, 1.532 + &cert->value.x509->thumbprint); 1.533 + if(rv == SECFailure) 1.534 + error = PR_TRUE; /* XXX Set error? */ 1.535 + } 1.536 + } 1.537 + } 1.538 + i++; 1.539 + } 1.540 + 1.541 + if(error == PR_TRUE) { 1.542 + return SECFailure; 1.543 + } 1.544 + 1.545 + return SECSuccess; 1.546 +} 1.547 + 1.548 +/* append a safe bag to the end of the safe contents list */ 1.549 +SECStatus 1.550 +sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe, 1.551 + SEC_PKCS12SafeBag *bag) 1.552 +{ 1.553 + int size; 1.554 + void *mark = NULL, *dummy = NULL; 1.555 + 1.556 + if((bag == NULL) || (safe == NULL)) 1.557 + return SECFailure; 1.558 + 1.559 + mark = PORT_ArenaMark(safe->poolp); 1.560 + 1.561 + size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *)); 1.562 + 1.563 + if(safe->safe_size > 0) { 1.564 + dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp, 1.565 + safe->contents, 1.566 + size, 1.567 + (size + sizeof(SEC_PKCS12SafeBag *))); 1.568 + safe->contents = dummy; 1.569 + } else { 1.570 + safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp, 1.571 + (2 * sizeof(SEC_PKCS12SafeBag *))); 1.572 + dummy = safe->contents; 1.573 + } 1.574 + 1.575 + if(dummy == NULL) { 1.576 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.577 + goto loser; 1.578 + } 1.579 + 1.580 + safe->contents[safe->safe_size] = bag; 1.581 + safe->safe_size++; 1.582 + safe->contents[safe->safe_size] = NULL; 1.583 + 1.584 + PORT_ArenaUnmark(safe->poolp, mark); 1.585 + return SECSuccess; 1.586 + 1.587 +loser: 1.588 + PORT_ArenaRelease(safe->poolp, mark); 1.589 + return SECFailure; 1.590 +} 1.591 + 1.592 +/* append a certificate onto the end of a cert bag */ 1.593 +static SECStatus 1.594 +sec_pkcs12_append_cert_to_bag(PLArenaPool *arena, 1.595 + SEC_PKCS12SafeBag *safebag, 1.596 + CERTCertificate *cert, 1.597 + SECItem *nickname) 1.598 +{ 1.599 + int size; 1.600 + void *dummy = NULL, *mark = NULL; 1.601 + SEC_PKCS12CertAndCRL *p12cert; 1.602 + SEC_PKCS12CertAndCRLBag *bag; 1.603 + 1.604 + if((arena == NULL) || (safebag == NULL) || 1.605 + (cert == NULL) || (nickname == NULL)) { 1.606 + return SECFailure; 1.607 + } 1.608 + 1.609 + bag = safebag->safeContent.certAndCRLBag; 1.610 + if(bag == NULL) { 1.611 + return SECFailure; 1.612 + } 1.613 + 1.614 + mark = PORT_ArenaMark(arena); 1.615 + 1.616 + p12cert = sec_pkcs12_get_cert(arena, cert, nickname); 1.617 + if(p12cert == NULL) { 1.618 + PORT_ArenaRelease(bag->poolp, mark); 1.619 + return SECFailure; 1.620 + } 1.621 + 1.622 + size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *); 1.623 + if(bag->bag_size > 0) { 1.624 + dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp, 1.625 + bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *)); 1.626 + bag->certAndCRLs = dummy; 1.627 + } else { 1.628 + bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp, 1.629 + (2 * sizeof(SEC_PKCS12CertAndCRL *))); 1.630 + dummy = bag->certAndCRLs; 1.631 + } 1.632 + 1.633 + if(dummy == NULL) { 1.634 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.635 + goto loser; 1.636 + } 1.637 + 1.638 + bag->certAndCRLs[bag->bag_size] = p12cert; 1.639 + bag->bag_size++; 1.640 + bag->certAndCRLs[bag->bag_size] = NULL; 1.641 + 1.642 + PORT_ArenaUnmark(bag->poolp, mark); 1.643 + return SECSuccess; 1.644 + 1.645 +loser: 1.646 + PORT_ArenaRelease(bag->poolp, mark); 1.647 + return SECFailure; 1.648 +} 1.649 + 1.650 +/* append a key onto the end of a list of keys in a key bag */ 1.651 +SECStatus 1.652 +sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag, 1.653 + SEC_PKCS12PrivateKey *pk) 1.654 +{ 1.655 + void *mark, *dummy; 1.656 + SEC_PKCS12PrivateKeyBag *bag; 1.657 + int size; 1.658 + 1.659 + if((safebag == NULL) || (pk == NULL)) 1.660 + return SECFailure; 1.661 + 1.662 + bag = safebag->safeContent.keyBag; 1.663 + if(bag == NULL) { 1.664 + return SECFailure; 1.665 + } 1.666 + 1.667 + mark = PORT_ArenaMark(bag->poolp); 1.668 + 1.669 + size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *)); 1.670 + 1.671 + if(bag->bag_size > 0) { 1.672 + dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp, 1.673 + bag->privateKeys, 1.674 + size, 1.675 + size + sizeof(SEC_PKCS12PrivateKey *)); 1.676 + bag->privateKeys = dummy; 1.677 + } else { 1.678 + bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp, 1.679 + (2 * sizeof(SEC_PKCS12PrivateKey *))); 1.680 + dummy = bag->privateKeys; 1.681 + } 1.682 + 1.683 + if(dummy == NULL) { 1.684 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.685 + goto loser; 1.686 + } 1.687 + 1.688 + bag->privateKeys[bag->bag_size] = pk; 1.689 + bag->bag_size++; 1.690 + bag->privateKeys[bag->bag_size] = NULL; 1.691 + 1.692 + PORT_ArenaUnmark(bag->poolp, mark); 1.693 + return SECSuccess; 1.694 + 1.695 +loser: 1.696 + /* XXX Free memory? */ 1.697 + PORT_ArenaRelease(bag->poolp, mark); 1.698 + return SECFailure; 1.699 +} 1.700 + 1.701 +/* append a safe bag to the baggage area */ 1.702 +static SECStatus 1.703 +sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag, 1.704 + SEC_PKCS12SafeBag *u_bag) 1.705 +{ 1.706 + int size; 1.707 + void *mark = NULL, *dummy = NULL; 1.708 + 1.709 + if((bag == NULL) || (u_bag == NULL)) 1.710 + return SECFailure; 1.711 + 1.712 + mark = PORT_ArenaMark(bag->poolp); 1.713 + 1.714 + /* dump things into the first bag */ 1.715 + size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *); 1.716 + dummy = PORT_ArenaGrow(bag->poolp, 1.717 + bag->unencSecrets, size, 1.718 + size + sizeof(SEC_PKCS12SafeBag *)); 1.719 + bag->unencSecrets = dummy; 1.720 + if(dummy == NULL) { 1.721 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.722 + goto loser; 1.723 + } 1.724 + 1.725 + bag->unencSecrets[bag->nSecrets] = u_bag; 1.726 + bag->nSecrets++; 1.727 + bag->unencSecrets[bag->nSecrets] = NULL; 1.728 + 1.729 + PORT_ArenaUnmark(bag->poolp, mark); 1.730 + return SECSuccess; 1.731 + 1.732 +loser: 1.733 + PORT_ArenaRelease(bag->poolp, mark); 1.734 + return SECFailure; 1.735 +} 1.736 + 1.737 +/* gather up all certificates and keys and package them up 1.738 + * in the safe, baggage, or both. 1.739 + * nicknames is the list of nicknames and corresponding certs in ref_certs 1.740 + * ref_certs a null terminated list of certificates 1.741 + * rSafe, rBaggage -- return areas for safe and baggage 1.742 + * shroud_keys -- store keys externally 1.743 + * pwitem -- password for computing integrity mac and encrypting contents 1.744 + * wincx -- window handle 1.745 + * 1.746 + * if a failure occurs, an error is set and SECFailure returned. 1.747 + */ 1.748 +static SECStatus 1.749 +sec_pkcs12_package_certs_and_keys(SECItem **nicknames, 1.750 + CERTCertificate **ref_certs, 1.751 + PRBool unencryptedCerts, 1.752 + SEC_PKCS12SafeContents **rSafe, 1.753 + SEC_PKCS12Baggage **rBaggage, 1.754 + PRBool shroud_keys, 1.755 + SECOidTag shroud_alg, 1.756 + SECItem *pwitem, 1.757 + PKCS12UnicodeConvertFunction unicodeFn, 1.758 + void *wincx) 1.759 +{ 1.760 + PLArenaPool *permArena; 1.761 + SEC_PKCS12SafeContents *safe = NULL; 1.762 + SEC_PKCS12Baggage *baggage = NULL; 1.763 + 1.764 + SECStatus rv = SECFailure; 1.765 + PRBool problem = PR_FALSE; 1.766 + 1.767 + SEC_PKCS12ESPVKItem *espvk = NULL; 1.768 + SEC_PKCS12PrivateKey *pk = NULL; 1.769 + CERTCertificate *add_cert = NULL; 1.770 + SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL; 1.771 + SEC_PKCS12BaggageItem *external_bag = NULL; 1.772 + int ncerts = 0, nkeys = 0; 1.773 + int i; 1.774 + 1.775 + if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) { 1.776 + return SECFailure; 1.777 + } 1.778 + 1.779 + *rBaggage = baggage; 1.780 + *rSafe = safe; 1.781 + 1.782 + permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1.783 + if(permArena == NULL) { 1.784 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.785 + return SECFailure; 1.786 + } 1.787 + 1.788 + /* allocate structures */ 1.789 + safe = sec_pkcs12_create_safe_contents(permArena); 1.790 + if(safe == NULL) { 1.791 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.792 + rv = SECFailure; 1.793 + goto loser; 1.794 + } 1.795 + 1.796 + certbag = sec_pkcs12_create_safe_bag(permArena, 1.797 + SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID); 1.798 + if(certbag == NULL) { 1.799 + rv = SECFailure; 1.800 + goto loser; 1.801 + } 1.802 + 1.803 + if(shroud_keys != PR_TRUE) { 1.804 + keybag = sec_pkcs12_create_safe_bag(permArena, 1.805 + SEC_OID_PKCS12_KEY_BAG_ID); 1.806 + if(keybag == NULL) { 1.807 + rv = SECFailure; 1.808 + goto loser; 1.809 + } 1.810 + } 1.811 + 1.812 + if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) { 1.813 + baggage = sec_pkcs12_create_baggage(permArena); 1.814 + if(baggage == NULL) { 1.815 + rv = SECFailure; 1.816 + goto loser; 1.817 + } 1.818 + external_bag = sec_pkcs12_create_external_bag(baggage); 1.819 + } 1.820 + 1.821 + /* package keys and certs */ 1.822 + i = 0; 1.823 + while((nicknames[i] != NULL) && (problem == PR_FALSE)) { 1.824 + if(ref_certs[i] != NULL) { 1.825 + /* append cert to bag o certs */ 1.826 + rv = sec_pkcs12_append_cert_to_bag(permArena, certbag, 1.827 + ref_certs[i], 1.828 + nicknames[i]); 1.829 + if(rv == SECFailure) { 1.830 + problem = PR_FALSE; 1.831 + } else { 1.832 + ncerts++; 1.833 + } 1.834 + 1.835 + if(rv == SECSuccess) { 1.836 + /* package up them keys */ 1.837 + if(shroud_keys == PR_TRUE) { 1.838 + espvk = sec_pkcs12_get_shrouded_key(permArena, 1.839 + nicknames[i], 1.840 + ref_certs[i], 1.841 + shroud_alg, 1.842 + pwitem, unicodeFn, 1.843 + wincx); 1.844 + if(espvk != NULL) { 1.845 + rv = sec_pkcs12_append_shrouded_key(external_bag, espvk); 1.846 + SECITEM_CopyItem(permArena, &espvk->derCert, 1.847 + &ref_certs[i]->derCert); 1.848 + } else { 1.849 + rv = SECFailure; 1.850 + } 1.851 + } else { 1.852 + pk = sec_pkcs12_get_private_key(permArena, nicknames[i], 1.853 + ref_certs[i], wincx); 1.854 + if(pk != NULL) { 1.855 + rv = sec_pkcs12_append_key_to_bag(keybag, pk); 1.856 + SECITEM_CopyItem(permArena, &espvk->derCert, 1.857 + &ref_certs[i]->derCert); 1.858 + } else { 1.859 + rv = SECFailure; 1.860 + } 1.861 + } 1.862 + 1.863 + if(rv == SECFailure) { 1.864 + problem = PR_TRUE; 1.865 + } else { 1.866 + nkeys++; 1.867 + } 1.868 + } 1.869 + } else { 1.870 + /* handle only keys here ? */ 1.871 + problem = PR_TRUE; 1.872 + } 1.873 + i++; 1.874 + } 1.875 + 1.876 + /* let success fall through */ 1.877 +loser: 1.878 + if(problem == PR_FALSE) { 1.879 + /* if we have certs, we want to append the cert bag to the 1.880 + * appropriate area 1.881 + */ 1.882 + if(ncerts > 0) { 1.883 + if(unencryptedCerts != PR_TRUE) { 1.884 + rv = sec_pkcs12_append_safe_bag(safe, certbag); 1.885 + } else { 1.886 + rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag); 1.887 + } 1.888 + } else { 1.889 + rv = SECSuccess; 1.890 + } 1.891 + 1.892 + /* append key bag, if they are stored in safe contents */ 1.893 + if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) { 1.894 + rv = sec_pkcs12_append_safe_bag(safe, keybag); 1.895 + } 1.896 + } else { 1.897 + rv = SECFailure; 1.898 + } 1.899 + 1.900 + /* if baggage not used, NULLify it */ 1.901 + if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) { 1.902 + if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) && 1.903 + ((shroud_keys == PR_TRUE) && (nkeys == 0))) 1.904 + baggage = NULL; 1.905 + } else { 1.906 + baggage = NULL; 1.907 + } 1.908 + 1.909 + if((problem == PR_TRUE) || (rv == SECFailure)) { 1.910 + PORT_FreeArena(permArena, PR_TRUE); 1.911 + rv = SECFailure; 1.912 + baggage = NULL; 1.913 + safe = NULL; 1.914 + } 1.915 + 1.916 + *rBaggage = baggage; 1.917 + *rSafe = safe; 1.918 + 1.919 + return rv; 1.920 +} 1.921 + 1.922 +/* DER encode the safe contents and return a SECItem. if an error 1.923 + * occurs, NULL is returned. 1.924 + */ 1.925 +static SECItem * 1.926 +sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe) 1.927 +{ 1.928 + SECItem *dsafe = NULL, *tsafe; 1.929 + void *dummy = NULL; 1.930 + PLArenaPool *arena; 1.931 + 1.932 + if(safe == NULL) { 1.933 + return NULL; 1.934 + } 1.935 + 1.936 +/* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE); 1.937 + if(rv != SECSuccess) { 1.938 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.939 + return NULL; 1.940 + }*/ 1.941 + 1.942 + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1.943 + if(arena == NULL) { 1.944 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.945 + return NULL; 1.946 + } 1.947 + 1.948 + tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem)); 1.949 + if(tsafe != NULL) { 1.950 + dummy = SEC_ASN1EncodeItem(arena, tsafe, safe, 1.951 + SEC_PKCS12SafeContentsTemplate); 1.952 + if(dummy != NULL) { 1.953 + dsafe = SECITEM_DupItem(tsafe); 1.954 + } else { 1.955 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.956 + } 1.957 + } else { 1.958 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.959 + } 1.960 + 1.961 + PORT_FreeArena(arena, PR_TRUE); 1.962 + 1.963 + return dsafe; 1.964 +} 1.965 + 1.966 +/* prepare the authenicated safe for encoding and encode it. 1.967 + * baggage is copied to the appropriate area, safe is encoded and 1.968 + * encrypted. the version and transport mode are set on the asafe. 1.969 + * the whole ball of wax is then der encoded and packaged up into 1.970 + * data content info 1.971 + * safe -- container of certs and keys, is encrypted. 1.972 + * baggage -- container of certs and keys, keys assumed to be encrypted by 1.973 + * another method, certs are in the clear 1.974 + * algorithm -- algorithm by which to encrypt safe 1.975 + * pwitem -- password for encryption 1.976 + * wincx - window handle 1.977 + * 1.978 + * return of NULL is an error condition. 1.979 + */ 1.980 +static SEC_PKCS7ContentInfo * 1.981 +sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe, 1.982 + SEC_PKCS12Baggage *baggage, 1.983 + SECOidTag algorithm, 1.984 + SECItem *pwitem, 1.985 + PKCS12UnicodeConvertFunction unicodeFn, 1.986 + void *wincx) 1.987 +{ 1.988 + SECItem *src = NULL, *dest = NULL, *psalt = NULL; 1.989 + PLArenaPool *poolp; 1.990 + SEC_PKCS12AuthenticatedSafe *asafe; 1.991 + SEC_PKCS7ContentInfo *safe_cinfo = NULL; 1.992 + SEC_PKCS7ContentInfo *asafe_cinfo = NULL; 1.993 + void *dummy; 1.994 + SECStatus rv = SECSuccess; 1.995 + PRBool swapUnicodeBytes = PR_FALSE; 1.996 + 1.997 +#ifdef IS_LITTLE_ENDIAN 1.998 + swapUnicodeBytes = PR_TRUE; 1.999 +#endif 1.1000 + 1.1001 + if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL)) 1.1002 + return NULL; 1.1003 + 1.1004 + poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1.1005 + if(poolp == NULL) { 1.1006 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1007 + return NULL; 1.1008 + } 1.1009 + 1.1010 + /* prepare authenticated safe for encode */ 1.1011 + asafe = sec_pkcs12_new_asafe(poolp); 1.1012 + if(asafe != NULL) { 1.1013 + 1.1014 + /* set version */ 1.1015 + dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version, 1.1016 + SEC_PKCS12_PFX_VERSION); 1.1017 + if(dummy == NULL) { 1.1018 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1019 + rv = SECFailure; 1.1020 + goto loser; 1.1021 + } 1.1022 + 1.1023 + /* generate the privacy salt used to create virtual pwd */ 1.1024 + psalt = sec_pkcs12_generate_salt(); 1.1025 + if(psalt != NULL) { 1.1026 + rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt, 1.1027 + psalt); 1.1028 + if(rv == SECSuccess) { 1.1029 + asafe->privacySalt.len *= 8; 1.1030 + } 1.1031 + else { 1.1032 + SECITEM_ZfreeItem(psalt, PR_TRUE); 1.1033 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1034 + goto loser; 1.1035 + } 1.1036 + } 1.1037 + 1.1038 + if((psalt == NULL) || (rv == SECFailure)) { 1.1039 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1040 + rv = SECFailure; 1.1041 + goto loser; 1.1042 + } 1.1043 + 1.1044 + /* package up safe contents */ 1.1045 + if(safe != NULL) 1.1046 + { 1.1047 + safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx); 1.1048 + if((safe_cinfo != NULL) && (safe->safe_size > 0)) { 1.1049 + /* encode the safe and encrypt the contents of the 1.1050 + * content info 1.1051 + */ 1.1052 + src = sec_pkcs12_encode_safe_contents(safe); 1.1053 + 1.1054 + if(src != NULL) { 1.1055 + rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len); 1.1056 + SECITEM_ZfreeItem(src, PR_TRUE); 1.1057 + if(rv == SECSuccess) { 1.1058 + SECItem *vpwd; 1.1059 + vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt, 1.1060 + unicodeFn, swapUnicodeBytes); 1.1061 + if(vpwd != NULL) { 1.1062 + rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo, 1.1063 + vpwd, wincx); 1.1064 + SECITEM_ZfreeItem(vpwd, PR_TRUE); 1.1065 + } else { 1.1066 + rv = SECFailure; 1.1067 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1068 + } 1.1069 + } else { 1.1070 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1071 + } 1.1072 + } else { 1.1073 + rv = SECFailure; 1.1074 + } 1.1075 + } else if(safe->safe_size > 0) { 1.1076 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1077 + goto loser; 1.1078 + } else { 1.1079 + /* case where there is NULL content in the safe contents */ 1.1080 + rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0); 1.1081 + if(rv != SECFailure) { 1.1082 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1083 + } 1.1084 + } 1.1085 + 1.1086 + if(rv != SECSuccess) { 1.1087 + SEC_PKCS7DestroyContentInfo(safe_cinfo); 1.1088 + safe_cinfo = NULL; 1.1089 + goto loser; 1.1090 + } 1.1091 + 1.1092 + asafe->safe = safe_cinfo; 1.1093 + /* 1.1094 + PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo)); 1.1095 + */ 1.1096 + } 1.1097 + 1.1098 + /* copy the baggage to the authenticated safe baggage if present */ 1.1099 + if(baggage != NULL) { 1.1100 + PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage)); 1.1101 + } 1.1102 + 1.1103 + /* encode authenticated safe and store it in a Data content info */ 1.1104 + dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem)); 1.1105 + if(dest != NULL) { 1.1106 + dummy = SEC_ASN1EncodeItem(poolp, dest, asafe, 1.1107 + SEC_PKCS12AuthenticatedSafeTemplate); 1.1108 + if(dummy != NULL) { 1.1109 + asafe_cinfo = SEC_PKCS7CreateData(); 1.1110 + if(asafe_cinfo != NULL) { 1.1111 + rv = SEC_PKCS7SetContent(asafe_cinfo, 1.1112 + (char *)dest->data, 1.1113 + dest->len); 1.1114 + if(rv != SECSuccess) { 1.1115 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1116 + SEC_PKCS7DestroyContentInfo(asafe_cinfo); 1.1117 + asafe_cinfo = NULL; 1.1118 + } 1.1119 + } 1.1120 + } else { 1.1121 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1122 + rv = SECFailure; 1.1123 + } 1.1124 + } 1.1125 + } 1.1126 + 1.1127 +loser: 1.1128 + PORT_FreeArena(poolp, PR_TRUE); 1.1129 + if(safe_cinfo != NULL) { 1.1130 + SEC_PKCS7DestroyContentInfo(safe_cinfo); 1.1131 + } 1.1132 + if(psalt != NULL) { 1.1133 + SECITEM_ZfreeItem(psalt, PR_TRUE); 1.1134 + } 1.1135 + 1.1136 + if(rv == SECFailure) { 1.1137 + return NULL; 1.1138 + } 1.1139 + 1.1140 + return asafe_cinfo; 1.1141 +} 1.1142 + 1.1143 +/* generates the PFX and computes the mac on the authenticated safe 1.1144 + * NULL implies an error 1.1145 + */ 1.1146 +static SEC_PKCS12PFXItem * 1.1147 +sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo, 1.1148 + PRBool do_mac, 1.1149 + SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn) 1.1150 +{ 1.1151 + SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL; 1.1152 + SEC_PKCS12PFXItem *pfx; 1.1153 + SECStatus rv = SECFailure; 1.1154 + SGNDigestInfo *di; 1.1155 + SECItem *vpwd; 1.1156 + PRBool swapUnicodeBytes = PR_FALSE; 1.1157 + 1.1158 +#ifdef IS_LITTLE_ENDIAN 1.1159 + swapUnicodeBytes = PR_TRUE; 1.1160 +#endif 1.1161 + 1.1162 + if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) { 1.1163 + return NULL; 1.1164 + } 1.1165 + 1.1166 + /* allocate new pfx structure */ 1.1167 + pfx = sec_pkcs12_new_pfx(); 1.1168 + if(pfx == NULL) { 1.1169 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1170 + return NULL; 1.1171 + } 1.1172 + 1.1173 + PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo)); 1.1174 + if(do_mac == PR_TRUE) { 1.1175 + 1.1176 + /* salt for computing mac */ 1.1177 + salt = sec_pkcs12_generate_salt(); 1.1178 + if(salt != NULL) { 1.1179 + rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt); 1.1180 + pfx->macData.macSalt.len *= 8; 1.1181 + 1.1182 + vpwd = sec_pkcs12_create_virtual_password(pwitem, salt, 1.1183 + unicodeFn, swapUnicodeBytes); 1.1184 + if(vpwd == NULL) { 1.1185 + rv = SECFailure; 1.1186 + key = NULL; 1.1187 + } else { 1.1188 + key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1, 1.1189 + salt, vpwd); 1.1190 + SECITEM_ZfreeItem(vpwd, PR_TRUE); 1.1191 + } 1.1192 + 1.1193 + if((key != NULL) && (rv == SECSuccess)) { 1.1194 + dest = SEC_PKCS7GetContent(cinfo); 1.1195 + if(dest != NULL) { 1.1196 + 1.1197 + /* compute mac on data -- for password integrity mode */ 1.1198 + mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE); 1.1199 + if(mac != NULL) { 1.1200 + di = SGN_CreateDigestInfo(SEC_OID_SHA1, 1.1201 + mac->data, mac->len); 1.1202 + if(di != NULL) { 1.1203 + rv = SGN_CopyDigestInfo(pfx->poolp, 1.1204 + &pfx->macData.safeMac, di); 1.1205 + SGN_DestroyDigestInfo(di); 1.1206 + } else { 1.1207 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1208 + } 1.1209 + SECITEM_ZfreeItem(mac, PR_TRUE); 1.1210 + } 1.1211 + } else { 1.1212 + rv = SECFailure; 1.1213 + } 1.1214 + } else { 1.1215 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1216 + rv = SECFailure; 1.1217 + } 1.1218 + 1.1219 + if(key != NULL) { 1.1220 + SECITEM_ZfreeItem(key, PR_TRUE); 1.1221 + } 1.1222 + SECITEM_ZfreeItem(salt, PR_TRUE); 1.1223 + } 1.1224 + } 1.1225 + 1.1226 + if(rv == SECFailure) { 1.1227 + SEC_PKCS12DestroyPFX(pfx); 1.1228 + pfx = NULL; 1.1229 + } 1.1230 + 1.1231 + return pfx; 1.1232 +} 1.1233 + 1.1234 +/* der encode the pfx */ 1.1235 +static SECItem * 1.1236 +sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx) 1.1237 +{ 1.1238 + SECItem *dest; 1.1239 + void *dummy; 1.1240 + 1.1241 + if(pfx == NULL) { 1.1242 + return NULL; 1.1243 + } 1.1244 + 1.1245 + dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); 1.1246 + if(dest == NULL) { 1.1247 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1248 + return NULL; 1.1249 + } 1.1250 + 1.1251 + dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate); 1.1252 + if(dummy == NULL) { 1.1253 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.1254 + SECITEM_ZfreeItem(dest, PR_TRUE); 1.1255 + dest = NULL; 1.1256 + } 1.1257 + 1.1258 + return dest; 1.1259 +} 1.1260 + 1.1261 +SECItem * 1.1262 +SEC_PKCS12GetPFX(char **nicknames, 1.1263 + CERTCertificate **ref_certs, 1.1264 + PRBool shroud_keys, 1.1265 + SEC_PKCS5GetPBEPassword pbef, 1.1266 + void *pbearg, 1.1267 + PKCS12UnicodeConvertFunction unicodeFn, 1.1268 + void *wincx) 1.1269 +{ 1.1270 + SECItem **nicks = NULL; 1.1271 + SEC_PKCS12PFXItem *pfx = NULL; 1.1272 + SEC_PKCS12Baggage *baggage = NULL; 1.1273 + SEC_PKCS12SafeContents *safe = NULL; 1.1274 + SEC_PKCS7ContentInfo *cinfo = NULL; 1.1275 + SECStatus rv = SECFailure; 1.1276 + SECItem *dest = NULL, *pwitem = NULL; 1.1277 + PRBool problem = PR_FALSE; 1.1278 + PRBool unencryptedCerts; 1.1279 + SECOidTag shroud_alg, safe_alg; 1.1280 + 1.1281 + /* how should we encrypt certs ? */ 1.1282 + unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed(); 1.1283 + if(!unencryptedCerts) { 1.1284 + safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm(); 1.1285 + if(safe_alg == SEC_OID_UNKNOWN) { 1.1286 + safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm(); 1.1287 + } 1.1288 + if(safe_alg == SEC_OID_UNKNOWN) { 1.1289 + unencryptedCerts = PR_TRUE; 1.1290 + /* for export where no encryption is allowed, we still need 1.1291 + * to encrypt the NULL contents per the spec. encrypted info 1.1292 + * is known plaintext, so it shouldn't be a problem. 1.1293 + */ 1.1294 + safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC; 1.1295 + } 1.1296 + } else { 1.1297 + /* for export where no encryption is allowed, we still need 1.1298 + * to encrypt the NULL contents per the spec. encrypted info 1.1299 + * is known plaintext, so it shouldn't be a problem. 1.1300 + */ 1.1301 + safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC; 1.1302 + } 1.1303 + 1.1304 + /* keys are always stored with triple DES */ 1.1305 + shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC; 1.1306 + 1.1307 + /* check for FIPS, if so, do not encrypt certs */ 1.1308 + if(PK11_IsFIPS() && !unencryptedCerts) { 1.1309 + unencryptedCerts = PR_TRUE; 1.1310 + } 1.1311 + 1.1312 + if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) { 1.1313 + problem = PR_TRUE; 1.1314 + goto loser; 1.1315 + } 1.1316 + 1.1317 + 1.1318 + /* get password */ 1.1319 + pwitem = (*pbef)(pbearg); 1.1320 + if(pwitem == NULL) { 1.1321 + problem = PR_TRUE; 1.1322 + goto loser; 1.1323 + } 1.1324 + nicks = sec_pkcs12_convert_nickname_list(nicknames); 1.1325 + 1.1326 + /* get safe and baggage */ 1.1327 + rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts, 1.1328 + &safe, &baggage, shroud_keys, 1.1329 + shroud_alg, pwitem, unicodeFn, wincx); 1.1330 + if(rv == SECFailure) { 1.1331 + problem = PR_TRUE; 1.1332 + } 1.1333 + 1.1334 + if((safe != NULL) && (problem == PR_FALSE)) { 1.1335 + /* copy thumbprints */ 1.1336 + rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage); 1.1337 + 1.1338 + /* package everything up into AuthenticatedSafe */ 1.1339 + cinfo = sec_pkcs12_get_auth_safe(safe, baggage, 1.1340 + safe_alg, pwitem, unicodeFn, wincx); 1.1341 + 1.1342 + sec_pkcs12_destroy_cert_content_infos(safe, baggage); 1.1343 + 1.1344 + /* get the pfx and mac it */ 1.1345 + if(cinfo != NULL) { 1.1346 + pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn); 1.1347 + if(pfx != NULL) { 1.1348 + dest = sec_pkcs12_encode_pfx(pfx); 1.1349 + SEC_PKCS12DestroyPFX(pfx); 1.1350 + } 1.1351 + SEC_PKCS7DestroyContentInfo(cinfo); 1.1352 + } 1.1353 + 1.1354 + if(safe != NULL) { 1.1355 + PORT_FreeArena(safe->poolp, PR_TRUE); 1.1356 + } 1.1357 + } else { 1.1358 + if(safe != NULL) { 1.1359 + PORT_FreeArena(safe->poolp, PR_TRUE); 1.1360 + } 1.1361 + } 1.1362 + 1.1363 +loser: 1.1364 + if(nicks != NULL) { 1.1365 + sec_pkcs12_destroy_nickname_list(nicks); 1.1366 + } 1.1367 + 1.1368 + if(ref_certs != NULL) { 1.1369 + sec_pkcs12_destroy_certificate_list(ref_certs); 1.1370 + } 1.1371 + 1.1372 + if(pwitem != NULL) { 1.1373 + SECITEM_ZfreeItem(pwitem, PR_TRUE); 1.1374 + } 1.1375 + 1.1376 + if(problem == PR_TRUE) { 1.1377 + dest = NULL; 1.1378 + } 1.1379 + 1.1380 + return dest; 1.1381 +}